@contember/engine-content-api 1.2.0-alpha.6 → 1.2.0-alpha.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@contember/engine-content-api",
3
- "version": "1.2.0-alpha.6",
3
+ "version": "1.2.0-alpha.9",
4
4
  "license": "Apache-2.0",
5
5
  "main": "dist/src/index.js",
6
6
  "typings": "dist/src/index.d.ts",
@@ -10,24 +10,24 @@
10
10
  "test": "vitest --no-threads"
11
11
  },
12
12
  "dependencies": {
13
- "@contember/database": "^1.2.0-alpha.6",
14
- "@contember/dic": "^1.2.0-alpha.6",
15
- "@contember/engine-common": "^1.2.0-alpha.6",
16
- "@contember/graphql-utils": "^1.2.0-alpha.6",
17
- "@contember/schema": "^1.2.0-alpha.6",
18
- "@contember/schema-utils": "^1.2.0-alpha.6",
13
+ "@contember/database": "^1.2.0-alpha.9",
14
+ "@contember/dic": "^1.2.0-alpha.9",
15
+ "@contember/engine-common": "^1.2.0-alpha.9",
16
+ "@contember/graphql-utils": "^1.2.0-alpha.9",
17
+ "@contember/schema": "^1.2.0-alpha.9",
18
+ "@contember/schema-utils": "^1.2.0-alpha.9",
19
19
  "@graphql-tools/schema": "^8.3.5",
20
20
  "graphql-tag": "^2.12.5"
21
21
  },
22
22
  "devDependencies": {
23
- "@contember/database-tester": "^1.2.0-alpha.6",
24
- "@contember/engine-api-tester": "^1.2.0-alpha.6",
25
- "@contember/schema-definition": "^1.2.0-alpha.6",
23
+ "@contember/database-tester": "^1.2.0-alpha.9",
24
+ "@contember/engine-api-tester": "^1.2.0-alpha.9",
25
+ "@contember/schema-definition": "^1.2.0-alpha.9",
26
26
  "@graphql-codegen/cli": "^2.6.2",
27
27
  "@graphql-codegen/typescript": "^2.5.1",
28
28
  "@graphql-codegen/typescript-operations": "^2.4.2",
29
29
  "@graphql-codegen/typescript-resolvers": "^2.6.6",
30
- "@types/node": "^16",
30
+ "@types/node": "^18",
31
31
  "graphql": "^16.5.0",
32
32
  "pg": "^8.5.0"
33
33
  },
@@ -17,7 +17,7 @@ export class PermissionFactory {
17
17
  }
18
18
  result = this.mergePermissions(result, rolePermissions)
19
19
  }
20
- this.makePrimaryPredicatesUnionOfAllFields(result)
20
+ result = this.makePrimaryPredicatesUnionOfAllFields(result)
21
21
 
22
22
  return result
23
23
  }
@@ -45,18 +45,20 @@ export class PermissionFactory {
45
45
  }))
46
46
  }
47
47
 
48
- private makePrimaryPredicatesUnionOfAllFields(permissions: Acl.Permissions): void {
49
- for (let entityName in permissions) {
48
+ private makePrimaryPredicatesUnionOfAllFields(permissions: Acl.Permissions): Acl.Permissions {
49
+ return mapObject(permissions, (permission, entityName): Acl.EntityPermissions => {
50
50
  const entity = getEntity(this.schema, entityName)
51
- const entityPermissions: Acl.EntityPermissions = permissions[entityName]
52
- const entityPredicates: Writable<Acl.PredicateMap> = entityPermissions.predicates
51
+ const entityPredicates: Writable<Acl.PredicateMap> = { ...permission.predicates }
52
+ const entityOperations: Writable<Acl.EntityOperations> = { ...permission.operations }
53
53
 
54
54
  const operationNames = ['read', 'create', 'update'] as const
55
55
  for (let operation of operationNames) {
56
- const fieldPermissions: Writable<Acl.FieldPermissions> | undefined = entityPermissions.operations[operation]
57
- if (fieldPermissions === undefined) {
56
+ if (!entityOperations[operation]) {
58
57
  continue
59
58
  }
59
+ const fieldPermissions: Writable<Acl.FieldPermissions> = { ...entityOperations[operation] }
60
+ entityOperations[operation] = fieldPermissions
61
+
60
62
  if (Object.values(fieldPermissions).some(it => it === true)) {
61
63
  fieldPermissions[entity.primary] = true
62
64
  }
@@ -70,25 +72,28 @@ export class PermissionFactory {
70
72
  .filter((value, index, array): value is string => array.indexOf(value) === index)
71
73
 
72
74
  let idPermissions: Acl.Predicate = fieldPermissions[entity.primary] || false
73
- const predicates = { ...entityPermissions.predicates }
74
75
 
75
76
  for (let predicateReference of predicateReferences) {
76
77
  const [predicateDefinition, predicate] = this.mergePredicates(
77
- predicates,
78
+ entityPredicates,
78
79
  idPermissions,
79
- predicates,
80
+ entityPredicates,
80
81
  predicateReference,
81
82
  )
82
83
  if (typeof predicate !== 'string' || predicateDefinition === undefined) {
83
84
  throw new Error('should not happen')
84
85
  }
85
86
  idPermissions = predicate
86
- predicates[predicate] = predicateDefinition
87
+ entityPredicates[predicate] = predicateDefinition
87
88
  }
88
89
  fieldPermissions[entity.primary] = idPermissions
89
- entityPredicates[idPermissions as Acl.PredicateReference] = predicates[idPermissions as Acl.PredicateReference]
90
+ entityPredicates[idPermissions as Acl.PredicateReference] = entityPredicates[idPermissions as Acl.PredicateReference]
90
91
  }
91
- }
92
+ return {
93
+ operations: entityOperations,
94
+ predicates: entityPredicates,
95
+ }
96
+ })
92
97
  }
93
98
 
94
99
  private mergePermissions(left: Acl.Permissions, right: Acl.Permissions): Acl.Permissions {
@@ -1,10 +1,12 @@
1
1
  export const optimizeOr = <P extends Record<string, unknown>>(operands: readonly (P | boolean)[]): P | { or?: P[] } | boolean => {
2
2
  const normalized: P[] = []
3
-
3
+ let hasNever = false
4
4
  for (const operand of operands) {
5
5
  if (operand === true) {
6
6
  return true
7
- } else if (operand !== false) {
7
+ } else if (operand === false) {
8
+ hasNever = true
9
+ } else {
8
10
  normalized.push(...Array.isArray(operand.or) ? operand.or : [operand])
9
11
  }
10
12
  }
@@ -13,6 +15,8 @@ export const optimizeOr = <P extends Record<string, unknown>>(operands: readonly
13
15
  return { or: normalized }
14
16
  } else if (normalized.length === 1) {
15
17
  return normalized[0]
18
+ } else if (hasNever) {
19
+ return false
16
20
  } else {
17
21
  return {}
18
22
  }
@@ -9,18 +9,18 @@ function filterObject<Input extends {}, Result extends { [Key in keyof Input]: I
9
9
  object: Input,
10
10
  callback: TypeGuard<Input, Result> | Filter<Input>,
11
11
  ): Result {
12
- return (Object.entries(object) as any)
13
- .filter(<K extends keyof Input>(it: [K, Input[K]]): it is [K, Result[K]] =>
14
- (callback as any)(it[0] as K, it[1] as Input[K], object),
15
- )
16
- .reduce((result: Result, [key, value]: [string, any]) => ({ ...(result as any), [key]: value }), {} as Result)
12
+ return Object.fromEntries(Object.entries(object)
13
+ .filter(([key, value]) => (callback as any)(key, value, object)),
14
+ ) as Result
17
15
  }
18
16
 
19
17
  function mapObject<Input, Result>(
20
18
  input: { [key: string]: Input },
21
19
  callback: (value: Input, key: string) => Result,
22
20
  ): { [key: string]: Result } {
23
- return Object.keys(input).reduce((acc, key) => ({ ...acc, [key]: callback(input[key], key) }), {})
21
+ return Object.fromEntries(
22
+ Object.entries(input).map(([key, value]) => [key, callback(value, key)]),
23
+ )
24
24
  }
25
25
 
26
26
  export { filterObject, mapObject }
@@ -18,6 +18,12 @@ describe('condition optimizer', () => {
18
18
  })
19
19
  })
20
20
 
21
+ it('keep never in OR', () => {
22
+ assert.deepStrictEqual(optimizer.optimize({
23
+ or: [{ never: true }],
24
+ }), false)
25
+ })
26
+
21
27
  it('optimizes OR with never', () => {
22
28
  assert.deepStrictEqual(optimizer.optimize({
23
29
  or: [{ eq: 1 }, { never: true }],
@@ -15,8 +15,10 @@ const execute = (test: Test) => {
15
15
  .entity('Entity2', e => e.oneHasOne('xyz', r => r.target('Entity1')))
16
16
  .buildSchema()
17
17
  const merger = new PermissionFactory(schema)
18
+ const initialAcl = JSON.parse(JSON.stringify(test.acl))
18
19
  const result = merger.create(test.acl, test.roles)
19
20
  assert.deepStrictEqual(result, test.result)
21
+ assert.deepStrictEqual(test.acl, initialAcl)
20
22
  }
21
23
 
22
24
  describe('Permission merger', () => {
@@ -74,4 +74,20 @@ describe('where optimized', () => {
74
74
  },
75
75
  })
76
76
  })
77
+
78
+ it('keep never', () => {
79
+ assert.deepStrictEqual(whereOptimizer.optimize({
80
+ and: [
81
+ {
82
+ or: [
83
+ { url: { never: true } },
84
+ { url: { never: true } },
85
+ ],
86
+ },
87
+ ],
88
+ }, model.entities.Image), {
89
+ id: { never: true },
90
+ },
91
+ )
92
+ })
77
93
  })