@contember/engine-content-api 1.2.0-alpha.8 → 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/dist/src/acl/PermissionFactory.d.ts.map +1 -1
- package/dist/src/acl/PermissionFactory.js +15 -11
- package/dist/src/acl/PermissionFactory.js.map +1 -1
- package/dist/src/mapper/select/optimizer/helpers.d.ts.map +1 -1
- package/dist/src/mapper/select/optimizer/helpers.js +8 -1
- package/dist/src/mapper/select/optimizer/helpers.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/src/utils/object.d.ts.map +1 -1
- package/dist/src/utils/object.js +3 -4
- package/dist/src/utils/object.js.map +1 -1
- package/dist/tests/cases/integration/graphQlSchema/model.js.map +1 -1
- package/dist/tests/cases/unit/conditionOptimizer.test.js +5 -0
- package/dist/tests/cases/unit/conditionOptimizer.test.js.map +1 -1
- package/dist/tests/cases/unit/permissionMerger.test.js +2 -0
- package/dist/tests/cases/unit/permissionMerger.test.js.map +1 -1
- package/dist/tests/cases/unit/whereOptimizer.test.js +14 -0
- package/dist/tests/cases/unit/whereOptimizer.test.js.map +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/package.json +11 -11
- package/src/acl/PermissionFactory.ts +18 -13
- package/src/mapper/select/optimizer/helpers.ts +6 -2
- package/src/utils/object.ts +6 -6
- package/tests/cases/unit/conditionOptimizer.test.ts +6 -0
- package/tests/cases/unit/permissionMerger.test.ts +2 -0
- package/tests/cases/unit/whereOptimizer.test.ts +16 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@contember/engine-content-api",
|
|
3
|
-
"version": "
|
|
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": "^
|
|
14
|
-
"@contember/dic": "^
|
|
15
|
-
"@contember/engine-common": "^
|
|
16
|
-
"@contember/graphql-utils": "^
|
|
17
|
-
"@contember/schema": "^
|
|
18
|
-
"@contember/schema-utils": "^
|
|
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": "^
|
|
24
|
-
"@contember/engine-api-tester": "^
|
|
25
|
-
"@contember/schema-definition": "^
|
|
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": "^
|
|
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):
|
|
49
|
-
|
|
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
|
|
52
|
-
const
|
|
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
|
-
|
|
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
|
-
|
|
78
|
+
entityPredicates,
|
|
78
79
|
idPermissions,
|
|
79
|
-
|
|
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
|
-
|
|
87
|
+
entityPredicates[predicate] = predicateDefinition
|
|
87
88
|
}
|
|
88
89
|
fieldPermissions[entity.primary] = idPermissions
|
|
89
|
-
entityPredicates[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
|
|
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
|
}
|
package/src/utils/object.ts
CHANGED
|
@@ -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)
|
|
13
|
-
.filter(
|
|
14
|
-
|
|
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.
|
|
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
|
})
|