@contember/schema-definition 1.3.6 → 1.4.0-alpha.2

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 (72) hide show
  1. package/dist/src/createSchema.d.ts +4 -1
  2. package/dist/src/createSchema.d.ts.map +1 -1
  3. package/dist/src/createSchema.js +8 -2
  4. package/dist/src/createSchema.js.map +1 -1
  5. package/dist/src/model/definition/UniqueDefinition.d.ts +4 -2
  6. package/dist/src/model/definition/UniqueDefinition.d.ts.map +1 -1
  7. package/dist/src/model/definition/UniqueDefinition.js +4 -2
  8. package/dist/src/model/definition/UniqueDefinition.js.map +1 -1
  9. package/dist/src/model/definition/context.d.ts +10 -0
  10. package/dist/src/model/definition/context.d.ts.map +1 -0
  11. package/dist/src/model/definition/context.js +3 -0
  12. package/dist/src/model/definition/context.js.map +1 -0
  13. package/dist/src/model/definition/extensions.d.ts +4 -8
  14. package/dist/src/model/definition/extensions.d.ts.map +1 -1
  15. package/dist/src/model/definition/extensions.js.map +1 -1
  16. package/dist/src/model/definition/fieldDefinitions/ColumnDefinition.d.ts +6 -2
  17. package/dist/src/model/definition/fieldDefinitions/ColumnDefinition.d.ts.map +1 -1
  18. package/dist/src/model/definition/fieldDefinitions/ColumnDefinition.js +2 -2
  19. package/dist/src/model/definition/fieldDefinitions/ColumnDefinition.js.map +1 -1
  20. package/dist/src/model/definition/fieldDefinitions/FieldDefinition.d.ts +3 -7
  21. package/dist/src/model/definition/fieldDefinitions/FieldDefinition.d.ts.map +1 -1
  22. package/dist/src/model/definition/fieldDefinitions/FieldDefinition.js.map +1 -1
  23. package/dist/src/model/definition/fieldDefinitions/ManyHasManyDefinition.d.ts +1 -1
  24. package/dist/src/model/definition/fieldDefinitions/ManyHasManyDefinition.d.ts.map +1 -1
  25. package/dist/src/model/definition/fieldDefinitions/ManyHasManyDefinition.js +2 -1
  26. package/dist/src/model/definition/fieldDefinitions/ManyHasManyDefinition.js.map +1 -1
  27. package/dist/src/model/definition/fieldDefinitions/ManyHasOneDefinition.d.ts +3 -3
  28. package/dist/src/model/definition/fieldDefinitions/ManyHasOneDefinition.d.ts.map +1 -1
  29. package/dist/src/model/definition/fieldDefinitions/ManyHasOneDefinition.js +6 -1
  30. package/dist/src/model/definition/fieldDefinitions/ManyHasOneDefinition.js.map +1 -1
  31. package/dist/src/model/definition/fieldDefinitions/OneHasOneDefinition.d.ts +2 -1
  32. package/dist/src/model/definition/fieldDefinitions/OneHasOneDefinition.d.ts.map +1 -1
  33. package/dist/src/model/definition/fieldDefinitions/OneHasOneDefinition.js +6 -1
  34. package/dist/src/model/definition/fieldDefinitions/OneHasOneDefinition.js.map +1 -1
  35. package/dist/src/model/definition/index.d.ts +4 -1
  36. package/dist/src/model/definition/index.d.ts.map +1 -1
  37. package/dist/src/model/definition/index.js +2 -2
  38. package/dist/src/model/definition/index.js.map +1 -1
  39. package/dist/src/model/definition/internal/SchemaBuilder.d.ts +3 -1
  40. package/dist/src/model/definition/internal/SchemaBuilder.d.ts.map +1 -1
  41. package/dist/src/model/definition/internal/SchemaBuilder.js +6 -2
  42. package/dist/src/model/definition/internal/SchemaBuilder.js.map +1 -1
  43. package/dist/src/presets.d.ts +1 -0
  44. package/dist/src/presets.d.ts.map +1 -1
  45. package/dist/src/presets.js +10 -0
  46. package/dist/src/presets.js.map +1 -1
  47. package/dist/src/strict.d.ts +22 -0
  48. package/dist/src/strict.d.ts.map +1 -0
  49. package/dist/src/strict.js +28 -0
  50. package/dist/src/strict.js.map +1 -0
  51. package/dist/src/tsconfig.tsbuildinfo +1 -1
  52. package/dist/tests/cases/unit/createSchema.test.js +25 -0
  53. package/dist/tests/cases/unit/createSchema.test.js.map +1 -1
  54. package/dist/tests/cases/unit/extendEntity.test.js +2 -4
  55. package/dist/tests/cases/unit/extendEntity.test.js.map +1 -1
  56. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  57. package/package.json +3 -3
  58. package/src/createSchema.ts +13 -2
  59. package/src/model/definition/UniqueDefinition.ts +11 -5
  60. package/src/model/definition/context.ts +10 -0
  61. package/src/model/definition/extensions.ts +10 -12
  62. package/src/model/definition/fieldDefinitions/ColumnDefinition.ts +3 -3
  63. package/src/model/definition/fieldDefinitions/FieldDefinition.ts +8 -9
  64. package/src/model/definition/fieldDefinitions/ManyHasManyDefinition.ts +3 -1
  65. package/src/model/definition/fieldDefinitions/ManyHasOneDefinition.ts +9 -3
  66. package/src/model/definition/fieldDefinitions/OneHasOneDefinition.ts +8 -1
  67. package/src/model/definition/index.ts +8 -2
  68. package/src/model/definition/internal/SchemaBuilder.ts +8 -2
  69. package/src/presets.ts +13 -0
  70. package/src/strict.ts +40 -0
  71. package/tests/cases/unit/createSchema.test.ts +23 -0
  72. package/tests/cases/unit/extendEntity.test.ts +2 -4
@@ -21,7 +21,7 @@ export class ManyHasManyDefinitionImpl extends FieldDefinition<ManyHasManyDefini
21
21
  return this.withOption('orderBy', [...(this.options.orderBy || []), { path, direction: direction as Model.OrderDirection }])
22
22
  }
23
23
 
24
- createField({ name, conventions, entityName, entityRegistry }: CreateFieldContext): Model.AnyField {
24
+ createField({ name, conventions, entityName, entityRegistry, strictDefinitionValidator }: CreateFieldContext): Model.AnyField {
25
25
  const options = this.options
26
26
  const columnNames = conventions.getJoiningTableColumnNames(
27
27
  entityName,
@@ -37,6 +37,8 @@ export class ManyHasManyDefinitionImpl extends FieldDefinition<ManyHasManyDefini
37
37
  ...options.joiningTable,
38
38
  }
39
39
 
40
+ strictDefinitionValidator.validateInverseSide(entityName, name, options)
41
+
40
42
  return {
41
43
  type: Model.RelationType.ManyHasMany,
42
44
  name,
@@ -1,7 +1,6 @@
1
- import { EntityConstructor, Interface } from '../types'
1
+ import { EntityConstructor, Interface, RelationTarget } from '../types'
2
2
  import { Model } from '@contember/schema'
3
3
  import { CreateFieldContext, FieldDefinition } from './FieldDefinition'
4
- import { RelationTarget } from '../types'
5
4
 
6
5
  export class ManyHasOneDefinitionImpl extends FieldDefinition<ManyHasOneDefinitionOptions> {
7
6
  type = 'ManyHasOneDefinition' as const
@@ -26,13 +25,20 @@ export class ManyHasOneDefinitionImpl extends FieldDefinition<ManyHasOneDefiniti
26
25
  return this.withOption('joiningColumn', { ...this.options.joiningColumn, onDelete: Model.OnDelete.setNull })
27
26
  }
28
27
 
28
+ restrictOnDelete(): Interface<ManyHasOneDefinition> {
29
+ return this.withOption('joiningColumn', { ...this.options.joiningColumn, onDelete: Model.OnDelete.restrict })
30
+ }
31
+
29
32
  notNull(): Interface<ManyHasOneDefinition> {
30
33
  return this.withOption('nullable', false)
31
34
  }
32
35
 
33
- createField({ name, conventions, entityName, entityRegistry }: CreateFieldContext): Model.AnyField {
36
+ createField({ name, conventions, entityName, entityRegistry, strictDefinitionValidator }: CreateFieldContext): Model.AnyField {
34
37
  const options = this.options
35
38
  const joiningColumn = options.joiningColumn || {}
39
+ strictDefinitionValidator.validateInverseSide(entityName, name, options)
40
+ strictDefinitionValidator.validateOnCascade(entityName, name, joiningColumn)
41
+
36
42
  return {
37
43
  name: name,
38
44
  ...(typeof options.inversedBy === 'undefined' ? {} : { inversedBy: options.inversedBy }),
@@ -25,6 +25,10 @@ export class OneHasOneDefinitionImpl extends FieldDefinition<OneHasOneDefinition
25
25
  return this.withOption('joiningColumn', { ...this.options.joiningColumn, onDelete: Model.OnDelete.setNull })
26
26
  }
27
27
 
28
+ restrictOnDelete(): Interface<OneHasOneDefinition> {
29
+ return this.withOption('joiningColumn', { ...this.options.joiningColumn, onDelete: Model.OnDelete.restrict })
30
+ }
31
+
28
32
  notNull(): Interface<OneHasOneDefinition> {
29
33
  return this.withOption('nullable', false)
30
34
  }
@@ -33,10 +37,13 @@ export class OneHasOneDefinitionImpl extends FieldDefinition<OneHasOneDefinition
33
37
  return this.withOption('orphanRemoval', true)
34
38
  }
35
39
 
36
- createField({ name, conventions, entityRegistry }: CreateFieldContext): Model.AnyField {
40
+ createField({ name, conventions, entityRegistry, strictDefinitionValidator, entityName }: CreateFieldContext): Model.AnyField {
37
41
  const options = this.options
38
42
  const joiningColumn: Partial<Model.JoiningColumn> = options.joiningColumn || {}
39
43
 
44
+ strictDefinitionValidator.validateInverseSide(entityName, name, options)
45
+ strictDefinitionValidator.validateOnCascade(entityName, name, joiningColumn)
46
+
40
47
  return {
41
48
  name: name,
42
49
  ...(typeof options.inversedBy === 'undefined' ? {} : { inversedBy: options.inversedBy }),
@@ -6,6 +6,7 @@ import 'reflect-metadata'
6
6
  import { FieldDefinition } from './fieldDefinitions'
7
7
  import { isEntityConstructor } from '../../utils'
8
8
  import { DefaultNamingConventions } from '@contember/schema-utils'
9
+ import { StrictOptions, StrictDefinitionValidator } from '../../strict'
9
10
 
10
11
  export * from './fieldDefinitions'
11
12
  export * from './EventLogDefinition'
@@ -24,8 +25,13 @@ export type ModelDefinition<M> = {
24
25
  [K in keyof M]: unknown
25
26
  }
26
27
 
27
- export function createModel<M extends ModelDefinition<M>>(definitions: M): Model.Schema {
28
- const schemaBuilder = new SchemaBuilder(new DefaultNamingConventions())
28
+ export function createModel<M extends ModelDefinition<M>>(definitions: M, options: {
29
+ strictDefinitionValidator?: StrictDefinitionValidator
30
+ } = {}): Model.Schema {
31
+ const schemaBuilder = new SchemaBuilder(
32
+ new DefaultNamingConventions(),
33
+ options.strictDefinitionValidator,
34
+ )
29
35
  for (const [name, definition] of Object.entries(definitions)) {
30
36
  if (definition instanceof EnumDefinition) {
31
37
  schemaBuilder.addEnum(name, definition)
@@ -8,13 +8,17 @@ import { EntityRegistry } from './EntityRegistry'
8
8
  import { EnumRegistry } from './EnumRegistry'
9
9
  import { ColumnDefinition } from '../fieldDefinitions'
10
10
  import { applyEntityExtensions } from '../extensions'
11
+ import { StrictOptions, StrictDefinitionValidator } from '../../../strict'
11
12
 
12
13
  export class SchemaBuilder {
13
14
  private entityRegistry = new EntityRegistry()
14
15
 
15
16
  private enumRegistry = new EnumRegistry()
16
17
 
17
- constructor(private readonly conventions: NamingConventions) {}
18
+ constructor(
19
+ private readonly conventions: NamingConventions,
20
+ private readonly strictDefinitionValidator: StrictDefinitionValidator = new StrictDefinitionValidator({}),
21
+ ) {}
18
22
 
19
23
  public addEntity(name: string, entity: EntityConstructor): void {
20
24
  this.entityRegistry.register(name, entity)
@@ -47,6 +51,7 @@ export class SchemaBuilder {
47
51
  conventions: this.conventions,
48
52
  enumRegistry: this.enumRegistry,
49
53
  entityRegistry: this.entityRegistry,
54
+ strictDefinitionValidator: this.strictDefinitionValidator,
50
55
  })
51
56
  })
52
57
  .reduce<Model.Entity['fields']>((acc, field) => {
@@ -67,6 +72,7 @@ export class SchemaBuilder {
67
72
  entityRegistry: this.entityRegistry,
68
73
  conventions: this.conventions,
69
74
  enumRegistry: this.enumRegistry,
75
+ strictDefinitionValidator: this.strictDefinitionValidator,
70
76
  })
71
77
  })
72
78
 
@@ -87,7 +93,7 @@ export class SchemaBuilder {
87
93
  const unique: Model.UniqueConstraint[] = []
88
94
  for (const [fieldName, definition] of Object.entries(fieldDefinitions)) {
89
95
  if (definition.options.unique) {
90
- unique.push({ fields: [fieldName] })
96
+ unique.push({ fields: [fieldName], ...definition.options.unique })
91
97
  }
92
98
  }
93
99
  return unique
package/src/presets.ts CHANGED
@@ -6,6 +6,19 @@ const v1_3preset: Settings.Schema = {
6
6
  inviteExpirationMinutes: 60 * 24 * 7, // 7 days
7
7
  },
8
8
  }
9
+
10
+
11
+ const v1_4preset: Settings.Schema = {
12
+ tenant: {
13
+ inviteExpirationMinutes: 60 * 24 * 7, // 7 days
14
+ },
15
+ content: {
16
+ shortDateResponse: true,
17
+ useExistsInHasManyFilter: true,
18
+ },
19
+ }
20
+
9
21
  export const settingsPresets = {
10
22
  'v1.3': v1_3preset,
23
+ 'v1.4': v1_4preset,
11
24
  }
package/src/strict.ts ADDED
@@ -0,0 +1,40 @@
1
+ import { Model } from '@contember/schema'
2
+
3
+ export type StrictOptions = {
4
+ requireOnDelete?: boolean
5
+ requireInverseSide?: boolean
6
+ }
7
+
8
+ export const allStrict: StrictOptions = {
9
+ requireOnDelete: true,
10
+ requireInverseSide: true,
11
+ }
12
+
13
+
14
+ export type Warning = { message: string }
15
+
16
+ export class StrictDefinitionValidator {
17
+ public readonly warnings: Warning[] = []
18
+
19
+ constructor(
20
+ private readonly options: StrictOptions,
21
+ ) {
22
+ }
23
+
24
+ public validateInverseSide(entityName: string, field: string, definition: { inversedBy?: string }): void {
25
+ if (!definition.inversedBy && this.options.requireInverseSide) {
26
+ this.registerWarning(`${entityName}.${field}: inverse side of the relation is not defined.`)
27
+ }
28
+ }
29
+
30
+
31
+ public validateOnCascade(entityName: string, field: string, definition: { onDelete?: Model.OnDelete}): void {
32
+ if (!definition.onDelete && this.options.requireOnDelete) {
33
+ this.registerWarning(`${entityName}.${field}: onDelete behaviour is not set. Use one of cascadeOnDelete(), setNullOnDelete() or restrictOnDelete().`)
34
+ }
35
+ }
36
+
37
+ public registerWarning(message: string): void {
38
+ this.warnings.push({ message })
39
+ }
40
+ }
@@ -97,3 +97,26 @@ test('basic createSchema test', () => {
97
97
  }
98
98
  `)
99
99
  })
100
+
101
+
102
+ namespace StrictModel {
103
+ export class Genre {
104
+ name = c.stringColumn()
105
+
106
+ }
107
+ export class Book {
108
+ title = c.stringColumn()
109
+ genre = c.manyHasOne(Genre)
110
+ }
111
+ }
112
+
113
+ test('strict test', () => {
114
+ const cb = () => createSchema(StrictModel, schema => ({
115
+ ...schema,
116
+ settings: settingsPresets['v1.3'],
117
+ }), { strict: true })
118
+
119
+ expect(cb).toThrow(`Strict schema validation failed:
120
+ - Book.genre: inverse side of the relation is not defined.
121
+ - Book.genre: onDelete behaviour is not set. Use one of cascadeOnDelete(), setNullOnDelete() or restrictOnDelete().`)
122
+ })
@@ -10,16 +10,14 @@ namespace ExtendedModel {
10
10
  }
11
11
 
12
12
  const addField = (name: string, field: FieldDefinition<any>): DecoratorFunction<any> => {
13
- return extendEntity(({ entity, conventions, entityRegistry, enumRegistry }) => ({
13
+ return extendEntity(({ entity, ...context }) => ({
14
14
  ...entity,
15
15
  fields: {
16
16
  ...entity.fields,
17
17
  [name]: field.createField({
18
18
  name,
19
- enumRegistry,
20
- entityRegistry,
21
- conventions,
22
19
  entityName: entity.name,
20
+ ...context,
23
21
  }),
24
22
  },
25
23
  }))