@contember/engine-content-api 1.1.2 → 1.2.0-alpha.11
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 +4 -4
- 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 +6 -3
- package/dist/src/mapper/select/WhereBuilder.d.ts.map +1 -1
- package/dist/src/mapper/select/WhereBuilder.js +31 -24
- 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/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/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 +4 -4
- 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 +46 -32
- 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/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/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/jasmine.json +0 -7
- package/src/inputProcessing/InputContext.ts +0 -49
|
@@ -5,6 +5,7 @@ import { Path, PathFactory } from './Path'
|
|
|
5
5
|
import { JoinBuilder } from './JoinBuilder'
|
|
6
6
|
import { ConditionBuilder } from './ConditionBuilder'
|
|
7
7
|
import { ConditionBuilder as SqlConditionBuilder, Operator, QueryBuilder, SelectBuilder } from '@contember/database'
|
|
8
|
+
import { WhereOptimizer } from './optimizer/WhereOptimizer'
|
|
8
9
|
|
|
9
10
|
export class WhereBuilder {
|
|
10
11
|
constructor(
|
|
@@ -12,6 +13,7 @@ export class WhereBuilder {
|
|
|
12
13
|
private readonly joinBuilder: JoinBuilder,
|
|
13
14
|
private readonly conditionBuilder: ConditionBuilder,
|
|
14
15
|
private readonly pathFactory: PathFactory,
|
|
16
|
+
private readonly whereOptimizer: WhereOptimizer,
|
|
15
17
|
) {}
|
|
16
18
|
|
|
17
19
|
public build(
|
|
@@ -19,28 +21,41 @@ export class WhereBuilder {
|
|
|
19
21
|
entity: Model.Entity,
|
|
20
22
|
path: Path,
|
|
21
23
|
where: Input.OptionalWhere,
|
|
22
|
-
|
|
24
|
+
relationPath: Model.AnyRelationContext[] = [],
|
|
23
25
|
) {
|
|
24
|
-
|
|
26
|
+
const optimizedWhere = this.whereOptimizer.optimize(where, entity, relationPath)
|
|
27
|
+
return this.buildInternal(entity, path, optimizedWhere, cb => qb.where(clause => cb(clause)), false)
|
|
25
28
|
}
|
|
26
29
|
|
|
30
|
+
|
|
27
31
|
public buildAdvanced(
|
|
28
32
|
entity: Model.Entity,
|
|
29
33
|
path: Path,
|
|
30
34
|
where: Input.OptionalWhere,
|
|
31
35
|
callback: (clauseCb: (clause: SqlConditionBuilder) => SqlConditionBuilder) => SelectBuilder<SelectBuilder.Result>,
|
|
32
|
-
|
|
36
|
+
relationPath: Model.AnyRelationContext[] = [],
|
|
37
|
+
) {
|
|
38
|
+
const optimizedWhere = this.whereOptimizer.optimize(where, entity, relationPath)
|
|
39
|
+
return this.buildInternal(entity, path, optimizedWhere, callback, false)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
private buildInternal(
|
|
43
|
+
entity: Model.Entity,
|
|
44
|
+
path: Path,
|
|
45
|
+
where: Input.OptionalWhere,
|
|
46
|
+
callback: (clauseCb: (clause: SqlConditionBuilder) => SqlConditionBuilder) => SelectBuilder<SelectBuilder.Result>,
|
|
47
|
+
allowManyJoin: boolean,
|
|
33
48
|
) {
|
|
34
49
|
const joinList: WhereJoinDefinition[] = []
|
|
35
50
|
|
|
36
|
-
const qbWithWhere = callback(clause => this.
|
|
51
|
+
const qbWithWhere = callback(clause => this.buildRecursive(clause, entity, path, where, allowManyJoin, joinList))
|
|
37
52
|
return joinList.reduce<SelectBuilder<SelectBuilder.Result>>(
|
|
38
53
|
(qb, { path, entity, relationName }) => this.joinBuilder.join(qb, path, entity, relationName),
|
|
39
54
|
qbWithWhere,
|
|
40
55
|
)
|
|
41
56
|
}
|
|
42
57
|
|
|
43
|
-
private
|
|
58
|
+
private buildRecursive(
|
|
44
59
|
conditionBuilder: SqlConditionBuilder,
|
|
45
60
|
entity: Model.Entity,
|
|
46
61
|
path: Path,
|
|
@@ -55,7 +70,7 @@ export class WhereBuilder {
|
|
|
55
70
|
conditionBuilder = conditionBuilder.and(clause =>
|
|
56
71
|
expr.reduce(
|
|
57
72
|
(clause2, where) =>
|
|
58
|
-
!where ? clause2 : this.
|
|
73
|
+
!where ? clause2 : this.buildRecursive(clause2, entity, path, where, allowManyJoin, joinList),
|
|
59
74
|
clause,
|
|
60
75
|
),
|
|
61
76
|
)
|
|
@@ -67,7 +82,7 @@ export class WhereBuilder {
|
|
|
67
82
|
(clause2, where) =>
|
|
68
83
|
!where
|
|
69
84
|
? clause2
|
|
70
|
-
: clause2.and(clause3 => this.
|
|
85
|
+
: clause2.and(clause3 => this.buildRecursive(clause3, entity, path, where, allowManyJoin, joinList)),
|
|
71
86
|
clause,
|
|
72
87
|
),
|
|
73
88
|
)
|
|
@@ -75,7 +90,7 @@ export class WhereBuilder {
|
|
|
75
90
|
if (where.not !== undefined) {
|
|
76
91
|
const expr = where.not
|
|
77
92
|
conditionBuilder = conditionBuilder.not(clause =>
|
|
78
|
-
this.
|
|
93
|
+
this.buildRecursive(clause, entity, path, expr, allowManyJoin, joinList),
|
|
79
94
|
)
|
|
80
95
|
}
|
|
81
96
|
|
|
@@ -84,11 +99,7 @@ export class WhereBuilder {
|
|
|
84
99
|
continue
|
|
85
100
|
}
|
|
86
101
|
|
|
87
|
-
const joinedWhere = (
|
|
88
|
-
entity: Model.Entity,
|
|
89
|
-
relation: Model.Relation,
|
|
90
|
-
targetEntity: Model.Entity,
|
|
91
|
-
): SqlConditionBuilder => {
|
|
102
|
+
const joinedWhere = ({ targetEntity, relation, entity }: Model.AnyRelationContext): SqlConditionBuilder => {
|
|
92
103
|
const targetPath = path.for(fieldName)
|
|
93
104
|
const relationWhere = where[fieldName] as Input.Where
|
|
94
105
|
if (Object.keys(relationWhere).length === 0) {
|
|
@@ -109,36 +120,37 @@ export class WhereBuilder {
|
|
|
109
120
|
|
|
110
121
|
joinList.push({ path: targetPath, entity, relationName: relation.name })
|
|
111
122
|
|
|
112
|
-
return this.
|
|
123
|
+
return this.buildRecursive(conditionBuilder, targetEntity, targetPath, relationWhere, allowManyJoin, joinList)
|
|
113
124
|
}
|
|
114
125
|
|
|
115
126
|
conditionBuilder = acceptFieldVisitor<SqlConditionBuilder>(this.schema, entity, fieldName, {
|
|
116
|
-
visitColumn: (entity, column) => {
|
|
127
|
+
visitColumn: ({ entity, column }) => {
|
|
117
128
|
const subWhere: Input.Condition<Input.ColumnValue> = where[column.name] as Input.Condition<Input.ColumnValue>
|
|
118
129
|
return this.conditionBuilder.build(conditionBuilder, tableName, column.columnName, column.columnType, subWhere)
|
|
119
130
|
},
|
|
120
131
|
visitOneHasOneInverse: joinedWhere,
|
|
121
132
|
visitOneHasOneOwning: joinedWhere,
|
|
122
133
|
visitManyHasOne: joinedWhere,
|
|
123
|
-
visitManyHasManyInverse:
|
|
134
|
+
visitManyHasManyInverse: context => {
|
|
124
135
|
if (allowManyJoin) {
|
|
125
|
-
return joinedWhere(
|
|
136
|
+
return joinedWhere(context)
|
|
126
137
|
}
|
|
138
|
+
|
|
127
139
|
const relationWhere = where[fieldName] as Input.Where
|
|
128
140
|
|
|
129
141
|
return conditionBuilder.exists(
|
|
130
142
|
this.createManyHasManySubquery(
|
|
131
143
|
[tableName, entity.primaryColumn],
|
|
132
144
|
relationWhere,
|
|
133
|
-
targetEntity,
|
|
134
|
-
targetRelation.joiningTable,
|
|
145
|
+
context.targetEntity,
|
|
146
|
+
context.targetRelation.joiningTable,
|
|
135
147
|
'inverse',
|
|
136
148
|
),
|
|
137
149
|
)
|
|
138
150
|
},
|
|
139
|
-
visitManyHasManyOwning:
|
|
151
|
+
visitManyHasManyOwning: context => {
|
|
140
152
|
if (allowManyJoin) {
|
|
141
|
-
return joinedWhere(
|
|
153
|
+
return joinedWhere(context)
|
|
142
154
|
}
|
|
143
155
|
|
|
144
156
|
const relationWhere = where[fieldName] as Input.Where
|
|
@@ -147,28 +159,30 @@ export class WhereBuilder {
|
|
|
147
159
|
this.createManyHasManySubquery(
|
|
148
160
|
[tableName, entity.primaryColumn],
|
|
149
161
|
relationWhere,
|
|
150
|
-
targetEntity,
|
|
151
|
-
relation.joiningTable,
|
|
162
|
+
context.targetEntity,
|
|
163
|
+
context.relation.joiningTable,
|
|
152
164
|
'owning',
|
|
153
165
|
),
|
|
154
166
|
)
|
|
155
167
|
},
|
|
156
|
-
visitOneHasMany:
|
|
168
|
+
visitOneHasMany: context => {
|
|
157
169
|
if (allowManyJoin) {
|
|
158
|
-
return joinedWhere(
|
|
170
|
+
return joinedWhere(context)
|
|
159
171
|
}
|
|
160
172
|
|
|
161
173
|
const relationWhere = where[fieldName] as Input.Where
|
|
162
174
|
|
|
175
|
+
const qb = SelectBuilder.create()
|
|
176
|
+
.select(it => it.raw('1'))
|
|
177
|
+
.from(context.targetEntity.tableName, 'sub_')
|
|
178
|
+
.where(it => it.columnsEq([tableName, entity.primaryColumn], ['sub_', context.targetRelation.joiningColumn.columnName]))
|
|
179
|
+
|
|
163
180
|
return conditionBuilder.exists(
|
|
164
|
-
this.
|
|
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,
|
|
181
|
+
this.buildInternal(
|
|
182
|
+
context.targetEntity,
|
|
170
183
|
this.pathFactory.create([], 'sub_'),
|
|
171
184
|
relationWhere,
|
|
185
|
+
cb => qb.where(clause => cb(clause)),
|
|
172
186
|
true,
|
|
173
187
|
),
|
|
174
188
|
)
|
|
@@ -205,7 +219,7 @@ export class WhereBuilder {
|
|
|
205
219
|
const qbJoined = qb.join(targetEntity.tableName, 'sub_', clause =>
|
|
206
220
|
clause.compareColumns(['junction_', toColumn], Operator.eq, ['sub_', targetEntity.primary]),
|
|
207
221
|
)
|
|
208
|
-
return this.
|
|
222
|
+
return this.buildInternal(
|
|
209
223
|
targetEntity,
|
|
210
224
|
this.pathFactory.create([], 'sub_'),
|
|
211
225
|
relationWhere,
|
|
@@ -4,7 +4,6 @@ import { RelationFetcher } from '../RelationFetcher'
|
|
|
4
4
|
import { SelectExecutionHandlerContext } from '../SelectExecutionHandler'
|
|
5
5
|
import { PredicateFactory } from '../../../acl'
|
|
6
6
|
import { WhereBuilder } from '../WhereBuilder'
|
|
7
|
-
import { JoiningColumns } from '../../types'
|
|
8
7
|
|
|
9
8
|
export class FieldsVisitor implements Model.RelationByTypeVisitor<void>, Model.ColumnVisitor<void> {
|
|
10
9
|
constructor(
|
|
@@ -14,9 +13,10 @@ export class FieldsVisitor implements Model.RelationByTypeVisitor<void>, Model.C
|
|
|
14
13
|
private readonly whereBuilder: WhereBuilder,
|
|
15
14
|
private readonly mapper: Mapper,
|
|
16
15
|
private readonly executionContext: SelectExecutionHandlerContext,
|
|
16
|
+
private readonly relationPath: Model.AnyRelationContext[],
|
|
17
17
|
) {}
|
|
18
18
|
|
|
19
|
-
visitColumn(entity
|
|
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
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
export const optimizeOr = <P extends Record<string, unknown>>(operands: readonly (P | boolean | undefined)[]): P | { or?: P[] } | boolean => {
|
|
2
|
+
const normalized: P[] = []
|
|
3
|
+
let hasNever = false
|
|
4
|
+
for (const operand of operands) {
|
|
5
|
+
if (operand === true) {
|
|
6
|
+
return true
|
|
7
|
+
} else if (operand === false) {
|
|
8
|
+
hasNever = true
|
|
9
|
+
} else if (operand !== undefined) {
|
|
10
|
+
normalized.push(...Array.isArray(operand.or) ? operand.or : [operand])
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (normalized.length > 1) {
|
|
15
|
+
return { or: normalized }
|
|
16
|
+
} else if (normalized.length === 1) {
|
|
17
|
+
return normalized[0]
|
|
18
|
+
} else if (hasNever) {
|
|
19
|
+
return false
|
|
20
|
+
} else {
|
|
21
|
+
return {}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export const optimizeAnd = <P extends Record<string, unknown>>(operands: readonly (P | boolean | undefined)[]): P | { and?: P[] } | boolean => {
|
|
26
|
+
const normalized: P[] = []
|
|
27
|
+
let hasAlways = false
|
|
28
|
+
|
|
29
|
+
for (const operand of operands) {
|
|
30
|
+
if (operand === true) {
|
|
31
|
+
hasAlways = true
|
|
32
|
+
} else if (operand === false) {
|
|
33
|
+
return false
|
|
34
|
+
} else if (operand !== undefined) {
|
|
35
|
+
normalized.push(...Array.isArray(operand.and) ? operand.and : [operand])
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
if (normalized.length > 1) {
|
|
40
|
+
return { and: normalized }
|
|
41
|
+
} else if (normalized.length === 1) {
|
|
42
|
+
return normalized[0]
|
|
43
|
+
} else if (hasAlways) {
|
|
44
|
+
return true
|
|
45
|
+
} else {
|
|
46
|
+
return {}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export const optimizeNot = <P extends Record<string, unknown>>(operand: P | boolean): P['not'] | { not: P } | boolean => {
|
|
51
|
+
if (typeof operand === 'boolean') {
|
|
52
|
+
return !operand
|
|
53
|
+
} else if (operand.not) {
|
|
54
|
+
return operand.not as P['not']
|
|
55
|
+
} else {
|
|
56
|
+
return { not: operand }
|
|
57
|
+
}
|
|
58
|
+
}
|
|
@@ -26,7 +26,7 @@ export class SqlUpdateInputProcessor implements UpdateInputProcessor<MutationRes
|
|
|
26
26
|
private readonly mapper: Mapper,
|
|
27
27
|
) {}
|
|
28
28
|
|
|
29
|
-
public column({ entity, column }:
|
|
29
|
+
public column({ entity, column }: Model.ColumnContext) {
|
|
30
30
|
if (this.data[column.name] !== undefined) {
|
|
31
31
|
this.updateBuilder.addFieldValue(column.name, this.data[column.name] as Value.AtomicValue)
|
|
32
32
|
}
|
|
@@ -74,9 +74,9 @@ export class UpdateBuilder {
|
|
|
74
74
|
const columns = new Set(resolvedData.map(it => it.columnName))
|
|
75
75
|
const allColumns: string[] = Object.values(
|
|
76
76
|
acceptEveryFieldVisitor(this.schema, this.entity, {
|
|
77
|
-
visitColumn: (
|
|
78
|
-
visitManyHasOne: (
|
|
79
|
-
visitOneHasOneOwning: (
|
|
77
|
+
visitColumn: ({ column }) => column.columnName,
|
|
78
|
+
visitManyHasOne: ({ relation }) => relation.joiningColumn.columnName,
|
|
79
|
+
visitOneHasOneOwning: ({ relation }) => relation.joiningColumn.columnName,
|
|
80
80
|
visitManyHasManyInverse: () => null,
|
|
81
81
|
visitManyHasManyOwning: () => null,
|
|
82
82
|
visitOneHasOneInverse: () => null,
|