@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.
- package/dist/src/acl/EvaluatedPredicateReplacer.d.ts +9 -0
- package/dist/src/acl/EvaluatedPredicateReplacer.d.ts.map +1 -0
- package/dist/src/acl/EvaluatedPredicateReplacer.js +31 -0
- package/dist/src/acl/EvaluatedPredicateReplacer.js.map +1 -0
- package/dist/src/acl/PermissionFactory.d.ts.map +1 -1
- package/dist/src/acl/PermissionFactory.js +15 -11
- package/dist/src/acl/PermissionFactory.js.map +1 -1
- package/dist/src/acl/PredicateFactory.d.ts +4 -2
- package/dist/src/acl/PredicateFactory.d.ts.map +1 -1
- package/dist/src/acl/PredicateFactory.js +17 -6
- package/dist/src/acl/PredicateFactory.js.map +1 -1
- package/dist/src/acl/PredicatesInjector.d.ts +1 -1
- package/dist/src/acl/PredicatesInjector.d.ts.map +1 -1
- package/dist/src/acl/PredicatesInjector.js +16 -19
- package/dist/src/acl/PredicatesInjector.js.map +1 -1
- package/dist/src/acl/VariableInjector.d.ts +0 -1
- package/dist/src/acl/VariableInjector.d.ts.map +1 -1
- package/dist/src/acl/VariableInjector.js +4 -14
- package/dist/src/acl/VariableInjector.js.map +1 -1
- package/dist/src/acl/VariableUtils.d.ts +2 -13
- package/dist/src/acl/VariableUtils.d.ts.map +1 -1
- package/dist/src/acl/VariableUtils.js +5 -16
- package/dist/src/acl/VariableUtils.js.map +1 -1
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducerExecutionHandler.d.ts +0 -1
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducerExecutionHandler.d.ts.map +1 -1
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducerExecutionHandler.js +14 -15
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducerExecutionHandler.js.map +1 -1
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.d.ts +1 -1
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.d.ts.map +1 -1
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.js +1 -1
- package/dist/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.js.map +1 -1
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyCountVisitor.d.ts +5 -4
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyCountVisitor.d.ts.map +1 -1
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyCountVisitor.js +29 -20
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyCountVisitor.js.map +1 -1
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyExecutionHandler.d.ts.map +1 -1
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyExecutionHandler.js +2 -2
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyExecutionHandler.js.map +1 -1
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.d.ts +3 -3
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.d.ts.map +1 -1
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.js +3 -3
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.js.map +1 -1
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyNodesVisitor.d.ts +5 -4
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyNodesVisitor.d.ts.map +1 -1
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyNodesVisitor.js +29 -20
- package/dist/src/extensions/paginatedHasMany/PaginatedHasManyNodesVisitor.js.map +1 -1
- package/dist/src/input-validation/ColumnValueResolver.d.ts +4 -3
- package/dist/src/input-validation/ColumnValueResolver.d.ts.map +1 -1
- package/dist/src/input-validation/ColumnValueResolver.js.map +1 -1
- package/dist/src/input-validation/EntityRulesResolver.js +7 -7
- package/dist/src/input-validation/EntityRulesResolver.js.map +1 -1
- package/dist/src/input-validation/QueryAstFactory.js +1 -1
- package/dist/src/input-validation/QueryAstFactory.js.map +1 -1
- package/dist/src/input-validation/ValidationContext.d.ts +2 -2
- package/dist/src/input-validation/ValidationContext.d.ts.map +1 -1
- package/dist/src/input-validation/ValidationContext.js.map +1 -1
- package/dist/src/input-validation/ValidationDataSelector.d.ts.map +1 -1
- package/dist/src/input-validation/ValidationDataSelector.js +1 -1
- package/dist/src/input-validation/ValidationDataSelector.js.map +1 -1
- package/dist/src/input-validation/preValidation/CreateInputPreValidationProcessor.d.ts +7 -8
- package/dist/src/input-validation/preValidation/CreateInputPreValidationProcessor.d.ts.map +1 -1
- package/dist/src/input-validation/preValidation/CreateInputPreValidationProcessor.js.map +1 -1
- package/dist/src/input-validation/preValidation/InputPreValidator.js +4 -4
- package/dist/src/input-validation/preValidation/InputPreValidator.js.map +1 -1
- package/dist/src/input-validation/preValidation/UpdateInputPreValidationProcessor.d.ts +7 -8
- package/dist/src/input-validation/preValidation/UpdateInputPreValidationProcessor.d.ts.map +1 -1
- package/dist/src/input-validation/preValidation/UpdateInputPreValidationProcessor.js.map +1 -1
- package/dist/src/inputProcessing/CreateInputProcessor.d.ts +8 -9
- package/dist/src/inputProcessing/CreateInputProcessor.d.ts.map +1 -1
- package/dist/src/inputProcessing/CreateInputVisitor.d.ts +7 -7
- package/dist/src/inputProcessing/CreateInputVisitor.d.ts.map +1 -1
- package/dist/src/inputProcessing/CreateInputVisitor.js +15 -46
- package/dist/src/inputProcessing/CreateInputVisitor.js.map +1 -1
- package/dist/src/inputProcessing/UpdateInputProcessor.d.ts +8 -9
- package/dist/src/inputProcessing/UpdateInputProcessor.d.ts.map +1 -1
- package/dist/src/inputProcessing/UpdateInputVisitor.d.ts +7 -7
- package/dist/src/inputProcessing/UpdateInputVisitor.d.ts.map +1 -1
- package/dist/src/inputProcessing/UpdateInputVisitor.js +13 -28
- package/dist/src/inputProcessing/UpdateInputVisitor.js.map +1 -1
- package/dist/src/inputProcessing/index.d.ts +0 -1
- package/dist/src/inputProcessing/index.d.ts.map +1 -1
- package/dist/src/inputProcessing/index.js +0 -1
- package/dist/src/inputProcessing/index.js.map +1 -1
- package/dist/src/introspection/IntrospectionSchemaFactory.js +7 -7
- package/dist/src/introspection/IntrospectionSchemaFactory.js.map +1 -1
- package/dist/src/introspection/content-schema.types.d.ts +19 -223
- package/dist/src/introspection/content-schema.types.d.ts.map +1 -1
- package/dist/src/introspection/content-schema.types.js +2 -2
- package/dist/src/introspection/content-schema.types.js.map +1 -1
- package/dist/src/mapper/Mapper.d.ts +6 -6
- package/dist/src/mapper/Mapper.d.ts.map +1 -1
- package/dist/src/mapper/Mapper.js +28 -23
- package/dist/src/mapper/Mapper.js.map +1 -1
- package/dist/src/mapper/MapperContainer.d.ts.map +1 -1
- package/dist/src/mapper/MapperContainer.js +7 -4
- package/dist/src/mapper/MapperContainer.js.map +1 -1
- package/dist/src/mapper/delete/DeleteExecutor.js +3 -3
- package/dist/src/mapper/delete/DeleteExecutor.js.map +1 -1
- package/dist/src/mapper/insert/SqlCreateInputProcessor.d.ts +4 -2
- package/dist/src/mapper/insert/SqlCreateInputProcessor.d.ts.map +1 -1
- package/dist/src/mapper/insert/SqlCreateInputProcessor.js.map +1 -1
- package/dist/src/mapper/select/JoinVisitor.d.ts +6 -6
- package/dist/src/mapper/select/JoinVisitor.d.ts.map +1 -1
- package/dist/src/mapper/select/JoinVisitor.js +6 -6
- package/dist/src/mapper/select/JoinVisitor.js.map +1 -1
- package/dist/src/mapper/select/RelationFetcher.d.ts +32 -5
- package/dist/src/mapper/select/RelationFetcher.d.ts.map +1 -1
- package/dist/src/mapper/select/RelationFetcher.js +37 -15
- package/dist/src/mapper/select/RelationFetcher.js.map +1 -1
- package/dist/src/mapper/select/SelectBuilder.d.ts +2 -1
- package/dist/src/mapper/select/SelectBuilder.d.ts.map +1 -1
- package/dist/src/mapper/select/SelectBuilder.js +4 -2
- package/dist/src/mapper/select/SelectBuilder.js.map +1 -1
- package/dist/src/mapper/select/SelectBuilderFactory.d.ts +2 -1
- package/dist/src/mapper/select/SelectBuilderFactory.d.ts.map +1 -1
- package/dist/src/mapper/select/SelectExecutionHandler.d.ts +1 -0
- package/dist/src/mapper/select/SelectExecutionHandler.d.ts.map +1 -1
- package/dist/src/mapper/select/WhereBuilder.d.ts +8 -3
- package/dist/src/mapper/select/WhereBuilder.d.ts.map +1 -1
- package/dist/src/mapper/select/WhereBuilder.js +71 -25
- package/dist/src/mapper/select/WhereBuilder.js.map +1 -1
- package/dist/src/mapper/select/handlers/FieldsVisitor.d.ts +9 -8
- package/dist/src/mapper/select/handlers/FieldsVisitor.d.ts.map +1 -1
- package/dist/src/mapper/select/handlers/FieldsVisitor.js +45 -24
- package/dist/src/mapper/select/handlers/FieldsVisitor.js.map +1 -1
- package/dist/src/mapper/select/handlers/FieldsVisitorFactory.d.ts.map +1 -1
- package/dist/src/mapper/select/handlers/FieldsVisitorFactory.js +1 -1
- package/dist/src/mapper/select/handlers/FieldsVisitorFactory.js.map +1 -1
- package/dist/src/mapper/select/optimizer/ConditionOptimizer.d.ts +5 -0
- package/dist/src/mapper/select/optimizer/ConditionOptimizer.d.ts.map +1 -0
- package/dist/src/mapper/select/optimizer/ConditionOptimizer.js +39 -0
- package/dist/src/mapper/select/optimizer/ConditionOptimizer.js.map +1 -0
- package/dist/src/mapper/select/optimizer/WhereOptimizer.d.ts +15 -0
- package/dist/src/mapper/select/optimizer/WhereOptimizer.d.ts.map +1 -0
- package/dist/src/mapper/select/optimizer/WhereOptimizer.js +118 -0
- package/dist/src/mapper/select/optimizer/WhereOptimizer.js.map +1 -0
- package/dist/src/mapper/select/optimizer/WhereReplacer.d.ts +6 -0
- package/dist/src/mapper/select/optimizer/WhereReplacer.d.ts.map +1 -0
- package/dist/src/mapper/select/optimizer/WhereReplacer.js +28 -0
- package/dist/src/mapper/select/optimizer/WhereReplacer.js.map +1 -0
- package/dist/src/mapper/select/optimizer/helpers.d.ts +10 -0
- package/dist/src/mapper/select/optimizer/helpers.d.ts.map +1 -0
- package/dist/src/mapper/select/optimizer/helpers.js +72 -0
- package/dist/src/mapper/select/optimizer/helpers.js.map +1 -0
- package/dist/src/mapper/update/SqlUpdateInputProcessor.d.ts +2 -3
- package/dist/src/mapper/update/SqlUpdateInputProcessor.d.ts.map +1 -1
- package/dist/src/mapper/update/SqlUpdateInputProcessor.js.map +1 -1
- package/dist/src/mapper/update/UpdateBuilder.js +3 -3
- package/dist/src/mapper/update/UpdateBuilder.js.map +1 -1
- package/dist/src/resolvers/GraphQlQueryAstFactory.js +2 -2
- package/dist/src/resolvers/GraphQlQueryAstFactory.js.map +1 -1
- package/dist/src/resolvers/MutationResolver.js +15 -15
- package/dist/src/resolvers/MutationResolver.js.map +1 -1
- package/dist/src/resolvers/ReadHelpers.js +10 -10
- package/dist/src/resolvers/ReadHelpers.js.map +1 -1
- package/dist/src/resolvers/ReadResolver.js +2 -2
- package/dist/src/resolvers/ReadResolver.js.map +1 -1
- package/dist/src/schema/FieldAccessVisitor.d.ts +2 -2
- package/dist/src/schema/FieldAccessVisitor.d.ts.map +1 -1
- package/dist/src/schema/FieldAccessVisitor.js +2 -2
- package/dist/src/schema/FieldAccessVisitor.js.map +1 -1
- package/dist/src/schema/MutationProvider.js +4 -4
- package/dist/src/schema/MutationProvider.js.map +1 -1
- package/dist/src/schema/OrderByTypeProvider.js +1 -1
- package/dist/src/schema/OrderByTypeProvider.js.map +1 -1
- package/dist/src/schema/QueryProvider.js +3 -3
- package/dist/src/schema/QueryProvider.js.map +1 -1
- package/dist/src/schema/ResultSchemaTypeProvider.d.ts +2 -2
- package/dist/src/schema/ResultSchemaTypeProvider.d.ts.map +1 -1
- package/dist/src/schema/WhereTypeProvider.js +4 -4
- package/dist/src/schema/WhereTypeProvider.js.map +1 -1
- package/dist/src/schema/entities/FieldArgsVisitor.d.ts +7 -7
- package/dist/src/schema/entities/FieldArgsVisitor.d.ts.map +1 -1
- package/dist/src/schema/entities/FieldArgsVisitor.js +3 -3
- package/dist/src/schema/entities/FieldArgsVisitor.js.map +1 -1
- package/dist/src/schema/entities/FieldTypeVisitor.d.ts +3 -3
- package/dist/src/schema/entities/FieldTypeVisitor.d.ts.map +1 -1
- package/dist/src/schema/entities/FieldTypeVisitor.js +3 -3
- package/dist/src/schema/entities/FieldTypeVisitor.js.map +1 -1
- package/dist/src/schema/mutations/CreateEntityInputFieldVisitor.d.ts +3 -3
- package/dist/src/schema/mutations/CreateEntityInputFieldVisitor.d.ts.map +1 -1
- package/dist/src/schema/mutations/CreateEntityInputFieldVisitor.js +3 -3
- package/dist/src/schema/mutations/CreateEntityInputFieldVisitor.js.map +1 -1
- package/dist/src/schema/mutations/CreateEntityRelationAllowedOperationsVisitor.d.ts +6 -6
- package/dist/src/schema/mutations/CreateEntityRelationAllowedOperationsVisitor.d.ts.map +1 -1
- package/dist/src/schema/mutations/CreateEntityRelationAllowedOperationsVisitor.js +6 -6
- package/dist/src/schema/mutations/CreateEntityRelationAllowedOperationsVisitor.js.map +1 -1
- package/dist/src/schema/mutations/CreateEntityRelationInputFieldVisitor.d.ts +3 -3
- package/dist/src/schema/mutations/CreateEntityRelationInputFieldVisitor.d.ts.map +1 -1
- package/dist/src/schema/mutations/CreateEntityRelationInputFieldVisitor.js +5 -5
- package/dist/src/schema/mutations/CreateEntityRelationInputFieldVisitor.js.map +1 -1
- package/dist/src/schema/mutations/UpdateEntityInputFieldVisitor.d.ts +10 -4
- package/dist/src/schema/mutations/UpdateEntityInputFieldVisitor.d.ts.map +1 -1
- package/dist/src/schema/mutations/UpdateEntityInputFieldVisitor.js +3 -3
- package/dist/src/schema/mutations/UpdateEntityInputFieldVisitor.js.map +1 -1
- package/dist/src/schema/mutations/UpdateEntityRelationAllowedOperationsVisitor.d.ts +6 -6
- package/dist/src/schema/mutations/UpdateEntityRelationAllowedOperationsVisitor.d.ts.map +1 -1
- package/dist/src/schema/mutations/UpdateEntityRelationAllowedOperationsVisitor.js +6 -6
- package/dist/src/schema/mutations/UpdateEntityRelationAllowedOperationsVisitor.js.map +1 -1
- package/dist/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.d.ts +2 -2
- package/dist/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.d.ts.map +1 -1
- package/dist/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.js +2 -2
- package/dist/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/src/utils/object.d.ts.map +1 -1
- package/dist/src/utils/object.js +3 -4
- package/dist/src/utils/object.js.map +1 -1
- package/dist/src/utils/uniqueWhereFields.js +3 -3
- package/dist/src/utils/uniqueWhereFields.js.map +1 -1
- package/dist/tests/cases/integration/graphQlDb/insert/insertSequence.test.d.ts +2 -0
- package/dist/tests/cases/integration/graphQlDb/insert/insertSequence.test.d.ts.map +1 -0
- package/dist/tests/cases/integration/graphQlDb/insert/insertSequence.test.js +38 -0
- package/dist/tests/cases/integration/graphQlDb/insert/insertSequence.test.js.map +1 -0
- package/dist/tests/cases/integration/graphQlRequests/delete/aclDelete.test.js +1 -1
- package/dist/tests/cases/integration/graphQlRequests/delete/aclDelete.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/insert/acl/setField.test.js +2 -2
- package/dist/tests/cases/integration/graphQlRequests/insert/acl/setField.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/insert/aclInsert.test.js +1 -1
- package/dist/tests/cases/integration/graphQlRequests/insert/aclInsert.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/acl/fieldRestrictedByLocale.test.js +7 -6
- package/dist/tests/cases/integration/graphQlRequests/query/acl/fieldRestrictedByLocale.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/acl/nestedPredicate.test.js +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/acl/nestedPredicate.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/acl/predicateElimination.test.d.ts +2 -0
- package/dist/tests/cases/integration/graphQlRequests/query/acl/predicateElimination.test.d.ts.map +1 -0
- package/dist/tests/cases/integration/graphQlRequests/query/acl/predicateElimination.test.js +137 -0
- package/dist/tests/cases/integration/graphQlRequests/query/acl/predicateElimination.test.js.map +1 -0
- package/dist/tests/cases/integration/graphQlRequests/query/filter/complexCondition.test.js +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/filter/composedFilter.test.js +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/filter/composedFilter.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/relations/manyHasManyInverse.test.js +73 -0
- package/dist/tests/cases/integration/graphQlRequests/query/relations/manyHasManyInverse.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/query/relations/manyHasManyOwning.test.js +73 -0
- package/dist/tests/cases/integration/graphQlRequests/query/relations/manyHasManyOwning.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlRequests/update/acl/aclUpdate.test.js +6 -6
- package/dist/tests/cases/integration/graphQlRequests/update/acl/aclUpdate.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.js +6 -3
- package/dist/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.js.map +1 -1
- package/dist/tests/cases/integration/graphQlSchema/model.js.map +1 -1
- package/dist/tests/cases/unit/aclVariablesFactory.test.js +7 -33
- package/dist/tests/cases/unit/aclVariablesFactory.test.js.map +1 -1
- package/dist/tests/cases/unit/conditionOptimizer.test.d.ts +2 -0
- package/dist/tests/cases/unit/conditionOptimizer.test.d.ts.map +1 -0
- package/dist/tests/cases/unit/conditionOptimizer.test.js +118 -0
- package/dist/tests/cases/unit/conditionOptimizer.test.js.map +1 -0
- package/dist/tests/cases/unit/orderbyHelper.test.js +1 -0
- package/dist/tests/cases/unit/orderbyHelper.test.js.map +1 -1
- package/dist/tests/cases/unit/permissionMerger.test.js +2 -0
- package/dist/tests/cases/unit/permissionMerger.test.js.map +1 -1
- package/dist/tests/cases/unit/predicatesFactory.test.d.ts +2 -0
- package/dist/tests/cases/unit/predicatesFactory.test.d.ts.map +1 -0
- package/dist/tests/cases/unit/predicatesFactory.test.js +109 -0
- package/dist/tests/cases/unit/predicatesFactory.test.js.map +1 -0
- package/dist/tests/cases/unit/predicatesInjector.test.js +88 -14
- package/dist/tests/cases/unit/predicatesInjector.test.js.map +1 -1
- package/dist/tests/cases/unit/variableInjector.test.js +4 -3
- package/dist/tests/cases/unit/variableInjector.test.js.map +1 -1
- package/dist/tests/cases/unit/whereBuilder.test.d.ts +2 -0
- package/dist/tests/cases/unit/whereBuilder.test.d.ts.map +1 -0
- package/dist/tests/cases/unit/whereBuilder.test.js +75 -0
- package/dist/tests/cases/unit/whereBuilder.test.js.map +1 -0
- package/dist/tests/cases/unit/whereOptimizer.test.d.ts +2 -0
- package/dist/tests/cases/unit/whereOptimizer.test.d.ts.map +1 -0
- package/dist/tests/cases/unit/whereOptimizer.test.js +265 -0
- package/dist/tests/cases/unit/whereOptimizer.test.js.map +1 -0
- package/dist/tests/src/testGraphql.d.ts.map +1 -1
- package/dist/tests/src/testGraphql.js +10 -2
- package/dist/tests/src/testGraphql.js.map +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/graphql.codegen.yml +0 -3
- package/package.json +16 -16
- package/src/acl/EvaluatedPredicateReplacer.ts +32 -0
- package/src/acl/PermissionFactory.ts +18 -13
- package/src/acl/PredicateFactory.ts +32 -8
- package/src/acl/PredicatesInjector.ts +25 -17
- package/src/acl/VariableInjector.ts +2 -15
- package/src/acl/VariableUtils.ts +7 -23
- package/src/extensions/hasManyToHasOneReducer/HasManyToHasOneReducerExecutionHandler.ts +17 -24
- package/src/extensions/hasManyToHasOneReducer/HasManyToHasOneRelationReducerVisitor.ts +1 -6
- package/src/extensions/paginatedHasMany/PaginatedHasManyCountVisitor.ts +26 -46
- package/src/extensions/paginatedHasMany/PaginatedHasManyExecutionHandler.ts +6 -3
- package/src/extensions/paginatedHasMany/PaginatedHasManyFieldProviderVisitor.ts +4 -22
- package/src/extensions/paginatedHasMany/PaginatedHasManyNodesVisitor.ts +26 -49
- package/src/input-validation/ColumnValueResolver.ts +2 -3
- package/src/input-validation/EntityRulesResolver.ts +7 -7
- package/src/input-validation/QueryAstFactory.ts +1 -1
- package/src/input-validation/ValidationContext.ts +2 -2
- package/src/input-validation/ValidationDataSelector.ts +2 -2
- package/src/input-validation/preValidation/CreateInputPreValidationProcessor.ts +7 -8
- package/src/input-validation/preValidation/InputPreValidator.ts +4 -4
- package/src/input-validation/preValidation/UpdateInputPreValidationProcessor.ts +7 -8
- package/src/inputProcessing/CreateInputProcessor.ts +8 -9
- package/src/inputProcessing/CreateInputVisitor.ts +27 -89
- package/src/inputProcessing/UpdateInputProcessor.ts +8 -9
- package/src/inputProcessing/UpdateInputVisitor.ts +25 -71
- package/src/inputProcessing/index.ts +0 -1
- package/src/introspection/IntrospectionSchemaFactory.ts +7 -7
- package/src/introspection/content-schema.types.ts +19 -286
- package/src/mapper/Mapper.ts +37 -30
- package/src/mapper/MapperContainer.ts +10 -5
- package/src/mapper/delete/DeleteExecutor.ts +3 -3
- package/src/mapper/insert/SqlCreateInputProcessor.ts +3 -3
- package/src/mapper/select/JoinVisitor.ts +6 -33
- package/src/mapper/select/RelationFetcher.ts +101 -41
- package/src/mapper/select/SelectBuilder.ts +3 -1
- package/src/mapper/select/SelectBuilderFactory.ts +2 -1
- package/src/mapper/select/SelectExecutionHandler.ts +1 -0
- package/src/mapper/select/WhereBuilder.ts +95 -34
- package/src/mapper/select/handlers/FieldsVisitor.ts +47 -57
- package/src/mapper/select/handlers/FieldsVisitorFactory.ts +1 -0
- package/src/mapper/select/optimizer/ConditionOptimizer.ts +41 -0
- package/src/mapper/select/optimizer/WhereOptimizer.ts +138 -0
- package/src/mapper/select/optimizer/WhereReplacer.ts +27 -0
- package/src/mapper/select/optimizer/helpers.ts +58 -0
- package/src/mapper/update/SqlUpdateInputProcessor.ts +1 -1
- package/src/mapper/update/UpdateBuilder.ts +3 -3
- package/src/resolvers/GraphQlQueryAstFactory.ts +3 -3
- package/src/resolvers/MutationResolver.ts +1 -1
- package/src/resolvers/ReadHelpers.ts +3 -3
- package/src/resolvers/ReadResolver.ts +2 -2
- package/src/schema/FieldAccessVisitor.ts +2 -2
- package/src/schema/OrderByTypeProvider.ts +1 -1
- package/src/schema/WhereTypeProvider.ts +4 -4
- package/src/schema/entities/FieldArgsVisitor.ts +3 -3
- package/src/schema/entities/FieldTypeVisitor.ts +3 -3
- package/src/schema/mutations/CreateEntityInputFieldVisitor.ts +3 -6
- package/src/schema/mutations/CreateEntityRelationAllowedOperationsVisitor.ts +6 -20
- package/src/schema/mutations/CreateEntityRelationInputFieldVisitor.ts +5 -18
- package/src/schema/mutations/UpdateEntityInputFieldVisitor.ts +3 -6
- package/src/schema/mutations/UpdateEntityRelationAllowedOperationsVisitor.ts +6 -20
- package/src/schema/mutations/UpdateEntityRelationInputFieldVisitor.ts +2 -12
- package/src/utils/object.ts +6 -6
- package/src/utils/uniqueWhereFields.ts +3 -3
- package/tests/cases/integration/graphQlDb/insert/insertSequence.test.ts +34 -0
- package/tests/cases/integration/graphQlRequests/delete/aclDelete.test.ts +2 -2
- package/tests/cases/integration/graphQlRequests/insert/acl/setField.test.ts +3 -3
- package/tests/cases/integration/graphQlRequests/insert/aclInsert.test.ts +2 -2
- package/tests/cases/integration/graphQlRequests/query/acl/fieldRestrictedByLocale.test.ts +7 -6
- package/tests/cases/integration/graphQlRequests/query/acl/nestedPredicate.test.ts +1 -1
- package/tests/cases/integration/graphQlRequests/query/acl/predicateElimination.test.ts +130 -0
- package/tests/cases/integration/graphQlRequests/query/filter/complexCondition.test.ts +1 -1
- package/tests/cases/integration/graphQlRequests/query/filter/composedFilter.test.ts +1 -1
- package/tests/cases/integration/graphQlRequests/query/relations/manyHasManyInverse.test.ts +74 -0
- package/tests/cases/integration/graphQlRequests/query/relations/manyHasManyOwning.test.ts +77 -0
- package/tests/cases/integration/graphQlRequests/update/acl/aclUpdate.test.ts +7 -7
- package/tests/cases/integration/graphQlSchema/graphQlSchemaBuilder.test.ts +5 -5
- package/tests/cases/unit/aclVariablesFactory.test.ts +8 -35
- package/tests/cases/unit/conditionOptimizer.test.ts +135 -0
- package/tests/cases/unit/orderbyHelper.test.ts +1 -0
- package/tests/cases/unit/permissionMerger.test.ts +2 -0
- package/tests/cases/unit/predicatesFactory.test.ts +103 -0
- package/tests/cases/unit/predicatesInjector.test.ts +78 -16
- package/tests/cases/unit/variableInjector.test.ts +6 -5
- package/tests/cases/unit/whereBuilder.test.ts +84 -0
- package/tests/cases/unit/whereOptimizer.test.ts +289 -0
- package/tests/src/testGraphql.ts +9 -2
- package/dist/src/inputProcessing/InputContext.d.ts +0 -43
- package/dist/src/inputProcessing/InputContext.d.ts.map +0 -1
- package/dist/src/inputProcessing/InputContext.js +0 -3
- package/dist/src/inputProcessing/InputContext.js.map +0 -1
- 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 {
|
|
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
|
-
|
|
30
|
+
relationPath: Model.AnyRelationContext[] = [],
|
|
23
31
|
) {
|
|
24
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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:
|
|
140
|
+
visitManyHasManyInverse: context => {
|
|
124
141
|
if (allowManyJoin) {
|
|
125
|
-
return joinedWhere(
|
|
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:
|
|
157
|
+
visitManyHasManyOwning: context => {
|
|
140
158
|
if (allowManyJoin) {
|
|
141
|
-
return joinedWhere(
|
|
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:
|
|
174
|
+
visitOneHasMany: context => {
|
|
157
175
|
if (allowManyJoin) {
|
|
158
|
-
return joinedWhere(
|
|
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.
|
|
165
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
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(
|
|
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(
|
|
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
|
|
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.
|
|
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
|
-
|
|
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.
|
|
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(
|
|
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.
|
|
191
|
+
return this.mapper.selectAssoc(targetEntity, objectWithWhere, [
|
|
192
|
+
...this.relationPath,
|
|
193
|
+
relationContext,
|
|
194
|
+
], targetEntity.primary)
|
|
205
195
|
},
|
|
206
196
|
null,
|
|
207
197
|
)
|
|
@@ -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
|
+
}
|