@contember/schema-utils 1.3.0-alpha.6 → 1.3.0-alpha.8
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/SchemaDatabaseMetadata.d.ts +40 -0
- package/dist/src/SchemaDatabaseMetadata.d.ts.map +1 -0
- package/dist/src/SchemaDatabaseMetadata.js +20 -0
- package/dist/src/SchemaDatabaseMetadata.js.map +1 -0
- package/dist/src/definition-generator/AclDefinitionCodeGenerator.d.ts +19 -0
- package/dist/src/definition-generator/AclDefinitionCodeGenerator.d.ts.map +1 -0
- package/dist/src/definition-generator/AclDefinitionCodeGenerator.js +116 -0
- package/dist/src/definition-generator/AclDefinitionCodeGenerator.js.map +1 -0
- package/dist/src/definition-generator/DefinitionCodeGenerator.d.ts +27 -0
- package/dist/src/definition-generator/DefinitionCodeGenerator.d.ts.map +1 -0
- package/dist/src/definition-generator/DefinitionCodeGenerator.js +216 -0
- package/dist/src/definition-generator/DefinitionCodeGenerator.js.map +1 -0
- package/dist/src/definition-generator/DefinitionNamingConventions.d.ts +7 -0
- package/dist/src/definition-generator/DefinitionNamingConventions.d.ts.map +1 -0
- package/dist/src/definition-generator/DefinitionNamingConventions.js +18 -0
- package/dist/src/definition-generator/DefinitionNamingConventions.js.map +1 -0
- package/dist/src/definition-generator/TsDefinitionGenerator.d.ts +4 -18
- package/dist/src/definition-generator/TsDefinitionGenerator.d.ts.map +1 -1
- package/dist/src/definition-generator/TsDefinitionGenerator.js +6 -232
- package/dist/src/definition-generator/TsDefinitionGenerator.js.map +1 -1
- package/dist/src/definition-generator/index.d.ts +3 -0
- package/dist/src/definition-generator/index.d.ts.map +1 -1
- package/dist/src/definition-generator/index.js +3 -0
- package/dist/src/definition-generator/index.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +1 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/lax/LaxSchemaConverter.js +2 -2
- package/dist/src/model/index.d.ts +0 -1
- package/dist/src/model/index.d.ts.map +1 -1
- package/dist/src/model/index.js +0 -1
- package/dist/src/model/index.js.map +1 -1
- package/dist/src/tsconfig.tsbuildinfo +1 -1
- package/dist/src/type-schema/model.d.ts +4 -6
- package/dist/src/type-schema/model.d.ts.map +1 -1
- package/dist/src/type-schema/model.js +5 -6
- package/dist/src/type-schema/model.js.map +1 -1
- package/dist/src/utils/printJsValue.d.ts +13 -0
- package/dist/src/utils/printJsValue.d.ts.map +1 -0
- package/dist/src/utils/printJsValue.js +57 -0
- package/dist/src/utils/printJsValue.js.map +1 -0
- package/dist/src/validation/ModelValidator.d.ts.map +1 -1
- package/dist/src/validation/ModelValidator.js +4 -30
- package/dist/src/validation/ModelValidator.js.map +1 -1
- package/dist/tests/cases/unit/modelValidator.test.js +6 -72
- package/dist/tests/cases/unit/modelValidator.test.js.map +1 -1
- package/dist/tests/cases/unit/printJsvalue.test.d.ts +2 -0
- package/dist/tests/cases/unit/printJsvalue.test.d.ts.map +1 -0
- package/dist/tests/cases/unit/printJsvalue.test.js +90 -0
- package/dist/tests/cases/unit/printJsvalue.test.js.map +1 -0
- package/dist/tests/cases/unit/schemas/acl.d.ts +13 -0
- package/dist/tests/cases/unit/schemas/acl.d.ts.map +1 -0
- package/dist/tests/cases/unit/schemas/acl.js +47 -0
- package/dist/tests/cases/unit/schemas/acl.js.map +1 -0
- package/dist/tests/cases/unit/schemas/basic.d.ts.map +1 -1
- package/dist/tests/cases/unit/schemas/basic.js.map +1 -1
- package/dist/tests/cases/unit/schemas/enum.d.ts.map +1 -1
- package/dist/tests/cases/unit/schemas/enum.js.map +1 -1
- package/dist/tests/cases/unit/schemas/relations.d.ts.map +1 -1
- package/dist/tests/cases/unit/schemas/relations.js.map +1 -1
- package/dist/tests/cases/unit/schemas/unique.d.ts.map +1 -1
- package/dist/tests/cases/unit/schemas/unique.js.map +1 -1
- package/dist/tests/cases/unit/tsDefinitionGenerator.test.js +5 -3
- package/dist/tests/cases/unit/tsDefinitionGenerator.test.js.map +1 -1
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/package.json +4 -6
- package/src/SchemaDatabaseMetadata.ts +66 -0
- package/src/definition-generator/AclDefinitionCodeGenerator.ts +126 -0
- package/src/definition-generator/DefinitionCodeGenerator.ts +250 -0
- package/src/definition-generator/DefinitionNamingConventions.ts +16 -0
- package/src/definition-generator/TsDefinitionGenerator.ts +8 -264
- package/src/definition-generator/index.ts +3 -0
- package/src/index.ts +1 -0
- package/src/lax/LaxSchemaConverter.ts +2 -2
- package/src/model/index.ts +0 -1
- package/src/type-schema/model.ts +20 -8
- package/src/utils/printJsValue.ts +62 -0
- package/src/validation/ModelValidator.ts +11 -35
- package/tests/cases/unit/__snapshots__/laxSchemaConverter.test.ts.snap +14 -14
- package/tests/cases/unit/modelValidator.test.ts +6 -73
- package/tests/cases/unit/printJsvalue.test.ts +100 -0
- package/tests/cases/unit/schemas/acl.ts +34 -0
- package/tests/cases/unit/schemas/basic.ts +1 -1
- package/tests/cases/unit/schemas/enum.ts +1 -1
- package/tests/cases/unit/schemas/relations.ts +1 -1
- package/tests/cases/unit/schemas/unique.ts +1 -1
- package/tests/cases/unit/tsDefinitionGenerator.test.ts +6 -4
- package/dist/src/model/NamingHelper.d.ts +0 -9
- package/dist/src/model/NamingHelper.d.ts.map +0 -1
- package/dist/src/model/NamingHelper.js +0 -44
- package/dist/src/model/NamingHelper.js.map +0 -1
- package/src/model/NamingHelper.ts +0 -41
|
@@ -7,7 +7,7 @@ const RESERVED_WORDS = ['and', 'or', 'not']
|
|
|
7
7
|
|
|
8
8
|
|
|
9
9
|
export class ModelValidator {
|
|
10
|
-
constructor(private readonly model: Model.Schema) {}
|
|
10
|
+
constructor(private readonly model: Model.Schema) { }
|
|
11
11
|
|
|
12
12
|
public validate(): ValidationError[] {
|
|
13
13
|
const errorBuilder = new ErrorBuilder([], [])
|
|
@@ -54,15 +54,10 @@ export class ModelValidator {
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
private validateUniqueConstraints(uniqueConstraints: Model.Entity['unique'], fields: Set<string>, errors: ErrorBuilder): void {
|
|
57
|
-
for (const
|
|
58
|
-
const uniqueErrors = errors.for(constraintName)
|
|
59
|
-
if (constraint.name !== constraintName) {
|
|
60
|
-
uniqueErrors.add('MODEL_NAME_MISMATCH', `Constraint name ${constraint.name} does not match the name in a map "${constraintName}"`)
|
|
61
|
-
continue
|
|
62
|
-
}
|
|
57
|
+
for (const constraint of uniqueConstraints) {
|
|
63
58
|
for (const field of constraint.fields) {
|
|
64
59
|
if (!fields.has(field)) {
|
|
65
|
-
|
|
60
|
+
errors.add('MODEL_UNDEFINED_FIELD', `Referenced field ${field} in a constraint does not exists`)
|
|
66
61
|
}
|
|
67
62
|
}
|
|
68
63
|
}
|
|
@@ -79,7 +74,7 @@ export class ModelValidator {
|
|
|
79
74
|
}
|
|
80
75
|
}
|
|
81
76
|
|
|
82
|
-
private validateRelation(partialEntity: Model.Entity, field: Model.AnyRelation, errors: ErrorBuilder):
|
|
77
|
+
private validateRelation(partialEntity: Model.Entity, field: Model.AnyRelation, errors: ErrorBuilder): void {
|
|
83
78
|
const entityName = partialEntity.name
|
|
84
79
|
const targetEntityName = field.target
|
|
85
80
|
const targetEntity = this.model.entities[targetEntityName] || undefined
|
|
@@ -148,7 +143,7 @@ export class ModelValidator {
|
|
|
148
143
|
return errors.add('MODEL_INVALID_RELATION_DEFINITION', `${relationDescription} inverse relation is not set`)
|
|
149
144
|
}
|
|
150
145
|
if (targetField.inversedBy !== field.name) {
|
|
151
|
-
return errors.add('MODEL_INVALID_RELATION_DEFINITION', `${relationDescription} back reference ${entityName}::${field.name}
|
|
146
|
+
return errors.add('MODEL_INVALID_RELATION_DEFINITION', `${relationDescription} back reference ${entityName}::${field.name} expected, ${targetField.target}::${targetField.inversedBy} given`)
|
|
152
147
|
}
|
|
153
148
|
if (field.type === Model.RelationType.OneHasOne && targetField.type !== Model.RelationType.OneHasOne) {
|
|
154
149
|
return errors.add('MODEL_INVALID_RELATION_DEFINITION', `${relationDescription} "OneHasOne" type expected, "${targetField.type}" given`)
|
|
@@ -185,7 +180,7 @@ export class ModelValidator {
|
|
|
185
180
|
return errors.add('MODEL_INVALID_RELATION_DEFINITION', `${relationDescription} owning relation is not set`)
|
|
186
181
|
}
|
|
187
182
|
if (targetField.ownedBy !== field.name) {
|
|
188
|
-
return errors.add('MODEL_INVALID_RELATION_DEFINITION', `${relationDescription} back reference ${entityName}::${field.name}
|
|
183
|
+
return errors.add('MODEL_INVALID_RELATION_DEFINITION', `${relationDescription} back reference ${entityName}::${field.name} expected, ${targetField.target}::${targetField.ownedBy} given`)
|
|
189
184
|
}
|
|
190
185
|
if (field.type === Model.RelationType.OneHasOne && targetField.type !== Model.RelationType.OneHasOne) {
|
|
191
186
|
return errors.add('MODEL_INVALID_RELATION_DEFINITION', `${relationDescription} "OneHasOne" type expected, "${targetField.type}" given`)
|
|
@@ -259,32 +254,13 @@ export class ModelValidator {
|
|
|
259
254
|
}
|
|
260
255
|
aliasedTypes.set(column.typeAlias, column.type)
|
|
261
256
|
},
|
|
262
|
-
visitManyHasManyInverse: () => {},
|
|
263
|
-
visitOneHasMany: () => {},
|
|
264
|
-
visitOneHasOneInverse: () => {},
|
|
265
|
-
visitOneHasOneOwning: () => {},
|
|
266
|
-
visitManyHasOne: () => {},
|
|
257
|
+
visitManyHasManyInverse: () => { },
|
|
258
|
+
visitOneHasMany: () => { },
|
|
259
|
+
visitOneHasOneInverse: () => { },
|
|
260
|
+
visitOneHasOneOwning: () => { },
|
|
261
|
+
visitManyHasOne: () => { },
|
|
267
262
|
})
|
|
268
263
|
}
|
|
269
|
-
for (const entity of entities) {
|
|
270
|
-
const entityErrorBuilder = errorBuilder.for(entity.name)
|
|
271
|
-
for (const index of Object.values(entity.indexes)) {
|
|
272
|
-
const description = `index name ${index.name} of entity ${entity.name}`
|
|
273
|
-
if (relationNames[index.name]) {
|
|
274
|
-
entityErrorBuilder.add('MODEL_NAME_COLLISION', `${description} collides with ${relationNames[index.name]}`)
|
|
275
|
-
} else {
|
|
276
|
-
relationNames[index.name] = description
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
for (const unique of Object.values(entity.unique)) {
|
|
280
|
-
const description = `unique index name ${unique.name} of entity ${entity.name}`
|
|
281
|
-
if (relationNames[unique.name]) {
|
|
282
|
-
entityErrorBuilder.add('MODEL_NAME_COLLISION', `${description} collides with ${relationNames[unique.name]}`)
|
|
283
|
-
} else {
|
|
284
|
-
relationNames[unique.name] = description
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
264
|
}
|
|
289
265
|
}
|
|
290
266
|
|
|
@@ -45,12 +45,12 @@ exports[`lax schema converter basic 1`] = `
|
|
|
45
45
|
"type": "String",
|
|
46
46
|
},
|
|
47
47
|
},
|
|
48
|
-
"indexes":
|
|
48
|
+
"indexes": [],
|
|
49
49
|
"name": "Article",
|
|
50
50
|
"primary": "id",
|
|
51
51
|
"primaryColumn": "id",
|
|
52
52
|
"tableName": "article",
|
|
53
|
-
"unique":
|
|
53
|
+
"unique": [],
|
|
54
54
|
},
|
|
55
55
|
},
|
|
56
56
|
"enums": {
|
|
@@ -117,12 +117,12 @@ exports[`lax schema converter many-has-many 1`] = `
|
|
|
117
117
|
"type": "String",
|
|
118
118
|
},
|
|
119
119
|
},
|
|
120
|
-
"indexes":
|
|
120
|
+
"indexes": [],
|
|
121
121
|
"name": "Article",
|
|
122
122
|
"primary": "id",
|
|
123
123
|
"primaryColumn": "id",
|
|
124
124
|
"tableName": "article",
|
|
125
|
-
"unique":
|
|
125
|
+
"unique": [],
|
|
126
126
|
},
|
|
127
127
|
"Tag": {
|
|
128
128
|
"eventLog": {
|
|
@@ -143,12 +143,12 @@ exports[`lax schema converter many-has-many 1`] = `
|
|
|
143
143
|
"type": "Uuid",
|
|
144
144
|
},
|
|
145
145
|
},
|
|
146
|
-
"indexes":
|
|
146
|
+
"indexes": [],
|
|
147
147
|
"name": "Tag",
|
|
148
148
|
"primary": "id",
|
|
149
149
|
"primaryColumn": "id",
|
|
150
150
|
"tableName": "tag",
|
|
151
|
-
"unique":
|
|
151
|
+
"unique": [],
|
|
152
152
|
},
|
|
153
153
|
},
|
|
154
154
|
"enums": {},
|
|
@@ -200,12 +200,12 @@ exports[`lax schema converter one-has-many 1`] = `
|
|
|
200
200
|
"type": "String",
|
|
201
201
|
},
|
|
202
202
|
},
|
|
203
|
-
"indexes":
|
|
203
|
+
"indexes": [],
|
|
204
204
|
"name": "Article",
|
|
205
205
|
"primary": "id",
|
|
206
206
|
"primaryColumn": "id",
|
|
207
207
|
"tableName": "article",
|
|
208
|
-
"unique":
|
|
208
|
+
"unique": [],
|
|
209
209
|
},
|
|
210
210
|
"Category": {
|
|
211
211
|
"eventLog": {
|
|
@@ -226,12 +226,12 @@ exports[`lax schema converter one-has-many 1`] = `
|
|
|
226
226
|
"type": "Uuid",
|
|
227
227
|
},
|
|
228
228
|
},
|
|
229
|
-
"indexes":
|
|
229
|
+
"indexes": [],
|
|
230
230
|
"name": "Category",
|
|
231
231
|
"primary": "id",
|
|
232
232
|
"primaryColumn": "id",
|
|
233
233
|
"tableName": "category",
|
|
234
|
-
"unique":
|
|
234
|
+
"unique": [],
|
|
235
235
|
},
|
|
236
236
|
},
|
|
237
237
|
"enums": {},
|
|
@@ -283,12 +283,12 @@ exports[`lax schema converter one-has-one 1`] = `
|
|
|
283
283
|
"type": "String",
|
|
284
284
|
},
|
|
285
285
|
},
|
|
286
|
-
"indexes":
|
|
286
|
+
"indexes": [],
|
|
287
287
|
"name": "Article",
|
|
288
288
|
"primary": "id",
|
|
289
289
|
"primaryColumn": "id",
|
|
290
290
|
"tableName": "article",
|
|
291
|
-
"unique":
|
|
291
|
+
"unique": [],
|
|
292
292
|
},
|
|
293
293
|
"Content": {
|
|
294
294
|
"eventLog": {
|
|
@@ -310,12 +310,12 @@ exports[`lax schema converter one-has-one 1`] = `
|
|
|
310
310
|
"type": "Uuid",
|
|
311
311
|
},
|
|
312
312
|
},
|
|
313
|
-
"indexes":
|
|
313
|
+
"indexes": [],
|
|
314
314
|
"name": "Content",
|
|
315
315
|
"primary": "id",
|
|
316
316
|
"primaryColumn": "id",
|
|
317
317
|
"tableName": "content",
|
|
318
|
-
"unique":
|
|
318
|
+
"unique": [],
|
|
319
319
|
},
|
|
320
320
|
},
|
|
321
321
|
"enums": {},
|
|
@@ -4,73 +4,6 @@ import { ModelValidator } from '../../../src'
|
|
|
4
4
|
|
|
5
5
|
|
|
6
6
|
|
|
7
|
-
test('index name collision', () => {
|
|
8
|
-
const model: Model.Schema = {
|
|
9
|
-
enums: {},
|
|
10
|
-
entities: {
|
|
11
|
-
Foo: {
|
|
12
|
-
fields: {
|
|
13
|
-
id: {
|
|
14
|
-
columnName: 'id',
|
|
15
|
-
name: 'id',
|
|
16
|
-
nullable: false,
|
|
17
|
-
type: Model.ColumnType.Uuid,
|
|
18
|
-
columnType: 'uuid',
|
|
19
|
-
},
|
|
20
|
-
},
|
|
21
|
-
name: 'Foo',
|
|
22
|
-
primary: 'id',
|
|
23
|
-
primaryColumn: 'id',
|
|
24
|
-
tableName: 'foo',
|
|
25
|
-
unique: {},
|
|
26
|
-
eventLog: {
|
|
27
|
-
enabled: true,
|
|
28
|
-
},
|
|
29
|
-
indexes: {
|
|
30
|
-
test: { fields: ['id'], name: 'test' },
|
|
31
|
-
},
|
|
32
|
-
},
|
|
33
|
-
Bar: {
|
|
34
|
-
fields: {
|
|
35
|
-
id: {
|
|
36
|
-
columnName: 'id',
|
|
37
|
-
name: 'id',
|
|
38
|
-
nullable: false,
|
|
39
|
-
type: Model.ColumnType.Uuid,
|
|
40
|
-
columnType: 'uuid',
|
|
41
|
-
},
|
|
42
|
-
},
|
|
43
|
-
name: 'Bar',
|
|
44
|
-
primary: 'id',
|
|
45
|
-
primaryColumn: 'id',
|
|
46
|
-
tableName: 'bar',
|
|
47
|
-
unique: {
|
|
48
|
-
test: { fields: ['id'], name: 'test' },
|
|
49
|
-
},
|
|
50
|
-
eventLog: {
|
|
51
|
-
enabled: true,
|
|
52
|
-
},
|
|
53
|
-
indexes: {
|
|
54
|
-
foo: { fields: ['id'], name: 'foo' },
|
|
55
|
-
},
|
|
56
|
-
},
|
|
57
|
-
},
|
|
58
|
-
}
|
|
59
|
-
const validator = new ModelValidator(model)
|
|
60
|
-
assert.deepStrictEqual(validator.validate(), [
|
|
61
|
-
{
|
|
62
|
-
code: 'MODEL_NAME_COLLISION',
|
|
63
|
-
message: 'index name foo of entity Bar collides with table name foo of entity Foo',
|
|
64
|
-
path: ['entities', 'Bar'],
|
|
65
|
-
},
|
|
66
|
-
{
|
|
67
|
-
code: 'MODEL_NAME_COLLISION',
|
|
68
|
-
message: 'unique index name test of entity Bar collides with index name test of entity Foo',
|
|
69
|
-
path: ['entities', 'Bar'],
|
|
70
|
-
},
|
|
71
|
-
])
|
|
72
|
-
})
|
|
73
|
-
|
|
74
7
|
|
|
75
8
|
test('"meta" collision', () => {
|
|
76
9
|
const model: Model.Schema = {
|
|
@@ -90,9 +23,9 @@ test('"meta" collision', () => {
|
|
|
90
23
|
primary: 'id',
|
|
91
24
|
primaryColumn: 'id',
|
|
92
25
|
tableName: 'foo',
|
|
93
|
-
unique:
|
|
26
|
+
unique: [],
|
|
94
27
|
eventLog: { enabled: true },
|
|
95
|
-
indexes:
|
|
28
|
+
indexes: [],
|
|
96
29
|
},
|
|
97
30
|
FooMeta: {
|
|
98
31
|
fields: {
|
|
@@ -108,9 +41,9 @@ test('"meta" collision', () => {
|
|
|
108
41
|
primary: 'id',
|
|
109
42
|
primaryColumn: 'id',
|
|
110
43
|
tableName: 'foo_meta',
|
|
111
|
-
unique:
|
|
44
|
+
unique: [],
|
|
112
45
|
eventLog: { enabled: true },
|
|
113
|
-
indexes:
|
|
46
|
+
indexes: [],
|
|
114
47
|
},
|
|
115
48
|
BarMeta: {
|
|
116
49
|
fields: {
|
|
@@ -126,9 +59,9 @@ test('"meta" collision', () => {
|
|
|
126
59
|
primary: 'id',
|
|
127
60
|
primaryColumn: 'id',
|
|
128
61
|
tableName: 'bar',
|
|
129
|
-
unique:
|
|
62
|
+
unique: [],
|
|
130
63
|
eventLog: { enabled: true },
|
|
131
|
-
indexes:
|
|
64
|
+
indexes: [],
|
|
132
65
|
},
|
|
133
66
|
},
|
|
134
67
|
}
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { beforeAll, describe, expect, test } from 'vitest'
|
|
2
|
+
import { printJsValue } from '../../../src/utils/printJsValue'
|
|
3
|
+
|
|
4
|
+
beforeAll(() => {
|
|
5
|
+
expect.addSnapshotSerializer({
|
|
6
|
+
test: val => typeof val === 'string',
|
|
7
|
+
print: val => String(val),
|
|
8
|
+
})
|
|
9
|
+
})
|
|
10
|
+
|
|
11
|
+
describe('printJsValue', () => {
|
|
12
|
+
test('string', () => {
|
|
13
|
+
expect(printJsValue('foobar')).toMatchInlineSnapshot(`'foobar'`)
|
|
14
|
+
})
|
|
15
|
+
|
|
16
|
+
test('string escape', () => {
|
|
17
|
+
expect(printJsValue('foo\'bar')).toMatchInlineSnapshot(`'foo\\'bar'`)
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
test('number', () => {
|
|
21
|
+
expect(printJsValue(11)).toMatchInlineSnapshot(`11`)
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
test('boolean', () => {
|
|
25
|
+
expect(printJsValue(true)).toMatchInlineSnapshot(`true`)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
test('null', () => {
|
|
29
|
+
expect(printJsValue(null)).toMatchInlineSnapshot(`null`)
|
|
30
|
+
})
|
|
31
|
+
|
|
32
|
+
test('inline array', () => {
|
|
33
|
+
expect(printJsValue([1, 2, 3])).toMatchInlineSnapshot(`[1, 2, 3]`)
|
|
34
|
+
})
|
|
35
|
+
test('block array', () => {
|
|
36
|
+
expect(printJsValue([1, 2, 3], () => true)).toMatchInlineSnapshot(`
|
|
37
|
+
[
|
|
38
|
+
1,
|
|
39
|
+
2,
|
|
40
|
+
3,
|
|
41
|
+
]
|
|
42
|
+
`)
|
|
43
|
+
})
|
|
44
|
+
|
|
45
|
+
test('inline object', () => {
|
|
46
|
+
expect(printJsValue({ a: 1, b: 2 })).toMatchInlineSnapshot('{ a: 1, b: 2 }')
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
test('block object', () => {
|
|
50
|
+
expect(printJsValue({ a: 1, b: 2 }, () => true)).toMatchInlineSnapshot(`
|
|
51
|
+
{
|
|
52
|
+
a: 1,
|
|
53
|
+
b: 2,
|
|
54
|
+
}
|
|
55
|
+
`)
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
test('nested block object', () => {
|
|
59
|
+
expect(printJsValue({ a: 1, b: { c: { d: { e: 1 } } } }, () => true)).toMatchInlineSnapshot(`
|
|
60
|
+
{
|
|
61
|
+
a: 1,
|
|
62
|
+
b: {
|
|
63
|
+
c: {
|
|
64
|
+
d: {
|
|
65
|
+
e: 1,
|
|
66
|
+
},
|
|
67
|
+
},
|
|
68
|
+
},
|
|
69
|
+
}
|
|
70
|
+
`)
|
|
71
|
+
})
|
|
72
|
+
|
|
73
|
+
|
|
74
|
+
test('one level nested block object', () => {
|
|
75
|
+
expect(printJsValue({ a: 1, b: { c: { d: { e: 1 } } } }, (_, path) => path.length === 0)).toMatchInlineSnapshot(`
|
|
76
|
+
{
|
|
77
|
+
a: 1,
|
|
78
|
+
b: { c: { d: { e: 1 } } },
|
|
79
|
+
}
|
|
80
|
+
`)
|
|
81
|
+
})
|
|
82
|
+
|
|
83
|
+
test('nested block object and arr', () => {
|
|
84
|
+
expect(printJsValue({ a: 1, b: [2, { c: 4 }, [5, 6]] }, () => true)).toMatchInlineSnapshot(`
|
|
85
|
+
{
|
|
86
|
+
a: 1,
|
|
87
|
+
b: [
|
|
88
|
+
2,
|
|
89
|
+
{
|
|
90
|
+
c: 4,
|
|
91
|
+
},
|
|
92
|
+
[
|
|
93
|
+
5,
|
|
94
|
+
6,
|
|
95
|
+
],
|
|
96
|
+
],
|
|
97
|
+
}
|
|
98
|
+
`)
|
|
99
|
+
})
|
|
100
|
+
})
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { SchemaDefinition as def, AclDefinition as acl } from '@contember/schema-definition'
|
|
2
|
+
|
|
3
|
+
export const readerRole = acl.createRole('reader', { stages: '*' })
|
|
4
|
+
|
|
5
|
+
export const editorRole = acl.createRole('editor', { stages: '*' })
|
|
6
|
+
|
|
7
|
+
export const categoryEditorVariable = acl.createEntityVariable('category', 'Category', editorRole)
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
@acl.allow(readerRole, {
|
|
11
|
+
read: true,
|
|
12
|
+
})
|
|
13
|
+
@acl.allow(editorRole, {
|
|
14
|
+
when: { category: { id: categoryEditorVariable } },
|
|
15
|
+
read: true,
|
|
16
|
+
create: ['title', 'category'],
|
|
17
|
+
update: ['title', 'category'],
|
|
18
|
+
})
|
|
19
|
+
export class Article {
|
|
20
|
+
title = def.stringColumn()
|
|
21
|
+
deletedAt = def.dateTimeColumn()
|
|
22
|
+
category = def.manyHasOne(Category)
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
@acl.allow(readerRole, {
|
|
27
|
+
read: true,
|
|
28
|
+
})
|
|
29
|
+
@acl.allow(editorRole, {
|
|
30
|
+
read: true,
|
|
31
|
+
})
|
|
32
|
+
export class Category {
|
|
33
|
+
name = def.stringColumn()
|
|
34
|
+
}
|
|
@@ -1,12 +1,13 @@
|
|
|
1
1
|
import { createSchema } from '@contember/schema-definition'
|
|
2
|
-
import {
|
|
2
|
+
import { expect, test } from 'vitest'
|
|
3
3
|
import * as basic from './schemas/basic'
|
|
4
4
|
import * as relations from './schemas/relations'
|
|
5
5
|
import * as unique from './schemas/unique'
|
|
6
6
|
import * as enum_ from './schemas/enum'
|
|
7
|
+
import * as acl from './schemas/acl'
|
|
7
8
|
import { readFile, writeFile } from 'fs/promises'
|
|
8
9
|
import { join } from 'path'
|
|
9
|
-
import {
|
|
10
|
+
import { DefinitionCodeGenerator } from '../../../src/definition-generator/DefinitionCodeGenerator'
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
const tests = [
|
|
@@ -14,13 +15,14 @@ const tests = [
|
|
|
14
15
|
['relations', relations],
|
|
15
16
|
['unique', unique],
|
|
16
17
|
['enum', enum_],
|
|
18
|
+
['acl', acl],
|
|
17
19
|
] as const
|
|
18
20
|
for (const [name, def] of tests) {
|
|
19
21
|
test(`generate schema: ${name}`, async () => {
|
|
20
22
|
const schema = createSchema(def)
|
|
21
|
-
const generator = new
|
|
23
|
+
const generator = new DefinitionCodeGenerator()
|
|
22
24
|
const content = await readFile(join(__dirname, `schemas/${name}.ts`), 'utf-8')
|
|
23
|
-
const generated = generator.generate()
|
|
25
|
+
const generated = generator.generate(schema)
|
|
24
26
|
try {
|
|
25
27
|
expect(generated).toBe(content)
|
|
26
28
|
} catch (e) {
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
export declare class NamingHelper {
|
|
2
|
-
static createForeignKeyIndexName(tableName: string, column: string): string;
|
|
3
|
-
static createJunctionTablePrimaryConstraintName(tableName: string): string;
|
|
4
|
-
static createForeignKeyName(fromTable: string, fromColumn: string, toTable: string, toColumn: string): string;
|
|
5
|
-
static createIndexName: (entityName: string, fields: readonly string[]) => string;
|
|
6
|
-
static createUniqueConstraintName: (entityName: string, fields: readonly string[]) => string;
|
|
7
|
-
private static createUniqueSuffix;
|
|
8
|
-
}
|
|
9
|
-
//# sourceMappingURL=NamingHelper.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"NamingHelper.d.ts","sourceRoot":"","sources":["../../../src/model/NamingHelper.ts"],"names":[],"mappings":"AAIA,qBAAa,YAAY;WACV,yBAAyB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;WAK3D,wCAAwC,CAAC,SAAS,EAAE,MAAM;WAK1D,oBAAoB,CAAC,SAAS,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM;IAOpH,OAAc,eAAe,eAAgB,MAAM,UAAU,SAAS,MAAM,EAAE,KAAG,MAAM,CAKtF;IAED,OAAc,0BAA0B,eAAgB,MAAM,UAAU,SAAS,MAAM,EAAE,KAAG,MAAM,CAKjG;IAED,OAAO,CAAC,MAAM,CAAC,kBAAkB,CAGhC;CACD"}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
var _a;
|
|
6
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
-
exports.NamingHelper = void 0;
|
|
8
|
-
const sha256_1 = __importDefault(require("crypto-js/sha256"));
|
|
9
|
-
const enc_hex_1 = __importDefault(require("crypto-js/enc-hex"));
|
|
10
|
-
class NamingHelper {
|
|
11
|
-
static createForeignKeyIndexName(tableName, column) {
|
|
12
|
-
// format matches https://github.com/salsita/node-pg-migrate/blob/9331f6fda98795e3f3733461f9b71345168b99d8/src/operations/indexes.ts#L21
|
|
13
|
-
return `${tableName}_${column}_index`;
|
|
14
|
-
}
|
|
15
|
-
static createJunctionTablePrimaryConstraintName(tableName) {
|
|
16
|
-
// format matches https://github.com/salsita/node-pg-migrate/blob/9331f6fda98795e3f3733461f9b71345168b99d8/src/operations/tables.ts#L204
|
|
17
|
-
return `${tableName}_pkey`;
|
|
18
|
-
}
|
|
19
|
-
static createForeignKeyName(fromTable, fromColumn, toTable, toColumn) {
|
|
20
|
-
return 'fk_'
|
|
21
|
-
+ fromTable + '_'
|
|
22
|
-
+ fromColumn + '_'
|
|
23
|
-
+ this.createUniqueSuffix([fromTable, fromColumn, toTable, toColumn]);
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
exports.NamingHelper = NamingHelper;
|
|
27
|
-
_a = NamingHelper;
|
|
28
|
-
NamingHelper.createIndexName = (entityName, fields) => {
|
|
29
|
-
return 'idx_'
|
|
30
|
-
+ entityName + '_'
|
|
31
|
-
+ fields.join('_') + '_'
|
|
32
|
-
+ _a.createUniqueSuffix([entityName, ...fields]);
|
|
33
|
-
};
|
|
34
|
-
NamingHelper.createUniqueConstraintName = (entityName, fields) => {
|
|
35
|
-
return 'unique_'
|
|
36
|
-
+ entityName + '_'
|
|
37
|
-
+ fields.join('_') + '_'
|
|
38
|
-
+ _a.createUniqueSuffix([entityName, ...fields]);
|
|
39
|
-
};
|
|
40
|
-
NamingHelper.createUniqueSuffix = (values) => {
|
|
41
|
-
const uniqueSuffix = (0, sha256_1.default)(JSON.stringify(values)).toString(enc_hex_1.default);
|
|
42
|
-
return uniqueSuffix.slice(0, 6);
|
|
43
|
-
};
|
|
44
|
-
//# sourceMappingURL=NamingHelper.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"NamingHelper.js","sourceRoot":"","sources":["../../../src/model/NamingHelper.ts"],"names":[],"mappings":";;;;;;;AAAA,8DAAqC;AACrC,gEAAsC;AAGtC,MAAa,YAAY;IACjB,MAAM,CAAC,yBAAyB,CAAC,SAAiB,EAAE,MAAc;QACxE,wIAAwI;QACxI,OAAO,GAAG,SAAS,IAAI,MAAM,QAAQ,CAAA;IACtC,CAAC;IAEM,MAAM,CAAC,wCAAwC,CAAC,SAAiB;QACvE,wIAAwI;QACxI,OAAO,GAAG,SAAS,OAAO,CAAA;IAC3B,CAAC;IAEM,MAAM,CAAC,oBAAoB,CAAC,SAAiB,EAAE,UAAkB,EAAE,OAAe,EAAE,QAAgB;QAC1G,OAAO,KAAK;cACT,SAAS,GAAG,GAAG;cACf,UAAU,GAAG,GAAG;cAChB,IAAI,CAAC,kBAAkB,CAAC,CAAC,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAA;IACvE,CAAC;;AAhBF,oCAoCC;;AAlBc,4BAAe,GAAG,CAAC,UAAkB,EAAE,MAAyB,EAAU,EAAE;IACzF,OAAO,MAAM;UACV,UAAU,GAAG,GAAG;UAChB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG;UACtB,EAAI,CAAC,kBAAkB,CAAC,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,CAAC,CAAA;AACpD,CAAC,CAAA;AAEa,uCAA0B,GAAG,CAAC,UAAkB,EAAE,MAAyB,EAAU,EAAE;IACpG,OAAO,SAAS;UACb,UAAU,GAAG,GAAG;UAChB,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,GAAG;UACtB,EAAI,CAAC,kBAAkB,CAAC,CAAC,UAAU,EAAE,GAAG,MAAM,CAAC,CAAC,CAAA;AACpD,CAAC,CAAA;AAEc,+BAAkB,GAAG,CAAC,MAAgB,EAAU,EAAE;IAChE,MAAM,YAAY,GAAG,IAAA,gBAAM,EAAC,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,QAAQ,CAAC,iBAAM,CAAC,CAAA;IACpE,OAAO,YAAY,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAA;AAChC,CAAC,CAAA"}
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
import Sha256 from 'crypto-js/sha256'
|
|
2
|
-
import EncHex from 'crypto-js/enc-hex'
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
export class NamingHelper {
|
|
6
|
-
public static createForeignKeyIndexName(tableName: string, column: string) {
|
|
7
|
-
// format matches https://github.com/salsita/node-pg-migrate/blob/9331f6fda98795e3f3733461f9b71345168b99d8/src/operations/indexes.ts#L21
|
|
8
|
-
return `${tableName}_${column}_index`
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
public static createJunctionTablePrimaryConstraintName(tableName: string) {
|
|
12
|
-
// format matches https://github.com/salsita/node-pg-migrate/blob/9331f6fda98795e3f3733461f9b71345168b99d8/src/operations/tables.ts#L204
|
|
13
|
-
return `${tableName}_pkey`
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
public static createForeignKeyName(fromTable: string, fromColumn: string, toTable: string, toColumn: string): string {
|
|
17
|
-
return 'fk_'
|
|
18
|
-
+ fromTable + '_'
|
|
19
|
-
+ fromColumn + '_'
|
|
20
|
-
+ this.createUniqueSuffix([fromTable, fromColumn, toTable, toColumn])
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
public static createIndexName = (entityName: string, fields: readonly string[]): string => {
|
|
24
|
-
return 'idx_'
|
|
25
|
-
+ entityName + '_'
|
|
26
|
-
+ fields.join('_') + '_'
|
|
27
|
-
+ this.createUniqueSuffix([entityName, ...fields])
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
public static createUniqueConstraintName = (entityName: string, fields: readonly string[]): string => {
|
|
31
|
-
return 'unique_'
|
|
32
|
-
+ entityName + '_'
|
|
33
|
-
+ fields.join('_') + '_'
|
|
34
|
-
+ this.createUniqueSuffix([entityName, ...fields])
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
private static createUniqueSuffix = (values: string[]): string => {
|
|
38
|
-
const uniqueSuffix = Sha256(JSON.stringify(values)).toString(EncHex)
|
|
39
|
-
return uniqueSuffix.slice(0, 6)
|
|
40
|
-
}
|
|
41
|
-
}
|