@contember/engine-content-api 1.2.0-alpha.1 → 1.2.0-alpha.12

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 (361) 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 +7 -7
  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 +8 -3
  119. package/dist/src/mapper/select/WhereBuilder.d.ts.map +1 -1
  120. package/dist/src/mapper/select/WhereBuilder.js +71 -25
  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/graphQlDb/insert/insertSequence.test.d.ts +2 -0
  211. package/dist/tests/cases/integration/graphQlDb/insert/insertSequence.test.d.ts.map +1 -0
  212. package/dist/tests/cases/integration/graphQlDb/insert/insertSequence.test.js +38 -0
  213. package/dist/tests/cases/integration/graphQlDb/insert/insertSequence.test.js.map +1 -0
  214. package/dist/tests/cases/integration/graphQlRequests/delete/aclDelete.test.js +1 -1
  215. package/dist/tests/cases/integration/graphQlRequests/delete/aclDelete.test.js.map +1 -1
  216. package/dist/tests/cases/integration/graphQlRequests/insert/acl/setField.test.js +2 -2
  217. package/dist/tests/cases/integration/graphQlRequests/insert/acl/setField.test.js.map +1 -1
  218. package/dist/tests/cases/integration/graphQlRequests/insert/aclInsert.test.js +1 -1
  219. package/dist/tests/cases/integration/graphQlRequests/insert/aclInsert.test.js.map +1 -1
  220. package/dist/tests/cases/integration/graphQlRequests/query/acl/fieldRestrictedByLocale.test.js +7 -6
  221. package/dist/tests/cases/integration/graphQlRequests/query/acl/fieldRestrictedByLocale.test.js.map +1 -1
  222. package/dist/tests/cases/integration/graphQlRequests/query/acl/nestedPredicate.test.js +1 -1
  223. package/dist/tests/cases/integration/graphQlRequests/query/acl/nestedPredicate.test.js.map +1 -1
  224. package/dist/tests/cases/integration/graphQlRequests/query/acl/predicateElimination.test.d.ts +2 -0
  225. package/dist/tests/cases/integration/graphQlRequests/query/acl/predicateElimination.test.d.ts.map +1 -0
  226. package/dist/tests/cases/integration/graphQlRequests/query/acl/predicateElimination.test.js +137 -0
  227. package/dist/tests/cases/integration/graphQlRequests/query/acl/predicateElimination.test.js.map +1 -0
  228. package/dist/tests/cases/integration/graphQlRequests/query/filter/complexCondition.test.js +1 -1
  229. package/dist/tests/cases/integration/graphQlRequests/query/filter/composedFilter.test.js +1 -1
  230. package/dist/tests/cases/integration/graphQlRequests/query/filter/composedFilter.test.js.map +1 -1
  231. package/dist/tests/cases/integration/graphQlRequests/query/relations/manyHasManyInverse.test.js +73 -0
  232. package/dist/tests/cases/integration/graphQlRequests/query/relations/manyHasManyInverse.test.js.map +1 -1
  233. package/dist/tests/cases/integration/graphQlRequests/query/relations/manyHasManyOwning.test.js +73 -0
  234. package/dist/tests/cases/integration/graphQlRequests/query/relations/manyHasManyOwning.test.js.map +1 -1
  235. package/dist/tests/cases/integration/graphQlRequests/update/acl/aclUpdate.test.js +6 -6
  236. package/dist/tests/cases/integration/graphQlRequests/update/acl/aclUpdate.test.js.map +1 -1
  237. package/dist/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.js +6 -3
  238. package/dist/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.js.map +1 -1
  239. package/dist/tests/cases/integration/graphQlSchema/model.js.map +1 -1
  240. package/dist/tests/cases/unit/aclVariablesFactory.test.js +7 -33
  241. package/dist/tests/cases/unit/aclVariablesFactory.test.js.map +1 -1
  242. package/dist/tests/cases/unit/conditionOptimizer.test.d.ts +2 -0
  243. package/dist/tests/cases/unit/conditionOptimizer.test.d.ts.map +1 -0
  244. package/dist/tests/cases/unit/conditionOptimizer.test.js +118 -0
  245. package/dist/tests/cases/unit/conditionOptimizer.test.js.map +1 -0
  246. package/dist/tests/cases/unit/orderbyHelper.test.js +1 -0
  247. package/dist/tests/cases/unit/orderbyHelper.test.js.map +1 -1
  248. package/dist/tests/cases/unit/permissionMerger.test.js +2 -0
  249. package/dist/tests/cases/unit/permissionMerger.test.js.map +1 -1
  250. package/dist/tests/cases/unit/predicatesFactory.test.d.ts +2 -0
  251. package/dist/tests/cases/unit/predicatesFactory.test.d.ts.map +1 -0
  252. package/dist/tests/cases/unit/predicatesFactory.test.js +109 -0
  253. package/dist/tests/cases/unit/predicatesFactory.test.js.map +1 -0
  254. package/dist/tests/cases/unit/predicatesInjector.test.js +88 -14
  255. package/dist/tests/cases/unit/predicatesInjector.test.js.map +1 -1
  256. package/dist/tests/cases/unit/variableInjector.test.js +4 -3
  257. package/dist/tests/cases/unit/variableInjector.test.js.map +1 -1
  258. package/dist/tests/cases/unit/whereBuilder.test.d.ts +2 -0
  259. package/dist/tests/cases/unit/whereBuilder.test.d.ts.map +1 -0
  260. package/dist/tests/cases/unit/whereBuilder.test.js +75 -0
  261. package/dist/tests/cases/unit/whereBuilder.test.js.map +1 -0
  262. package/dist/tests/cases/unit/whereOptimizer.test.d.ts +2 -0
  263. package/dist/tests/cases/unit/whereOptimizer.test.d.ts.map +1 -0
  264. package/dist/tests/cases/unit/whereOptimizer.test.js +265 -0
  265. package/dist/tests/cases/unit/whereOptimizer.test.js.map +1 -0
  266. package/dist/tests/src/testGraphql.d.ts.map +1 -1
  267. package/dist/tests/src/testGraphql.js +10 -2
  268. package/dist/tests/src/testGraphql.js.map +1 -1
  269. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  270. package/graphql.codegen.yml +0 -3
  271. package/package.json +16 -16
  272. package/src/acl/EvaluatedPredicateReplacer.ts +32 -0
  273. package/src/acl/PermissionFactory.ts +18 -13
  274. package/src/acl/PredicateFactory.ts +32 -8
  275. package/src/acl/PredicatesInjector.ts +25 -17
  276. package/src/acl/VariableInjector.ts +2 -15
  277. package/src/acl/VariableUtils.ts +7 -23
  278. package/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducerExecutionHandler.ts +17 -24
  279. package/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.ts +1 -6
  280. package/src/extensions/paginatedHasMany/PaginatedHasManyCountVisitor.ts +26 -46
  281. package/src/extensions/paginatedHasMany/PaginatedHasManyExecutionHandler.ts +6 -3
  282. package/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.ts +4 -22
  283. package/src/extensions/paginatedHasMany/PaginatedHasManyNodesVisitor.ts +26 -49
  284. package/src/input-validation/ColumnValueResolver.ts +2 -3
  285. package/src/input-validation/EntityRulesResolver.ts +7 -7
  286. package/src/input-validation/QueryAstFactory.ts +1 -1
  287. package/src/input-validation/ValidationContext.ts +2 -2
  288. package/src/input-validation/ValidationDataSelector.ts +2 -2
  289. package/src/input-validation/preValidation/CreateInputPreValidationProcessor.ts +7 -8
  290. package/src/input-validation/preValidation/InputPreValidator.ts +4 -4
  291. package/src/input-validation/preValidation/UpdateInputPreValidationProcessor.ts +7 -8
  292. package/src/inputProcessing/CreateInputProcessor.ts +8 -9
  293. package/src/inputProcessing/CreateInputVisitor.ts +27 -89
  294. package/src/inputProcessing/UpdateInputProcessor.ts +8 -9
  295. package/src/inputProcessing/UpdateInputVisitor.ts +25 -71
  296. package/src/inputProcessing/index.ts +0 -1
  297. package/src/introspection/IntrospectionSchemaFactory.ts +7 -7
  298. package/src/introspection/content-schema.types.ts +19 -286
  299. package/src/mapper/Mapper.ts +37 -30
  300. package/src/mapper/MapperContainer.ts +10 -5
  301. package/src/mapper/delete/DeleteExecutor.ts +3 -3
  302. package/src/mapper/insert/SqlCreateInputProcessor.ts +3 -3
  303. package/src/mapper/select/JoinVisitor.ts +6 -33
  304. package/src/mapper/select/RelationFetcher.ts +101 -41
  305. package/src/mapper/select/SelectBuilder.ts +3 -1
  306. package/src/mapper/select/SelectBuilderFactory.ts +2 -1
  307. package/src/mapper/select/SelectExecutionHandler.ts +1 -0
  308. package/src/mapper/select/WhereBuilder.ts +95 -34
  309. package/src/mapper/select/handlers/FieldsVisitor.ts +47 -57
  310. package/src/mapper/select/handlers/FieldsVisitorFactory.ts +1 -0
  311. package/src/mapper/select/optimizer/ConditionOptimizer.ts +41 -0
  312. package/src/mapper/select/optimizer/WhereOptimizer.ts +138 -0
  313. package/src/mapper/select/optimizer/WhereReplacer.ts +27 -0
  314. package/src/mapper/select/optimizer/helpers.ts +58 -0
  315. package/src/mapper/update/SqlUpdateInputProcessor.ts +1 -1
  316. package/src/mapper/update/UpdateBuilder.ts +3 -3
  317. package/src/resolvers/GraphQlQueryAstFactory.ts +3 -3
  318. package/src/resolvers/MutationResolver.ts +1 -1
  319. package/src/resolvers/ReadHelpers.ts +3 -3
  320. package/src/resolvers/ReadResolver.ts +2 -2
  321. package/src/schema/FieldAccessVisitor.ts +2 -2
  322. package/src/schema/OrderByTypeProvider.ts +1 -1
  323. package/src/schema/WhereTypeProvider.ts +4 -4
  324. package/src/schema/entities/FieldArgsVisitor.ts +3 -3
  325. package/src/schema/entities/FieldTypeVisitor.ts +3 -3
  326. package/src/schema/mutations/CreateEntityInputFieldVisitor.ts +3 -6
  327. package/src/schema/mutations/CreateEntityRelationAllowedOperationsVisitor.ts +6 -20
  328. package/src/schema/mutations/CreateEntityRelationInputFieldVisitor.ts +5 -18
  329. package/src/schema/mutations/UpdateEntityInputFieldVisitor.ts +3 -6
  330. package/src/schema/mutations/UpdateEntityRelationAllowedOperationsVisitor.ts +6 -20
  331. package/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.ts +2 -12
  332. package/src/utils/object.ts +6 -6
  333. package/src/utils/uniqueWhereFields.ts +3 -3
  334. package/tests/cases/integration/graphQlDb/insert/insertSequence.test.ts +34 -0
  335. package/tests/cases/integration/graphQlRequests/delete/aclDelete.test.ts +2 -2
  336. package/tests/cases/integration/graphQlRequests/insert/acl/setField.test.ts +3 -3
  337. package/tests/cases/integration/graphQlRequests/insert/aclInsert.test.ts +2 -2
  338. package/tests/cases/integration/graphQlRequests/query/acl/fieldRestrictedByLocale.test.ts +7 -6
  339. package/tests/cases/integration/graphQlRequests/query/acl/nestedPredicate.test.ts +1 -1
  340. package/tests/cases/integration/graphQlRequests/query/acl/predicateElimination.test.ts +130 -0
  341. package/tests/cases/integration/graphQlRequests/query/filter/complexCondition.test.ts +1 -1
  342. package/tests/cases/integration/graphQlRequests/query/filter/composedFilter.test.ts +1 -1
  343. package/tests/cases/integration/graphQlRequests/query/relations/manyHasManyInverse.test.ts +74 -0
  344. package/tests/cases/integration/graphQlRequests/query/relations/manyHasManyOwning.test.ts +77 -0
  345. package/tests/cases/integration/graphQlRequests/update/acl/aclUpdate.test.ts +7 -7
  346. package/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.ts +5 -5
  347. package/tests/cases/unit/aclVariablesFactory.test.ts +8 -35
  348. package/tests/cases/unit/conditionOptimizer.test.ts +135 -0
  349. package/tests/cases/unit/orderbyHelper.test.ts +1 -0
  350. package/tests/cases/unit/permissionMerger.test.ts +2 -0
  351. package/tests/cases/unit/predicatesFactory.test.ts +103 -0
  352. package/tests/cases/unit/predicatesInjector.test.ts +78 -16
  353. package/tests/cases/unit/variableInjector.test.ts +6 -5
  354. package/tests/cases/unit/whereBuilder.test.ts +84 -0
  355. package/tests/cases/unit/whereOptimizer.test.ts +289 -0
  356. package/tests/src/testGraphql.ts +9 -2
  357. package/dist/src/inputProcessing/InputContext.d.ts +0 -43
  358. package/dist/src/inputProcessing/InputContext.d.ts.map +0 -1
  359. package/dist/src/inputProcessing/InputContext.js +0 -3
  360. package/dist/src/inputProcessing/InputContext.js.map +0 -1
  361. package/src/inputProcessing/InputContext.ts +0 -49
@@ -1,10 +1,17 @@
1
1
  import { isIt } from '../../utils'
2
- import { acceptFieldVisitor } from '@contember/schema-utils'
2
+ import { acceptFieldVisitor, isColumn } from '@contember/schema-utils'
3
3
  import { Input, Model } from '@contember/schema'
4
4
  import { Path, PathFactory } from './Path'
5
5
  import { JoinBuilder } from './JoinBuilder'
6
6
  import { ConditionBuilder } from './ConditionBuilder'
7
- import { ConditionBuilder as SqlConditionBuilder, Operator, QueryBuilder, SelectBuilder } from '@contember/database'
7
+ import {
8
+ ConditionBuilder as SqlConditionBuilder,
9
+ Literal,
10
+ Operator,
11
+ QueryBuilder,
12
+ SelectBuilder, wrapIdentifier,
13
+ } from '@contember/database'
14
+ import { WhereOptimizer } from './optimizer/WhereOptimizer'
8
15
 
9
16
  export class WhereBuilder {
10
17
  constructor(
@@ -12,6 +19,7 @@ export class WhereBuilder {
12
19
  private readonly joinBuilder: JoinBuilder,
13
20
  private readonly conditionBuilder: ConditionBuilder,
14
21
  private readonly pathFactory: PathFactory,
22
+ private readonly whereOptimizer: WhereOptimizer,
15
23
  ) {}
16
24
 
17
25
  public build(
@@ -19,28 +27,41 @@ export class WhereBuilder {
19
27
  entity: Model.Entity,
20
28
  path: Path,
21
29
  where: Input.OptionalWhere,
22
- allowManyJoin: boolean = false,
30
+ relationPath: Model.AnyRelationContext[] = [],
23
31
  ) {
24
- return this.buildAdvanced(entity, path, where, cb => qb.where(clause => cb(clause)), allowManyJoin)
32
+ const optimizedWhere = this.whereOptimizer.optimize(where, entity, relationPath)
33
+ return this.buildInternal(entity, path, optimizedWhere, cb => qb.where(clause => cb(clause)), false)
25
34
  }
26
35
 
36
+
27
37
  public buildAdvanced(
28
38
  entity: Model.Entity,
29
39
  path: Path,
30
40
  where: Input.OptionalWhere,
31
41
  callback: (clauseCb: (clause: SqlConditionBuilder) => SqlConditionBuilder) => SelectBuilder<SelectBuilder.Result>,
32
- allowManyJoin: boolean = false,
42
+ relationPath: Model.AnyRelationContext[] = [],
43
+ ) {
44
+ const optimizedWhere = this.whereOptimizer.optimize(where, entity, relationPath)
45
+ return this.buildInternal(entity, path, optimizedWhere, callback, false)
46
+ }
47
+
48
+ private buildInternal(
49
+ entity: Model.Entity,
50
+ path: Path,
51
+ where: Input.OptionalWhere,
52
+ callback: (clauseCb: (clause: SqlConditionBuilder) => SqlConditionBuilder) => SelectBuilder<SelectBuilder.Result>,
53
+ allowManyJoin: boolean,
33
54
  ) {
34
55
  const joinList: WhereJoinDefinition[] = []
35
56
 
36
- const qbWithWhere = callback(clause => this.buildInternal(clause, entity, path, where, allowManyJoin, joinList))
57
+ const qbWithWhere = callback(clause => this.buildRecursive(clause, entity, path, where, allowManyJoin, joinList))
37
58
  return joinList.reduce<SelectBuilder<SelectBuilder.Result>>(
38
59
  (qb, { path, entity, relationName }) => this.joinBuilder.join(qb, path, entity, relationName),
39
60
  qbWithWhere,
40
61
  )
41
62
  }
42
63
 
43
- private buildInternal(
64
+ private buildRecursive(
44
65
  conditionBuilder: SqlConditionBuilder,
45
66
  entity: Model.Entity,
46
67
  path: Path,
@@ -55,7 +76,7 @@ export class WhereBuilder {
55
76
  conditionBuilder = conditionBuilder.and(clause =>
56
77
  expr.reduce(
57
78
  (clause2, where) =>
58
- !where ? clause2 : this.buildInternal(clause2, entity, path, where, allowManyJoin, joinList),
79
+ !where ? clause2 : this.buildRecursive(clause2, entity, path, where, allowManyJoin, joinList),
59
80
  clause,
60
81
  ),
61
82
  )
@@ -67,7 +88,7 @@ export class WhereBuilder {
67
88
  (clause2, where) =>
68
89
  !where
69
90
  ? clause2
70
- : clause2.and(clause3 => this.buildInternal(clause3, entity, path, where, allowManyJoin, joinList)),
91
+ : clause2.and(clause3 => this.buildRecursive(clause3, entity, path, where, allowManyJoin, joinList)),
71
92
  clause,
72
93
  ),
73
94
  )
@@ -75,7 +96,7 @@ export class WhereBuilder {
75
96
  if (where.not !== undefined) {
76
97
  const expr = where.not
77
98
  conditionBuilder = conditionBuilder.not(clause =>
78
- this.buildInternal(clause, entity, path, expr, allowManyJoin, joinList),
99
+ this.buildRecursive(clause, entity, path, expr, allowManyJoin, joinList),
79
100
  )
80
101
  }
81
102
 
@@ -84,11 +105,7 @@ export class WhereBuilder {
84
105
  continue
85
106
  }
86
107
 
87
- const joinedWhere = (
88
- entity: Model.Entity,
89
- relation: Model.Relation,
90
- targetEntity: Model.Entity,
91
- ): SqlConditionBuilder => {
108
+ const joinedWhere = ({ targetEntity, relation, entity }: Model.AnyRelationContext): SqlConditionBuilder => {
92
109
  const targetPath = path.for(fieldName)
93
110
  const relationWhere = where[fieldName] as Input.Where
94
111
  if (Object.keys(relationWhere).length === 0) {
@@ -109,36 +126,37 @@ export class WhereBuilder {
109
126
 
110
127
  joinList.push({ path: targetPath, entity, relationName: relation.name })
111
128
 
112
- return this.buildInternal(conditionBuilder, targetEntity, targetPath, relationWhere, allowManyJoin, joinList)
129
+ return this.buildRecursive(conditionBuilder, targetEntity, targetPath, relationWhere, allowManyJoin, joinList)
113
130
  }
114
131
 
115
132
  conditionBuilder = acceptFieldVisitor<SqlConditionBuilder>(this.schema, entity, fieldName, {
116
- visitColumn: (entity, column) => {
133
+ visitColumn: ({ entity, column }) => {
117
134
  const subWhere: Input.Condition<Input.ColumnValue> = where[column.name] as Input.Condition<Input.ColumnValue>
118
135
  return this.conditionBuilder.build(conditionBuilder, tableName, column.columnName, column.columnType, subWhere)
119
136
  },
120
137
  visitOneHasOneInverse: joinedWhere,
121
138
  visitOneHasOneOwning: joinedWhere,
122
139
  visitManyHasOne: joinedWhere,
123
- visitManyHasManyInverse: (entity, relation, targetEntity, targetRelation) => {
140
+ visitManyHasManyInverse: context => {
124
141
  if (allowManyJoin) {
125
- return joinedWhere(entity, relation, targetEntity)
142
+ return joinedWhere(context)
126
143
  }
144
+
127
145
  const relationWhere = where[fieldName] as Input.Where
128
146
 
129
147
  return conditionBuilder.exists(
130
148
  this.createManyHasManySubquery(
131
149
  [tableName, entity.primaryColumn],
132
150
  relationWhere,
133
- targetEntity,
134
- targetRelation.joiningTable,
151
+ context.targetEntity,
152
+ context.targetRelation.joiningTable,
135
153
  'inverse',
136
154
  ),
137
155
  )
138
156
  },
139
- visitManyHasManyOwning: (entity, relation, targetEntity) => {
157
+ visitManyHasManyOwning: context => {
140
158
  if (allowManyJoin) {
141
- return joinedWhere(entity, relation, targetEntity)
159
+ return joinedWhere(context)
142
160
  }
143
161
 
144
162
  const relationWhere = where[fieldName] as Input.Where
@@ -147,28 +165,37 @@ export class WhereBuilder {
147
165
  this.createManyHasManySubquery(
148
166
  [tableName, entity.primaryColumn],
149
167
  relationWhere,
150
- targetEntity,
151
- relation.joiningTable,
168
+ context.targetEntity,
169
+ context.relation.joiningTable,
152
170
  'owning',
153
171
  ),
154
172
  )
155
173
  },
156
- visitOneHasMany: (entity, relation, targetEntity, targetRelation) => {
174
+ visitOneHasMany: context => {
157
175
  if (allowManyJoin) {
158
- return joinedWhere(entity, relation, targetEntity)
176
+ return joinedWhere(context)
159
177
  }
160
178
 
161
179
  const relationWhere = where[fieldName] as Input.Where
162
180
 
181
+ const qb = this.hasRootIsNull(relationWhere, context.targetEntity)
182
+ ? SelectBuilder.create()
183
+ .select(it => it.raw('1'))
184
+ .from(new Literal(`(select ${wrapIdentifier(tableName)}.${wrapIdentifier(entity.primaryColumn)})`), 'sub2_')
185
+ .leftJoin(context.targetEntity.tableName, 'sub_', it =>
186
+ it.columnsEq(['sub2_', entity.primaryColumn], ['sub_', context.targetRelation.joiningColumn.columnName]),
187
+ )
188
+ : SelectBuilder.create()
189
+ .select(it => it.raw('1'))
190
+ .from(context.targetEntity.tableName, 'sub_')
191
+ .where(it => it.columnsEq([tableName, entity.primaryColumn], ['sub_', context.targetRelation.joiningColumn.columnName]))
192
+
163
193
  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,
194
+ this.buildInternal(
195
+ context.targetEntity,
170
196
  this.pathFactory.create([], 'sub_'),
171
197
  relationWhere,
198
+ cb => qb.where(clause => cb(clause)),
172
199
  true,
173
200
  ),
174
201
  )
@@ -178,6 +205,7 @@ export class WhereBuilder {
178
205
  return conditionBuilder
179
206
  }
180
207
 
208
+
181
209
  private createManyHasManySubquery(
182
210
  outerColumn: QueryBuilder.ColumnIdentifier,
183
211
  relationWhere: Input.Where,
@@ -205,7 +233,7 @@ export class WhereBuilder {
205
233
  const qbJoined = qb.join(targetEntity.tableName, 'sub_', clause =>
206
234
  clause.compareColumns(['junction_', toColumn], Operator.eq, ['sub_', targetEntity.primary]),
207
235
  )
208
- return this.buildAdvanced(
236
+ return this.buildInternal(
209
237
  targetEntity,
210
238
  this.pathFactory.create([], 'sub_'),
211
239
  relationWhere,
@@ -257,6 +285,39 @@ export class WhereBuilder {
257
285
  }
258
286
  return condition
259
287
  }
288
+
289
+ private hasRootIsNull(where: Input.Where, entity: Model.Entity): boolean {
290
+ for (const key in where) {
291
+ if (key === 'and' || key === 'or') {
292
+ if (where[key]?.some(it => this.hasRootIsNull(it, entity))) {
293
+ return true
294
+ }
295
+ } else if (key === 'not') {
296
+ if (where.not && this.hasRootIsNull(where.not, entity)) {
297
+ return true
298
+ }
299
+ } else if (isColumn(entity.fields[key]) && this.conditionHasIsNull(where[key] as Input.Condition)) {
300
+ return true
301
+ }
302
+ }
303
+ return false
304
+ }
305
+
306
+ private conditionHasIsNull(cond: Input.Condition): boolean {
307
+ if (cond.isNull !== undefined) {
308
+ return true
309
+ }
310
+ if (cond.and && cond.and.some(it => this.conditionHasIsNull(it))) {
311
+ return true
312
+ }
313
+ if (cond.or && cond.or.some(it => this.conditionHasIsNull(it))) {
314
+ return true
315
+ }
316
+ if (cond.not && this.conditionHasIsNull(cond.not)) {
317
+ return true
318
+ }
319
+ return false
320
+ }
260
321
  }
261
322
 
262
323
  export type WhereJoinDefinition = { path: Path; entity: Model.Entity; relationName: string }
@@ -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
+ }