@contember/engine-content-api 2.1.0-beta.1 → 2.1.0-rc.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (65) hide show
  1. package/dist/development/index.cjs +1 -0
  2. package/dist/development/index.cjs.map +1 -1
  3. package/dist/development/index.js +2 -1
  4. package/dist/development/src/ExecutionContainer.cjs +40 -4
  5. package/dist/development/src/ExecutionContainer.cjs.map +1 -1
  6. package/dist/development/src/ExecutionContainer.js +41 -5
  7. package/dist/development/src/ExecutionContainer.js.map +1 -1
  8. package/dist/development/src/acl/PermissionFactory.cjs +29 -15
  9. package/dist/development/src/acl/PermissionFactory.cjs.map +1 -1
  10. package/dist/development/src/acl/PermissionFactory.js +29 -15
  11. package/dist/development/src/acl/PermissionFactory.js.map +1 -1
  12. package/dist/development/src/acl/PredicateFactory.cjs +33 -13
  13. package/dist/development/src/acl/PredicateFactory.cjs.map +1 -1
  14. package/dist/development/src/acl/PredicateFactory.js +33 -13
  15. package/dist/development/src/acl/PredicateFactory.js.map +1 -1
  16. package/dist/development/src/acl/PredicatesInjector.cjs +21 -18
  17. package/dist/development/src/acl/PredicatesInjector.cjs.map +1 -1
  18. package/dist/development/src/acl/PredicatesInjector.js +21 -18
  19. package/dist/development/src/acl/PredicatesInjector.js.map +1 -1
  20. package/dist/development/src/mapper/select/handlers/FieldsVisitor.cjs +2 -1
  21. package/dist/development/src/mapper/select/handlers/FieldsVisitor.cjs.map +1 -1
  22. package/dist/development/src/mapper/select/handlers/FieldsVisitor.js +2 -1
  23. package/dist/development/src/mapper/select/handlers/FieldsVisitor.js.map +1 -1
  24. package/dist/production/index.cjs +1 -0
  25. package/dist/production/index.cjs.map +1 -1
  26. package/dist/production/index.js +2 -1
  27. package/dist/production/src/ExecutionContainer.cjs +40 -4
  28. package/dist/production/src/ExecutionContainer.cjs.map +1 -1
  29. package/dist/production/src/ExecutionContainer.js +41 -5
  30. package/dist/production/src/ExecutionContainer.js.map +1 -1
  31. package/dist/production/src/acl/PermissionFactory.cjs +29 -15
  32. package/dist/production/src/acl/PermissionFactory.cjs.map +1 -1
  33. package/dist/production/src/acl/PermissionFactory.js +29 -15
  34. package/dist/production/src/acl/PermissionFactory.js.map +1 -1
  35. package/dist/production/src/acl/PredicateFactory.cjs +33 -13
  36. package/dist/production/src/acl/PredicateFactory.cjs.map +1 -1
  37. package/dist/production/src/acl/PredicateFactory.js +33 -13
  38. package/dist/production/src/acl/PredicateFactory.js.map +1 -1
  39. package/dist/production/src/acl/PredicatesInjector.cjs +21 -18
  40. package/dist/production/src/acl/PredicatesInjector.cjs.map +1 -1
  41. package/dist/production/src/acl/PredicatesInjector.js +21 -18
  42. package/dist/production/src/acl/PredicatesInjector.js.map +1 -1
  43. package/dist/production/src/mapper/select/handlers/FieldsVisitor.cjs +2 -1
  44. package/dist/production/src/mapper/select/handlers/FieldsVisitor.cjs.map +1 -1
  45. package/dist/production/src/mapper/select/handlers/FieldsVisitor.js +2 -1
  46. package/dist/production/src/mapper/select/handlers/FieldsVisitor.js.map +1 -1
  47. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  48. package/dist/types/ExecutionContainer.d.ts +20 -1
  49. package/dist/types/ExecutionContainer.d.ts.map +1 -1
  50. package/dist/types/acl/PermissionFactory.d.ts +6 -0
  51. package/dist/types/acl/PermissionFactory.d.ts.map +1 -1
  52. package/dist/types/acl/PredicateFactory.d.ts +17 -6
  53. package/dist/types/acl/PredicateFactory.d.ts.map +1 -1
  54. package/dist/types/acl/PredicatesInjector.d.ts.map +1 -1
  55. package/dist/types/mapper/select/handlers/FieldsVisitor.d.ts.map +1 -1
  56. package/dist/types/tsconfig.tsbuildinfo +1 -1
  57. package/package.json +1 -2
  58. package/src/ExecutionContainer.ts +57 -4
  59. package/src/acl/PermissionFactory.ts +48 -15
  60. package/src/acl/PredicateFactory.ts +38 -9
  61. package/src/acl/PredicatesInjector.ts +19 -13
  62. package/src/mapper/select/handlers/FieldsVisitor.ts +2 -1
  63. package/tests/cases/unit/permissionMerger.test.ts +162 -0
  64. package/tests/cases/unit/predicatesFactory.test.ts +75 -0
  65. package/vitest.config.ts +0 -3
@@ -1 +1 @@
1
- {"version":3,"file":"PredicatesInjector.cjs","sources":["../../../../../packages/engine-content-api/src/acl/PredicatesInjector.ts"],"sourcesContent":["import { Acl, Input, Model, Writable } from '@contember/schema'\nimport { acceptFieldVisitor } from '@contember/schema-utils'\nimport { PredicateFactory } from './PredicateFactory'\n\nexport class PredicatesInjector {\n\tconstructor(private readonly schema: Model.Schema, private readonly predicateFactory: PredicateFactory) {}\n\n\tpublic inject(\n\t\tentity: Model.Entity,\n\t\twhere: Input.OptionalWhere,\n\t\trelationContext?: Model.AnyRelationContext,\n\t\tancestorPath?: readonly Model.AnyRelationContext[],\n\t): Input.OptionalWhere {\n\t\tconst restrictedWhere = this.injectToWhere(where, entity, true, relationContext, false, ancestorPath ?? [])\n\t\treturn this.createWhere(entity, undefined, restrictedWhere, relationContext, false, ancestorPath ?? [])\n\t}\n\n\t/**\n\t * Finds an ancestor in the path that matches the given relation as a back-reference.\n\t * A match occurs when:\n\t * 1. The relation we're traversing has the same name as the inverse (targetRelation) of a relation in the ancestor path\n\t * 2. AND the entity where our relation is defined matches the targetEntity in the path\n\t * (to prevent false positives when different entities have relations with the same name)\n\t */\n\tprivate findBackReferencedAncestor(\n\t\tancestorPath: readonly Model.AnyRelationContext[],\n\t\trelationName: string,\n\t\trelationSourceEntityName: string,\n\t): Model.AnyRelationContext | undefined {\n\t\treturn ancestorPath.find(ctx =>\n\t\t\tctx.targetRelation?.name === relationName\n\t\t\t&& ctx.targetEntity.name === relationSourceEntityName\n\t\t)\n\t}\n\n\tprivate createWhere(\n\t\tentity: Model.Entity,\n\t\tfieldNames: string[] | undefined,\n\t\twhere: Input.OptionalWhere,\n\t\trelationContext?: Model.AnyRelationContext,\n\t\tisBackReferenceContext?: boolean,\n\t\tancestorPath?: readonly Model.AnyRelationContext[],\n\t): Input.OptionalWhere {\n\t\t// Simplify predicates when:\n\t\t// 1. We're in a back-reference context (inside a filter that traverses back)\n\t\t// 2. AND the relation we traversed to get here corresponds to a relation in our query path\n\t\t// This ensures we only simplify when the traversed relation actually corresponds\n\t\t// to a relation in our query path (not just any relation to the same entity type)\n\t\tconst shouldSimplify = isBackReferenceContext === true\n\t\t\t&& ancestorPath !== undefined\n\t\t\t&& relationContext !== undefined\n\t\t\t&& this.findBackReferencedAncestor(ancestorPath, relationContext.relation.name, relationContext.entity.name) !== undefined\n\n\t\tlet predicatesWhere: Input.OptionalWhere\n\t\tif (shouldSimplify) {\n\t\t\tpredicatesWhere = { [entity.primary]: { always: true } }\n\t\t} else {\n\t\t\tconst rawPredicate = this.predicateFactory.create(entity, Acl.Operation.read, fieldNames, relationContext)\n\t\t\t// Process the predicate to inject nested entity predicates\n\t\t\tpredicatesWhere = this.injectPredicatesToPredicate(\n\t\t\t\trawPredicate,\n\t\t\t\tentity,\n\t\t\t\tisBackReferenceContext ?? false,\n\t\t\t\tancestorPath ?? [],\n\t\t\t)\n\t\t}\n\n\t\tconst and = [where, predicatesWhere].filter(it => Object.keys(it).length > 0)\n\t\tif (and.length === 0) {\n\t\t\treturn {}\n\t\t}\n\t\tif (and.length === 1) {\n\t\t\treturn and[0]\n\t\t}\n\t\treturn { and: and }\n\t}\n\n\t/**\n\t * Processes a predicate and injects nested entity predicates for any relation traversals.\n\t * This ensures that when a predicate like { department: { company: { name: 'Acme' } } }\n\t * is used, the predicates of Department and Company are also applied.\n\t */\n\tprivate injectPredicatesToPredicate(\n\t\twhere: Input.OptionalWhere,\n\t\tentity: Model.Entity,\n\t\tisBackReferenceContext: boolean,\n\t\tancestorPath: readonly Model.AnyRelationContext[],\n\t): Input.OptionalWhere {\n\t\tconst resultWhere: Writable<Input.OptionalWhere> = {}\n\n\t\tif (where.and) {\n\t\t\tresultWhere.and = where.and\n\t\t\t\t.filter((it): it is Input.Where => !!it)\n\t\t\t\t.map(it => this.injectPredicatesToPredicate(it, entity, isBackReferenceContext, ancestorPath))\n\t\t}\n\t\tif (where.or) {\n\t\t\tresultWhere.or = where.or\n\t\t\t\t.filter((it): it is Input.Where => !!it)\n\t\t\t\t.map(it => this.injectPredicatesToPredicate(it, entity, isBackReferenceContext, ancestorPath))\n\t\t}\n\t\tif (where.not) {\n\t\t\tresultWhere.not = this.injectPredicatesToPredicate(where.not, entity, isBackReferenceContext, ancestorPath)\n\t\t}\n\n\t\tconst fields = Object.keys(where).filter(it => !['and', 'or', 'not'].includes(it))\n\n\t\tfor (const field of fields) {\n\t\t\tresultWhere[field] = acceptFieldVisitor(this.schema, entity, field, {\n\t\t\t\tvisitColumn: () => where[field],\n\t\t\t\tvisitRelation: context => {\n\t\t\t\t\tconst relationWhere = where[field] as Input.OptionalWhere | null\n\t\t\t\t\tif (relationWhere === null) {\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check if this relation is a back-reference to somewhere in our ancestor path\n\t\t\t\t\tconst isBackReference = this.findBackReferencedAncestor(\n\t\t\t\t\t\tancestorPath,\n\t\t\t\t\t\tcontext.relation.name,\n\t\t\t\t\t\tcontext.entity.name,\n\t\t\t\t\t) !== undefined\n\t\t\t\t\tconst nestedIsBackReferenceContext = isBackReference || isBackReferenceContext\n\t\t\t\t\tconst nestedAncestorPath: readonly Model.AnyRelationContext[] = [...ancestorPath, context]\n\n\t\t\t\t\t// Recursively process the nested where (always do this to handle deeper nesting)\n\t\t\t\t\tconst processedNestedWhere = this.injectPredicatesToPredicate(\n\t\t\t\t\t\trelationWhere,\n\t\t\t\t\t\tcontext.targetEntity,\n\t\t\t\t\t\tnestedIsBackReferenceContext,\n\t\t\t\t\t\tnestedAncestorPath,\n\t\t\t\t\t)\n\n\t\t\t\t\t// Check if we should simplify the target entity's predicate\n\t\t\t\t\tconst shouldSimplifyNested = nestedIsBackReferenceContext\n\t\t\t\t\t\t&& this.findBackReferencedAncestor(nestedAncestorPath, context.relation.name, context.entity.name) !== undefined\n\n\t\t\t\t\t// Get target entity's predicate (simplified if back-reference)\n\t\t\t\t\tconst targetPredicate = shouldSimplifyNested\n\t\t\t\t\t\t? { [context.targetEntity.primary]: { always: true } }\n\t\t\t\t\t\t: this.predicateFactory.create(context.targetEntity, Acl.Operation.read, undefined, context)\n\n\t\t\t\t\t// Optimization: avoid duplicate { id: always } when both are simplified\n\t\t\t\t\tconst primaryKey = context.targetEntity.primary\n\t\t\t\t\tconst nestedIsAlwaysTrue = Object.keys(processedNestedWhere).length === 1\n\t\t\t\t\t\t&& (processedNestedWhere as Record<string, unknown>)[primaryKey] !== undefined\n\t\t\t\t\t\t&& (processedNestedWhere as Record<string, Record<string, unknown>>)[primaryKey]?.always === true\n\t\t\t\t\tconst targetIsAlwaysTrue = Object.keys(targetPredicate).length === 1\n\t\t\t\t\t\t&& (targetPredicate as Record<string, unknown>)[primaryKey] !== undefined\n\t\t\t\t\t\t&& (targetPredicate as Record<string, Record<string, unknown>>)[primaryKey]?.always === true\n\n\t\t\t\t\tif (nestedIsAlwaysTrue && targetIsAlwaysTrue) {\n\t\t\t\t\t\treturn processedNestedWhere\n\t\t\t\t\t}\n\n\t\t\t\t\t// Combine the processed nested where with target entity's predicate\n\t\t\t\t\tconst parts = [processedNestedWhere, targetPredicate].filter(it => Object.keys(it).length > 0)\n\t\t\t\t\tif (parts.length === 0) {\n\t\t\t\t\t\treturn {}\n\t\t\t\t\t}\n\t\t\t\t\tif (parts.length === 1) {\n\t\t\t\t\t\treturn parts[0]\n\t\t\t\t\t}\n\t\t\t\t\treturn { and: parts }\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\n\t\treturn resultWhere\n\t}\n\n\tprivate injectToWhere(\n\t\twhere: Input.OptionalWhere,\n\t\tentity: Model.Entity,\n\t\tisRoot: boolean,\n\t\trelationContext: Model.AnyRelationContext | undefined,\n\t\tisBackReferenceContext: boolean,\n\t\tancestorPath: readonly Model.AnyRelationContext[],\n\t): Input.OptionalWhere {\n\t\tconst resultWhere: Writable<Input.OptionalWhere> = {}\n\t\tif (where.and) {\n\t\t\tresultWhere.and = where.and.filter((it): it is Input.Where => !!it).map(it =>\n\t\t\t\tthis.injectToWhere(it, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath)\n\t\t\t)\n\t\t}\n\t\tif (where.or) {\n\t\t\tresultWhere.or = where.or.filter((it): it is Input.Where => !!it).map(it =>\n\t\t\t\tthis.injectToWhere(it, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath)\n\t\t\t)\n\t\t}\n\t\tif (where.not) {\n\t\t\tresultWhere.not = this.injectToWhere(where.not, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath)\n\t\t}\n\n\t\tconst fields = Object.keys(where).filter(it => !['and', 'or', 'not'].includes(it))\n\n\t\tif (fields.length === 0) {\n\t\t\treturn resultWhere\n\t\t}\n\t\tfor (let field of fields) {\n\t\t\tresultWhere[field] = acceptFieldVisitor(this.schema, entity, field, {\n\t\t\t\tvisitColumn: () => where[field],\n\t\t\t\tvisitRelation: context => {\n\t\t\t\t\tconst relationWhere = where[field] as Input.OptionalWhere | null\n\t\t\t\t\tif (relationWhere === null) {\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\t\t\t\t\t// Check if this relation is a back-reference to somewhere in our ancestor path\n\t\t\t\t\tconst isBackReference = this.findBackReferencedAncestor(ancestorPath, context.relation.name, context.entity.name) !== undefined\n\t\t\t\t\t// Once we enter a back-reference context, stay in it for nested relations\n\t\t\t\t\tconst nestedIsBackReferenceContext = isBackReference || isBackReferenceContext\n\t\t\t\t\t// Build extended ancestor path for nested traversal\n\t\t\t\t\tconst nestedAncestorPath: Model.AnyRelationContext[] = [...ancestorPath, context]\n\t\t\t\t\treturn this.injectToWhere(relationWhere, context.targetEntity, false, context, nestedIsBackReferenceContext, nestedAncestorPath)\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t\tconst fieldsForPredicate = !isRoot\n\t\t\t? fields\n\t\t\t: fields.filter(it => this.predicateFactory.shouldApplyCellLevelPredicate(entity, Acl.Operation.read, it))\n\n\t\treturn this.createWhere(entity, fieldsForPredicate, resultWhere, relationContext, isBackReferenceContext, ancestorPath)\n\t}\n}\n"],"names":["schema","Acl","acceptFieldVisitor"],"mappings":"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"}
1
+ {"version":3,"file":"PredicatesInjector.cjs","sources":["../../../../../packages/engine-content-api/src/acl/PredicatesInjector.ts"],"sourcesContent":["import { Acl, Input, Model, Writable } from '@contember/schema'\nimport { acceptFieldVisitor } from '@contember/schema-utils'\nimport { PredicateFactory } from './PredicateFactory'\n\nexport class PredicatesInjector {\n\tconstructor(private readonly schema: Model.Schema, private readonly predicateFactory: PredicateFactory) {}\n\n\tpublic inject(\n\t\tentity: Model.Entity,\n\t\twhere: Input.OptionalWhere,\n\t\trelationContext?: Model.AnyRelationContext,\n\t\tancestorPath?: readonly Model.AnyRelationContext[],\n\t): Input.OptionalWhere {\n\t\tconst isQueryRoot = !relationContext && (!ancestorPath || ancestorPath.length === 0)\n\t\tconst restrictedWhere = this.injectToWhere(where, entity, true, relationContext, false, ancestorPath ?? [], isQueryRoot)\n\t\treturn this.createWhere(entity, undefined, restrictedWhere, relationContext, false, ancestorPath ?? [], isQueryRoot)\n\t}\n\n\t/**\n\t * Finds an ancestor in the path that matches the given relation as a back-reference.\n\t * A match occurs when:\n\t * 1. The relation we're traversing has the same name as the inverse (targetRelation) of a relation in the ancestor path\n\t * 2. AND the entity where our relation is defined matches the targetEntity in the path\n\t * (to prevent false positives when different entities have relations with the same name)\n\t */\n\tprivate findBackReferencedAncestor(\n\t\tancestorPath: readonly Model.AnyRelationContext[],\n\t\trelationName: string,\n\t\trelationSourceEntityName: string,\n\t): Model.AnyRelationContext | undefined {\n\t\treturn ancestorPath.find(ctx =>\n\t\t\tctx.targetRelation?.name === relationName\n\t\t\t&& ctx.targetEntity.name === relationSourceEntityName\n\t\t)\n\t}\n\n\tprivate createWhere(\n\t\tentity: Model.Entity,\n\t\tfieldNames: string[] | undefined,\n\t\twhere: Input.OptionalWhere,\n\t\trelationContext?: Model.AnyRelationContext,\n\t\tisBackReferenceContext?: boolean,\n\t\tancestorPath?: readonly Model.AnyRelationContext[],\n\t\tisQueryRoot?: boolean,\n\t): Input.OptionalWhere {\n\t\t// Simplify predicates when:\n\t\t// 1. We're in a back-reference context (inside a filter that traverses back)\n\t\t// 2. AND the relation we traversed to get here corresponds to a relation in our query path\n\t\t// This ensures we only simplify when the traversed relation actually corresponds\n\t\t// to a relation in our query path (not just any relation to the same entity type)\n\t\tconst shouldSimplify = isBackReferenceContext === true\n\t\t\t&& ancestorPath !== undefined\n\t\t\t&& relationContext !== undefined\n\t\t\t&& this.findBackReferencedAncestor(ancestorPath, relationContext.relation.name, relationContext.entity.name) !== undefined\n\n\t\tlet predicatesWhere: Input.OptionalWhere\n\t\tif (shouldSimplify) {\n\t\t\tpredicatesWhere = { [entity.primary]: { always: true } }\n\t\t} else {\n\t\t\tconst rawPredicate = this.predicateFactory.create(entity, Acl.Operation.read, fieldNames, relationContext, isQueryRoot)\n\t\t\t// Process the predicate to inject nested entity predicates\n\t\t\tpredicatesWhere = this.injectPredicatesToPredicate(\n\t\t\t\trawPredicate,\n\t\t\t\tentity,\n\t\t\t\tisBackReferenceContext ?? false,\n\t\t\t\tancestorPath ?? [],\n\t\t\t\tisQueryRoot,\n\t\t\t)\n\t\t}\n\n\t\tconst and = [where, predicatesWhere].filter(it => Object.keys(it).length > 0)\n\t\tif (and.length === 0) {\n\t\t\treturn {}\n\t\t}\n\t\tif (and.length === 1) {\n\t\t\treturn and[0]\n\t\t}\n\t\treturn { and: and }\n\t}\n\n\t/**\n\t * Processes a predicate and injects nested entity predicates for any relation traversals.\n\t * This ensures that when a predicate like { department: { company: { name: 'Acme' } } }\n\t * is used, the predicates of Department and Company are also applied.\n\t */\n\tprivate injectPredicatesToPredicate(\n\t\twhere: Input.OptionalWhere,\n\t\tentity: Model.Entity,\n\t\tisBackReferenceContext: boolean,\n\t\tancestorPath: readonly Model.AnyRelationContext[],\n\t\tisQueryRoot?: boolean,\n\t): Input.OptionalWhere {\n\t\tconst resultWhere: Writable<Input.OptionalWhere> = {}\n\n\t\tif (where.and) {\n\t\t\tresultWhere.and = where.and\n\t\t\t\t.filter((it): it is Input.Where => !!it)\n\t\t\t\t.map(it => this.injectPredicatesToPredicate(it, entity, isBackReferenceContext, ancestorPath, isQueryRoot))\n\t\t}\n\t\tif (where.or) {\n\t\t\tresultWhere.or = where.or\n\t\t\t\t.filter((it): it is Input.Where => !!it)\n\t\t\t\t.map(it => this.injectPredicatesToPredicate(it, entity, isBackReferenceContext, ancestorPath, isQueryRoot))\n\t\t}\n\t\tif (where.not) {\n\t\t\tresultWhere.not = this.injectPredicatesToPredicate(where.not, entity, isBackReferenceContext, ancestorPath, isQueryRoot)\n\t\t}\n\n\t\tconst fields = Object.keys(where).filter(it => !['and', 'or', 'not'].includes(it))\n\n\t\tfor (const field of fields) {\n\t\t\tresultWhere[field] = acceptFieldVisitor(this.schema, entity, field, {\n\t\t\t\tvisitColumn: () => where[field],\n\t\t\t\tvisitRelation: context => {\n\t\t\t\t\tconst relationWhere = where[field] as Input.OptionalWhere | null\n\t\t\t\t\tif (relationWhere === null) {\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check if this relation is a back-reference to somewhere in our ancestor path\n\t\t\t\t\tconst isBackReference = this.findBackReferencedAncestor(\n\t\t\t\t\t\tancestorPath,\n\t\t\t\t\t\tcontext.relation.name,\n\t\t\t\t\t\tcontext.entity.name,\n\t\t\t\t\t) !== undefined\n\t\t\t\t\tconst nestedIsBackReferenceContext = isBackReference || isBackReferenceContext\n\t\t\t\t\tconst nestedAncestorPath: readonly Model.AnyRelationContext[] = [...ancestorPath, context]\n\n\t\t\t\t\t// Recursively process the nested where (always do this to handle deeper nesting)\n\t\t\t\t\tconst processedNestedWhere = this.injectPredicatesToPredicate(\n\t\t\t\t\t\trelationWhere,\n\t\t\t\t\t\tcontext.targetEntity,\n\t\t\t\t\t\tnestedIsBackReferenceContext,\n\t\t\t\t\t\tnestedAncestorPath,\n\t\t\t\t\t\tisQueryRoot,\n\t\t\t\t\t)\n\n\t\t\t\t\t// Check if we should simplify the target entity's predicate\n\t\t\t\t\tconst shouldSimplifyNested = nestedIsBackReferenceContext\n\t\t\t\t\t\t&& this.findBackReferencedAncestor(nestedAncestorPath, context.relation.name, context.entity.name) !== undefined\n\n\t\t\t\t\t// Get target entity's predicate (simplified if back-reference)\n\t\t\t\t\tconst targetPredicate = shouldSimplifyNested\n\t\t\t\t\t\t? { [context.targetEntity.primary]: { always: true } }\n\t\t\t\t\t\t: this.predicateFactory.create(context.targetEntity, Acl.Operation.read, undefined, context, isQueryRoot)\n\n\t\t\t\t\t// Optimization: avoid duplicate { id: always } when both are simplified\n\t\t\t\t\tconst primaryKey = context.targetEntity.primary\n\t\t\t\t\tconst nestedIsAlwaysTrue = Object.keys(processedNestedWhere).length === 1\n\t\t\t\t\t\t&& (processedNestedWhere as Record<string, unknown>)[primaryKey] !== undefined\n\t\t\t\t\t\t&& (processedNestedWhere as Record<string, Record<string, unknown>>)[primaryKey]?.always === true\n\t\t\t\t\tconst targetIsAlwaysTrue = Object.keys(targetPredicate).length === 1\n\t\t\t\t\t\t&& (targetPredicate as Record<string, unknown>)[primaryKey] !== undefined\n\t\t\t\t\t\t&& (targetPredicate as Record<string, Record<string, unknown>>)[primaryKey]?.always === true\n\n\t\t\t\t\tif (nestedIsAlwaysTrue && targetIsAlwaysTrue) {\n\t\t\t\t\t\treturn processedNestedWhere\n\t\t\t\t\t}\n\n\t\t\t\t\t// Combine the processed nested where with target entity's predicate\n\t\t\t\t\tconst parts = [processedNestedWhere, targetPredicate].filter(it => Object.keys(it).length > 0)\n\t\t\t\t\tif (parts.length === 0) {\n\t\t\t\t\t\treturn {}\n\t\t\t\t\t}\n\t\t\t\t\tif (parts.length === 1) {\n\t\t\t\t\t\treturn parts[0]\n\t\t\t\t\t}\n\t\t\t\t\treturn { and: parts }\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\n\t\treturn resultWhere\n\t}\n\n\tprivate injectToWhere(\n\t\twhere: Input.OptionalWhere,\n\t\tentity: Model.Entity,\n\t\tisRoot: boolean,\n\t\trelationContext: Model.AnyRelationContext | undefined,\n\t\tisBackReferenceContext: boolean,\n\t\tancestorPath: readonly Model.AnyRelationContext[],\n\t\tisQueryRoot?: boolean,\n\t): Input.OptionalWhere {\n\t\tconst resultWhere: Writable<Input.OptionalWhere> = {}\n\t\tif (where.and) {\n\t\t\tresultWhere.and = where.and.filter((it): it is Input.Where => !!it).map(it =>\n\t\t\t\tthis.injectToWhere(it, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath, isQueryRoot)\n\t\t\t)\n\t\t}\n\t\tif (where.or) {\n\t\t\tresultWhere.or = where.or.filter((it): it is Input.Where => !!it).map(it =>\n\t\t\t\tthis.injectToWhere(it, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath, isQueryRoot)\n\t\t\t)\n\t\t}\n\t\tif (where.not) {\n\t\t\tresultWhere.not = this.injectToWhere(where.not, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath, isQueryRoot)\n\t\t}\n\n\t\tconst fields = Object.keys(where).filter(it => !['and', 'or', 'not'].includes(it))\n\n\t\tif (fields.length === 0) {\n\t\t\treturn resultWhere\n\t\t}\n\t\tfor (let field of fields) {\n\t\t\tresultWhere[field] = acceptFieldVisitor(this.schema, entity, field, {\n\t\t\t\tvisitColumn: () => where[field],\n\t\t\t\tvisitRelation: context => {\n\t\t\t\t\tconst relationWhere = where[field] as Input.OptionalWhere | null\n\t\t\t\t\tif (relationWhere === null) {\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\t\t\t\t\t// Check if this relation is a back-reference to somewhere in our ancestor path\n\t\t\t\t\tconst isBackReference = this.findBackReferencedAncestor(ancestorPath, context.relation.name, context.entity.name) !== undefined\n\t\t\t\t\t// Once we enter a back-reference context, stay in it for nested relations\n\t\t\t\t\tconst nestedIsBackReferenceContext = isBackReference || isBackReferenceContext\n\t\t\t\t\t// Build extended ancestor path for nested traversal\n\t\t\t\t\tconst nestedAncestorPath: Model.AnyRelationContext[] = [...ancestorPath, context]\n\t\t\t\t\treturn this.injectToWhere(relationWhere, context.targetEntity, false, context, nestedIsBackReferenceContext, nestedAncestorPath, isQueryRoot)\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t\tconst fieldsForPredicate = !isRoot\n\t\t\t? fields\n\t\t\t: fields.filter(it => this.predicateFactory.shouldApplyCellLevelPredicate(entity, Acl.Operation.read, it, isQueryRoot))\n\n\t\treturn this.createWhere(entity, fieldsForPredicate, resultWhere, relationContext, isBackReferenceContext, ancestorPath, isQueryRoot)\n\t}\n}\n"],"names":["schema","Acl","acceptFieldVisitor"],"mappings":"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"}
@@ -6,8 +6,9 @@ class PredicatesInjector {
6
6
  this.predicateFactory = predicateFactory;
7
7
  }
8
8
  inject(entity, where, relationContext, ancestorPath) {
9
- const restrictedWhere = this.injectToWhere(where, entity, true, relationContext, false, ancestorPath ?? []);
10
- return this.createWhere(entity, void 0, restrictedWhere, relationContext, false, ancestorPath ?? []);
9
+ const isQueryRoot = !relationContext && (!ancestorPath || ancestorPath.length === 0);
10
+ const restrictedWhere = this.injectToWhere(where, entity, true, relationContext, false, ancestorPath ?? [], isQueryRoot);
11
+ return this.createWhere(entity, void 0, restrictedWhere, relationContext, false, ancestorPath ?? [], isQueryRoot);
11
12
  }
12
13
  /**
13
14
  * Finds an ancestor in the path that matches the given relation as a back-reference.
@@ -21,18 +22,19 @@ class PredicatesInjector {
21
22
  (ctx) => ctx.targetRelation?.name === relationName && ctx.targetEntity.name === relationSourceEntityName
22
23
  );
23
24
  }
24
- createWhere(entity, fieldNames, where, relationContext, isBackReferenceContext, ancestorPath) {
25
+ createWhere(entity, fieldNames, where, relationContext, isBackReferenceContext, ancestorPath, isQueryRoot) {
25
26
  const shouldSimplify = isBackReferenceContext === true && ancestorPath !== void 0 && relationContext !== void 0 && this.findBackReferencedAncestor(ancestorPath, relationContext.relation.name, relationContext.entity.name) !== void 0;
26
27
  let predicatesWhere;
27
28
  if (shouldSimplify) {
28
29
  predicatesWhere = { [entity.primary]: { always: true } };
29
30
  } else {
30
- const rawPredicate = this.predicateFactory.create(entity, Acl.Operation.read, fieldNames, relationContext);
31
+ const rawPredicate = this.predicateFactory.create(entity, Acl.Operation.read, fieldNames, relationContext, isQueryRoot);
31
32
  predicatesWhere = this.injectPredicatesToPredicate(
32
33
  rawPredicate,
33
34
  entity,
34
35
  isBackReferenceContext ?? false,
35
- ancestorPath ?? []
36
+ ancestorPath ?? [],
37
+ isQueryRoot
36
38
  );
37
39
  }
38
40
  const and = [where, predicatesWhere].filter((it) => Object.keys(it).length > 0);
@@ -49,16 +51,16 @@ class PredicatesInjector {
49
51
  * This ensures that when a predicate like { department: { company: { name: 'Acme' } } }
50
52
  * is used, the predicates of Department and Company are also applied.
51
53
  */
52
- injectPredicatesToPredicate(where, entity, isBackReferenceContext, ancestorPath) {
54
+ injectPredicatesToPredicate(where, entity, isBackReferenceContext, ancestorPath, isQueryRoot) {
53
55
  const resultWhere = {};
54
56
  if (where.and) {
55
- resultWhere.and = where.and.filter((it) => !!it).map((it) => this.injectPredicatesToPredicate(it, entity, isBackReferenceContext, ancestorPath));
57
+ resultWhere.and = where.and.filter((it) => !!it).map((it) => this.injectPredicatesToPredicate(it, entity, isBackReferenceContext, ancestorPath, isQueryRoot));
56
58
  }
57
59
  if (where.or) {
58
- resultWhere.or = where.or.filter((it) => !!it).map((it) => this.injectPredicatesToPredicate(it, entity, isBackReferenceContext, ancestorPath));
60
+ resultWhere.or = where.or.filter((it) => !!it).map((it) => this.injectPredicatesToPredicate(it, entity, isBackReferenceContext, ancestorPath, isQueryRoot));
59
61
  }
60
62
  if (where.not) {
61
- resultWhere.not = this.injectPredicatesToPredicate(where.not, entity, isBackReferenceContext, ancestorPath);
63
+ resultWhere.not = this.injectPredicatesToPredicate(where.not, entity, isBackReferenceContext, ancestorPath, isQueryRoot);
62
64
  }
63
65
  const fields = Object.keys(where).filter((it) => !["and", "or", "not"].includes(it));
64
66
  for (const field of fields) {
@@ -80,10 +82,11 @@ class PredicatesInjector {
80
82
  relationWhere,
81
83
  context.targetEntity,
82
84
  nestedIsBackReferenceContext,
83
- nestedAncestorPath
85
+ nestedAncestorPath,
86
+ isQueryRoot
84
87
  );
85
88
  const shouldSimplifyNested = nestedIsBackReferenceContext && this.findBackReferencedAncestor(nestedAncestorPath, context.relation.name, context.entity.name) !== void 0;
86
- const targetPredicate = shouldSimplifyNested ? { [context.targetEntity.primary]: { always: true } } : this.predicateFactory.create(context.targetEntity, Acl.Operation.read, void 0, context);
89
+ const targetPredicate = shouldSimplifyNested ? { [context.targetEntity.primary]: { always: true } } : this.predicateFactory.create(context.targetEntity, Acl.Operation.read, void 0, context, isQueryRoot);
87
90
  const primaryKey = context.targetEntity.primary;
88
91
  const nestedIsAlwaysTrue = Object.keys(processedNestedWhere).length === 1 && processedNestedWhere[primaryKey] !== void 0 && processedNestedWhere[primaryKey]?.always === true;
89
92
  const targetIsAlwaysTrue = Object.keys(targetPredicate).length === 1 && targetPredicate[primaryKey] !== void 0 && targetPredicate[primaryKey]?.always === true;
@@ -103,20 +106,20 @@ class PredicatesInjector {
103
106
  }
104
107
  return resultWhere;
105
108
  }
106
- injectToWhere(where, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath) {
109
+ injectToWhere(where, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath, isQueryRoot) {
107
110
  const resultWhere = {};
108
111
  if (where.and) {
109
112
  resultWhere.and = where.and.filter((it) => !!it).map(
110
- (it) => this.injectToWhere(it, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath)
113
+ (it) => this.injectToWhere(it, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath, isQueryRoot)
111
114
  );
112
115
  }
113
116
  if (where.or) {
114
117
  resultWhere.or = where.or.filter((it) => !!it).map(
115
- (it) => this.injectToWhere(it, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath)
118
+ (it) => this.injectToWhere(it, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath, isQueryRoot)
116
119
  );
117
120
  }
118
121
  if (where.not) {
119
- resultWhere.not = this.injectToWhere(where.not, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath);
122
+ resultWhere.not = this.injectToWhere(where.not, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath, isQueryRoot);
120
123
  }
121
124
  const fields = Object.keys(where).filter((it) => !["and", "or", "not"].includes(it));
122
125
  if (fields.length === 0) {
@@ -133,12 +136,12 @@ class PredicatesInjector {
133
136
  const isBackReference = this.findBackReferencedAncestor(ancestorPath, context.relation.name, context.entity.name) !== void 0;
134
137
  const nestedIsBackReferenceContext = isBackReference || isBackReferenceContext;
135
138
  const nestedAncestorPath = [...ancestorPath, context];
136
- return this.injectToWhere(relationWhere, context.targetEntity, false, context, nestedIsBackReferenceContext, nestedAncestorPath);
139
+ return this.injectToWhere(relationWhere, context.targetEntity, false, context, nestedIsBackReferenceContext, nestedAncestorPath, isQueryRoot);
137
140
  }
138
141
  });
139
142
  }
140
- const fieldsForPredicate = !isRoot ? fields : fields.filter((it) => this.predicateFactory.shouldApplyCellLevelPredicate(entity, Acl.Operation.read, it));
141
- return this.createWhere(entity, fieldsForPredicate, resultWhere, relationContext, isBackReferenceContext, ancestorPath);
143
+ const fieldsForPredicate = !isRoot ? fields : fields.filter((it) => this.predicateFactory.shouldApplyCellLevelPredicate(entity, Acl.Operation.read, it, isQueryRoot));
144
+ return this.createWhere(entity, fieldsForPredicate, resultWhere, relationContext, isBackReferenceContext, ancestorPath, isQueryRoot);
142
145
  }
143
146
  }
144
147
  export {
@@ -1 +1 @@
1
- {"version":3,"file":"PredicatesInjector.js","sources":["../../../../../packages/engine-content-api/src/acl/PredicatesInjector.ts"],"sourcesContent":["import { Acl, Input, Model, Writable } from '@contember/schema'\nimport { acceptFieldVisitor } from '@contember/schema-utils'\nimport { PredicateFactory } from './PredicateFactory'\n\nexport class PredicatesInjector {\n\tconstructor(private readonly schema: Model.Schema, private readonly predicateFactory: PredicateFactory) {}\n\n\tpublic inject(\n\t\tentity: Model.Entity,\n\t\twhere: Input.OptionalWhere,\n\t\trelationContext?: Model.AnyRelationContext,\n\t\tancestorPath?: readonly Model.AnyRelationContext[],\n\t): Input.OptionalWhere {\n\t\tconst restrictedWhere = this.injectToWhere(where, entity, true, relationContext, false, ancestorPath ?? [])\n\t\treturn this.createWhere(entity, undefined, restrictedWhere, relationContext, false, ancestorPath ?? [])\n\t}\n\n\t/**\n\t * Finds an ancestor in the path that matches the given relation as a back-reference.\n\t * A match occurs when:\n\t * 1. The relation we're traversing has the same name as the inverse (targetRelation) of a relation in the ancestor path\n\t * 2. AND the entity where our relation is defined matches the targetEntity in the path\n\t * (to prevent false positives when different entities have relations with the same name)\n\t */\n\tprivate findBackReferencedAncestor(\n\t\tancestorPath: readonly Model.AnyRelationContext[],\n\t\trelationName: string,\n\t\trelationSourceEntityName: string,\n\t): Model.AnyRelationContext | undefined {\n\t\treturn ancestorPath.find(ctx =>\n\t\t\tctx.targetRelation?.name === relationName\n\t\t\t&& ctx.targetEntity.name === relationSourceEntityName\n\t\t)\n\t}\n\n\tprivate createWhere(\n\t\tentity: Model.Entity,\n\t\tfieldNames: string[] | undefined,\n\t\twhere: Input.OptionalWhere,\n\t\trelationContext?: Model.AnyRelationContext,\n\t\tisBackReferenceContext?: boolean,\n\t\tancestorPath?: readonly Model.AnyRelationContext[],\n\t): Input.OptionalWhere {\n\t\t// Simplify predicates when:\n\t\t// 1. We're in a back-reference context (inside a filter that traverses back)\n\t\t// 2. AND the relation we traversed to get here corresponds to a relation in our query path\n\t\t// This ensures we only simplify when the traversed relation actually corresponds\n\t\t// to a relation in our query path (not just any relation to the same entity type)\n\t\tconst shouldSimplify = isBackReferenceContext === true\n\t\t\t&& ancestorPath !== undefined\n\t\t\t&& relationContext !== undefined\n\t\t\t&& this.findBackReferencedAncestor(ancestorPath, relationContext.relation.name, relationContext.entity.name) !== undefined\n\n\t\tlet predicatesWhere: Input.OptionalWhere\n\t\tif (shouldSimplify) {\n\t\t\tpredicatesWhere = { [entity.primary]: { always: true } }\n\t\t} else {\n\t\t\tconst rawPredicate = this.predicateFactory.create(entity, Acl.Operation.read, fieldNames, relationContext)\n\t\t\t// Process the predicate to inject nested entity predicates\n\t\t\tpredicatesWhere = this.injectPredicatesToPredicate(\n\t\t\t\trawPredicate,\n\t\t\t\tentity,\n\t\t\t\tisBackReferenceContext ?? false,\n\t\t\t\tancestorPath ?? [],\n\t\t\t)\n\t\t}\n\n\t\tconst and = [where, predicatesWhere].filter(it => Object.keys(it).length > 0)\n\t\tif (and.length === 0) {\n\t\t\treturn {}\n\t\t}\n\t\tif (and.length === 1) {\n\t\t\treturn and[0]\n\t\t}\n\t\treturn { and: and }\n\t}\n\n\t/**\n\t * Processes a predicate and injects nested entity predicates for any relation traversals.\n\t * This ensures that when a predicate like { department: { company: { name: 'Acme' } } }\n\t * is used, the predicates of Department and Company are also applied.\n\t */\n\tprivate injectPredicatesToPredicate(\n\t\twhere: Input.OptionalWhere,\n\t\tentity: Model.Entity,\n\t\tisBackReferenceContext: boolean,\n\t\tancestorPath: readonly Model.AnyRelationContext[],\n\t): Input.OptionalWhere {\n\t\tconst resultWhere: Writable<Input.OptionalWhere> = {}\n\n\t\tif (where.and) {\n\t\t\tresultWhere.and = where.and\n\t\t\t\t.filter((it): it is Input.Where => !!it)\n\t\t\t\t.map(it => this.injectPredicatesToPredicate(it, entity, isBackReferenceContext, ancestorPath))\n\t\t}\n\t\tif (where.or) {\n\t\t\tresultWhere.or = where.or\n\t\t\t\t.filter((it): it is Input.Where => !!it)\n\t\t\t\t.map(it => this.injectPredicatesToPredicate(it, entity, isBackReferenceContext, ancestorPath))\n\t\t}\n\t\tif (where.not) {\n\t\t\tresultWhere.not = this.injectPredicatesToPredicate(where.not, entity, isBackReferenceContext, ancestorPath)\n\t\t}\n\n\t\tconst fields = Object.keys(where).filter(it => !['and', 'or', 'not'].includes(it))\n\n\t\tfor (const field of fields) {\n\t\t\tresultWhere[field] = acceptFieldVisitor(this.schema, entity, field, {\n\t\t\t\tvisitColumn: () => where[field],\n\t\t\t\tvisitRelation: context => {\n\t\t\t\t\tconst relationWhere = where[field] as Input.OptionalWhere | null\n\t\t\t\t\tif (relationWhere === null) {\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check if this relation is a back-reference to somewhere in our ancestor path\n\t\t\t\t\tconst isBackReference = this.findBackReferencedAncestor(\n\t\t\t\t\t\tancestorPath,\n\t\t\t\t\t\tcontext.relation.name,\n\t\t\t\t\t\tcontext.entity.name,\n\t\t\t\t\t) !== undefined\n\t\t\t\t\tconst nestedIsBackReferenceContext = isBackReference || isBackReferenceContext\n\t\t\t\t\tconst nestedAncestorPath: readonly Model.AnyRelationContext[] = [...ancestorPath, context]\n\n\t\t\t\t\t// Recursively process the nested where (always do this to handle deeper nesting)\n\t\t\t\t\tconst processedNestedWhere = this.injectPredicatesToPredicate(\n\t\t\t\t\t\trelationWhere,\n\t\t\t\t\t\tcontext.targetEntity,\n\t\t\t\t\t\tnestedIsBackReferenceContext,\n\t\t\t\t\t\tnestedAncestorPath,\n\t\t\t\t\t)\n\n\t\t\t\t\t// Check if we should simplify the target entity's predicate\n\t\t\t\t\tconst shouldSimplifyNested = nestedIsBackReferenceContext\n\t\t\t\t\t\t&& this.findBackReferencedAncestor(nestedAncestorPath, context.relation.name, context.entity.name) !== undefined\n\n\t\t\t\t\t// Get target entity's predicate (simplified if back-reference)\n\t\t\t\t\tconst targetPredicate = shouldSimplifyNested\n\t\t\t\t\t\t? { [context.targetEntity.primary]: { always: true } }\n\t\t\t\t\t\t: this.predicateFactory.create(context.targetEntity, Acl.Operation.read, undefined, context)\n\n\t\t\t\t\t// Optimization: avoid duplicate { id: always } when both are simplified\n\t\t\t\t\tconst primaryKey = context.targetEntity.primary\n\t\t\t\t\tconst nestedIsAlwaysTrue = Object.keys(processedNestedWhere).length === 1\n\t\t\t\t\t\t&& (processedNestedWhere as Record<string, unknown>)[primaryKey] !== undefined\n\t\t\t\t\t\t&& (processedNestedWhere as Record<string, Record<string, unknown>>)[primaryKey]?.always === true\n\t\t\t\t\tconst targetIsAlwaysTrue = Object.keys(targetPredicate).length === 1\n\t\t\t\t\t\t&& (targetPredicate as Record<string, unknown>)[primaryKey] !== undefined\n\t\t\t\t\t\t&& (targetPredicate as Record<string, Record<string, unknown>>)[primaryKey]?.always === true\n\n\t\t\t\t\tif (nestedIsAlwaysTrue && targetIsAlwaysTrue) {\n\t\t\t\t\t\treturn processedNestedWhere\n\t\t\t\t\t}\n\n\t\t\t\t\t// Combine the processed nested where with target entity's predicate\n\t\t\t\t\tconst parts = [processedNestedWhere, targetPredicate].filter(it => Object.keys(it).length > 0)\n\t\t\t\t\tif (parts.length === 0) {\n\t\t\t\t\t\treturn {}\n\t\t\t\t\t}\n\t\t\t\t\tif (parts.length === 1) {\n\t\t\t\t\t\treturn parts[0]\n\t\t\t\t\t}\n\t\t\t\t\treturn { and: parts }\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\n\t\treturn resultWhere\n\t}\n\n\tprivate injectToWhere(\n\t\twhere: Input.OptionalWhere,\n\t\tentity: Model.Entity,\n\t\tisRoot: boolean,\n\t\trelationContext: Model.AnyRelationContext | undefined,\n\t\tisBackReferenceContext: boolean,\n\t\tancestorPath: readonly Model.AnyRelationContext[],\n\t): Input.OptionalWhere {\n\t\tconst resultWhere: Writable<Input.OptionalWhere> = {}\n\t\tif (where.and) {\n\t\t\tresultWhere.and = where.and.filter((it): it is Input.Where => !!it).map(it =>\n\t\t\t\tthis.injectToWhere(it, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath)\n\t\t\t)\n\t\t}\n\t\tif (where.or) {\n\t\t\tresultWhere.or = where.or.filter((it): it is Input.Where => !!it).map(it =>\n\t\t\t\tthis.injectToWhere(it, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath)\n\t\t\t)\n\t\t}\n\t\tif (where.not) {\n\t\t\tresultWhere.not = this.injectToWhere(where.not, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath)\n\t\t}\n\n\t\tconst fields = Object.keys(where).filter(it => !['and', 'or', 'not'].includes(it))\n\n\t\tif (fields.length === 0) {\n\t\t\treturn resultWhere\n\t\t}\n\t\tfor (let field of fields) {\n\t\t\tresultWhere[field] = acceptFieldVisitor(this.schema, entity, field, {\n\t\t\t\tvisitColumn: () => where[field],\n\t\t\t\tvisitRelation: context => {\n\t\t\t\t\tconst relationWhere = where[field] as Input.OptionalWhere | null\n\t\t\t\t\tif (relationWhere === null) {\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\t\t\t\t\t// Check if this relation is a back-reference to somewhere in our ancestor path\n\t\t\t\t\tconst isBackReference = this.findBackReferencedAncestor(ancestorPath, context.relation.name, context.entity.name) !== undefined\n\t\t\t\t\t// Once we enter a back-reference context, stay in it for nested relations\n\t\t\t\t\tconst nestedIsBackReferenceContext = isBackReference || isBackReferenceContext\n\t\t\t\t\t// Build extended ancestor path for nested traversal\n\t\t\t\t\tconst nestedAncestorPath: Model.AnyRelationContext[] = [...ancestorPath, context]\n\t\t\t\t\treturn this.injectToWhere(relationWhere, context.targetEntity, false, context, nestedIsBackReferenceContext, nestedAncestorPath)\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t\tconst fieldsForPredicate = !isRoot\n\t\t\t? fields\n\t\t\t: fields.filter(it => this.predicateFactory.shouldApplyCellLevelPredicate(entity, Acl.Operation.read, it))\n\n\t\treturn this.createWhere(entity, fieldsForPredicate, resultWhere, relationContext, isBackReferenceContext, ancestorPath)\n\t}\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"PredicatesInjector.js","sources":["../../../../../packages/engine-content-api/src/acl/PredicatesInjector.ts"],"sourcesContent":["import { Acl, Input, Model, Writable } from '@contember/schema'\nimport { acceptFieldVisitor } from '@contember/schema-utils'\nimport { PredicateFactory } from './PredicateFactory'\n\nexport class PredicatesInjector {\n\tconstructor(private readonly schema: Model.Schema, private readonly predicateFactory: PredicateFactory) {}\n\n\tpublic inject(\n\t\tentity: Model.Entity,\n\t\twhere: Input.OptionalWhere,\n\t\trelationContext?: Model.AnyRelationContext,\n\t\tancestorPath?: readonly Model.AnyRelationContext[],\n\t): Input.OptionalWhere {\n\t\tconst isQueryRoot = !relationContext && (!ancestorPath || ancestorPath.length === 0)\n\t\tconst restrictedWhere = this.injectToWhere(where, entity, true, relationContext, false, ancestorPath ?? [], isQueryRoot)\n\t\treturn this.createWhere(entity, undefined, restrictedWhere, relationContext, false, ancestorPath ?? [], isQueryRoot)\n\t}\n\n\t/**\n\t * Finds an ancestor in the path that matches the given relation as a back-reference.\n\t * A match occurs when:\n\t * 1. The relation we're traversing has the same name as the inverse (targetRelation) of a relation in the ancestor path\n\t * 2. AND the entity where our relation is defined matches the targetEntity in the path\n\t * (to prevent false positives when different entities have relations with the same name)\n\t */\n\tprivate findBackReferencedAncestor(\n\t\tancestorPath: readonly Model.AnyRelationContext[],\n\t\trelationName: string,\n\t\trelationSourceEntityName: string,\n\t): Model.AnyRelationContext | undefined {\n\t\treturn ancestorPath.find(ctx =>\n\t\t\tctx.targetRelation?.name === relationName\n\t\t\t&& ctx.targetEntity.name === relationSourceEntityName\n\t\t)\n\t}\n\n\tprivate createWhere(\n\t\tentity: Model.Entity,\n\t\tfieldNames: string[] | undefined,\n\t\twhere: Input.OptionalWhere,\n\t\trelationContext?: Model.AnyRelationContext,\n\t\tisBackReferenceContext?: boolean,\n\t\tancestorPath?: readonly Model.AnyRelationContext[],\n\t\tisQueryRoot?: boolean,\n\t): Input.OptionalWhere {\n\t\t// Simplify predicates when:\n\t\t// 1. We're in a back-reference context (inside a filter that traverses back)\n\t\t// 2. AND the relation we traversed to get here corresponds to a relation in our query path\n\t\t// This ensures we only simplify when the traversed relation actually corresponds\n\t\t// to a relation in our query path (not just any relation to the same entity type)\n\t\tconst shouldSimplify = isBackReferenceContext === true\n\t\t\t&& ancestorPath !== undefined\n\t\t\t&& relationContext !== undefined\n\t\t\t&& this.findBackReferencedAncestor(ancestorPath, relationContext.relation.name, relationContext.entity.name) !== undefined\n\n\t\tlet predicatesWhere: Input.OptionalWhere\n\t\tif (shouldSimplify) {\n\t\t\tpredicatesWhere = { [entity.primary]: { always: true } }\n\t\t} else {\n\t\t\tconst rawPredicate = this.predicateFactory.create(entity, Acl.Operation.read, fieldNames, relationContext, isQueryRoot)\n\t\t\t// Process the predicate to inject nested entity predicates\n\t\t\tpredicatesWhere = this.injectPredicatesToPredicate(\n\t\t\t\trawPredicate,\n\t\t\t\tentity,\n\t\t\t\tisBackReferenceContext ?? false,\n\t\t\t\tancestorPath ?? [],\n\t\t\t\tisQueryRoot,\n\t\t\t)\n\t\t}\n\n\t\tconst and = [where, predicatesWhere].filter(it => Object.keys(it).length > 0)\n\t\tif (and.length === 0) {\n\t\t\treturn {}\n\t\t}\n\t\tif (and.length === 1) {\n\t\t\treturn and[0]\n\t\t}\n\t\treturn { and: and }\n\t}\n\n\t/**\n\t * Processes a predicate and injects nested entity predicates for any relation traversals.\n\t * This ensures that when a predicate like { department: { company: { name: 'Acme' } } }\n\t * is used, the predicates of Department and Company are also applied.\n\t */\n\tprivate injectPredicatesToPredicate(\n\t\twhere: Input.OptionalWhere,\n\t\tentity: Model.Entity,\n\t\tisBackReferenceContext: boolean,\n\t\tancestorPath: readonly Model.AnyRelationContext[],\n\t\tisQueryRoot?: boolean,\n\t): Input.OptionalWhere {\n\t\tconst resultWhere: Writable<Input.OptionalWhere> = {}\n\n\t\tif (where.and) {\n\t\t\tresultWhere.and = where.and\n\t\t\t\t.filter((it): it is Input.Where => !!it)\n\t\t\t\t.map(it => this.injectPredicatesToPredicate(it, entity, isBackReferenceContext, ancestorPath, isQueryRoot))\n\t\t}\n\t\tif (where.or) {\n\t\t\tresultWhere.or = where.or\n\t\t\t\t.filter((it): it is Input.Where => !!it)\n\t\t\t\t.map(it => this.injectPredicatesToPredicate(it, entity, isBackReferenceContext, ancestorPath, isQueryRoot))\n\t\t}\n\t\tif (where.not) {\n\t\t\tresultWhere.not = this.injectPredicatesToPredicate(where.not, entity, isBackReferenceContext, ancestorPath, isQueryRoot)\n\t\t}\n\n\t\tconst fields = Object.keys(where).filter(it => !['and', 'or', 'not'].includes(it))\n\n\t\tfor (const field of fields) {\n\t\t\tresultWhere[field] = acceptFieldVisitor(this.schema, entity, field, {\n\t\t\t\tvisitColumn: () => where[field],\n\t\t\t\tvisitRelation: context => {\n\t\t\t\t\tconst relationWhere = where[field] as Input.OptionalWhere | null\n\t\t\t\t\tif (relationWhere === null) {\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\n\t\t\t\t\t// Check if this relation is a back-reference to somewhere in our ancestor path\n\t\t\t\t\tconst isBackReference = this.findBackReferencedAncestor(\n\t\t\t\t\t\tancestorPath,\n\t\t\t\t\t\tcontext.relation.name,\n\t\t\t\t\t\tcontext.entity.name,\n\t\t\t\t\t) !== undefined\n\t\t\t\t\tconst nestedIsBackReferenceContext = isBackReference || isBackReferenceContext\n\t\t\t\t\tconst nestedAncestorPath: readonly Model.AnyRelationContext[] = [...ancestorPath, context]\n\n\t\t\t\t\t// Recursively process the nested where (always do this to handle deeper nesting)\n\t\t\t\t\tconst processedNestedWhere = this.injectPredicatesToPredicate(\n\t\t\t\t\t\trelationWhere,\n\t\t\t\t\t\tcontext.targetEntity,\n\t\t\t\t\t\tnestedIsBackReferenceContext,\n\t\t\t\t\t\tnestedAncestorPath,\n\t\t\t\t\t\tisQueryRoot,\n\t\t\t\t\t)\n\n\t\t\t\t\t// Check if we should simplify the target entity's predicate\n\t\t\t\t\tconst shouldSimplifyNested = nestedIsBackReferenceContext\n\t\t\t\t\t\t&& this.findBackReferencedAncestor(nestedAncestorPath, context.relation.name, context.entity.name) !== undefined\n\n\t\t\t\t\t// Get target entity's predicate (simplified if back-reference)\n\t\t\t\t\tconst targetPredicate = shouldSimplifyNested\n\t\t\t\t\t\t? { [context.targetEntity.primary]: { always: true } }\n\t\t\t\t\t\t: this.predicateFactory.create(context.targetEntity, Acl.Operation.read, undefined, context, isQueryRoot)\n\n\t\t\t\t\t// Optimization: avoid duplicate { id: always } when both are simplified\n\t\t\t\t\tconst primaryKey = context.targetEntity.primary\n\t\t\t\t\tconst nestedIsAlwaysTrue = Object.keys(processedNestedWhere).length === 1\n\t\t\t\t\t\t&& (processedNestedWhere as Record<string, unknown>)[primaryKey] !== undefined\n\t\t\t\t\t\t&& (processedNestedWhere as Record<string, Record<string, unknown>>)[primaryKey]?.always === true\n\t\t\t\t\tconst targetIsAlwaysTrue = Object.keys(targetPredicate).length === 1\n\t\t\t\t\t\t&& (targetPredicate as Record<string, unknown>)[primaryKey] !== undefined\n\t\t\t\t\t\t&& (targetPredicate as Record<string, Record<string, unknown>>)[primaryKey]?.always === true\n\n\t\t\t\t\tif (nestedIsAlwaysTrue && targetIsAlwaysTrue) {\n\t\t\t\t\t\treturn processedNestedWhere\n\t\t\t\t\t}\n\n\t\t\t\t\t// Combine the processed nested where with target entity's predicate\n\t\t\t\t\tconst parts = [processedNestedWhere, targetPredicate].filter(it => Object.keys(it).length > 0)\n\t\t\t\t\tif (parts.length === 0) {\n\t\t\t\t\t\treturn {}\n\t\t\t\t\t}\n\t\t\t\t\tif (parts.length === 1) {\n\t\t\t\t\t\treturn parts[0]\n\t\t\t\t\t}\n\t\t\t\t\treturn { and: parts }\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\n\t\treturn resultWhere\n\t}\n\n\tprivate injectToWhere(\n\t\twhere: Input.OptionalWhere,\n\t\tentity: Model.Entity,\n\t\tisRoot: boolean,\n\t\trelationContext: Model.AnyRelationContext | undefined,\n\t\tisBackReferenceContext: boolean,\n\t\tancestorPath: readonly Model.AnyRelationContext[],\n\t\tisQueryRoot?: boolean,\n\t): Input.OptionalWhere {\n\t\tconst resultWhere: Writable<Input.OptionalWhere> = {}\n\t\tif (where.and) {\n\t\t\tresultWhere.and = where.and.filter((it): it is Input.Where => !!it).map(it =>\n\t\t\t\tthis.injectToWhere(it, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath, isQueryRoot)\n\t\t\t)\n\t\t}\n\t\tif (where.or) {\n\t\t\tresultWhere.or = where.or.filter((it): it is Input.Where => !!it).map(it =>\n\t\t\t\tthis.injectToWhere(it, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath, isQueryRoot)\n\t\t\t)\n\t\t}\n\t\tif (where.not) {\n\t\t\tresultWhere.not = this.injectToWhere(where.not, entity, isRoot, relationContext, isBackReferenceContext, ancestorPath, isQueryRoot)\n\t\t}\n\n\t\tconst fields = Object.keys(where).filter(it => !['and', 'or', 'not'].includes(it))\n\n\t\tif (fields.length === 0) {\n\t\t\treturn resultWhere\n\t\t}\n\t\tfor (let field of fields) {\n\t\t\tresultWhere[field] = acceptFieldVisitor(this.schema, entity, field, {\n\t\t\t\tvisitColumn: () => where[field],\n\t\t\t\tvisitRelation: context => {\n\t\t\t\t\tconst relationWhere = where[field] as Input.OptionalWhere | null\n\t\t\t\t\tif (relationWhere === null) {\n\t\t\t\t\t\treturn null\n\t\t\t\t\t}\n\t\t\t\t\t// Check if this relation is a back-reference to somewhere in our ancestor path\n\t\t\t\t\tconst isBackReference = this.findBackReferencedAncestor(ancestorPath, context.relation.name, context.entity.name) !== undefined\n\t\t\t\t\t// Once we enter a back-reference context, stay in it for nested relations\n\t\t\t\t\tconst nestedIsBackReferenceContext = isBackReference || isBackReferenceContext\n\t\t\t\t\t// Build extended ancestor path for nested traversal\n\t\t\t\t\tconst nestedAncestorPath: Model.AnyRelationContext[] = [...ancestorPath, context]\n\t\t\t\t\treturn this.injectToWhere(relationWhere, context.targetEntity, false, context, nestedIsBackReferenceContext, nestedAncestorPath, isQueryRoot)\n\t\t\t\t},\n\t\t\t})\n\t\t}\n\t\tconst fieldsForPredicate = !isRoot\n\t\t\t? fields\n\t\t\t: fields.filter(it => this.predicateFactory.shouldApplyCellLevelPredicate(entity, Acl.Operation.read, it, isQueryRoot))\n\n\t\treturn this.createWhere(entity, fieldsForPredicate, resultWhere, relationContext, isBackReferenceContext, ancestorPath, isQueryRoot)\n\t}\n}\n"],"names":[],"mappings":"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"}
@@ -195,7 +195,8 @@ class FieldsVisitor {
195
195
  });
196
196
  }
197
197
  getRequiredPredicate(entity, field) {
198
- const fieldPredicate = this.predicateFactory.getFieldPredicate(entity, schema.Acl.Operation.read, field.name);
198
+ const isRoot = this.relationPath.length === 0;
199
+ const fieldPredicate = this.predicateFactory.getFieldPredicate(entity, schema.Acl.Operation.read, field.name, isRoot);
199
200
  return fieldPredicate.isSameAsPrimary ? void 0 : fieldPredicate.predicate;
200
201
  }
201
202
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FieldsVisitor.cjs","sources":["../../../../../../../packages/engine-content-api/src/mapper/select/handlers/FieldsVisitor.ts"],"sourcesContent":["import { Acl, Input, Model, Settings } from '@contember/schema'\nimport { Mapper } from '../../Mapper'\nimport { RelationFetcher } from '../RelationFetcher'\nimport { SelectExecutionHandlerContext } from '../SelectExecutionHandler'\nimport { PredicateFactory } from '../../../acl'\nimport { Literal, wrapIdentifier } from '@contember/database'\nimport { ColumnValueGetter } from '../SelectHydrator'\nimport { Providers } from '@contember/schema-utils'\nimport { getColumnName } from '@contember/schema-utils'\nimport { viewComputedId } from '../../../utils/viewComputedId'\n\nexport class FieldsVisitor implements Model.RelationByTypeVisitor<void>, Model.ColumnVisitor<void> {\n\tconstructor(\n\t\tprivate readonly schema: Model.Schema,\n\t\tprivate readonly relationFetcher: RelationFetcher,\n\t\tprivate readonly predicateFactory: PredicateFactory,\n\t\tprivate readonly mapper: Mapper,\n\t\tprivate readonly executionContext: SelectExecutionHandlerContext,\n\t\tprivate readonly relationPath: Model.AnyRelationContext[],\n\t\tprivate readonly settings: Settings.ContentSettings,\n\t\tprivate readonly providers: Providers,\n\t) {}\n\n\tvisitColumn({ entity, column }: Model.ColumnContext): void {\n\t\tconst columnPath = this.executionContext.path\n\t\tconst tablePath = columnPath.back()\n\t\tconst tableAlias = tablePath.alias\n\t\tconst columnAlias = columnPath.alias\n\n\t\tlet selectFrom = wrapIdentifier(tableAlias) + '.' + wrapIdentifier(column.columnName)\n\t\tif (column.type === Model.ColumnType.Date && this.settings.shortDateResponse) {\n\t\t\tselectFrom += '::text'\n\t\t}\n\t\tif (column.type === Model.ColumnType.DateTime && this.settings.fullDateTimeResponse) {\n\t\t\tselectFrom += '::text'\n\t\t}\n\t\tif (column.type === Model.ColumnType.Enum && column.list) {\n\t\t\tselectFrom += '::text[]'\n\t\t}\n\n\t\tlet columnValueGetter: ColumnValueGetter | undefined\n\t\tif (entity.view && column.name === entity.primary && column.type === Model.ColumnType.Uuid) {\n\t\t\tif (entity.view.idSource) {\n\t\t\t\tconst aliases: string[] = []\n\t\t\t\tfor (const source of entity.view.idSource) {\n\t\t\t\t\tconst columnName = getColumnName(this.schema, entity, source)\n\t\t\t\t\tconst idSrcPath = columnPath.for(source + '__id_src')\n\t\t\t\t\taliases.push(idSrcPath.alias)\n\t\t\t\t\tthis.executionContext.addColumn({\n\t\t\t\t\t\tquery: qb => qb.select([tableAlias, columnName], idSrcPath.alias),\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tcolumnValueGetter = row => {\n\t\t\t\t\treturn viewComputedId(aliases.map(it => row[it]?.toString() || ''))\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcolumnValueGetter = row => {\n\t\t\t\t\treturn row[columnAlias] ?? (this.providers.uuid({ version: this.settings.uuidVersion }))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.executionContext.addColumn({\n\t\t\tquery: qb => qb.select(new Literal(selectFrom), columnAlias),\n\t\t\tpredicate: this.getRequiredPredicate(entity, column),\n\t\t\tvalueGetter: columnValueGetter,\n\t\t})\n\t}\n\n\tpublic visitManyHasManyInverse(relationContext: Model.ManyHasManyInverseContext): void {\n\t\tconst field = this.executionContext.objectNode\n\t\tif (!field) {\n\t\t\tthrow new Error()\n\t\t}\n\t\tthis.executionContext.addData({\n\t\t\tfield: relationContext.entity.primary,\n\t\t\tdataProvider: async ids =>\n\t\t\t\tthis.relationFetcher.fetchManyHasManyGroups({\n\t\t\t\t\tmapper: this.mapper,\n\t\t\t\t\tfield: field,\n\t\t\t\t\trelationContext,\n\t\t\t\t\trelationPath: this.relationPath,\n\t\t\t\t\tids: ids,\n\t\t\t\t}),\n\t\t\tdefaultValue: [],\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitManyHasManyOwning(relationContext: Model.ManyHasManyOwningContext): void {\n\t\tconst field = this.executionContext.objectNode\n\t\tif (!field) {\n\t\t\tthrow new Error()\n\t\t}\n\n\t\tthis.executionContext.addData({\n\t\t\tfield: relationContext.entity.primary,\n\t\t\tdataProvider: async ids =>\n\t\t\t\tthis.relationFetcher.fetchManyHasManyGroups({\n\t\t\t\t\tmapper: this.mapper,\n\t\t\t\t\tfield: field,\n\t\t\t\t\trelationContext,\n\t\t\t\t\trelationPath: this.relationPath,\n\t\t\t\t\tids: ids,\n\t\t\t\t}),\n\t\t\tdefaultValue: [],\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitOneHasMany(relationContext: Model.OneHasManyContext): void {\n\t\tconst field = this.executionContext.objectNode\n\t\tif (!field) {\n\t\t\tthrow new Error()\n\t\t}\n\n\t\tthis.executionContext.addData({\n\t\t\tfield: relationContext.entity.primary,\n\t\t\tdataProvider: async ids =>\n\t\t\t\tthis.relationFetcher.fetchOneHasManyGroups({\n\t\t\t\t\tmapper: this.mapper,\n\t\t\t\t\tobjectNode: field,\n\t\t\t\t\trelationContext,\n\t\t\t\t\trelationPath: this.relationPath,\n\t\t\t\t\tids: ids,\n\t\t\t\t}),\n\t\t\tdefaultValue: [],\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitOneHasOneInverse(relationContext: Model.OneHasOneInverseContext): void {\n\t\tconst { entity, targetRelation, targetEntity } = relationContext\n\t\tthis.executionContext.addData({\n\t\t\tfield: entity.primary,\n\t\t\tdataProvider: async ids => {\n\t\t\t\tconst idsWhere: Input.Where = {\n\t\t\t\t\t[targetRelation.name]: {\n\t\t\t\t\t\t[entity.primary]: {\n\t\t\t\t\t\t\tin: ids,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tconst field = this.executionContext.objectNode\n\t\t\t\tif (!field) {\n\t\t\t\t\tthrow new Error()\n\t\t\t\t}\n\t\t\t\tconst where: Input.Where = {\n\t\t\t\t\tand: [idsWhere, field.args.filter].filter((it): it is Input.Where => it !== undefined),\n\t\t\t\t}\n\t\t\t\tconst objectWithWhere = field.withArg('filter', where)\n\n\t\t\t\treturn this.mapper.selectAssoc(targetEntity, objectWithWhere, [\n\t\t\t\t\t...this.relationPath,\n\t\t\t\t\trelationContext,\n\t\t\t\t], targetRelation.name)\n\t\t\t},\n\t\t\tdefaultValue: null,\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitOneHasOneOwning(relationContext: Model.OneHasOneOwningContext): void {\n\t\tconst { relation, targetEntity } = relationContext\n\t\tthis.executionContext.addData({\n\t\t\tfield: relation.name,\n\t\t\tdataProvider: async ids => {\n\t\t\t\tconst idsWhere: Input.Where = {\n\t\t\t\t\t[targetEntity.primary]: {\n\t\t\t\t\t\tin: ids,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tconst objectNode = this.executionContext.objectNode\n\t\t\t\tif (!objectNode) {\n\t\t\t\t\tthrow new Error()\n\t\t\t\t}\n\t\t\t\tconst where: Input.Where = {\n\t\t\t\t\tand: [idsWhere, objectNode.args.filter].filter((it): it is Input.Where => it !== undefined),\n\t\t\t\t}\n\t\t\t\tconst objectWithWhere = objectNode.withArg('filter', where)\n\n\t\t\t\treturn this.mapper.selectAssoc(targetEntity, objectWithWhere, [\n\t\t\t\t\t...this.relationPath,\n\t\t\t\t\trelationContext,\n\t\t\t\t], targetEntity.primary)\n\t\t\t},\n\t\t\tdefaultValue: null,\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitManyHasOne(relationContext: Model.ManyHasOneContext): void {\n\t\tconst { relation, targetEntity } = relationContext\n\t\tthis.executionContext.addData({\n\t\t\tfield: relation.name,\n\t\t\tdataProvider: async ids => {\n\t\t\t\tconst idsWhere: Input.Where = {\n\t\t\t\t\t[targetEntity.primary]: {\n\t\t\t\t\t\tin: ids,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tconst objectNode = this.executionContext.objectNode\n\t\t\t\tif (!objectNode) {\n\t\t\t\t\tthrow new Error()\n\t\t\t\t}\n\t\t\t\tconst where: Input.Where = {\n\t\t\t\t\tand: [idsWhere, objectNode.args.filter].filter((it): it is Input.Where => it !== undefined),\n\t\t\t\t}\n\t\t\t\tconst objectWithWhere = objectNode.withArg('filter', where)\n\n\t\t\t\treturn this.mapper.selectAssoc(targetEntity, objectWithWhere, [\n\t\t\t\t\t...this.relationPath,\n\t\t\t\t\trelationContext,\n\t\t\t\t], targetEntity.primary)\n\t\t\t},\n\t\t\tdefaultValue: null,\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tprivate getRequiredPredicate(entity: Model.Entity, field: Model.AnyField): Acl.Predicate | undefined {\n\t\tconst fieldPredicate = this.predicateFactory.getFieldPredicate(entity, Acl.Operation.read, field.name)\n\t\treturn fieldPredicate.isSameAsPrimary ? undefined : fieldPredicate.predicate\n\t}\n}\n"],"names":["schema","wrapIdentifier","Model","getColumnName","viewComputedId","Literal","Acl"],"mappings":"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"}
1
+ {"version":3,"file":"FieldsVisitor.cjs","sources":["../../../../../../../packages/engine-content-api/src/mapper/select/handlers/FieldsVisitor.ts"],"sourcesContent":["import { Acl, Input, Model, Settings } from '@contember/schema'\nimport { Mapper } from '../../Mapper'\nimport { RelationFetcher } from '../RelationFetcher'\nimport { SelectExecutionHandlerContext } from '../SelectExecutionHandler'\nimport { PredicateFactory } from '../../../acl'\nimport { Literal, wrapIdentifier } from '@contember/database'\nimport { ColumnValueGetter } from '../SelectHydrator'\nimport { Providers } from '@contember/schema-utils'\nimport { getColumnName } from '@contember/schema-utils'\nimport { viewComputedId } from '../../../utils/viewComputedId'\n\nexport class FieldsVisitor implements Model.RelationByTypeVisitor<void>, Model.ColumnVisitor<void> {\n\tconstructor(\n\t\tprivate readonly schema: Model.Schema,\n\t\tprivate readonly relationFetcher: RelationFetcher,\n\t\tprivate readonly predicateFactory: PredicateFactory,\n\t\tprivate readonly mapper: Mapper,\n\t\tprivate readonly executionContext: SelectExecutionHandlerContext,\n\t\tprivate readonly relationPath: Model.AnyRelationContext[],\n\t\tprivate readonly settings: Settings.ContentSettings,\n\t\tprivate readonly providers: Providers,\n\t) {}\n\n\tvisitColumn({ entity, column }: Model.ColumnContext): void {\n\t\tconst columnPath = this.executionContext.path\n\t\tconst tablePath = columnPath.back()\n\t\tconst tableAlias = tablePath.alias\n\t\tconst columnAlias = columnPath.alias\n\n\t\tlet selectFrom = wrapIdentifier(tableAlias) + '.' + wrapIdentifier(column.columnName)\n\t\tif (column.type === Model.ColumnType.Date && this.settings.shortDateResponse) {\n\t\t\tselectFrom += '::text'\n\t\t}\n\t\tif (column.type === Model.ColumnType.DateTime && this.settings.fullDateTimeResponse) {\n\t\t\tselectFrom += '::text'\n\t\t}\n\t\tif (column.type === Model.ColumnType.Enum && column.list) {\n\t\t\tselectFrom += '::text[]'\n\t\t}\n\n\t\tlet columnValueGetter: ColumnValueGetter | undefined\n\t\tif (entity.view && column.name === entity.primary && column.type === Model.ColumnType.Uuid) {\n\t\t\tif (entity.view.idSource) {\n\t\t\t\tconst aliases: string[] = []\n\t\t\t\tfor (const source of entity.view.idSource) {\n\t\t\t\t\tconst columnName = getColumnName(this.schema, entity, source)\n\t\t\t\t\tconst idSrcPath = columnPath.for(source + '__id_src')\n\t\t\t\t\taliases.push(idSrcPath.alias)\n\t\t\t\t\tthis.executionContext.addColumn({\n\t\t\t\t\t\tquery: qb => qb.select([tableAlias, columnName], idSrcPath.alias),\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tcolumnValueGetter = row => {\n\t\t\t\t\treturn viewComputedId(aliases.map(it => row[it]?.toString() || ''))\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcolumnValueGetter = row => {\n\t\t\t\t\treturn row[columnAlias] ?? (this.providers.uuid({ version: this.settings.uuidVersion }))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.executionContext.addColumn({\n\t\t\tquery: qb => qb.select(new Literal(selectFrom), columnAlias),\n\t\t\tpredicate: this.getRequiredPredicate(entity, column),\n\t\t\tvalueGetter: columnValueGetter,\n\t\t})\n\t}\n\n\tpublic visitManyHasManyInverse(relationContext: Model.ManyHasManyInverseContext): void {\n\t\tconst field = this.executionContext.objectNode\n\t\tif (!field) {\n\t\t\tthrow new Error()\n\t\t}\n\t\tthis.executionContext.addData({\n\t\t\tfield: relationContext.entity.primary,\n\t\t\tdataProvider: async ids =>\n\t\t\t\tthis.relationFetcher.fetchManyHasManyGroups({\n\t\t\t\t\tmapper: this.mapper,\n\t\t\t\t\tfield: field,\n\t\t\t\t\trelationContext,\n\t\t\t\t\trelationPath: this.relationPath,\n\t\t\t\t\tids: ids,\n\t\t\t\t}),\n\t\t\tdefaultValue: [],\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitManyHasManyOwning(relationContext: Model.ManyHasManyOwningContext): void {\n\t\tconst field = this.executionContext.objectNode\n\t\tif (!field) {\n\t\t\tthrow new Error()\n\t\t}\n\n\t\tthis.executionContext.addData({\n\t\t\tfield: relationContext.entity.primary,\n\t\t\tdataProvider: async ids =>\n\t\t\t\tthis.relationFetcher.fetchManyHasManyGroups({\n\t\t\t\t\tmapper: this.mapper,\n\t\t\t\t\tfield: field,\n\t\t\t\t\trelationContext,\n\t\t\t\t\trelationPath: this.relationPath,\n\t\t\t\t\tids: ids,\n\t\t\t\t}),\n\t\t\tdefaultValue: [],\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitOneHasMany(relationContext: Model.OneHasManyContext): void {\n\t\tconst field = this.executionContext.objectNode\n\t\tif (!field) {\n\t\t\tthrow new Error()\n\t\t}\n\n\t\tthis.executionContext.addData({\n\t\t\tfield: relationContext.entity.primary,\n\t\t\tdataProvider: async ids =>\n\t\t\t\tthis.relationFetcher.fetchOneHasManyGroups({\n\t\t\t\t\tmapper: this.mapper,\n\t\t\t\t\tobjectNode: field,\n\t\t\t\t\trelationContext,\n\t\t\t\t\trelationPath: this.relationPath,\n\t\t\t\t\tids: ids,\n\t\t\t\t}),\n\t\t\tdefaultValue: [],\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitOneHasOneInverse(relationContext: Model.OneHasOneInverseContext): void {\n\t\tconst { entity, targetRelation, targetEntity } = relationContext\n\t\tthis.executionContext.addData({\n\t\t\tfield: entity.primary,\n\t\t\tdataProvider: async ids => {\n\t\t\t\tconst idsWhere: Input.Where = {\n\t\t\t\t\t[targetRelation.name]: {\n\t\t\t\t\t\t[entity.primary]: {\n\t\t\t\t\t\t\tin: ids,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tconst field = this.executionContext.objectNode\n\t\t\t\tif (!field) {\n\t\t\t\t\tthrow new Error()\n\t\t\t\t}\n\t\t\t\tconst where: Input.Where = {\n\t\t\t\t\tand: [idsWhere, field.args.filter].filter((it): it is Input.Where => it !== undefined),\n\t\t\t\t}\n\t\t\t\tconst objectWithWhere = field.withArg('filter', where)\n\n\t\t\t\treturn this.mapper.selectAssoc(targetEntity, objectWithWhere, [\n\t\t\t\t\t...this.relationPath,\n\t\t\t\t\trelationContext,\n\t\t\t\t], targetRelation.name)\n\t\t\t},\n\t\t\tdefaultValue: null,\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitOneHasOneOwning(relationContext: Model.OneHasOneOwningContext): void {\n\t\tconst { relation, targetEntity } = relationContext\n\t\tthis.executionContext.addData({\n\t\t\tfield: relation.name,\n\t\t\tdataProvider: async ids => {\n\t\t\t\tconst idsWhere: Input.Where = {\n\t\t\t\t\t[targetEntity.primary]: {\n\t\t\t\t\t\tin: ids,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tconst objectNode = this.executionContext.objectNode\n\t\t\t\tif (!objectNode) {\n\t\t\t\t\tthrow new Error()\n\t\t\t\t}\n\t\t\t\tconst where: Input.Where = {\n\t\t\t\t\tand: [idsWhere, objectNode.args.filter].filter((it): it is Input.Where => it !== undefined),\n\t\t\t\t}\n\t\t\t\tconst objectWithWhere = objectNode.withArg('filter', where)\n\n\t\t\t\treturn this.mapper.selectAssoc(targetEntity, objectWithWhere, [\n\t\t\t\t\t...this.relationPath,\n\t\t\t\t\trelationContext,\n\t\t\t\t], targetEntity.primary)\n\t\t\t},\n\t\t\tdefaultValue: null,\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitManyHasOne(relationContext: Model.ManyHasOneContext): void {\n\t\tconst { relation, targetEntity } = relationContext\n\t\tthis.executionContext.addData({\n\t\t\tfield: relation.name,\n\t\t\tdataProvider: async ids => {\n\t\t\t\tconst idsWhere: Input.Where = {\n\t\t\t\t\t[targetEntity.primary]: {\n\t\t\t\t\t\tin: ids,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tconst objectNode = this.executionContext.objectNode\n\t\t\t\tif (!objectNode) {\n\t\t\t\t\tthrow new Error()\n\t\t\t\t}\n\t\t\t\tconst where: Input.Where = {\n\t\t\t\t\tand: [idsWhere, objectNode.args.filter].filter((it): it is Input.Where => it !== undefined),\n\t\t\t\t}\n\t\t\t\tconst objectWithWhere = objectNode.withArg('filter', where)\n\n\t\t\t\treturn this.mapper.selectAssoc(targetEntity, objectWithWhere, [\n\t\t\t\t\t...this.relationPath,\n\t\t\t\t\trelationContext,\n\t\t\t\t], targetEntity.primary)\n\t\t\t},\n\t\t\tdefaultValue: null,\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tprivate getRequiredPredicate(entity: Model.Entity, field: Model.AnyField): Acl.Predicate | undefined {\n\t\tconst isRoot = this.relationPath.length === 0\n\t\tconst fieldPredicate = this.predicateFactory.getFieldPredicate(entity, Acl.Operation.read, field.name, isRoot)\n\t\treturn fieldPredicate.isSameAsPrimary ? undefined : fieldPredicate.predicate\n\t}\n}\n"],"names":["schema","wrapIdentifier","Model","getColumnName","viewComputedId","Literal","Acl"],"mappings":"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"}
@@ -193,7 +193,8 @@ class FieldsVisitor {
193
193
  });
194
194
  }
195
195
  getRequiredPredicate(entity, field) {
196
- const fieldPredicate = this.predicateFactory.getFieldPredicate(entity, Acl.Operation.read, field.name);
196
+ const isRoot = this.relationPath.length === 0;
197
+ const fieldPredicate = this.predicateFactory.getFieldPredicate(entity, Acl.Operation.read, field.name, isRoot);
197
198
  return fieldPredicate.isSameAsPrimary ? void 0 : fieldPredicate.predicate;
198
199
  }
199
200
  }
@@ -1 +1 @@
1
- {"version":3,"file":"FieldsVisitor.js","sources":["../../../../../../../packages/engine-content-api/src/mapper/select/handlers/FieldsVisitor.ts"],"sourcesContent":["import { Acl, Input, Model, Settings } from '@contember/schema'\nimport { Mapper } from '../../Mapper'\nimport { RelationFetcher } from '../RelationFetcher'\nimport { SelectExecutionHandlerContext } from '../SelectExecutionHandler'\nimport { PredicateFactory } from '../../../acl'\nimport { Literal, wrapIdentifier } from '@contember/database'\nimport { ColumnValueGetter } from '../SelectHydrator'\nimport { Providers } from '@contember/schema-utils'\nimport { getColumnName } from '@contember/schema-utils'\nimport { viewComputedId } from '../../../utils/viewComputedId'\n\nexport class FieldsVisitor implements Model.RelationByTypeVisitor<void>, Model.ColumnVisitor<void> {\n\tconstructor(\n\t\tprivate readonly schema: Model.Schema,\n\t\tprivate readonly relationFetcher: RelationFetcher,\n\t\tprivate readonly predicateFactory: PredicateFactory,\n\t\tprivate readonly mapper: Mapper,\n\t\tprivate readonly executionContext: SelectExecutionHandlerContext,\n\t\tprivate readonly relationPath: Model.AnyRelationContext[],\n\t\tprivate readonly settings: Settings.ContentSettings,\n\t\tprivate readonly providers: Providers,\n\t) {}\n\n\tvisitColumn({ entity, column }: Model.ColumnContext): void {\n\t\tconst columnPath = this.executionContext.path\n\t\tconst tablePath = columnPath.back()\n\t\tconst tableAlias = tablePath.alias\n\t\tconst columnAlias = columnPath.alias\n\n\t\tlet selectFrom = wrapIdentifier(tableAlias) + '.' + wrapIdentifier(column.columnName)\n\t\tif (column.type === Model.ColumnType.Date && this.settings.shortDateResponse) {\n\t\t\tselectFrom += '::text'\n\t\t}\n\t\tif (column.type === Model.ColumnType.DateTime && this.settings.fullDateTimeResponse) {\n\t\t\tselectFrom += '::text'\n\t\t}\n\t\tif (column.type === Model.ColumnType.Enum && column.list) {\n\t\t\tselectFrom += '::text[]'\n\t\t}\n\n\t\tlet columnValueGetter: ColumnValueGetter | undefined\n\t\tif (entity.view && column.name === entity.primary && column.type === Model.ColumnType.Uuid) {\n\t\t\tif (entity.view.idSource) {\n\t\t\t\tconst aliases: string[] = []\n\t\t\t\tfor (const source of entity.view.idSource) {\n\t\t\t\t\tconst columnName = getColumnName(this.schema, entity, source)\n\t\t\t\t\tconst idSrcPath = columnPath.for(source + '__id_src')\n\t\t\t\t\taliases.push(idSrcPath.alias)\n\t\t\t\t\tthis.executionContext.addColumn({\n\t\t\t\t\t\tquery: qb => qb.select([tableAlias, columnName], idSrcPath.alias),\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tcolumnValueGetter = row => {\n\t\t\t\t\treturn viewComputedId(aliases.map(it => row[it]?.toString() || ''))\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcolumnValueGetter = row => {\n\t\t\t\t\treturn row[columnAlias] ?? (this.providers.uuid({ version: this.settings.uuidVersion }))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.executionContext.addColumn({\n\t\t\tquery: qb => qb.select(new Literal(selectFrom), columnAlias),\n\t\t\tpredicate: this.getRequiredPredicate(entity, column),\n\t\t\tvalueGetter: columnValueGetter,\n\t\t})\n\t}\n\n\tpublic visitManyHasManyInverse(relationContext: Model.ManyHasManyInverseContext): void {\n\t\tconst field = this.executionContext.objectNode\n\t\tif (!field) {\n\t\t\tthrow new Error()\n\t\t}\n\t\tthis.executionContext.addData({\n\t\t\tfield: relationContext.entity.primary,\n\t\t\tdataProvider: async ids =>\n\t\t\t\tthis.relationFetcher.fetchManyHasManyGroups({\n\t\t\t\t\tmapper: this.mapper,\n\t\t\t\t\tfield: field,\n\t\t\t\t\trelationContext,\n\t\t\t\t\trelationPath: this.relationPath,\n\t\t\t\t\tids: ids,\n\t\t\t\t}),\n\t\t\tdefaultValue: [],\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitManyHasManyOwning(relationContext: Model.ManyHasManyOwningContext): void {\n\t\tconst field = this.executionContext.objectNode\n\t\tif (!field) {\n\t\t\tthrow new Error()\n\t\t}\n\n\t\tthis.executionContext.addData({\n\t\t\tfield: relationContext.entity.primary,\n\t\t\tdataProvider: async ids =>\n\t\t\t\tthis.relationFetcher.fetchManyHasManyGroups({\n\t\t\t\t\tmapper: this.mapper,\n\t\t\t\t\tfield: field,\n\t\t\t\t\trelationContext,\n\t\t\t\t\trelationPath: this.relationPath,\n\t\t\t\t\tids: ids,\n\t\t\t\t}),\n\t\t\tdefaultValue: [],\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitOneHasMany(relationContext: Model.OneHasManyContext): void {\n\t\tconst field = this.executionContext.objectNode\n\t\tif (!field) {\n\t\t\tthrow new Error()\n\t\t}\n\n\t\tthis.executionContext.addData({\n\t\t\tfield: relationContext.entity.primary,\n\t\t\tdataProvider: async ids =>\n\t\t\t\tthis.relationFetcher.fetchOneHasManyGroups({\n\t\t\t\t\tmapper: this.mapper,\n\t\t\t\t\tobjectNode: field,\n\t\t\t\t\trelationContext,\n\t\t\t\t\trelationPath: this.relationPath,\n\t\t\t\t\tids: ids,\n\t\t\t\t}),\n\t\t\tdefaultValue: [],\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitOneHasOneInverse(relationContext: Model.OneHasOneInverseContext): void {\n\t\tconst { entity, targetRelation, targetEntity } = relationContext\n\t\tthis.executionContext.addData({\n\t\t\tfield: entity.primary,\n\t\t\tdataProvider: async ids => {\n\t\t\t\tconst idsWhere: Input.Where = {\n\t\t\t\t\t[targetRelation.name]: {\n\t\t\t\t\t\t[entity.primary]: {\n\t\t\t\t\t\t\tin: ids,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tconst field = this.executionContext.objectNode\n\t\t\t\tif (!field) {\n\t\t\t\t\tthrow new Error()\n\t\t\t\t}\n\t\t\t\tconst where: Input.Where = {\n\t\t\t\t\tand: [idsWhere, field.args.filter].filter((it): it is Input.Where => it !== undefined),\n\t\t\t\t}\n\t\t\t\tconst objectWithWhere = field.withArg('filter', where)\n\n\t\t\t\treturn this.mapper.selectAssoc(targetEntity, objectWithWhere, [\n\t\t\t\t\t...this.relationPath,\n\t\t\t\t\trelationContext,\n\t\t\t\t], targetRelation.name)\n\t\t\t},\n\t\t\tdefaultValue: null,\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitOneHasOneOwning(relationContext: Model.OneHasOneOwningContext): void {\n\t\tconst { relation, targetEntity } = relationContext\n\t\tthis.executionContext.addData({\n\t\t\tfield: relation.name,\n\t\t\tdataProvider: async ids => {\n\t\t\t\tconst idsWhere: Input.Where = {\n\t\t\t\t\t[targetEntity.primary]: {\n\t\t\t\t\t\tin: ids,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tconst objectNode = this.executionContext.objectNode\n\t\t\t\tif (!objectNode) {\n\t\t\t\t\tthrow new Error()\n\t\t\t\t}\n\t\t\t\tconst where: Input.Where = {\n\t\t\t\t\tand: [idsWhere, objectNode.args.filter].filter((it): it is Input.Where => it !== undefined),\n\t\t\t\t}\n\t\t\t\tconst objectWithWhere = objectNode.withArg('filter', where)\n\n\t\t\t\treturn this.mapper.selectAssoc(targetEntity, objectWithWhere, [\n\t\t\t\t\t...this.relationPath,\n\t\t\t\t\trelationContext,\n\t\t\t\t], targetEntity.primary)\n\t\t\t},\n\t\t\tdefaultValue: null,\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitManyHasOne(relationContext: Model.ManyHasOneContext): void {\n\t\tconst { relation, targetEntity } = relationContext\n\t\tthis.executionContext.addData({\n\t\t\tfield: relation.name,\n\t\t\tdataProvider: async ids => {\n\t\t\t\tconst idsWhere: Input.Where = {\n\t\t\t\t\t[targetEntity.primary]: {\n\t\t\t\t\t\tin: ids,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tconst objectNode = this.executionContext.objectNode\n\t\t\t\tif (!objectNode) {\n\t\t\t\t\tthrow new Error()\n\t\t\t\t}\n\t\t\t\tconst where: Input.Where = {\n\t\t\t\t\tand: [idsWhere, objectNode.args.filter].filter((it): it is Input.Where => it !== undefined),\n\t\t\t\t}\n\t\t\t\tconst objectWithWhere = objectNode.withArg('filter', where)\n\n\t\t\t\treturn this.mapper.selectAssoc(targetEntity, objectWithWhere, [\n\t\t\t\t\t...this.relationPath,\n\t\t\t\t\trelationContext,\n\t\t\t\t], targetEntity.primary)\n\t\t\t},\n\t\t\tdefaultValue: null,\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tprivate getRequiredPredicate(entity: Model.Entity, field: Model.AnyField): Acl.Predicate | undefined {\n\t\tconst fieldPredicate = this.predicateFactory.getFieldPredicate(entity, Acl.Operation.read, field.name)\n\t\treturn fieldPredicate.isSameAsPrimary ? undefined : fieldPredicate.predicate\n\t}\n}\n"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"FieldsVisitor.js","sources":["../../../../../../../packages/engine-content-api/src/mapper/select/handlers/FieldsVisitor.ts"],"sourcesContent":["import { Acl, Input, Model, Settings } from '@contember/schema'\nimport { Mapper } from '../../Mapper'\nimport { RelationFetcher } from '../RelationFetcher'\nimport { SelectExecutionHandlerContext } from '../SelectExecutionHandler'\nimport { PredicateFactory } from '../../../acl'\nimport { Literal, wrapIdentifier } from '@contember/database'\nimport { ColumnValueGetter } from '../SelectHydrator'\nimport { Providers } from '@contember/schema-utils'\nimport { getColumnName } from '@contember/schema-utils'\nimport { viewComputedId } from '../../../utils/viewComputedId'\n\nexport class FieldsVisitor implements Model.RelationByTypeVisitor<void>, Model.ColumnVisitor<void> {\n\tconstructor(\n\t\tprivate readonly schema: Model.Schema,\n\t\tprivate readonly relationFetcher: RelationFetcher,\n\t\tprivate readonly predicateFactory: PredicateFactory,\n\t\tprivate readonly mapper: Mapper,\n\t\tprivate readonly executionContext: SelectExecutionHandlerContext,\n\t\tprivate readonly relationPath: Model.AnyRelationContext[],\n\t\tprivate readonly settings: Settings.ContentSettings,\n\t\tprivate readonly providers: Providers,\n\t) {}\n\n\tvisitColumn({ entity, column }: Model.ColumnContext): void {\n\t\tconst columnPath = this.executionContext.path\n\t\tconst tablePath = columnPath.back()\n\t\tconst tableAlias = tablePath.alias\n\t\tconst columnAlias = columnPath.alias\n\n\t\tlet selectFrom = wrapIdentifier(tableAlias) + '.' + wrapIdentifier(column.columnName)\n\t\tif (column.type === Model.ColumnType.Date && this.settings.shortDateResponse) {\n\t\t\tselectFrom += '::text'\n\t\t}\n\t\tif (column.type === Model.ColumnType.DateTime && this.settings.fullDateTimeResponse) {\n\t\t\tselectFrom += '::text'\n\t\t}\n\t\tif (column.type === Model.ColumnType.Enum && column.list) {\n\t\t\tselectFrom += '::text[]'\n\t\t}\n\n\t\tlet columnValueGetter: ColumnValueGetter | undefined\n\t\tif (entity.view && column.name === entity.primary && column.type === Model.ColumnType.Uuid) {\n\t\t\tif (entity.view.idSource) {\n\t\t\t\tconst aliases: string[] = []\n\t\t\t\tfor (const source of entity.view.idSource) {\n\t\t\t\t\tconst columnName = getColumnName(this.schema, entity, source)\n\t\t\t\t\tconst idSrcPath = columnPath.for(source + '__id_src')\n\t\t\t\t\taliases.push(idSrcPath.alias)\n\t\t\t\t\tthis.executionContext.addColumn({\n\t\t\t\t\t\tquery: qb => qb.select([tableAlias, columnName], idSrcPath.alias),\n\t\t\t\t\t})\n\t\t\t\t}\n\n\t\t\t\tcolumnValueGetter = row => {\n\t\t\t\t\treturn viewComputedId(aliases.map(it => row[it]?.toString() || ''))\n\t\t\t\t}\n\t\t\t} else {\n\t\t\t\tcolumnValueGetter = row => {\n\t\t\t\t\treturn row[columnAlias] ?? (this.providers.uuid({ version: this.settings.uuidVersion }))\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\tthis.executionContext.addColumn({\n\t\t\tquery: qb => qb.select(new Literal(selectFrom), columnAlias),\n\t\t\tpredicate: this.getRequiredPredicate(entity, column),\n\t\t\tvalueGetter: columnValueGetter,\n\t\t})\n\t}\n\n\tpublic visitManyHasManyInverse(relationContext: Model.ManyHasManyInverseContext): void {\n\t\tconst field = this.executionContext.objectNode\n\t\tif (!field) {\n\t\t\tthrow new Error()\n\t\t}\n\t\tthis.executionContext.addData({\n\t\t\tfield: relationContext.entity.primary,\n\t\t\tdataProvider: async ids =>\n\t\t\t\tthis.relationFetcher.fetchManyHasManyGroups({\n\t\t\t\t\tmapper: this.mapper,\n\t\t\t\t\tfield: field,\n\t\t\t\t\trelationContext,\n\t\t\t\t\trelationPath: this.relationPath,\n\t\t\t\t\tids: ids,\n\t\t\t\t}),\n\t\t\tdefaultValue: [],\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitManyHasManyOwning(relationContext: Model.ManyHasManyOwningContext): void {\n\t\tconst field = this.executionContext.objectNode\n\t\tif (!field) {\n\t\t\tthrow new Error()\n\t\t}\n\n\t\tthis.executionContext.addData({\n\t\t\tfield: relationContext.entity.primary,\n\t\t\tdataProvider: async ids =>\n\t\t\t\tthis.relationFetcher.fetchManyHasManyGroups({\n\t\t\t\t\tmapper: this.mapper,\n\t\t\t\t\tfield: field,\n\t\t\t\t\trelationContext,\n\t\t\t\t\trelationPath: this.relationPath,\n\t\t\t\t\tids: ids,\n\t\t\t\t}),\n\t\t\tdefaultValue: [],\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitOneHasMany(relationContext: Model.OneHasManyContext): void {\n\t\tconst field = this.executionContext.objectNode\n\t\tif (!field) {\n\t\t\tthrow new Error()\n\t\t}\n\n\t\tthis.executionContext.addData({\n\t\t\tfield: relationContext.entity.primary,\n\t\t\tdataProvider: async ids =>\n\t\t\t\tthis.relationFetcher.fetchOneHasManyGroups({\n\t\t\t\t\tmapper: this.mapper,\n\t\t\t\t\tobjectNode: field,\n\t\t\t\t\trelationContext,\n\t\t\t\t\trelationPath: this.relationPath,\n\t\t\t\t\tids: ids,\n\t\t\t\t}),\n\t\t\tdefaultValue: [],\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitOneHasOneInverse(relationContext: Model.OneHasOneInverseContext): void {\n\t\tconst { entity, targetRelation, targetEntity } = relationContext\n\t\tthis.executionContext.addData({\n\t\t\tfield: entity.primary,\n\t\t\tdataProvider: async ids => {\n\t\t\t\tconst idsWhere: Input.Where = {\n\t\t\t\t\t[targetRelation.name]: {\n\t\t\t\t\t\t[entity.primary]: {\n\t\t\t\t\t\t\tin: ids,\n\t\t\t\t\t\t},\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tconst field = this.executionContext.objectNode\n\t\t\t\tif (!field) {\n\t\t\t\t\tthrow new Error()\n\t\t\t\t}\n\t\t\t\tconst where: Input.Where = {\n\t\t\t\t\tand: [idsWhere, field.args.filter].filter((it): it is Input.Where => it !== undefined),\n\t\t\t\t}\n\t\t\t\tconst objectWithWhere = field.withArg('filter', where)\n\n\t\t\t\treturn this.mapper.selectAssoc(targetEntity, objectWithWhere, [\n\t\t\t\t\t...this.relationPath,\n\t\t\t\t\trelationContext,\n\t\t\t\t], targetRelation.name)\n\t\t\t},\n\t\t\tdefaultValue: null,\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitOneHasOneOwning(relationContext: Model.OneHasOneOwningContext): void {\n\t\tconst { relation, targetEntity } = relationContext\n\t\tthis.executionContext.addData({\n\t\t\tfield: relation.name,\n\t\t\tdataProvider: async ids => {\n\t\t\t\tconst idsWhere: Input.Where = {\n\t\t\t\t\t[targetEntity.primary]: {\n\t\t\t\t\t\tin: ids,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tconst objectNode = this.executionContext.objectNode\n\t\t\t\tif (!objectNode) {\n\t\t\t\t\tthrow new Error()\n\t\t\t\t}\n\t\t\t\tconst where: Input.Where = {\n\t\t\t\t\tand: [idsWhere, objectNode.args.filter].filter((it): it is Input.Where => it !== undefined),\n\t\t\t\t}\n\t\t\t\tconst objectWithWhere = objectNode.withArg('filter', where)\n\n\t\t\t\treturn this.mapper.selectAssoc(targetEntity, objectWithWhere, [\n\t\t\t\t\t...this.relationPath,\n\t\t\t\t\trelationContext,\n\t\t\t\t], targetEntity.primary)\n\t\t\t},\n\t\t\tdefaultValue: null,\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tpublic visitManyHasOne(relationContext: Model.ManyHasOneContext): void {\n\t\tconst { relation, targetEntity } = relationContext\n\t\tthis.executionContext.addData({\n\t\t\tfield: relation.name,\n\t\t\tdataProvider: async ids => {\n\t\t\t\tconst idsWhere: Input.Where = {\n\t\t\t\t\t[targetEntity.primary]: {\n\t\t\t\t\t\tin: ids,\n\t\t\t\t\t},\n\t\t\t\t}\n\t\t\t\tconst objectNode = this.executionContext.objectNode\n\t\t\t\tif (!objectNode) {\n\t\t\t\t\tthrow new Error()\n\t\t\t\t}\n\t\t\t\tconst where: Input.Where = {\n\t\t\t\t\tand: [idsWhere, objectNode.args.filter].filter((it): it is Input.Where => it !== undefined),\n\t\t\t\t}\n\t\t\t\tconst objectWithWhere = objectNode.withArg('filter', where)\n\n\t\t\t\treturn this.mapper.selectAssoc(targetEntity, objectWithWhere, [\n\t\t\t\t\t...this.relationPath,\n\t\t\t\t\trelationContext,\n\t\t\t\t], targetEntity.primary)\n\t\t\t},\n\t\t\tdefaultValue: null,\n\t\t\tpredicate: this.getRequiredPredicate(relationContext.entity, relationContext.relation),\n\t\t})\n\t}\n\n\tprivate getRequiredPredicate(entity: Model.Entity, field: Model.AnyField): Acl.Predicate | undefined {\n\t\tconst isRoot = this.relationPath.length === 0\n\t\tconst fieldPredicate = this.predicateFactory.getFieldPredicate(entity, Acl.Operation.read, field.name, isRoot)\n\t\treturn fieldPredicate.isSameAsPrimary ? undefined : fieldPredicate.predicate\n\t}\n}\n"],"names":[],"mappings":"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"}
@@ -120,6 +120,7 @@ exports.UserError = exception.UserError;
120
120
  exports.getFieldsForUniqueWhere = uniqueWhereFields.getFieldsForUniqueWhere;
121
121
  exports.EntityRulesResolver = EntityRulesResolver.EntityRulesResolver;
122
122
  exports.ExecutionContainerFactory = ExecutionContainer.ExecutionContainerFactory;
123
+ exports.InMemoryTriggeredActionsCollector = ExecutionContainer.InMemoryTriggeredActionsCollector;
123
124
  Object.defineProperty(exports, "graphql", {
124
125
  enumerable: true,
125
126
  get: () => graphql.graphql
@@ -1 +1 @@
1
- {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
1
+ {"version":3,"file":"index.cjs","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}
@@ -52,7 +52,7 @@ import "@contember/schema-utils";
52
52
  import "./src/input-validation/ValidationContext.js";
53
53
  import "./src/input-validation/ValidationEvaluation.js";
54
54
  import { EntityRulesResolver } from "./src/input-validation/EntityRulesResolver.js";
55
- import { ExecutionContainerFactory } from "./src/ExecutionContainer.js";
55
+ import { ExecutionContainerFactory, InMemoryTriggeredActionsCollector } from "./src/ExecutionContainer.js";
56
56
  import { graphql } from "graphql";
57
57
  import "@contember/database";
58
58
  import { AfterCommitEvent, AfterInsertEvent, AfterJunctionUpdateEvent, AfterUpdateEvent, BeforeCommitEvent, BeforeDeleteEvent, BeforeInsertEvent, BeforeJunctionUpdateEvent, BeforeUpdateEvent, EventManager } from "./src/mapper/EventManager.js";
@@ -98,6 +98,7 @@ export {
98
98
  GraphQlQueryAstFactory,
99
99
  GraphQlSchemaBuilder,
100
100
  GraphQlSchemaBuilderFactory,
101
+ InMemoryTriggeredActionsCollector,
101
102
  IntrospectionSchemaDefinitionFactory,
102
103
  IntrospectionSchemaFactory,
103
104
  Mapper,
@@ -49,7 +49,20 @@ const RefreshViewResolver = require("./resolvers/RefreshViewResolver.cjs");
49
49
  const MapperFactory = require("./mapper/MapperFactory.cjs");
50
50
  var __defProp = Object.defineProperty;
51
51
  var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
52
- var __publicField = (obj, key, value) => __defNormalProp(obj, key + "", value);
52
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
53
+ class InMemoryTriggeredActionsCollector {
54
+ constructor() {
55
+ __publicField(this, "events", []);
56
+ }
57
+ add(events) {
58
+ for (const event of events) {
59
+ this.events.push(event);
60
+ }
61
+ }
62
+ getEvents() {
63
+ return this.events;
64
+ }
65
+ }
53
66
  class ExecutionContainerFactory {
54
67
  constructor(providers, whereOptimizerOptions) {
55
68
  this.providers = providers;
@@ -60,8 +73,24 @@ class ExecutionContainerFactory {
60
73
  const builder = this.createBuilderInternal(args);
61
74
  return this.hooks.reduce((acc, cb) => cb(acc), builder);
62
75
  }
63
- createBuilderInternal({ permissions, identityVariables, identityId, db, schema, schemaMeta, systemSchema, stage, project, schemaDatabaseMetadata, userInfo }) {
64
- return new dic.Builder({}).addService("systemSchema", () => systemSchema).addService("db", () => db).addService("project", () => project).addService("stage", () => stage).addService("schema", () => schema).addService("schemaMeta", () => schemaMeta).addService("schemaDatabaseMetadata", () => schemaDatabaseMetadata).addService("userInfo", () => userInfo).addService("providers", () => this.providers).addService("variableInjector", ({ schema: schema2 }) => new VariableInjector.VariableInjector(schema2.model, identityVariables)).addService("predicateFactory", ({ variableInjector, schema: schema2 }) => new PredicateFactory.PredicateFactory(permissions, schema2.model, variableInjector)).addService("predicatesInjector", ({ predicateFactory, schema: schema2 }) => new PredicatesInjector.PredicatesInjector(schema2.model, predicateFactory)).addService("joinBuilder", ({ schema: schema2 }) => new JoinBuilder.JoinBuilder(schema2.model)).addService("conditionBuilder", () => new ConditionBuilder.ConditionBuilder()).addService("pathFactory", () => new Path.PathFactory()).addService("whereOptimized", ({ schema: schema2 }) => new WhereOptimizer.WhereOptimizer(schema2.model, new ConditionOptimizer.ConditionOptimizer(), this.whereOptimizerOptions)).addService("whereBuilder", ({ joinBuilder, conditionBuilder, pathFactory, whereOptimized, schema: schema2 }) => new WhereBuilder.WhereBuilder(
76
+ createBuilderInternal({
77
+ permissions,
78
+ allPermissions,
79
+ identityVariables,
80
+ identityId,
81
+ db,
82
+ schema,
83
+ schemaMeta,
84
+ systemSchema,
85
+ stage,
86
+ project,
87
+ schemaDatabaseMetadata,
88
+ userInfo
89
+ }) {
90
+ return new dic.Builder({}).addService("systemSchema", () => systemSchema).addService("db", () => db).addService("project", () => project).addService("stage", () => stage).addService("triggeredActionsCollector", () => schema.settings.actions?.returnTriggeredActions === true ? new InMemoryTriggeredActionsCollector() : void 0).addService("schema", () => schema).addService("schemaMeta", () => schemaMeta).addService("schemaDatabaseMetadata", () => schemaDatabaseMetadata).addService("userInfo", () => userInfo).addService("providers", () => this.providers).addService("variableInjector", ({ schema: schema2 }) => new VariableInjector.VariableInjector(schema2.model, identityVariables)).addService(
91
+ "predicateFactory",
92
+ ({ variableInjector, schema: schema2 }) => new PredicateFactory.PredicateFactory(permissions, schema2.model, variableInjector, allPermissions)
93
+ ).addService("predicatesInjector", ({ predicateFactory, schema: schema2 }) => new PredicatesInjector.PredicatesInjector(schema2.model, predicateFactory)).addService("joinBuilder", ({ schema: schema2 }) => new JoinBuilder.JoinBuilder(schema2.model)).addService("conditionBuilder", () => new ConditionBuilder.ConditionBuilder()).addService("pathFactory", () => new Path.PathFactory()).addService("whereOptimized", ({ schema: schema2 }) => new WhereOptimizer.WhereOptimizer(schema2.model, new ConditionOptimizer.ConditionOptimizer(), this.whereOptimizerOptions)).addService("whereBuilder", ({ joinBuilder, conditionBuilder, pathFactory, whereOptimized, schema: schema2 }) => new WhereBuilder.WhereBuilder(
65
94
  schema2.model,
66
95
  joinBuilder,
67
96
  conditionBuilder,
@@ -159,8 +188,15 @@ class ExecutionContainerFactory {
159
188
  ).addService("validationResolver", ({ inputPreValidator, mapperFactory }) => new ValidationResolver.ValidationResolver(mapperFactory, inputPreValidator)).addService("refreshViewResolver", ({ schema: schema2, mapperFactory }) => new RefreshViewResolver.RefreshViewResolver(schema2, mapperFactory));
160
189
  }
161
190
  create(args) {
162
- return this.createBuilder(args).build().pick("validationResolver", "readResolver", "mutationResolver", "refreshViewResolver");
191
+ return this.createBuilder(args).build().pick(
192
+ "validationResolver",
193
+ "readResolver",
194
+ "mutationResolver",
195
+ "refreshViewResolver",
196
+ "triggeredActionsCollector"
197
+ );
163
198
  }
164
199
  }
165
200
  exports.ExecutionContainerFactory = ExecutionContainerFactory;
201
+ exports.InMemoryTriggeredActionsCollector = InMemoryTriggeredActionsCollector;
166
202
  //# sourceMappingURL=ExecutionContainer.cjs.map