@contember/engine-content-api 1.1.2 → 1.2.0-alpha.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (352) hide show
  1. package/dist/src/acl/EvaluatedPredicateReplacer.d.ts +9 -0
  2. package/dist/src/acl/EvaluatedPredicateReplacer.d.ts.map +1 -0
  3. package/dist/src/acl/EvaluatedPredicateReplacer.js +31 -0
  4. package/dist/src/acl/EvaluatedPredicateReplacer.js.map +1 -0
  5. package/dist/src/acl/PermissionFactory.d.ts.map +1 -1
  6. package/dist/src/acl/PermissionFactory.js +15 -11
  7. package/dist/src/acl/PermissionFactory.js.map +1 -1
  8. package/dist/src/acl/PredicateFactory.d.ts +4 -2
  9. package/dist/src/acl/PredicateFactory.d.ts.map +1 -1
  10. package/dist/src/acl/PredicateFactory.js +17 -6
  11. package/dist/src/acl/PredicateFactory.js.map +1 -1
  12. package/dist/src/acl/PredicatesInjector.d.ts +1 -1
  13. package/dist/src/acl/PredicatesInjector.d.ts.map +1 -1
  14. package/dist/src/acl/PredicatesInjector.js +16 -19
  15. package/dist/src/acl/PredicatesInjector.js.map +1 -1
  16. package/dist/src/acl/VariableInjector.d.ts +0 -1
  17. package/dist/src/acl/VariableInjector.d.ts.map +1 -1
  18. package/dist/src/acl/VariableInjector.js +4 -14
  19. package/dist/src/acl/VariableInjector.js.map +1 -1
  20. package/dist/src/acl/VariableUtils.d.ts +2 -13
  21. package/dist/src/acl/VariableUtils.d.ts.map +1 -1
  22. package/dist/src/acl/VariableUtils.js +5 -16
  23. package/dist/src/acl/VariableUtils.js.map +1 -1
  24. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducerExecutionHandler.d.ts +0 -1
  25. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducerExecutionHandler.d.ts.map +1 -1
  26. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducerExecutionHandler.js +14 -15
  27. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducerExecutionHandler.js.map +1 -1
  28. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.d.ts +1 -1
  29. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.d.ts.map +1 -1
  30. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.js +1 -1
  31. package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.js.map +1 -1
  32. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyCountVisitor.d.ts +5 -4
  33. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyCountVisitor.d.ts.map +1 -1
  34. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyCountVisitor.js +29 -20
  35. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyCountVisitor.js.map +1 -1
  36. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyExecutionHandler.d.ts.map +1 -1
  37. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyExecutionHandler.js +2 -2
  38. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyExecutionHandler.js.map +1 -1
  39. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.d.ts +3 -3
  40. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.d.ts.map +1 -1
  41. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.js +3 -3
  42. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.js.map +1 -1
  43. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyNodesVisitor.d.ts +5 -4
  44. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyNodesVisitor.d.ts.map +1 -1
  45. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyNodesVisitor.js +29 -20
  46. package/dist/src/extensions/paginatedHasMany/PaginatedHasManyNodesVisitor.js.map +1 -1
  47. package/dist/src/input-validation/ColumnValueResolver.d.ts +4 -3
  48. package/dist/src/input-validation/ColumnValueResolver.d.ts.map +1 -1
  49. package/dist/src/input-validation/ColumnValueResolver.js.map +1 -1
  50. package/dist/src/input-validation/EntityRulesResolver.js +4 -4
  51. package/dist/src/input-validation/EntityRulesResolver.js.map +1 -1
  52. package/dist/src/input-validation/QueryAstFactory.js +1 -1
  53. package/dist/src/input-validation/QueryAstFactory.js.map +1 -1
  54. package/dist/src/input-validation/ValidationContext.d.ts +2 -2
  55. package/dist/src/input-validation/ValidationContext.d.ts.map +1 -1
  56. package/dist/src/input-validation/ValidationContext.js.map +1 -1
  57. package/dist/src/input-validation/ValidationDataSelector.d.ts.map +1 -1
  58. package/dist/src/input-validation/ValidationDataSelector.js +1 -1
  59. package/dist/src/input-validation/ValidationDataSelector.js.map +1 -1
  60. package/dist/src/input-validation/preValidation/CreateInputPreValidationProcessor.d.ts +7 -8
  61. package/dist/src/input-validation/preValidation/CreateInputPreValidationProcessor.d.ts.map +1 -1
  62. package/dist/src/input-validation/preValidation/CreateInputPreValidationProcessor.js.map +1 -1
  63. package/dist/src/input-validation/preValidation/InputPreValidator.js +4 -4
  64. package/dist/src/input-validation/preValidation/InputPreValidator.js.map +1 -1
  65. package/dist/src/input-validation/preValidation/UpdateInputPreValidationProcessor.d.ts +7 -8
  66. package/dist/src/input-validation/preValidation/UpdateInputPreValidationProcessor.d.ts.map +1 -1
  67. package/dist/src/input-validation/preValidation/UpdateInputPreValidationProcessor.js.map +1 -1
  68. package/dist/src/inputProcessing/CreateInputProcessor.d.ts +8 -9
  69. package/dist/src/inputProcessing/CreateInputProcessor.d.ts.map +1 -1
  70. package/dist/src/inputProcessing/CreateInputVisitor.d.ts +7 -7
  71. package/dist/src/inputProcessing/CreateInputVisitor.d.ts.map +1 -1
  72. package/dist/src/inputProcessing/CreateInputVisitor.js +15 -46
  73. package/dist/src/inputProcessing/CreateInputVisitor.js.map +1 -1
  74. package/dist/src/inputProcessing/UpdateInputProcessor.d.ts +8 -9
  75. package/dist/src/inputProcessing/UpdateInputProcessor.d.ts.map +1 -1
  76. package/dist/src/inputProcessing/UpdateInputVisitor.d.ts +7 -7
  77. package/dist/src/inputProcessing/UpdateInputVisitor.d.ts.map +1 -1
  78. package/dist/src/inputProcessing/UpdateInputVisitor.js +13 -28
  79. package/dist/src/inputProcessing/UpdateInputVisitor.js.map +1 -1
  80. package/dist/src/inputProcessing/index.d.ts +0 -1
  81. package/dist/src/inputProcessing/index.d.ts.map +1 -1
  82. package/dist/src/inputProcessing/index.js +0 -1
  83. package/dist/src/inputProcessing/index.js.map +1 -1
  84. package/dist/src/introspection/IntrospectionSchemaFactory.js +7 -7
  85. package/dist/src/introspection/IntrospectionSchemaFactory.js.map +1 -1
  86. package/dist/src/introspection/content-schema.types.d.ts +19 -223
  87. package/dist/src/introspection/content-schema.types.d.ts.map +1 -1
  88. package/dist/src/introspection/content-schema.types.js +2 -2
  89. package/dist/src/introspection/content-schema.types.js.map +1 -1
  90. package/dist/src/mapper/Mapper.d.ts +6 -6
  91. package/dist/src/mapper/Mapper.d.ts.map +1 -1
  92. package/dist/src/mapper/Mapper.js +28 -23
  93. package/dist/src/mapper/Mapper.js.map +1 -1
  94. package/dist/src/mapper/MapperContainer.d.ts.map +1 -1
  95. package/dist/src/mapper/MapperContainer.js +7 -4
  96. package/dist/src/mapper/MapperContainer.js.map +1 -1
  97. package/dist/src/mapper/delete/DeleteExecutor.js +3 -3
  98. package/dist/src/mapper/delete/DeleteExecutor.js.map +1 -1
  99. package/dist/src/mapper/insert/SqlCreateInputProcessor.d.ts +4 -2
  100. package/dist/src/mapper/insert/SqlCreateInputProcessor.d.ts.map +1 -1
  101. package/dist/src/mapper/insert/SqlCreateInputProcessor.js.map +1 -1
  102. package/dist/src/mapper/select/JoinVisitor.d.ts +6 -6
  103. package/dist/src/mapper/select/JoinVisitor.d.ts.map +1 -1
  104. package/dist/src/mapper/select/JoinVisitor.js +6 -6
  105. package/dist/src/mapper/select/JoinVisitor.js.map +1 -1
  106. package/dist/src/mapper/select/RelationFetcher.d.ts +32 -5
  107. package/dist/src/mapper/select/RelationFetcher.d.ts.map +1 -1
  108. package/dist/src/mapper/select/RelationFetcher.js +37 -15
  109. package/dist/src/mapper/select/RelationFetcher.js.map +1 -1
  110. package/dist/src/mapper/select/SelectBuilder.d.ts +2 -1
  111. package/dist/src/mapper/select/SelectBuilder.d.ts.map +1 -1
  112. package/dist/src/mapper/select/SelectBuilder.js +4 -2
  113. package/dist/src/mapper/select/SelectBuilder.js.map +1 -1
  114. package/dist/src/mapper/select/SelectBuilderFactory.d.ts +2 -1
  115. package/dist/src/mapper/select/SelectBuilderFactory.d.ts.map +1 -1
  116. package/dist/src/mapper/select/SelectExecutionHandler.d.ts +1 -0
  117. package/dist/src/mapper/select/SelectExecutionHandler.d.ts.map +1 -1
  118. package/dist/src/mapper/select/WhereBuilder.d.ts +6 -3
  119. package/dist/src/mapper/select/WhereBuilder.d.ts.map +1 -1
  120. package/dist/src/mapper/select/WhereBuilder.js +31 -24
  121. package/dist/src/mapper/select/WhereBuilder.js.map +1 -1
  122. package/dist/src/mapper/select/handlers/FieldsVisitor.d.ts +9 -8
  123. package/dist/src/mapper/select/handlers/FieldsVisitor.d.ts.map +1 -1
  124. package/dist/src/mapper/select/handlers/FieldsVisitor.js +45 -24
  125. package/dist/src/mapper/select/handlers/FieldsVisitor.js.map +1 -1
  126. package/dist/src/mapper/select/handlers/FieldsVisitorFactory.d.ts.map +1 -1
  127. package/dist/src/mapper/select/handlers/FieldsVisitorFactory.js +1 -1
  128. package/dist/src/mapper/select/handlers/FieldsVisitorFactory.js.map +1 -1
  129. package/dist/src/mapper/select/optimizer/ConditionOptimizer.d.ts +5 -0
  130. package/dist/src/mapper/select/optimizer/ConditionOptimizer.d.ts.map +1 -0
  131. package/dist/src/mapper/select/optimizer/ConditionOptimizer.js +39 -0
  132. package/dist/src/mapper/select/optimizer/ConditionOptimizer.js.map +1 -0
  133. package/dist/src/mapper/select/optimizer/WhereOptimizer.d.ts +15 -0
  134. package/dist/src/mapper/select/optimizer/WhereOptimizer.d.ts.map +1 -0
  135. package/dist/src/mapper/select/optimizer/WhereOptimizer.js +118 -0
  136. package/dist/src/mapper/select/optimizer/WhereOptimizer.js.map +1 -0
  137. package/dist/src/mapper/select/optimizer/WhereReplacer.d.ts +6 -0
  138. package/dist/src/mapper/select/optimizer/WhereReplacer.d.ts.map +1 -0
  139. package/dist/src/mapper/select/optimizer/WhereReplacer.js +28 -0
  140. package/dist/src/mapper/select/optimizer/WhereReplacer.js.map +1 -0
  141. package/dist/src/mapper/select/optimizer/helpers.d.ts +10 -0
  142. package/dist/src/mapper/select/optimizer/helpers.d.ts.map +1 -0
  143. package/dist/src/mapper/select/optimizer/helpers.js +72 -0
  144. package/dist/src/mapper/select/optimizer/helpers.js.map +1 -0
  145. package/dist/src/mapper/update/SqlUpdateInputProcessor.d.ts +2 -3
  146. package/dist/src/mapper/update/SqlUpdateInputProcessor.d.ts.map +1 -1
  147. package/dist/src/mapper/update/SqlUpdateInputProcessor.js.map +1 -1
  148. package/dist/src/mapper/update/UpdateBuilder.js +3 -3
  149. package/dist/src/mapper/update/UpdateBuilder.js.map +1 -1
  150. package/dist/src/resolvers/GraphQlQueryAstFactory.js +2 -2
  151. package/dist/src/resolvers/GraphQlQueryAstFactory.js.map +1 -1
  152. package/dist/src/resolvers/MutationResolver.js +15 -15
  153. package/dist/src/resolvers/MutationResolver.js.map +1 -1
  154. package/dist/src/resolvers/ReadHelpers.js +10 -10
  155. package/dist/src/resolvers/ReadHelpers.js.map +1 -1
  156. package/dist/src/resolvers/ReadResolver.js +2 -2
  157. package/dist/src/resolvers/ReadResolver.js.map +1 -1
  158. package/dist/src/schema/FieldAccessVisitor.d.ts +2 -2
  159. package/dist/src/schema/FieldAccessVisitor.d.ts.map +1 -1
  160. package/dist/src/schema/FieldAccessVisitor.js +2 -2
  161. package/dist/src/schema/FieldAccessVisitor.js.map +1 -1
  162. package/dist/src/schema/MutationProvider.js +4 -4
  163. package/dist/src/schema/MutationProvider.js.map +1 -1
  164. package/dist/src/schema/OrderByTypeProvider.js +1 -1
  165. package/dist/src/schema/OrderByTypeProvider.js.map +1 -1
  166. package/dist/src/schema/QueryProvider.js +3 -3
  167. package/dist/src/schema/QueryProvider.js.map +1 -1
  168. package/dist/src/schema/ResultSchemaTypeProvider.d.ts +2 -2
  169. package/dist/src/schema/ResultSchemaTypeProvider.d.ts.map +1 -1
  170. package/dist/src/schema/WhereTypeProvider.js +4 -4
  171. package/dist/src/schema/WhereTypeProvider.js.map +1 -1
  172. package/dist/src/schema/entities/FieldArgsVisitor.d.ts +7 -7
  173. package/dist/src/schema/entities/FieldArgsVisitor.d.ts.map +1 -1
  174. package/dist/src/schema/entities/FieldArgsVisitor.js +3 -3
  175. package/dist/src/schema/entities/FieldArgsVisitor.js.map +1 -1
  176. package/dist/src/schema/entities/FieldTypeVisitor.d.ts +3 -3
  177. package/dist/src/schema/entities/FieldTypeVisitor.d.ts.map +1 -1
  178. package/dist/src/schema/entities/FieldTypeVisitor.js +3 -3
  179. package/dist/src/schema/entities/FieldTypeVisitor.js.map +1 -1
  180. package/dist/src/schema/mutations/CreateEntityInputFieldVisitor.d.ts +3 -3
  181. package/dist/src/schema/mutations/CreateEntityInputFieldVisitor.d.ts.map +1 -1
  182. package/dist/src/schema/mutations/CreateEntityInputFieldVisitor.js +3 -3
  183. package/dist/src/schema/mutations/CreateEntityInputFieldVisitor.js.map +1 -1
  184. package/dist/src/schema/mutations/CreateEntityRelationAllowedOperationsVisitor.d.ts +6 -6
  185. package/dist/src/schema/mutations/CreateEntityRelationAllowedOperationsVisitor.d.ts.map +1 -1
  186. package/dist/src/schema/mutations/CreateEntityRelationAllowedOperationsVisitor.js +6 -6
  187. package/dist/src/schema/mutations/CreateEntityRelationAllowedOperationsVisitor.js.map +1 -1
  188. package/dist/src/schema/mutations/CreateEntityRelationInputFieldVisitor.d.ts +3 -3
  189. package/dist/src/schema/mutations/CreateEntityRelationInputFieldVisitor.d.ts.map +1 -1
  190. package/dist/src/schema/mutations/CreateEntityRelationInputFieldVisitor.js +5 -5
  191. package/dist/src/schema/mutations/CreateEntityRelationInputFieldVisitor.js.map +1 -1
  192. package/dist/src/schema/mutations/UpdateEntityInputFieldVisitor.d.ts +10 -4
  193. package/dist/src/schema/mutations/UpdateEntityInputFieldVisitor.d.ts.map +1 -1
  194. package/dist/src/schema/mutations/UpdateEntityInputFieldVisitor.js +3 -3
  195. package/dist/src/schema/mutations/UpdateEntityInputFieldVisitor.js.map +1 -1
  196. package/dist/src/schema/mutations/UpdateEntityRelationAllowedOperationsVisitor.d.ts +6 -6
  197. package/dist/src/schema/mutations/UpdateEntityRelationAllowedOperationsVisitor.d.ts.map +1 -1
  198. package/dist/src/schema/mutations/UpdateEntityRelationAllowedOperationsVisitor.js +6 -6
  199. package/dist/src/schema/mutations/UpdateEntityRelationAllowedOperationsVisitor.js.map +1 -1
  200. package/dist/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.d.ts +2 -2
  201. package/dist/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.d.ts.map +1 -1
  202. package/dist/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.js +2 -2
  203. package/dist/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.js.map +1 -1
  204. package/dist/src/tsconfig.tsbuildinfo +1 -1
  205. package/dist/src/utils/object.d.ts.map +1 -1
  206. package/dist/src/utils/object.js +3 -4
  207. package/dist/src/utils/object.js.map +1 -1
  208. package/dist/src/utils/uniqueWhereFields.js +3 -3
  209. package/dist/src/utils/uniqueWhereFields.js.map +1 -1
  210. package/dist/tests/cases/integration/graphQlRequests/delete/aclDelete.test.js +1 -1
  211. package/dist/tests/cases/integration/graphQlRequests/delete/aclDelete.test.js.map +1 -1
  212. package/dist/tests/cases/integration/graphQlRequests/insert/acl/setField.test.js +2 -2
  213. package/dist/tests/cases/integration/graphQlRequests/insert/acl/setField.test.js.map +1 -1
  214. package/dist/tests/cases/integration/graphQlRequests/insert/aclInsert.test.js +1 -1
  215. package/dist/tests/cases/integration/graphQlRequests/insert/aclInsert.test.js.map +1 -1
  216. package/dist/tests/cases/integration/graphQlRequests/query/acl/fieldRestrictedByLocale.test.js +7 -6
  217. package/dist/tests/cases/integration/graphQlRequests/query/acl/fieldRestrictedByLocale.test.js.map +1 -1
  218. package/dist/tests/cases/integration/graphQlRequests/query/acl/nestedPredicate.test.js +1 -1
  219. package/dist/tests/cases/integration/graphQlRequests/query/acl/nestedPredicate.test.js.map +1 -1
  220. package/dist/tests/cases/integration/graphQlRequests/query/acl/predicateElimination.test.d.ts +2 -0
  221. package/dist/tests/cases/integration/graphQlRequests/query/acl/predicateElimination.test.d.ts.map +1 -0
  222. package/dist/tests/cases/integration/graphQlRequests/query/acl/predicateElimination.test.js +137 -0
  223. package/dist/tests/cases/integration/graphQlRequests/query/acl/predicateElimination.test.js.map +1 -0
  224. package/dist/tests/cases/integration/graphQlRequests/query/filter/complexCondition.test.js +1 -1
  225. package/dist/tests/cases/integration/graphQlRequests/query/filter/composedFilter.test.js +1 -1
  226. package/dist/tests/cases/integration/graphQlRequests/query/filter/composedFilter.test.js.map +1 -1
  227. package/dist/tests/cases/integration/graphQlRequests/query/relations/manyHasManyInverse.test.js +73 -0
  228. package/dist/tests/cases/integration/graphQlRequests/query/relations/manyHasManyInverse.test.js.map +1 -1
  229. package/dist/tests/cases/integration/graphQlRequests/query/relations/manyHasManyOwning.test.js +73 -0
  230. package/dist/tests/cases/integration/graphQlRequests/query/relations/manyHasManyOwning.test.js.map +1 -1
  231. package/dist/tests/cases/integration/graphQlRequests/update/acl/aclUpdate.test.js +6 -6
  232. package/dist/tests/cases/integration/graphQlRequests/update/acl/aclUpdate.test.js.map +1 -1
  233. package/dist/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.js +6 -3
  234. package/dist/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.js.map +1 -1
  235. package/dist/tests/cases/integration/graphQlSchema/model.js.map +1 -1
  236. package/dist/tests/cases/unit/aclVariablesFactory.test.js +7 -33
  237. package/dist/tests/cases/unit/aclVariablesFactory.test.js.map +1 -1
  238. package/dist/tests/cases/unit/conditionOptimizer.test.d.ts +2 -0
  239. package/dist/tests/cases/unit/conditionOptimizer.test.d.ts.map +1 -0
  240. package/dist/tests/cases/unit/conditionOptimizer.test.js +118 -0
  241. package/dist/tests/cases/unit/conditionOptimizer.test.js.map +1 -0
  242. package/dist/tests/cases/unit/orderbyHelper.test.js +1 -0
  243. package/dist/tests/cases/unit/orderbyHelper.test.js.map +1 -1
  244. package/dist/tests/cases/unit/permissionMerger.test.js +2 -0
  245. package/dist/tests/cases/unit/permissionMerger.test.js.map +1 -1
  246. package/dist/tests/cases/unit/predicatesFactory.test.d.ts +2 -0
  247. package/dist/tests/cases/unit/predicatesFactory.test.d.ts.map +1 -0
  248. package/dist/tests/cases/unit/predicatesFactory.test.js +109 -0
  249. package/dist/tests/cases/unit/predicatesFactory.test.js.map +1 -0
  250. package/dist/tests/cases/unit/predicatesInjector.test.js +88 -14
  251. package/dist/tests/cases/unit/predicatesInjector.test.js.map +1 -1
  252. package/dist/tests/cases/unit/variableInjector.test.js +4 -3
  253. package/dist/tests/cases/unit/variableInjector.test.js.map +1 -1
  254. package/dist/tests/cases/unit/whereOptimizer.test.d.ts +2 -0
  255. package/dist/tests/cases/unit/whereOptimizer.test.d.ts.map +1 -0
  256. package/dist/tests/cases/unit/whereOptimizer.test.js +265 -0
  257. package/dist/tests/cases/unit/whereOptimizer.test.js.map +1 -0
  258. package/dist/tests/src/testGraphql.d.ts.map +1 -1
  259. package/dist/tests/src/testGraphql.js +10 -2
  260. package/dist/tests/src/testGraphql.js.map +1 -1
  261. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  262. package/graphql.codegen.yml +0 -3
  263. package/package.json +16 -16
  264. package/src/acl/EvaluatedPredicateReplacer.ts +32 -0
  265. package/src/acl/PermissionFactory.ts +18 -13
  266. package/src/acl/PredicateFactory.ts +32 -8
  267. package/src/acl/PredicatesInjector.ts +25 -17
  268. package/src/acl/VariableInjector.ts +2 -15
  269. package/src/acl/VariableUtils.ts +7 -23
  270. package/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducerExecutionHandler.ts +17 -24
  271. package/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.ts +1 -6
  272. package/src/extensions/paginatedHasMany/PaginatedHasManyCountVisitor.ts +26 -46
  273. package/src/extensions/paginatedHasMany/PaginatedHasManyExecutionHandler.ts +6 -3
  274. package/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.ts +4 -22
  275. package/src/extensions/paginatedHasMany/PaginatedHasManyNodesVisitor.ts +26 -49
  276. package/src/input-validation/ColumnValueResolver.ts +2 -3
  277. package/src/input-validation/EntityRulesResolver.ts +4 -4
  278. package/src/input-validation/QueryAstFactory.ts +1 -1
  279. package/src/input-validation/ValidationContext.ts +2 -2
  280. package/src/input-validation/ValidationDataSelector.ts +2 -2
  281. package/src/input-validation/preValidation/CreateInputPreValidationProcessor.ts +7 -8
  282. package/src/input-validation/preValidation/InputPreValidator.ts +4 -4
  283. package/src/input-validation/preValidation/UpdateInputPreValidationProcessor.ts +7 -8
  284. package/src/inputProcessing/CreateInputProcessor.ts +8 -9
  285. package/src/inputProcessing/CreateInputVisitor.ts +27 -89
  286. package/src/inputProcessing/UpdateInputProcessor.ts +8 -9
  287. package/src/inputProcessing/UpdateInputVisitor.ts +25 -71
  288. package/src/inputProcessing/index.ts +0 -1
  289. package/src/introspection/IntrospectionSchemaFactory.ts +7 -7
  290. package/src/introspection/content-schema.types.ts +19 -286
  291. package/src/mapper/Mapper.ts +37 -30
  292. package/src/mapper/MapperContainer.ts +10 -5
  293. package/src/mapper/delete/DeleteExecutor.ts +3 -3
  294. package/src/mapper/insert/SqlCreateInputProcessor.ts +3 -3
  295. package/src/mapper/select/JoinVisitor.ts +6 -33
  296. package/src/mapper/select/RelationFetcher.ts +101 -41
  297. package/src/mapper/select/SelectBuilder.ts +3 -1
  298. package/src/mapper/select/SelectBuilderFactory.ts +2 -1
  299. package/src/mapper/select/SelectExecutionHandler.ts +1 -0
  300. package/src/mapper/select/WhereBuilder.ts +46 -32
  301. package/src/mapper/select/handlers/FieldsVisitor.ts +47 -57
  302. package/src/mapper/select/handlers/FieldsVisitorFactory.ts +1 -0
  303. package/src/mapper/select/optimizer/ConditionOptimizer.ts +41 -0
  304. package/src/mapper/select/optimizer/WhereOptimizer.ts +138 -0
  305. package/src/mapper/select/optimizer/WhereReplacer.ts +27 -0
  306. package/src/mapper/select/optimizer/helpers.ts +58 -0
  307. package/src/mapper/update/SqlUpdateInputProcessor.ts +1 -1
  308. package/src/mapper/update/UpdateBuilder.ts +3 -3
  309. package/src/resolvers/GraphQlQueryAstFactory.ts +3 -3
  310. package/src/resolvers/MutationResolver.ts +1 -1
  311. package/src/resolvers/ReadHelpers.ts +3 -3
  312. package/src/resolvers/ReadResolver.ts +2 -2
  313. package/src/schema/FieldAccessVisitor.ts +2 -2
  314. package/src/schema/OrderByTypeProvider.ts +1 -1
  315. package/src/schema/WhereTypeProvider.ts +4 -4
  316. package/src/schema/entities/FieldArgsVisitor.ts +3 -3
  317. package/src/schema/entities/FieldTypeVisitor.ts +3 -3
  318. package/src/schema/mutations/CreateEntityInputFieldVisitor.ts +3 -6
  319. package/src/schema/mutations/CreateEntityRelationAllowedOperationsVisitor.ts +6 -20
  320. package/src/schema/mutations/CreateEntityRelationInputFieldVisitor.ts +5 -18
  321. package/src/schema/mutations/UpdateEntityInputFieldVisitor.ts +3 -6
  322. package/src/schema/mutations/UpdateEntityRelationAllowedOperationsVisitor.ts +6 -20
  323. package/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.ts +2 -12
  324. package/src/utils/object.ts +6 -6
  325. package/src/utils/uniqueWhereFields.ts +3 -3
  326. package/tests/cases/integration/graphQlRequests/delete/aclDelete.test.ts +2 -2
  327. package/tests/cases/integration/graphQlRequests/insert/acl/setField.test.ts +3 -3
  328. package/tests/cases/integration/graphQlRequests/insert/aclInsert.test.ts +2 -2
  329. package/tests/cases/integration/graphQlRequests/query/acl/fieldRestrictedByLocale.test.ts +7 -6
  330. package/tests/cases/integration/graphQlRequests/query/acl/nestedPredicate.test.ts +1 -1
  331. package/tests/cases/integration/graphQlRequests/query/acl/predicateElimination.test.ts +130 -0
  332. package/tests/cases/integration/graphQlRequests/query/filter/complexCondition.test.ts +1 -1
  333. package/tests/cases/integration/graphQlRequests/query/filter/composedFilter.test.ts +1 -1
  334. package/tests/cases/integration/graphQlRequests/query/relations/manyHasManyInverse.test.ts +74 -0
  335. package/tests/cases/integration/graphQlRequests/query/relations/manyHasManyOwning.test.ts +77 -0
  336. package/tests/cases/integration/graphQlRequests/update/acl/aclUpdate.test.ts +7 -7
  337. package/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.ts +5 -5
  338. package/tests/cases/unit/aclVariablesFactory.test.ts +8 -35
  339. package/tests/cases/unit/conditionOptimizer.test.ts +135 -0
  340. package/tests/cases/unit/orderbyHelper.test.ts +1 -0
  341. package/tests/cases/unit/permissionMerger.test.ts +2 -0
  342. package/tests/cases/unit/predicatesFactory.test.ts +103 -0
  343. package/tests/cases/unit/predicatesInjector.test.ts +78 -16
  344. package/tests/cases/unit/variableInjector.test.ts +6 -5
  345. package/tests/cases/unit/whereOptimizer.test.ts +289 -0
  346. package/tests/src/testGraphql.ts +9 -2
  347. package/dist/src/inputProcessing/InputContext.d.ts +0 -43
  348. package/dist/src/inputProcessing/InputContext.d.ts.map +0 -1
  349. package/dist/src/inputProcessing/InputContext.js +0 -3
  350. package/dist/src/inputProcessing/InputContext.js.map +0 -1
  351. package/jasmine.json +0 -7
  352. package/src/inputProcessing/InputContext.ts +0 -49
@@ -5,6 +5,7 @@ import { Path, PathFactory } from './Path'
5
5
  import { JoinBuilder } from './JoinBuilder'
6
6
  import { ConditionBuilder } from './ConditionBuilder'
7
7
  import { ConditionBuilder as SqlConditionBuilder, Operator, QueryBuilder, SelectBuilder } from '@contember/database'
8
+ import { WhereOptimizer } from './optimizer/WhereOptimizer'
8
9
 
9
10
  export class WhereBuilder {
10
11
  constructor(
@@ -12,6 +13,7 @@ export class WhereBuilder {
12
13
  private readonly joinBuilder: JoinBuilder,
13
14
  private readonly conditionBuilder: ConditionBuilder,
14
15
  private readonly pathFactory: PathFactory,
16
+ private readonly whereOptimizer: WhereOptimizer,
15
17
  ) {}
16
18
 
17
19
  public build(
@@ -19,28 +21,41 @@ export class WhereBuilder {
19
21
  entity: Model.Entity,
20
22
  path: Path,
21
23
  where: Input.OptionalWhere,
22
- allowManyJoin: boolean = false,
24
+ relationPath: Model.AnyRelationContext[] = [],
23
25
  ) {
24
- return this.buildAdvanced(entity, path, where, cb => qb.where(clause => cb(clause)), allowManyJoin)
26
+ const optimizedWhere = this.whereOptimizer.optimize(where, entity, relationPath)
27
+ return this.buildInternal(entity, path, optimizedWhere, cb => qb.where(clause => cb(clause)), false)
25
28
  }
26
29
 
30
+
27
31
  public buildAdvanced(
28
32
  entity: Model.Entity,
29
33
  path: Path,
30
34
  where: Input.OptionalWhere,
31
35
  callback: (clauseCb: (clause: SqlConditionBuilder) => SqlConditionBuilder) => SelectBuilder<SelectBuilder.Result>,
32
- allowManyJoin: boolean = false,
36
+ relationPath: Model.AnyRelationContext[] = [],
37
+ ) {
38
+ const optimizedWhere = this.whereOptimizer.optimize(where, entity, relationPath)
39
+ return this.buildInternal(entity, path, optimizedWhere, callback, false)
40
+ }
41
+
42
+ private buildInternal(
43
+ entity: Model.Entity,
44
+ path: Path,
45
+ where: Input.OptionalWhere,
46
+ callback: (clauseCb: (clause: SqlConditionBuilder) => SqlConditionBuilder) => SelectBuilder<SelectBuilder.Result>,
47
+ allowManyJoin: boolean,
33
48
  ) {
34
49
  const joinList: WhereJoinDefinition[] = []
35
50
 
36
- const qbWithWhere = callback(clause => this.buildInternal(clause, entity, path, where, allowManyJoin, joinList))
51
+ const qbWithWhere = callback(clause => this.buildRecursive(clause, entity, path, where, allowManyJoin, joinList))
37
52
  return joinList.reduce<SelectBuilder<SelectBuilder.Result>>(
38
53
  (qb, { path, entity, relationName }) => this.joinBuilder.join(qb, path, entity, relationName),
39
54
  qbWithWhere,
40
55
  )
41
56
  }
42
57
 
43
- private buildInternal(
58
+ private buildRecursive(
44
59
  conditionBuilder: SqlConditionBuilder,
45
60
  entity: Model.Entity,
46
61
  path: Path,
@@ -55,7 +70,7 @@ export class WhereBuilder {
55
70
  conditionBuilder = conditionBuilder.and(clause =>
56
71
  expr.reduce(
57
72
  (clause2, where) =>
58
- !where ? clause2 : this.buildInternal(clause2, entity, path, where, allowManyJoin, joinList),
73
+ !where ? clause2 : this.buildRecursive(clause2, entity, path, where, allowManyJoin, joinList),
59
74
  clause,
60
75
  ),
61
76
  )
@@ -67,7 +82,7 @@ export class WhereBuilder {
67
82
  (clause2, where) =>
68
83
  !where
69
84
  ? clause2
70
- : clause2.and(clause3 => this.buildInternal(clause3, entity, path, where, allowManyJoin, joinList)),
85
+ : clause2.and(clause3 => this.buildRecursive(clause3, entity, path, where, allowManyJoin, joinList)),
71
86
  clause,
72
87
  ),
73
88
  )
@@ -75,7 +90,7 @@ export class WhereBuilder {
75
90
  if (where.not !== undefined) {
76
91
  const expr = where.not
77
92
  conditionBuilder = conditionBuilder.not(clause =>
78
- this.buildInternal(clause, entity, path, expr, allowManyJoin, joinList),
93
+ this.buildRecursive(clause, entity, path, expr, allowManyJoin, joinList),
79
94
  )
80
95
  }
81
96
 
@@ -84,11 +99,7 @@ export class WhereBuilder {
84
99
  continue
85
100
  }
86
101
 
87
- const joinedWhere = (
88
- entity: Model.Entity,
89
- relation: Model.Relation,
90
- targetEntity: Model.Entity,
91
- ): SqlConditionBuilder => {
102
+ const joinedWhere = ({ targetEntity, relation, entity }: Model.AnyRelationContext): SqlConditionBuilder => {
92
103
  const targetPath = path.for(fieldName)
93
104
  const relationWhere = where[fieldName] as Input.Where
94
105
  if (Object.keys(relationWhere).length === 0) {
@@ -109,36 +120,37 @@ export class WhereBuilder {
109
120
 
110
121
  joinList.push({ path: targetPath, entity, relationName: relation.name })
111
122
 
112
- return this.buildInternal(conditionBuilder, targetEntity, targetPath, relationWhere, allowManyJoin, joinList)
123
+ return this.buildRecursive(conditionBuilder, targetEntity, targetPath, relationWhere, allowManyJoin, joinList)
113
124
  }
114
125
 
115
126
  conditionBuilder = acceptFieldVisitor<SqlConditionBuilder>(this.schema, entity, fieldName, {
116
- visitColumn: (entity, column) => {
127
+ visitColumn: ({ entity, column }) => {
117
128
  const subWhere: Input.Condition<Input.ColumnValue> = where[column.name] as Input.Condition<Input.ColumnValue>
118
129
  return this.conditionBuilder.build(conditionBuilder, tableName, column.columnName, column.columnType, subWhere)
119
130
  },
120
131
  visitOneHasOneInverse: joinedWhere,
121
132
  visitOneHasOneOwning: joinedWhere,
122
133
  visitManyHasOne: joinedWhere,
123
- visitManyHasManyInverse: (entity, relation, targetEntity, targetRelation) => {
134
+ visitManyHasManyInverse: context => {
124
135
  if (allowManyJoin) {
125
- return joinedWhere(entity, relation, targetEntity)
136
+ return joinedWhere(context)
126
137
  }
138
+
127
139
  const relationWhere = where[fieldName] as Input.Where
128
140
 
129
141
  return conditionBuilder.exists(
130
142
  this.createManyHasManySubquery(
131
143
  [tableName, entity.primaryColumn],
132
144
  relationWhere,
133
- targetEntity,
134
- targetRelation.joiningTable,
145
+ context.targetEntity,
146
+ context.targetRelation.joiningTable,
135
147
  'inverse',
136
148
  ),
137
149
  )
138
150
  },
139
- visitManyHasManyOwning: (entity, relation, targetEntity) => {
151
+ visitManyHasManyOwning: context => {
140
152
  if (allowManyJoin) {
141
- return joinedWhere(entity, relation, targetEntity)
153
+ return joinedWhere(context)
142
154
  }
143
155
 
144
156
  const relationWhere = where[fieldName] as Input.Where
@@ -147,28 +159,30 @@ export class WhereBuilder {
147
159
  this.createManyHasManySubquery(
148
160
  [tableName, entity.primaryColumn],
149
161
  relationWhere,
150
- targetEntity,
151
- relation.joiningTable,
162
+ context.targetEntity,
163
+ context.relation.joiningTable,
152
164
  'owning',
153
165
  ),
154
166
  )
155
167
  },
156
- visitOneHasMany: (entity, relation, targetEntity, targetRelation) => {
168
+ visitOneHasMany: context => {
157
169
  if (allowManyJoin) {
158
- return joinedWhere(entity, relation, targetEntity)
170
+ return joinedWhere(context)
159
171
  }
160
172
 
161
173
  const relationWhere = where[fieldName] as Input.Where
162
174
 
175
+ const qb = SelectBuilder.create()
176
+ .select(it => it.raw('1'))
177
+ .from(context.targetEntity.tableName, 'sub_')
178
+ .where(it => it.columnsEq([tableName, entity.primaryColumn], ['sub_', context.targetRelation.joiningColumn.columnName]))
179
+
163
180
  return conditionBuilder.exists(
164
- this.build(
165
- SelectBuilder.create()
166
- .select(it => it.raw('1'))
167
- .from(targetEntity.tableName, 'sub_')
168
- .where(it => it.columnsEq([tableName, entity.primaryColumn], ['sub_', targetRelation.joiningColumn.columnName])),
169
- targetEntity,
181
+ this.buildInternal(
182
+ context.targetEntity,
170
183
  this.pathFactory.create([], 'sub_'),
171
184
  relationWhere,
185
+ cb => qb.where(clause => cb(clause)),
172
186
  true,
173
187
  ),
174
188
  )
@@ -205,7 +219,7 @@ export class WhereBuilder {
205
219
  const qbJoined = qb.join(targetEntity.tableName, 'sub_', clause =>
206
220
  clause.compareColumns(['junction_', toColumn], Operator.eq, ['sub_', targetEntity.primary]),
207
221
  )
208
- return this.buildAdvanced(
222
+ return this.buildInternal(
209
223
  targetEntity,
210
224
  this.pathFactory.create([], 'sub_'),
211
225
  relationWhere,
@@ -4,7 +4,6 @@ import { RelationFetcher } from '../RelationFetcher'
4
4
  import { SelectExecutionHandlerContext } from '../SelectExecutionHandler'
5
5
  import { PredicateFactory } from '../../../acl'
6
6
  import { WhereBuilder } from '../WhereBuilder'
7
- import { JoiningColumns } from '../../types'
8
7
 
9
8
  export class FieldsVisitor implements Model.RelationByTypeVisitor<void>, Model.ColumnVisitor<void> {
10
9
  constructor(
@@ -14,9 +13,10 @@ export class FieldsVisitor implements Model.RelationByTypeVisitor<void>, Model.C
14
13
  private readonly whereBuilder: WhereBuilder,
15
14
  private readonly mapper: Mapper,
16
15
  private readonly executionContext: SelectExecutionHandlerContext,
16
+ private readonly relationPath: Model.AnyRelationContext[],
17
17
  ) {}
18
18
 
19
- visitColumn(entity: Model.Entity, column: Model.AnyColumn): void {
19
+ visitColumn({ entity, column }: Model.ColumnContext): void {
20
20
  const columnPath = this.executionContext.path
21
21
  this.executionContext.addColumn(qb => {
22
22
  const tableAlias = columnPath.back().alias
@@ -50,85 +50,69 @@ export class FieldsVisitor implements Model.RelationByTypeVisitor<void>, Model.C
50
50
  })
51
51
  }
52
52
 
53
- public visitManyHasManyInverse(
54
- entity: Model.Entity,
55
- relation: Model.ManyHasManyInverseRelation,
56
- targetEntity: Model.Entity,
57
- targetRelation: Model.ManyHasManyOwningRelation,
58
- ): void {
59
- const joiningTable = targetRelation.joiningTable
60
- const columns: JoiningColumns = {
61
- sourceColumn: joiningTable.inverseJoiningColumn,
62
- targetColumn: joiningTable.joiningColumn,
63
- }
53
+ public visitManyHasManyInverse(relationContext: Model.ManyHasManyInverseContext): void {
64
54
  const field = this.executionContext.objectNode
65
55
  if (!field) {
66
56
  throw new Error()
67
57
  }
68
58
  this.executionContext.addData(
69
- entity.primary,
59
+ relationContext.entity.primary,
70
60
  async ids =>
71
61
  this.relationFetcher.fetchManyHasManyGroups(
72
- this.mapper,
73
- field,
74
- targetEntity,
75
- relation,
76
- targetRelation,
77
- columns,
78
- ids,
62
+ {
63
+ mapper: this.mapper,
64
+ field: field,
65
+ relationContext,
66
+ relationPath: this.relationPath,
67
+ ids: ids,
68
+ },
79
69
  ),
80
70
  [],
81
71
  )
82
72
  }
83
73
 
84
- public visitManyHasManyOwning(
85
- entity: Model.Entity,
86
- relation: Model.ManyHasManyOwningRelation,
87
- targetEntity: Model.Entity,
88
- ): void {
89
- const joiningTable = relation.joiningTable
90
- const columns: JoiningColumns = {
91
- sourceColumn: joiningTable.joiningColumn,
92
- targetColumn: joiningTable.inverseJoiningColumn,
93
- }
74
+ public visitManyHasManyOwning(relationContext: Model.ManyHasManyOwningContext): void {
94
75
  const field = this.executionContext.objectNode
95
76
  if (!field) {
96
77
  throw new Error()
97
78
  }
98
79
 
99
80
  this.executionContext.addData(
100
- entity.primary,
81
+ relationContext.entity.primary,
101
82
  async ids =>
102
- this.relationFetcher.fetchManyHasManyGroups(this.mapper, field, targetEntity, relation, relation, columns, ids),
83
+ this.relationFetcher.fetchManyHasManyGroups({
84
+ mapper: this.mapper,
85
+ field: field,
86
+ relationContext,
87
+ relationPath: this.relationPath,
88
+ ids: ids,
89
+ }),
103
90
  [],
104
91
  )
105
92
  }
106
93
 
107
- public visitOneHasMany(
108
- entity: Model.Entity,
109
- relation: Model.OneHasManyRelation,
110
- targetEntity: Model.Entity,
111
- targetRelation: Model.ManyHasOneRelation,
112
- ): void {
94
+ public visitOneHasMany(relationContext: Model.OneHasManyContext): void {
113
95
  const field = this.executionContext.objectNode
114
96
  if (!field) {
115
97
  throw new Error()
116
98
  }
117
99
 
118
100
  this.executionContext.addData(
119
- entity.primary,
101
+ relationContext.entity.primary,
120
102
  async ids =>
121
- this.relationFetcher.fetchOneHasManyGroups(this.mapper, field, targetEntity, relation, targetRelation, ids),
103
+ this.relationFetcher.fetchOneHasManyGroups({
104
+ mapper: this.mapper,
105
+ objectNode: field,
106
+ relationContext,
107
+ relationPath: this.relationPath,
108
+ ids: ids,
109
+ }),
122
110
  [],
123
111
  )
124
112
  }
125
113
 
126
- public visitOneHasOneInverse(
127
- entity: Model.Entity,
128
- relation: Model.OneHasOneInverseRelation,
129
- targetEntity: Model.Entity,
130
- targetRelation: Model.OneHasOneOwningRelation,
131
- ): void {
114
+ public visitOneHasOneInverse(relationContext: Model.OneHasOneInverseContext): void {
115
+ const { entity, targetRelation, targetEntity } = relationContext
132
116
  this.executionContext.addData(
133
117
  entity.primary,
134
118
  async ids => {
@@ -148,18 +132,17 @@ export class FieldsVisitor implements Model.RelationByTypeVisitor<void>, Model.C
148
132
  }
149
133
  const objectWithWhere = field.withArg('filter', where)
150
134
 
151
- return this.mapper.select(targetEntity, objectWithWhere, targetRelation.name)
135
+ return this.mapper.selectAssoc(targetEntity, objectWithWhere, [
136
+ ...this.relationPath,
137
+ relationContext,
138
+ ], targetRelation.name)
152
139
  },
153
140
  null,
154
141
  )
155
142
  }
156
143
 
157
- public visitOneHasOneOwning(
158
- entity: Model.Entity,
159
- relation: Model.OneHasOneOwningRelation,
160
- targetEntity: Model.Entity,
161
- targetRelation: Model.OneHasOneInverseRelation | null,
162
- ): void {
144
+ public visitOneHasOneOwning(relationContext: Model.OneHasOneOwningContext): void {
145
+ const { relation, targetEntity } = relationContext
163
146
  this.executionContext.addData(
164
147
  relation.name,
165
148
  async ids => {
@@ -177,13 +160,17 @@ export class FieldsVisitor implements Model.RelationByTypeVisitor<void>, Model.C
177
160
  }
178
161
  const objectWithWhere = objectNode.withArg('filter', where)
179
162
 
180
- return this.mapper.select(targetEntity, objectWithWhere, targetEntity.primary)
163
+ return this.mapper.selectAssoc(targetEntity, objectWithWhere, [
164
+ ...this.relationPath,
165
+ relationContext,
166
+ ], targetEntity.primary)
181
167
  },
182
168
  null,
183
169
  )
184
170
  }
185
171
 
186
- public visitManyHasOne(entity: Model.Entity, relation: Model.ManyHasOneRelation, targetEntity: Model.Entity): void {
172
+ public visitManyHasOne(relationContext: Model.ManyHasOneContext): void {
173
+ const { relation, targetEntity } = relationContext
187
174
  this.executionContext.addData(
188
175
  relation.name,
189
176
  async ids => {
@@ -201,7 +188,10 @@ export class FieldsVisitor implements Model.RelationByTypeVisitor<void>, Model.C
201
188
  }
202
189
  const objectWithWhere = objectNode.withArg('filter', where)
203
190
 
204
- return this.mapper.select(targetEntity, objectWithWhere, targetEntity.primary)
191
+ return this.mapper.selectAssoc(targetEntity, objectWithWhere, [
192
+ ...this.relationPath,
193
+ relationContext,
194
+ ], targetEntity.primary)
205
195
  },
206
196
  null,
207
197
  )
@@ -22,6 +22,7 @@ export class FieldsVisitorFactory {
22
22
  this.whereBuilder,
23
23
  mapper,
24
24
  context,
25
+ context.relationPath,
25
26
  )
26
27
  }
27
28
  }
@@ -0,0 +1,41 @@
1
+ import { Input } from '@contember/schema'
2
+ import { optimizeAnd, optimizeNot, optimizeOr } from './helpers'
3
+
4
+ type ObjectEntry<T> = { [K in keyof Required<T>]: [K, T[K]] }[keyof T]
5
+
6
+ export class ConditionOptimizer {
7
+ public optimize(condition: Input.Condition): Omit<Input.Condition, 'always' | 'never'> | boolean {
8
+ if (condition.never) {
9
+ return false
10
+ }
11
+
12
+ return optimizeAnd(
13
+ (Object.entries(condition) as ObjectEntry<typeof condition>[]).map(([key, value]) => {
14
+ if (value === undefined || value === null) {
15
+ return undefined
16
+
17
+ } else if (key === 'always') {
18
+ return true
19
+
20
+ } else if (key === 'and') {
21
+ return optimizeAnd(value.map(it => this.optimize(it)))
22
+
23
+ } else if (key === 'or') {
24
+ return optimizeOr(value.map(it => this.optimize(it)))
25
+
26
+ } else if (key === 'in' && value.length === 0) {
27
+ return false
28
+
29
+ } else if (key === 'notIn' && value.length === 0) {
30
+ return true
31
+
32
+ } else if (key === 'not') {
33
+ return optimizeNot(this.optimize(value))
34
+
35
+ } else {
36
+ return { [key]: value }
37
+ }
38
+ }),
39
+ )
40
+ }
41
+ }
@@ -0,0 +1,138 @@
1
+ import { Input, Model } from '@contember/schema'
2
+ import { ConditionOptimizer } from './ConditionOptimizer'
3
+ import { acceptFieldVisitor } from '@contember/schema-utils'
4
+ import { optimizeAnd, optimizeNot, optimizeOr } from './helpers'
5
+ import { replaceWhere } from './WhereReplacer'
6
+
7
+ type ExtendedRelationContext =
8
+ & Model.AnyRelationContext
9
+ & {
10
+ canEliminate: boolean
11
+ isLast: boolean
12
+ }
13
+
14
+ export class WhereOptimizer {
15
+ private static eliminableRelations = new Set<Model.AnyRelationContext['type']>(['oneHasMany', 'oneHasOneInverse', 'oneHasOneOwning'])
16
+
17
+ constructor(
18
+ private readonly model: Model.Schema,
19
+ private readonly conditionOptimizer: ConditionOptimizer,
20
+ ) {
21
+ }
22
+
23
+ public optimize(where: Input.OptionalWhere, entity: Model.Entity, relationPath: Model.AnyRelationContext[] = []): Input.Where {
24
+ let processedRelationPath: ExtendedRelationContext[] = []
25
+ for (const i in relationPath) {
26
+ const el = relationPath[i]
27
+ if (!WhereOptimizer.eliminableRelations.has(el.type)) {
28
+ processedRelationPath = []
29
+ } else {
30
+ processedRelationPath.push({ ...el, canEliminate: true, isLast: Number(i) === relationPath.length })
31
+ }
32
+ processedRelationPath.push({ ...el, canEliminate: true, isLast: Number(i) === relationPath.length })
33
+ }
34
+ const result = this.optimizeWhere(where, entity, processedRelationPath)
35
+
36
+ if (typeof result === 'boolean') {
37
+ return { [entity.primary]: { [result ? 'always' : 'never']: true } }
38
+ }
39
+
40
+ return result
41
+ }
42
+
43
+ private optimizeWhere(where: Input.OptionalWhere, entity: Model.Entity, relationPath: ExtendedRelationContext[]): Input.Where | boolean {
44
+ return this.optimizeAnd(
45
+ Object.entries(where).map(([key, value]) => {
46
+ if (value === undefined || value === null) {
47
+ return undefined
48
+
49
+ } else if (key === 'and') {
50
+ return this.optimizeAnd((value as readonly Input.Where[]).map(it => this.optimizeWhere(it, entity, relationPath)), entity, relationPath)
51
+
52
+ } else if (key === 'or') {
53
+ return this.optimizeOr((value as readonly Input.Where[]).map(it => this.optimizeWhere(it, entity, relationPath)), entity, relationPath)
54
+
55
+ } else if (key === 'not') {
56
+ return optimizeNot(this.optimizeWhere(value as Input.Where, entity, relationPath))
57
+
58
+ } else {
59
+ return this.resolveFieldValue(entity, key, value, relationPath)
60
+ }
61
+ }),
62
+ entity,
63
+ relationPath,
64
+ )
65
+ }
66
+
67
+ private optimizeOr(operands: readonly (Input.Where | undefined | boolean)[], entity: Model.Entity, relationPath: ExtendedRelationContext[]): Input.Where | boolean {
68
+ const optimized = optimizeOr(operands)
69
+ if (typeof optimized === 'boolean' || !Array.isArray(optimized.or)) {
70
+ return optimized
71
+ }
72
+ const result = this.crossOptimize(optimized.or, entity, { never: true }, relationPath)
73
+ return optimizeOr(result)
74
+ }
75
+
76
+ private optimizeAnd(operands: readonly (Input.Where | undefined | boolean)[], entity: Model.Entity, relationPath: ExtendedRelationContext[]): Input.Where | boolean {
77
+ const optimized = optimizeAnd(operands)
78
+ if (typeof optimized === 'boolean' || !Array.isArray(optimized.and)) {
79
+ return optimized
80
+ }
81
+ const result = this.crossOptimize(optimized.and, entity, { always: true }, relationPath)
82
+ return optimizeAnd(result)
83
+ }
84
+
85
+ private crossOptimize(operands: Input.Where[], entity: Model.Entity, replacement: Input.Condition, relationPath: ExtendedRelationContext[]): (Input.Where | boolean)[] {
86
+ const result: (Input.Where | boolean)[] = [...operands]
87
+ const count = result.length
88
+ for (let i = 0; i < count; i++) {
89
+ for (let j = 0; j < count; j++) {
90
+ const a = result[j]
91
+ const b = result[i]
92
+ if (i !== j && typeof a !== 'boolean' && typeof b !== 'boolean') {
93
+ const tracker = { count: 0 }
94
+ const elResult = replaceWhere(a, b, { [entity.primary]: replacement }, tracker)
95
+ result[j] = tracker.count > 0 ? this.optimizeWhere(elResult, entity, relationPath) : elResult
96
+ }
97
+ }
98
+ }
99
+ return result
100
+ }
101
+
102
+ private resolveFieldValue(entity: Model.Entity, key: string, value: Input.OptionalWhere[string], relationPath: ExtendedRelationContext[]) {
103
+ return acceptFieldVisitor<Input.Where | boolean>(this.model, entity, key, {
104
+ visitColumn: () => {
105
+ const optimizedCondition = this.conditionOptimizer.optimize(value as Input.Condition)
106
+
107
+ if (typeof optimizedCondition === 'boolean') {
108
+ return optimizedCondition
109
+ }
110
+
111
+ return { [key]: optimizedCondition }
112
+ },
113
+ visitRelation: context => {
114
+ const { targetEntity, relation } = context
115
+ let where = value as Input.Where
116
+ const newRelationPath: ExtendedRelationContext[] = [...relationPath]
117
+ if (relationPath.length && relationPath[relationPath.length - 1].targetRelation?.name === relation.name) {
118
+ const item = newRelationPath.pop()
119
+ if (item?.canEliminate && (item.type === 'oneHasMany' || item.type === 'oneHasOneOwning' || item.type === 'oneHasOneInverse')) {
120
+ where = replaceWhere(where, { [targetEntity.primary]: { isNull: true } }, { [targetEntity.primary]: { never: true } })
121
+ where = replaceWhere(where, { [targetEntity.primary]: { isNull: false } }, { [targetEntity.primary]: { always: true } })
122
+ }
123
+ } else {
124
+ // first level relation - we are sure root exists
125
+ const canEliminate = relationPath.length === 0 || relationPath[relationPath.length - 1].isLast
126
+ newRelationPath.push({ ...context, isLast: false, canEliminate })
127
+ }
128
+ const optimizedWhere = this.optimizeWhere(where, targetEntity, newRelationPath)
129
+
130
+ if (typeof optimizedWhere === 'boolean') {
131
+ return optimizedWhere
132
+ }
133
+
134
+ return { [key]: optimizedWhere }
135
+ },
136
+ })
137
+ }
138
+ }
@@ -0,0 +1,27 @@
1
+ import { Input, Writable } from '@contember/schema'
2
+ import deepEqual from 'fast-deep-equal'
3
+
4
+ export interface ReplaceWhereResult {
5
+ count: number
6
+ }
7
+
8
+ export const replaceWhere = (subject: Input.Where, find: Input.Where, replace: Input.Where, resultTracker: ReplaceWhereResult = { count: 0 }): Input.Where => {
9
+ if (deepEqual(subject, find)) {
10
+ resultTracker.count++
11
+ return replace
12
+ }
13
+ const result: Writable<Input.Where> = {}
14
+ for (const [key, value] of Object.entries(subject)) {
15
+ if (key === 'not') {
16
+ result['not'] = replaceWhere(value as Input.Where, find, replace, resultTracker)
17
+
18
+ } else if (key === 'and' || key === 'or') {
19
+ result[key] = (value as Input.Where[]).map(it => replaceWhere(it, find, replace, resultTracker))
20
+
21
+ } else {
22
+ result[key] = value
23
+ }
24
+
25
+ }
26
+ return result
27
+ }
@@ -0,0 +1,58 @@
1
+ export const optimizeOr = <P extends Record<string, unknown>>(operands: readonly (P | boolean | undefined)[]): P | { or?: P[] } | boolean => {
2
+ const normalized: P[] = []
3
+ let hasNever = false
4
+ for (const operand of operands) {
5
+ if (operand === true) {
6
+ return true
7
+ } else if (operand === false) {
8
+ hasNever = true
9
+ } else if (operand !== undefined) {
10
+ normalized.push(...Array.isArray(operand.or) ? operand.or : [operand])
11
+ }
12
+ }
13
+
14
+ if (normalized.length > 1) {
15
+ return { or: normalized }
16
+ } else if (normalized.length === 1) {
17
+ return normalized[0]
18
+ } else if (hasNever) {
19
+ return false
20
+ } else {
21
+ return {}
22
+ }
23
+ }
24
+
25
+ export const optimizeAnd = <P extends Record<string, unknown>>(operands: readonly (P | boolean | undefined)[]): P | { and?: P[] } | boolean => {
26
+ const normalized: P[] = []
27
+ let hasAlways = false
28
+
29
+ for (const operand of operands) {
30
+ if (operand === true) {
31
+ hasAlways = true
32
+ } else if (operand === false) {
33
+ return false
34
+ } else if (operand !== undefined) {
35
+ normalized.push(...Array.isArray(operand.and) ? operand.and : [operand])
36
+ }
37
+ }
38
+
39
+ if (normalized.length > 1) {
40
+ return { and: normalized }
41
+ } else if (normalized.length === 1) {
42
+ return normalized[0]
43
+ } else if (hasAlways) {
44
+ return true
45
+ } else {
46
+ return {}
47
+ }
48
+ }
49
+
50
+ export const optimizeNot = <P extends Record<string, unknown>>(operand: P | boolean): P['not'] | { not: P } | boolean => {
51
+ if (typeof operand === 'boolean') {
52
+ return !operand
53
+ } else if (operand.not) {
54
+ return operand.not as P['not']
55
+ } else {
56
+ return { not: operand }
57
+ }
58
+ }
@@ -26,7 +26,7 @@ export class SqlUpdateInputProcessor implements UpdateInputProcessor<MutationRes
26
26
  private readonly mapper: Mapper,
27
27
  ) {}
28
28
 
29
- public column({ entity, column }: Context.ColumnContext) {
29
+ public column({ entity, column }: Model.ColumnContext) {
30
30
  if (this.data[column.name] !== undefined) {
31
31
  this.updateBuilder.addFieldValue(column.name, this.data[column.name] as Value.AtomicValue)
32
32
  }
@@ -74,9 +74,9 @@ export class UpdateBuilder {
74
74
  const columns = new Set(resolvedData.map(it => it.columnName))
75
75
  const allColumns: string[] = Object.values(
76
76
  acceptEveryFieldVisitor(this.schema, this.entity, {
77
- visitColumn: (entity, column) => column.columnName,
78
- visitManyHasOne: (entity, relation) => relation.joiningColumn.columnName,
79
- visitOneHasOneOwning: (entity, relation) => relation.joiningColumn.columnName,
77
+ visitColumn: ({ column }) => column.columnName,
78
+ visitManyHasOne: ({ relation }) => relation.joiningColumn.columnName,
79
+ visitOneHasOneOwning: ({ relation }) => relation.joiningColumn.columnName,
80
80
  visitManyHasManyInverse: () => null,
81
81
  visitManyHasManyOwning: () => null,
82
82
  visitOneHasOneInverse: () => null,