@contember/schema-utils 2.0.1 → 2.1.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 (125) hide show
  1. package/dist/development/index.cjs +0 -1
  2. package/dist/development/index.cjs.map +1 -1
  3. package/dist/development/index.js +1 -2
  4. package/dist/development/src/dataUtils.cjs +9 -9
  5. package/dist/development/src/dataUtils.cjs.map +1 -1
  6. package/dist/development/src/dataUtils.js +10 -10
  7. package/dist/development/src/dataUtils.js.map +1 -1
  8. package/dist/development/src/definition-generator/DefinitionCodeGenerator.cjs +1 -0
  9. package/dist/development/src/definition-generator/DefinitionCodeGenerator.cjs.map +1 -1
  10. package/dist/development/src/definition-generator/DefinitionCodeGenerator.js +1 -0
  11. package/dist/development/src/definition-generator/DefinitionCodeGenerator.js.map +1 -1
  12. package/dist/development/src/model/modelUtils.cjs +1 -1
  13. package/dist/development/src/model/modelUtils.cjs.map +1 -1
  14. package/dist/development/src/model/modelUtils.js +1 -1
  15. package/dist/development/src/model/modelUtils.js.map +1 -1
  16. package/dist/development/src/model/resolveDefaultColumnType.cjs +2 -0
  17. package/dist/development/src/model/resolveDefaultColumnType.cjs.map +1 -1
  18. package/dist/development/src/model/resolveDefaultColumnType.js +2 -0
  19. package/dist/development/src/model/resolveDefaultColumnType.js.map +1 -1
  20. package/dist/development/src/schemaNormalizer.cjs +2 -0
  21. package/dist/development/src/schemaNormalizer.cjs.map +1 -1
  22. package/dist/development/src/schemaNormalizer.js +2 -0
  23. package/dist/development/src/schemaNormalizer.js.map +1 -1
  24. package/dist/development/src/type-schema/acl.cjs +3 -1
  25. package/dist/development/src/type-schema/acl.cjs.map +1 -1
  26. package/dist/development/src/type-schema/acl.js +3 -1
  27. package/dist/development/src/type-schema/acl.js.map +1 -1
  28. package/dist/development/src/type-schema/condition.cjs +2 -0
  29. package/dist/development/src/type-schema/condition.cjs.map +1 -1
  30. package/dist/development/src/type-schema/condition.js +2 -0
  31. package/dist/development/src/type-schema/condition.js.map +1 -1
  32. package/dist/development/src/type-schema/model.cjs +25 -8
  33. package/dist/development/src/type-schema/model.cjs.map +1 -1
  34. package/dist/development/src/type-schema/model.js +25 -8
  35. package/dist/development/src/type-schema/model.js.map +1 -1
  36. package/dist/development/src/type-schema/settings.cjs +2 -1
  37. package/dist/development/src/type-schema/settings.cjs.map +1 -1
  38. package/dist/development/src/type-schema/settings.js +2 -1
  39. package/dist/development/src/type-schema/settings.js.map +1 -1
  40. package/dist/development/src/validation/ModelValidator.cjs +10 -5
  41. package/dist/development/src/validation/ModelValidator.cjs.map +1 -1
  42. package/dist/development/src/validation/ModelValidator.js +11 -6
  43. package/dist/development/src/validation/ModelValidator.js.map +1 -1
  44. package/dist/development/src/validation/errors.cjs.map +1 -1
  45. package/dist/development/src/validation/errors.js.map +1 -1
  46. package/dist/production/index.cjs +0 -1
  47. package/dist/production/index.cjs.map +1 -1
  48. package/dist/production/index.js +1 -2
  49. package/dist/production/src/dataUtils.cjs +9 -9
  50. package/dist/production/src/dataUtils.cjs.map +1 -1
  51. package/dist/production/src/dataUtils.js +10 -10
  52. package/dist/production/src/dataUtils.js.map +1 -1
  53. package/dist/production/src/definition-generator/DefinitionCodeGenerator.cjs +1 -0
  54. package/dist/production/src/definition-generator/DefinitionCodeGenerator.cjs.map +1 -1
  55. package/dist/production/src/definition-generator/DefinitionCodeGenerator.js +1 -0
  56. package/dist/production/src/definition-generator/DefinitionCodeGenerator.js.map +1 -1
  57. package/dist/production/src/model/modelUtils.cjs +1 -1
  58. package/dist/production/src/model/modelUtils.cjs.map +1 -1
  59. package/dist/production/src/model/modelUtils.js +1 -1
  60. package/dist/production/src/model/modelUtils.js.map +1 -1
  61. package/dist/production/src/model/resolveDefaultColumnType.cjs +2 -0
  62. package/dist/production/src/model/resolveDefaultColumnType.cjs.map +1 -1
  63. package/dist/production/src/model/resolveDefaultColumnType.js +2 -0
  64. package/dist/production/src/model/resolveDefaultColumnType.js.map +1 -1
  65. package/dist/production/src/schemaNormalizer.cjs +2 -0
  66. package/dist/production/src/schemaNormalizer.cjs.map +1 -1
  67. package/dist/production/src/schemaNormalizer.js +2 -0
  68. package/dist/production/src/schemaNormalizer.js.map +1 -1
  69. package/dist/production/src/type-schema/acl.cjs +3 -1
  70. package/dist/production/src/type-schema/acl.cjs.map +1 -1
  71. package/dist/production/src/type-schema/acl.js +3 -1
  72. package/dist/production/src/type-schema/acl.js.map +1 -1
  73. package/dist/production/src/type-schema/condition.cjs +2 -0
  74. package/dist/production/src/type-schema/condition.cjs.map +1 -1
  75. package/dist/production/src/type-schema/condition.js +2 -0
  76. package/dist/production/src/type-schema/condition.js.map +1 -1
  77. package/dist/production/src/type-schema/model.cjs +25 -8
  78. package/dist/production/src/type-schema/model.cjs.map +1 -1
  79. package/dist/production/src/type-schema/model.js +25 -8
  80. package/dist/production/src/type-schema/model.js.map +1 -1
  81. package/dist/production/src/type-schema/settings.cjs +2 -1
  82. package/dist/production/src/type-schema/settings.cjs.map +1 -1
  83. package/dist/production/src/type-schema/settings.js +2 -1
  84. package/dist/production/src/type-schema/settings.js.map +1 -1
  85. package/dist/production/src/validation/ModelValidator.cjs +10 -5
  86. package/dist/production/src/validation/ModelValidator.cjs.map +1 -1
  87. package/dist/production/src/validation/ModelValidator.js +11 -6
  88. package/dist/production/src/validation/ModelValidator.js.map +1 -1
  89. package/dist/production/src/validation/errors.cjs.map +1 -1
  90. package/dist/production/src/validation/errors.js.map +1 -1
  91. package/dist/tests/tsconfig.tsbuildinfo +1 -1
  92. package/dist/types/acl/schemaUtils.d.ts.map +1 -1
  93. package/dist/types/dataUtils.d.ts +7 -4
  94. package/dist/types/dataUtils.d.ts.map +1 -1
  95. package/dist/types/model/modelUtils.d.ts.map +1 -1
  96. package/dist/types/model/resolveDefaultColumnType.d.ts.map +1 -1
  97. package/dist/types/schemaChecksum.d.ts.map +1 -1
  98. package/dist/types/schemaFilter.d.ts.map +1 -1
  99. package/dist/types/schemaNormalizer.d.ts.map +1 -1
  100. package/dist/types/tsconfig.tsbuildinfo +1 -1
  101. package/dist/types/type-schema/acl.d.ts.map +1 -1
  102. package/dist/types/type-schema/condition.d.ts.map +1 -1
  103. package/dist/types/type-schema/model.d.ts +1 -1
  104. package/dist/types/type-schema/model.d.ts.map +1 -1
  105. package/dist/types/type-schema/settings.d.ts +3 -0
  106. package/dist/types/type-schema/settings.d.ts.map +1 -1
  107. package/dist/types/type-schema/where.d.ts.map +1 -1
  108. package/dist/types/utils/deepCompare.d.ts.map +1 -1
  109. package/dist/types/utils/isIt.d.ts.map +1 -1
  110. package/dist/types/utils/printJsValue.d.ts.map +1 -1
  111. package/dist/types/validation/ModelValidator.d.ts.map +1 -1
  112. package/dist/types/validation/errors.d.ts +1 -1
  113. package/dist/types/validation/errors.d.ts.map +1 -1
  114. package/package.json +5 -5
  115. package/src/dataUtils.ts +12 -9
  116. package/src/definition-generator/DefinitionCodeGenerator.ts +2 -1
  117. package/src/model/modelUtils.ts +1 -1
  118. package/src/model/resolveDefaultColumnType.ts +2 -0
  119. package/src/schemaNormalizer.ts +2 -0
  120. package/src/type-schema/acl.ts +2 -0
  121. package/src/type-schema/condition.ts +1 -0
  122. package/src/type-schema/model.ts +25 -6
  123. package/src/type-schema/settings.ts +1 -0
  124. package/src/validation/ModelValidator.ts +11 -6
  125. package/src/validation/errors.ts +2 -0
package/src/dataUtils.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Input, Model, Value } from '@contember/schema'
2
2
 
3
3
  export interface Providers {
4
- uuid: () => string
4
+ uuid: (args?: { version?: 4 | 7 }) => string
5
5
  now: () => Date
6
6
  }
7
7
 
@@ -25,9 +25,13 @@ export const resolveDefaultValue = (column: Model.AnyColumn, providers: Pick<Pro
25
25
  break
26
26
  case Model.ColumnType.DateTime:
27
27
  case Model.ColumnType.Date:
28
+ case Model.ColumnType.Time:
28
29
  if (column.default === 'now') {
29
30
  return providers.now().toISOString()
30
31
  }
32
+ if (typeof column.default !== 'undefined') {
33
+ return column.default
34
+ }
31
35
  break
32
36
  case Model.ColumnType.Uuid:
33
37
  break
@@ -42,13 +46,6 @@ export const resolveDefaultValue = (column: Model.AnyColumn, providers: Pick<Pro
42
46
  throw new NoDataError(`No data for column ${column.name}`)
43
47
  }
44
48
 
45
- export const resolvePrimaryGenerator = (column: Model.AnyColumn, providers: Providers): (() => Input.PrimaryValue | undefined) => {
46
- if (column.type === Model.ColumnType.Uuid) {
47
- return providers.uuid
48
- }
49
- return () => undefined
50
- }
51
-
52
49
  export const resolveColumnValue = (
53
50
  {
54
51
  entity,
@@ -60,12 +57,18 @@ export const resolveColumnValue = (
60
57
  input: Input.ColumnValue | undefined
61
58
  },
62
59
  providers: Providers,
60
+ options: {
61
+ uuidVersion?: 4 | 7
62
+ },
63
63
  ): Value.FieldValue | undefined => {
64
64
  if (input !== undefined) {
65
65
  return input
66
66
  }
67
67
  if (entity.primary === column.name) {
68
- return resolvePrimaryGenerator(column, providers)()
68
+ if (column.type === Model.ColumnType.Uuid) {
69
+ return providers.uuid({ version: options.uuidVersion })
70
+ }
71
+ return undefined
69
72
  }
70
73
 
71
74
  return resolveDefaultValue(column, providers)
@@ -45,7 +45,7 @@ ${Object.values(entity.fields).map(field => this.generateField({ field, entity,
45
45
  }\n`
46
46
  }
47
47
 
48
- private generateUniqueConstraint({ entity, constraint }: { entity: Model.Entity; constraint: Model.UniqueConstraint }): string {
48
+ private generateUniqueConstraint({ entity, constraint }: { entity: Model.Entity; constraint: Model.UniqueConstraint | Model.UniqueIndex }): string {
49
49
  const fieldsList = `${constraint.fields.map(it => printJsValue(it)).join(', ')}`
50
50
 
51
51
  return `@c.Unique(${fieldsList})`
@@ -234,6 +234,7 @@ const ColumnToMethodMapping: {
234
234
  [Model.ColumnType.Bool]: 'boolColumn',
235
235
  [Model.ColumnType.Date]: 'dateColumn',
236
236
  [Model.ColumnType.DateTime]: 'dateTimeColumn',
237
+ [Model.ColumnType.Time]: 'timeColumn',
237
238
  [Model.ColumnType.Json]: 'jsonColumn',
238
239
  [Model.ColumnType.Double]: 'doubleColumn',
239
240
  [Model.ColumnType.Uuid]: 'uuidColumn',
@@ -65,7 +65,7 @@ export const tryGetColumnName = (schema: Model.Schema, entity: Model.Entity, fie
65
65
  export const getColumnType = (schema: Model.Schema, entity: Model.Entity, fieldName: string): string => {
66
66
  return acceptFieldVisitor(schema, entity, fieldName, {
67
67
  // TODO solve enum handling properly maybe we should distinguish between domain and column type
68
- visitColumn: ({ column }) => (column.type === Model.ColumnType.Enum ? 'text' : column.columnType),
68
+ visitColumn: ({ column }) => (column.type === Model.ColumnType.Enum ? 'text' : column.columnType) + (column.list ? '[]' : ''),
69
69
  visitRelation: ({ entity, relation, targetEntity }) => {
70
70
  if (isIt<Model.JoiningColumnRelation>(relation, 'joiningColumn')) {
71
71
  return getColumnType(schema, targetEntity, targetEntity.primary)
@@ -17,6 +17,8 @@ export const resolveDefaultColumnType = (type: Exclude<Model.ColumnType, Model.C
17
17
  return 'timestamptz'
18
18
  case Model.ColumnType.Date:
19
19
  return 'date'
20
+ case Model.ColumnType.Time:
21
+ return 'time'
20
22
  case Model.ColumnType.Json:
21
23
  return 'jsonb'
22
24
  default:
@@ -24,6 +24,7 @@ export const normalizeSchema = <S extends Schema>(schema: S): S => {
24
24
  content: {
25
25
  export: true,
26
26
  import: true,
27
+ refreshMaterializedView: true,
27
28
  ...adminRoleDefinition.content,
28
29
  },
29
30
  system: {
@@ -47,6 +48,7 @@ export const normalizeSchema = <S extends Schema>(schema: S): S => {
47
48
  content: {
48
49
  export: true,
49
50
  import: true,
51
+ refreshMaterializedView: true,
50
52
  ...contentAdminRoleDefinition.content,
51
53
  },
52
54
  system: {
@@ -39,6 +39,7 @@ const contentPermissionsSchema = Typesafe.partial({
39
39
  assumeMembership: membershipMatchRuleSchema,
40
40
  export: Typesafe.boolean,
41
41
  import: Typesafe.boolean,
42
+ refreshMaterializedView: Typesafe.boolean,
42
43
  })
43
44
  const contentSchemaCheck: Typesafe.Equals<Acl.ContentPermissions, ReturnType<typeof contentPermissionsSchema>> = true
44
45
 
@@ -95,6 +96,7 @@ const entityOperationsSchema = Typesafe.partial({
95
96
  update: fieldPermissionsSchema,
96
97
  delete: Typesafe.union(Typesafe.string, Typesafe.boolean),
97
98
  customPrimary: Typesafe.boolean,
99
+ refreshMaterializedView: Typesafe.boolean,
98
100
  noRoot: Typesafe.array(Typesafe.enumeration('create', 'read', 'update', 'delete')),
99
101
  })
100
102
 
@@ -67,6 +67,7 @@ const resolveColumnTypeSchema = (type: Model.ColumnType) => {
67
67
  // todo: validate format of string-like inputs uuid, date, enum
68
68
  case Model.ColumnType.Date:
69
69
  case Model.ColumnType.DateTime:
70
+ case Model.ColumnType.Time:
70
71
  case Model.ColumnType.Uuid:
71
72
  case Model.ColumnType.Enum:
72
73
  case Model.ColumnType.String:
@@ -130,8 +130,10 @@ const columnSchema = Typesafe.intersection(
130
130
  }),
131
131
  Typesafe.partial({
132
132
  typeAlias: Typesafe.string,
133
- default: Typesafe.union(Typesafe.string, Typesafe.number, Typesafe.boolean, Typesafe.null_),
133
+ list: Typesafe.boolean,
134
+ default: Typesafe.anyJson,
134
135
  sequence: intersectionSchema as Typesafe.Type<Model.AnyColumn['sequence']>,
136
+ collation: Typesafe.string as Typesafe.Type<Model.AnyColumn['collation']>,
135
137
  }),
136
138
  )
137
139
  const columnSchemaCheck: Typesafe.Equals<Model.AnyColumn, ReturnType<typeof columnSchema>> = true
@@ -153,13 +155,15 @@ const viewSchemaInner = Typesafe.intersection(
153
155
  }),
154
156
  Typesafe.partial({
155
157
  dependencies: Typesafe.array(Typesafe.string),
158
+ idSource: Typesafe.array(Typesafe.string),
159
+ materialized: Typesafe.boolean,
156
160
  }),
157
161
  )
158
162
  const viewSchemaCheck: Typesafe.Equals<Model.View, ReturnType<typeof viewSchemaInner>> = true
159
163
  const viewSchema: Typesafe.Type<Model.View> = viewSchemaInner
160
164
 
161
165
 
162
- const indexLike: Typesafe.Type<{readonly fields: readonly string[]; readonly name?: string | undefined}> = Typesafe.intersection(
166
+ const indexSchemaBase = Typesafe.intersection(
163
167
  Typesafe.object({
164
168
  fields: Typesafe.array(Typesafe.string),
165
169
  }),
@@ -167,22 +171,37 @@ const indexLike: Typesafe.Type<{readonly fields: readonly string[]; readonly nam
167
171
  name: Typesafe.string,
168
172
  }),
169
173
  )
174
+ const indexCheck: Typesafe.Equals<Model.Index, ReturnType<typeof indexSchemaBase>> = true
170
175
 
171
176
  const indexesSchema = Typesafe.coalesce<Model.Indexes, Model.Indexes>(
172
177
  Typesafe.preprocess(
173
- Typesafe.array(indexLike),
178
+ Typesafe.array(indexSchemaBase),
174
179
  it => it?.constructor === Object ? Object.values(it) : it,
175
180
  ),
176
181
  [],
177
182
  )
178
183
 
179
184
  const uniqueConstraint = Typesafe.intersection(
180
- indexLike,
185
+ Typesafe.object({
186
+ fields: Typesafe.array(Typesafe.string),
187
+ }),
181
188
  Typesafe.partial({
182
189
  timing: Typesafe.enumeration('deferrable', 'deferred'),
190
+ name: Typesafe.string,
191
+ index: Typesafe.literal(false),
192
+ }),
193
+ )
194
+ const uniqueIndex = Typesafe.intersection(
195
+ Typesafe.object({
196
+ fields: Typesafe.array(Typesafe.string),
197
+ index: Typesafe.literal(true),
198
+ }),
199
+ Typesafe.partial({
200
+ nulls: Typesafe.enumeration('distinct', 'not distinct'),
183
201
  }),
184
202
  )
185
203
  const uniqueConstraintCheck: Typesafe.Equals<Model.UniqueConstraint, ReturnType<typeof uniqueConstraint>> = true
204
+ const uniqueIndexCheck: Typesafe.Equals<Model.UniqueIndex, ReturnType<typeof uniqueIndex>> = true
186
205
 
187
206
  const entitySchema = Typesafe.intersection(
188
207
  Typesafe.object({
@@ -191,8 +210,8 @@ const entitySchema = Typesafe.intersection(
191
210
  primaryColumn: Typesafe.string,
192
211
  tableName: Typesafe.string,
193
212
  fields: Typesafe.record(Typesafe.string, fieldSchema),
194
- unique: Typesafe.preprocess<Model.UniqueConstraints>(
195
- Typesafe.array(uniqueConstraint),
213
+ unique: Typesafe.preprocess<Model.Uniques>(
214
+ Typesafe.array(Typesafe.union(uniqueConstraint, uniqueIndex)),
196
215
  it => it?.constructor === Object ? Object.values(it) : it,
197
216
  ),
198
217
  indexes: indexesSchema,
@@ -11,6 +11,7 @@ export const settingsSchema = Typesafe.partial({
11
11
  useExistsInHasManyFilter: Typesafe.boolean,
12
12
  fullDateTimeResponse: Typesafe.boolean,
13
13
  shortDateResponse: Typesafe.boolean,
14
+ uuidVersion: Typesafe.union(Typesafe.literal(4), Typesafe.literal(7)),
14
15
  }),
15
16
  })
16
17
 
@@ -1,6 +1,6 @@
1
1
  import { Model } from '@contember/schema'
2
2
  import { ErrorBuilder, ValidationError } from './errors'
3
- import { acceptEveryFieldVisitor, getTargetEntity, isInverseRelation, isOwningRelation } from '../model'
3
+ import { acceptEveryFieldVisitor, getTargetEntity, isColumn, isInverseRelation, isOwningRelation } from '../model'
4
4
 
5
5
  const IDENTIFIER_PATTERN = /^[_a-zA-Z][_a-zA-Z0-9]*$/
6
6
  const RESERVED_WORDS = ['and', 'or', 'not']
@@ -52,18 +52,23 @@ export class ModelValidator {
52
52
  }
53
53
  }
54
54
  this.validateUniqueConstraints(
55
- entity.unique,
56
- new Set(Object.keys(entity.fields)),
55
+ entity,
57
56
  errors.for('unique'),
58
57
  )
59
58
  this.validateColumnNamesCollision(entity, errors)
60
59
  }
61
60
 
62
- private validateUniqueConstraints(uniqueConstraints: Model.Entity['unique'], fields: Set<string>, errors: ErrorBuilder): void {
63
- for (const constraint of uniqueConstraints) {
61
+ private validateUniqueConstraints(entity: Model.Entity, errors: ErrorBuilder): void {
62
+ for (const constraint of entity.unique) {
63
+ if (entity.view && !constraint.index) {
64
+ errors.add('MODEL_INVALID_CONSTRAINT', 'Unique constraint on view entity must be an index. Please set index: true')
65
+ }
64
66
  for (const field of constraint.fields) {
65
- if (!fields.has(field)) {
67
+ const fieldDef = entity.fields[field]
68
+ if (!fieldDef) {
66
69
  errors.add('MODEL_UNDEFINED_FIELD', `Referenced field ${field} in a constraint does not exists`)
70
+ } else if (isColumn(fieldDef) && fieldDef.list) {
71
+ errors.add('MODEL_INVALID_FIELD', `Field ${field} in a unique constraint cannot be an array`)
67
72
  }
68
73
  }
69
74
  }
@@ -1,6 +1,7 @@
1
1
  export type ValidationErrorCode =
2
2
  | 'MODEL_NAME_MISMATCH'
3
3
  | 'MODEL_UNDEFINED_FIELD'
4
+ | 'MODEL_INVALID_FIELD'
4
5
  | 'MODEL_UNDEFINED_ENTITY'
5
6
  | 'MODEL_RELATION_REQUIRED'
6
7
  | 'MODEL_INVALID_RELATION_DEFINITION'
@@ -8,6 +9,7 @@ export type ValidationErrorCode =
8
9
  | 'MODEL_INVALID_VIEW_USAGE'
9
10
  | 'MODEL_INVALID_IDENTIFIER'
10
11
  | 'MODEL_INVALID_ENTITY_NAME'
12
+ | 'MODEL_INVALID_CONSTRAINT'
11
13
  | 'MODEL_NAME_COLLISION'
12
14
 
13
15
  | 'ACL_INVALID_CONDITION'