@contember/schema-definition 1.2.0-alpha.9 → 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.
Files changed (52) hide show
  1. package/dist/src/acl/builder/EntitySelector.d.ts +1 -1
  2. package/dist/src/acl/builder/EntitySelector.d.ts.map +1 -1
  3. package/dist/src/acl/builder/EntitySelector.js +2 -2
  4. package/dist/src/acl/builder/EntitySelector.js.map +1 -1
  5. package/dist/src/acl/definition/internal/AclFactory.d.ts.map +1 -1
  6. package/dist/src/acl/definition/internal/AclFactory.js +1 -0
  7. package/dist/src/acl/definition/internal/AclFactory.js.map +1 -1
  8. package/dist/src/acl/definition/internal/EntityPredicateResolver.d.ts.map +1 -1
  9. package/dist/src/acl/definition/internal/EntityPredicateResolver.js +15 -8
  10. package/dist/src/acl/definition/internal/EntityPredicateResolver.js.map +1 -1
  11. package/dist/src/acl/definition/roles.d.ts +4 -6
  12. package/dist/src/acl/definition/roles.d.ts.map +1 -1
  13. package/dist/src/acl/definition/variables.d.ts +4 -4
  14. package/dist/src/acl/definition/variables.d.ts.map +1 -1
  15. package/dist/src/acl/definition/variables.js +5 -5
  16. package/dist/src/acl/definition/variables.js.map +1 -1
  17. package/dist/src/createSchema.d.ts.map +1 -1
  18. package/dist/src/createSchema.js +2 -1
  19. package/dist/src/createSchema.js.map +1 -1
  20. package/dist/src/model/definition/ViewDefinition.js +2 -2
  21. package/dist/src/model/definition/ViewDefinition.js.map +1 -1
  22. package/dist/src/model/definition/extensions.d.ts +6 -1
  23. package/dist/src/model/definition/extensions.d.ts.map +1 -1
  24. package/dist/src/model/definition/extensions.js.map +1 -1
  25. package/dist/src/model/definition/fieldDefinitions/ColumnDefinition.d.ts +1 -1
  26. package/dist/src/model/definition/fieldDefinitions/ColumnDefinition.d.ts.map +1 -1
  27. package/dist/src/model/definition/fieldDefinitions/ColumnDefinition.js +1 -1
  28. package/dist/src/model/definition/fieldDefinitions/ColumnDefinition.js.map +1 -1
  29. package/dist/src/model/definition/internal/SchemaBuilder.d.ts.map +1 -1
  30. package/dist/src/model/definition/internal/SchemaBuilder.js +8 -1
  31. package/dist/src/model/definition/internal/SchemaBuilder.js.map +1 -1
  32. package/dist/src/tsconfig.tsbuildinfo +1 -1
  33. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  34. package/dist/tests/unit/extendEntity.test.d.ts +2 -0
  35. package/dist/tests/unit/extendEntity.test.d.ts.map +1 -0
  36. package/dist/tests/unit/extendEntity.test.js +42 -0
  37. package/dist/tests/unit/extendEntity.test.js.map +1 -0
  38. package/dist/tests/unit/readAclDefinitions.test.js +91 -0
  39. package/dist/tests/unit/readAclDefinitions.test.js.map +1 -1
  40. package/package.json +3 -3
  41. package/src/acl/builder/EntitySelector.ts +2 -2
  42. package/src/acl/definition/internal/AclFactory.ts +1 -0
  43. package/src/acl/definition/internal/EntityPredicateResolver.ts +13 -7
  44. package/src/acl/definition/roles.ts +6 -6
  45. package/src/acl/definition/variables.ts +6 -5
  46. package/src/createSchema.ts +2 -1
  47. package/src/model/definition/ViewDefinition.ts +2 -2
  48. package/src/model/definition/extensions.ts +7 -1
  49. package/src/model/definition/fieldDefinitions/ColumnDefinition.ts +2 -2
  50. package/src/model/definition/internal/SchemaBuilder.ts +8 -1
  51. package/tests/unit/extendEntity.test.ts +42 -0
  52. 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
  }
@@ -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, registry }) => {
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 => registry.getName(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', options ?? { precedence: 'BY DEFAULT' })
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, { entity, definition: definitionInstance, registry: this.entityRegistry })
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')