@contember/schema-definition 1.2.0-alpha.8 → 1.2.0-beta.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.
- package/dist/src/acl/builder/EntitySelector.d.ts +1 -1
- package/dist/src/acl/builder/EntitySelector.d.ts.map +1 -1
- package/dist/src/acl/builder/EntitySelector.js +2 -2
- package/dist/src/acl/builder/EntitySelector.js.map +1 -1
- package/dist/src/acl/builder/PredicateReference.d.ts.map +1 -1
- package/dist/src/acl/definition/internal/AclFactory.d.ts.map +1 -1
- package/dist/src/acl/definition/internal/AclFactory.js +1 -0
- package/dist/src/acl/definition/internal/AclFactory.js.map +1 -1
- package/dist/src/acl/definition/internal/EntityPredicateResolver.d.ts.map +1 -1
- package/dist/src/acl/definition/internal/EntityPredicateResolver.js +15 -8
- package/dist/src/acl/definition/internal/EntityPredicateResolver.js.map +1 -1
- package/dist/src/acl/definition/roles.d.ts +4 -6
- package/dist/src/acl/definition/roles.d.ts.map +1 -1
- package/dist/src/acl/definition/variables.d.ts +4 -4
- package/dist/src/acl/definition/variables.d.ts.map +1 -1
- package/dist/src/acl/definition/variables.js +5 -5
- package/dist/src/acl/definition/variables.js.map +1 -1
- package/dist/src/createSchema.d.ts.map +1 -1
- package/dist/src/createSchema.js +2 -1
- package/dist/src/createSchema.js.map +1 -1
- package/dist/src/model/definition/ViewDefinition.js +2 -2
- package/dist/src/model/definition/ViewDefinition.js.map +1 -1
- package/dist/src/model/definition/extensions.d.ts +6 -1
- package/dist/src/model/definition/extensions.d.ts.map +1 -1
- package/dist/src/model/definition/extensions.js.map +1 -1
- package/dist/src/model/definition/fieldDefinitions/ColumnDefinition.d.ts +1 -1
- package/dist/src/model/definition/fieldDefinitions/ColumnDefinition.d.ts.map +1 -1
- package/dist/src/model/definition/fieldDefinitions/ColumnDefinition.js +1 -1
- package/dist/src/model/definition/fieldDefinitions/ColumnDefinition.js.map +1 -1
- package/dist/src/model/definition/internal/SchemaBuilder.d.ts.map +1 -1
- package/dist/src/model/definition/internal/SchemaBuilder.js +8 -1
- package/dist/src/model/definition/internal/SchemaBuilder.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/dist/tests/unit/extendEntity.test.d.ts +2 -0
- package/dist/tests/unit/extendEntity.test.d.ts.map +1 -0
- package/dist/tests/unit/extendEntity.test.js +42 -0
- package/dist/tests/unit/extendEntity.test.js.map +1 -0
- package/dist/tests/unit/readAclDefinitions.test.js +91 -0
- package/dist/tests/unit/readAclDefinitions.test.js.map +1 -1
- package/package.json +3 -3
- package/src/acl/builder/EntitySelector.ts +2 -2
- package/src/acl/definition/internal/AclFactory.ts +1 -0
- package/src/acl/definition/internal/EntityPredicateResolver.ts +13 -7
- package/src/acl/definition/roles.ts +6 -6
- package/src/acl/definition/variables.ts +6 -5
- package/src/createSchema.ts +2 -1
- package/src/model/definition/ViewDefinition.ts +2 -2
- package/src/model/definition/extensions.ts +7 -1
- package/src/model/definition/fieldDefinitions/ColumnDefinition.ts +2 -2
- package/src/model/definition/internal/SchemaBuilder.ts +8 -1
- package/tests/unit/extendEntity.test.ts +42 -0
- package/tests/unit/readAclDefinitions.test.ts +92 -0
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Role } from './roles'
|
|
2
|
-
import { Acl } from '@contember/schema'
|
|
2
|
+
import { Acl, Input } from '@contember/schema'
|
|
3
3
|
|
|
4
4
|
export class VariableDefinition<Name extends string = string, Roles extends Role<string> = Role<string>, Variable extends Acl.Variable = Acl.Variable> {
|
|
5
5
|
constructor(
|
|
@@ -10,24 +10,24 @@ export class VariableDefinition<Name extends string = string, Roles extends Role
|
|
|
10
10
|
}
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
|
|
14
13
|
export const createEntityVariable = <R extends Role<string>, Name extends string>(
|
|
15
14
|
name: Name,
|
|
16
15
|
entityName: string,
|
|
17
16
|
roles: R | R[],
|
|
17
|
+
fallback?: Input.Condition,
|
|
18
18
|
): VariableDefinition<Name, R, Acl.EntityVariable> => {
|
|
19
19
|
return new VariableDefinition(
|
|
20
20
|
name,
|
|
21
21
|
Array.isArray(roles) ? roles : [roles],
|
|
22
|
-
{ type: Acl.VariableType.entity, entityName },
|
|
22
|
+
{ type: Acl.VariableType.entity, entityName, ...(fallback ? { fallback } : {}) },
|
|
23
23
|
)
|
|
24
24
|
}
|
|
25
25
|
|
|
26
|
-
|
|
27
26
|
export const createPredefinedVariable = <R extends Role<string>, Name extends string>(
|
|
28
27
|
name: Name,
|
|
29
28
|
value: Acl.PredefinedVariableValue,
|
|
30
29
|
roles: R | R[],
|
|
30
|
+
fallback?: Input.Condition,
|
|
31
31
|
): VariableDefinition<Name, R, Acl.EntityVariable> => {
|
|
32
32
|
return new VariableDefinition(
|
|
33
33
|
name,
|
|
@@ -39,10 +39,11 @@ export const createPredefinedVariable = <R extends Role<string>, Name extends st
|
|
|
39
39
|
export const createConditionVariable = <R extends Role<string>, Name extends string>(
|
|
40
40
|
name: Name,
|
|
41
41
|
roles: R | R[],
|
|
42
|
+
fallback?: Input.Condition,
|
|
42
43
|
): VariableDefinition<Name, R, Acl.ConditionVariable> => {
|
|
43
44
|
return new VariableDefinition(
|
|
44
45
|
name,
|
|
45
46
|
Array.isArray(roles) ? roles : [roles],
|
|
46
|
-
{ type: Acl.VariableType.condition
|
|
47
|
+
{ type: Acl.VariableType.condition, ...(fallback ? { fallback } : {}) },
|
|
47
48
|
)
|
|
48
49
|
}
|
package/src/createSchema.ts
CHANGED
|
@@ -2,11 +2,12 @@ import { SchemaDefinition } from './model'
|
|
|
2
2
|
import * as InputValidation from './validation'
|
|
3
3
|
import * as AclDefinition from './acl/definition'
|
|
4
4
|
import { Schema } from '@contember/schema'
|
|
5
|
+
import { emptySchema } from '@contember/schema-utils'
|
|
5
6
|
|
|
6
7
|
export const createSchema = (definitions: Record<string, any>, modifyCallback?: (schema: Schema) => Schema): Schema => {
|
|
7
8
|
const model = SchemaDefinition.createModel(definitions)
|
|
8
9
|
const validation = InputValidation.parseDefinition(definitions)
|
|
9
10
|
const acl = AclDefinition.createAcl(definitions, model)
|
|
10
|
-
const schema = { model, validation, acl }
|
|
11
|
+
const schema = { ...emptySchema, model, validation, acl }
|
|
11
12
|
return modifyCallback ? modifyCallback(schema) : schema
|
|
12
13
|
}
|
|
@@ -2,7 +2,7 @@ import { extendEntity } from './extensions'
|
|
|
2
2
|
import { EntityConstructor } from './types'
|
|
3
3
|
|
|
4
4
|
export const View = (sql: string, { dependencies }: { dependencies?: (() => EntityConstructor[]) | EntityConstructor[] } = {}) =>
|
|
5
|
-
extendEntity(({ entity,
|
|
5
|
+
extendEntity(({ entity, entityRegistry }) => {
|
|
6
6
|
const dependenciesResolved = typeof dependencies === 'function' ? dependencies() : dependencies
|
|
7
7
|
if (dependenciesResolved?.some(it => it === undefined)) {
|
|
8
8
|
throw `"undefined" value detected in dependencies of view entity ${entity.name}. This is possibly caused by circular imports.
|
|
@@ -18,7 +18,7 @@ dependencies: () => [MyEntity]
|
|
|
18
18
|
...entity,
|
|
19
19
|
view: {
|
|
20
20
|
sql,
|
|
21
|
-
...(dependenciesResolved ? { dependencies: dependenciesResolved.map(it =>
|
|
21
|
+
...(dependenciesResolved ? { dependencies: dependenciesResolved.map(it => entityRegistry.getName(it)) } : {}),
|
|
22
22
|
},
|
|
23
23
|
})
|
|
24
24
|
})
|
|
@@ -1,10 +1,16 @@
|
|
|
1
1
|
import { Model } from '@contember/schema'
|
|
2
2
|
import { DecoratorFunction, EntityConstructor, FieldsDefinition } from './types'
|
|
3
|
-
import { EntityRegistry } from './internal'
|
|
3
|
+
import { EntityRegistry, EnumRegistry } from './internal'
|
|
4
|
+
import { NamingConventions } from './NamingConventions'
|
|
4
5
|
|
|
5
6
|
interface EntityExtensionArgs {
|
|
6
7
|
entity: Model.Entity
|
|
7
8
|
definition: FieldsDefinition
|
|
9
|
+
conventions: NamingConventions
|
|
10
|
+
enumRegistry: EnumRegistry
|
|
11
|
+
entityRegistry: EntityRegistry
|
|
12
|
+
|
|
13
|
+
/** @deprecated use entityRegistry */
|
|
8
14
|
registry: EntityRegistry
|
|
9
15
|
}
|
|
10
16
|
|
|
@@ -34,8 +34,8 @@ export class ColumnDefinition extends FieldDefinition<ColumnDefinitionOptions> {
|
|
|
34
34
|
return this.withOption('nullable', false)
|
|
35
35
|
}
|
|
36
36
|
|
|
37
|
-
public sequence(options?: Model.ColumnTypeDefinition['sequence']): Interface<ColumnDefinition> {
|
|
38
|
-
return this.withOption('sequence',
|
|
37
|
+
public sequence(options?: Partial<Model.ColumnTypeDefinition['sequence']>): Interface<ColumnDefinition> {
|
|
38
|
+
return this.withOption('sequence', { precedence: 'BY DEFAULT', ...options })
|
|
39
39
|
}
|
|
40
40
|
|
|
41
41
|
public unique(): Interface<ColumnDefinition> {
|
|
@@ -61,7 +61,14 @@ export class SchemaBuilder {
|
|
|
61
61
|
enabled: true,
|
|
62
62
|
},
|
|
63
63
|
}
|
|
64
|
-
return applyEntityExtensions(definition, {
|
|
64
|
+
return applyEntityExtensions(definition, {
|
|
65
|
+
entity,
|
|
66
|
+
definition: definitionInstance,
|
|
67
|
+
registry: this.entityRegistry,
|
|
68
|
+
entityRegistry: this.entityRegistry,
|
|
69
|
+
conventions: this.conventions,
|
|
70
|
+
enumRegistry: this.enumRegistry,
|
|
71
|
+
})
|
|
65
72
|
})
|
|
66
73
|
|
|
67
74
|
return {
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { Model } from '@contember/schema'
|
|
2
|
+
import { assert, test } from 'vitest'
|
|
3
|
+
import { createSchema, SchemaDefinition as def } from '../../src'
|
|
4
|
+
import { extendEntity, FieldDefinition } from '../../src/model/definition'
|
|
5
|
+
import { DecoratorFunction } from '../../src/model/definition/types'
|
|
6
|
+
|
|
7
|
+
namespace ExtendedModel {
|
|
8
|
+
export class Article {
|
|
9
|
+
title = def.stringColumn()
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const addField = (name: string, field: FieldDefinition<any>): DecoratorFunction<any> => {
|
|
13
|
+
return extendEntity(({ entity, conventions, entityRegistry, enumRegistry }) => ({
|
|
14
|
+
...entity,
|
|
15
|
+
fields: {
|
|
16
|
+
...entity.fields,
|
|
17
|
+
[name]: field.createField({
|
|
18
|
+
name,
|
|
19
|
+
enumRegistry,
|
|
20
|
+
entityRegistry,
|
|
21
|
+
conventions,
|
|
22
|
+
entityName: entity.name,
|
|
23
|
+
}),
|
|
24
|
+
},
|
|
25
|
+
}))
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
addField('lead', def.stringColumn())(Article)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
test('add a field to entity using an extension', () => {
|
|
33
|
+
const schema = createSchema(ExtendedModel)
|
|
34
|
+
|
|
35
|
+
assert.deepEqual(schema.model.entities.Article.fields.lead, {
|
|
36
|
+
columnName: 'lead',
|
|
37
|
+
name: 'lead',
|
|
38
|
+
columnType: 'text',
|
|
39
|
+
type: Model.ColumnType.String,
|
|
40
|
+
nullable: true,
|
|
41
|
+
})
|
|
42
|
+
})
|
|
@@ -24,6 +24,32 @@ test('simple definitions', () => {
|
|
|
24
24
|
`)
|
|
25
25
|
})
|
|
26
26
|
|
|
27
|
+
|
|
28
|
+
namespace RoleOptions {
|
|
29
|
+
export const publicRole = acl.createRole('public', {
|
|
30
|
+
debug: true,
|
|
31
|
+
s3: {
|
|
32
|
+
foo: 'bar',
|
|
33
|
+
},
|
|
34
|
+
})
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
test('role options', () => {
|
|
38
|
+
const schema = createSchema(RoleOptions)
|
|
39
|
+
expect(schema.acl.roles.public).toMatchInlineSnapshot(`
|
|
40
|
+
{
|
|
41
|
+
"debug": true,
|
|
42
|
+
"entities": {},
|
|
43
|
+
"s3": {
|
|
44
|
+
"foo": "bar",
|
|
45
|
+
},
|
|
46
|
+
"stages": "*",
|
|
47
|
+
"variables": {},
|
|
48
|
+
}
|
|
49
|
+
`)
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
|
|
27
53
|
namespace ModelWithPredicate {
|
|
28
54
|
export const publicRole = acl.createRole('public')
|
|
29
55
|
|
|
@@ -181,6 +207,72 @@ test('definition with multiple predicates on a single field', () => {
|
|
|
181
207
|
})
|
|
182
208
|
|
|
183
209
|
|
|
210
|
+
namespace ModelWithJoinedPredicateCollision {
|
|
211
|
+
export const publicRole = acl.createRole('public')
|
|
212
|
+
|
|
213
|
+
@acl.allow(publicRole, {
|
|
214
|
+
when: { isPublishedLoremIpsumDolorSitAmet: { eq: true } },
|
|
215
|
+
read: ['title'],
|
|
216
|
+
})
|
|
217
|
+
@acl.allow(publicRole, {
|
|
218
|
+
when: { isPublishedLoremIpsumDolorSitAmet: { eq: false } },
|
|
219
|
+
read: ['title', 'isPublishedLoremIpsumDolorSitAmet'],
|
|
220
|
+
})
|
|
221
|
+
@acl.allow(publicRole, {
|
|
222
|
+
when: { isPublishedLoremIpsumDolorSitAmet: { eq: false } },
|
|
223
|
+
read: ['isPublishedLoremIpsumDolorSitAmet'],
|
|
224
|
+
})
|
|
225
|
+
export class Book {
|
|
226
|
+
title = def.stringColumn()
|
|
227
|
+
isPublishedLoremIpsumDolorSitAmet = def.boolColumn()
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
test('definition with collision', () => {
|
|
232
|
+
const schema = createSchema(ModelWithJoinedPredicateCollision)
|
|
233
|
+
expect(schema.acl.roles.public.entities.Book).toMatchInlineSnapshot(`
|
|
234
|
+
{
|
|
235
|
+
"operations": {
|
|
236
|
+
"read": {
|
|
237
|
+
"isPublishedLoremIpsumDolorSitAmet": "or_isPublishedLoremIpsumDolor_1",
|
|
238
|
+
"title": "or_isPublishedLoremIpsumDolor",
|
|
239
|
+
},
|
|
240
|
+
},
|
|
241
|
+
"predicates": {
|
|
242
|
+
"or_isPublishedLoremIpsumDolor": {
|
|
243
|
+
"or": [
|
|
244
|
+
{
|
|
245
|
+
"isPublishedLoremIpsumDolorSitAmet": {
|
|
246
|
+
"eq": false,
|
|
247
|
+
},
|
|
248
|
+
},
|
|
249
|
+
{
|
|
250
|
+
"isPublishedLoremIpsumDolorSitAmet": {
|
|
251
|
+
"eq": true,
|
|
252
|
+
},
|
|
253
|
+
},
|
|
254
|
+
],
|
|
255
|
+
},
|
|
256
|
+
"or_isPublishedLoremIpsumDolor_1": {
|
|
257
|
+
"or": [
|
|
258
|
+
{
|
|
259
|
+
"isPublishedLoremIpsumDolorSitAmet": {
|
|
260
|
+
"eq": false,
|
|
261
|
+
},
|
|
262
|
+
},
|
|
263
|
+
{
|
|
264
|
+
"isPublishedLoremIpsumDolorSitAmet": {
|
|
265
|
+
"eq": false,
|
|
266
|
+
},
|
|
267
|
+
},
|
|
268
|
+
],
|
|
269
|
+
},
|
|
270
|
+
},
|
|
271
|
+
}
|
|
272
|
+
`)
|
|
273
|
+
})
|
|
274
|
+
|
|
275
|
+
|
|
184
276
|
namespace ModelWithMultipleRolesForSinglePredicate {
|
|
185
277
|
export const publicRole = acl.createRole('public')
|
|
186
278
|
export const adminRole = acl.createRole('admin')
|