@contember/schema-utils 2.0.0-alpha.9 → 2.0.0-beta.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.
- package/dist/development/index.cjs +2 -0
- package/dist/development/index.cjs.map +1 -1
- package/dist/development/index.js +2 -0
- package/dist/development/index.js.map +1 -1
- package/dist/development/src/acl/AllowAllPermissionFactory.cjs.map +1 -1
- package/dist/development/src/acl/AllowAllPermissionFactory.js.map +1 -1
- package/dist/development/src/acl/PredicateDefinitionProcessor.cjs.map +1 -1
- package/dist/development/src/acl/PredicateDefinitionProcessor.js.map +1 -1
- package/dist/development/src/acl/schemaUtils.cjs.map +1 -1
- package/dist/development/src/acl/schemaUtils.js.map +1 -1
- package/dist/development/src/dataUtils.cjs.map +1 -1
- package/dist/development/src/dataUtils.js.map +1 -1
- package/dist/development/src/definition-generator/AclDefinitionCodeGenerator.cjs +1 -2
- package/dist/development/src/definition-generator/AclDefinitionCodeGenerator.cjs.map +1 -1
- package/dist/development/src/definition-generator/AclDefinitionCodeGenerator.js +1 -2
- package/dist/development/src/definition-generator/AclDefinitionCodeGenerator.js.map +1 -1
- package/dist/development/src/definition-generator/DefinitionCodeGenerator.cjs +5 -9
- package/dist/development/src/definition-generator/DefinitionCodeGenerator.cjs.map +1 -1
- package/dist/development/src/definition-generator/DefinitionCodeGenerator.js +5 -9
- package/dist/development/src/definition-generator/DefinitionCodeGenerator.js.map +1 -1
- package/dist/development/src/definition-generator/DefinitionNamingConventions.cjs.map +1 -1
- package/dist/development/src/definition-generator/DefinitionNamingConventions.js.map +1 -1
- package/dist/development/src/definition-generator/TsDefinitionGenerator.cjs.map +1 -1
- package/dist/development/src/definition-generator/TsDefinitionGenerator.js.map +1 -1
- package/dist/development/src/lax/LaxSchemaConverter.cjs.map +1 -1
- package/dist/development/src/lax/LaxSchemaConverter.js.map +1 -1
- package/dist/development/src/lax/schema.cjs.map +1 -1
- package/dist/development/src/lax/schema.js.map +1 -1
- package/dist/development/src/model/NamingConventions.cjs.map +1 -1
- package/dist/development/src/model/NamingConventions.js.map +1 -1
- package/dist/development/src/model/modelUtils.cjs.map +1 -1
- package/dist/development/src/model/modelUtils.js.map +1 -1
- package/dist/development/src/model/resolveDefaultColumnType.cjs.map +1 -1
- package/dist/development/src/model/resolveDefaultColumnType.js.map +1 -1
- package/dist/development/src/schemaChecksum.cjs +9 -0
- package/dist/development/src/schemaChecksum.cjs.map +1 -0
- package/dist/development/src/schemaChecksum.js +9 -0
- package/dist/development/src/schemaChecksum.js.map +1 -0
- package/dist/development/src/schemaFilter.cjs.map +1 -1
- package/dist/development/src/schemaFilter.js.map +1 -1
- package/dist/development/src/schemaNormalizer.cjs.map +1 -1
- package/dist/development/src/schemaNormalizer.js.map +1 -1
- package/dist/development/src/type-schema/acl.cjs.map +1 -1
- package/dist/development/src/type-schema/acl.js.map +1 -1
- package/dist/development/src/type-schema/actions.cjs.map +1 -1
- package/dist/development/src/type-schema/actions.js.map +1 -1
- package/dist/development/src/type-schema/condition.cjs.map +1 -1
- package/dist/development/src/type-schema/condition.js.map +1 -1
- package/dist/development/src/type-schema/model.cjs +6 -1
- package/dist/development/src/type-schema/model.cjs.map +1 -1
- package/dist/development/src/type-schema/model.js +7 -1
- package/dist/development/src/type-schema/model.js.map +1 -1
- package/dist/development/src/type-schema/settings.cjs +1 -0
- package/dist/development/src/type-schema/settings.cjs.map +1 -1
- package/dist/development/src/type-schema/settings.js +1 -0
- package/dist/development/src/type-schema/settings.js.map +1 -1
- package/dist/development/src/type-schema/validation.cjs.map +1 -1
- package/dist/development/src/type-schema/validation.js.map +1 -1
- package/dist/development/src/type-schema/where.cjs.map +1 -1
- package/dist/development/src/type-schema/where.js.map +1 -1
- package/dist/development/src/utils/deepCompare.cjs.map +1 -1
- package/dist/development/src/utils/deepCompare.js.map +1 -1
- package/dist/development/src/utils/printJsValue.cjs.map +1 -1
- package/dist/development/src/utils/printJsValue.js.map +1 -1
- package/dist/development/src/validation/AclValidator.cjs.map +1 -1
- package/dist/development/src/validation/AclValidator.js.map +1 -1
- package/dist/development/src/validation/ActionsValidator.cjs.map +1 -1
- package/dist/development/src/validation/ActionsValidator.js.map +1 -1
- package/dist/development/src/validation/MembershipResolver.cjs.map +1 -1
- package/dist/development/src/validation/MembershipResolver.js.map +1 -1
- package/dist/development/src/validation/ModelValidator.cjs.map +1 -1
- package/dist/development/src/validation/ModelValidator.js.map +1 -1
- package/dist/development/src/validation/SchemaValidator.cjs.map +1 -1
- package/dist/development/src/validation/SchemaValidator.js.map +1 -1
- package/dist/development/src/validation/ValidationValidator.cjs.map +1 -1
- package/dist/development/src/validation/ValidationValidator.js.map +1 -1
- package/dist/development/src/validation/errors.cjs.map +1 -1
- package/dist/development/src/validation/errors.js.map +1 -1
- package/dist/production/index.cjs +2 -0
- package/dist/production/index.cjs.map +1 -1
- package/dist/production/index.js +2 -0
- package/dist/production/index.js.map +1 -1
- package/dist/production/src/acl/AllowAllPermissionFactory.cjs.map +1 -1
- package/dist/production/src/acl/AllowAllPermissionFactory.js.map +1 -1
- package/dist/production/src/acl/PredicateDefinitionProcessor.cjs.map +1 -1
- package/dist/production/src/acl/PredicateDefinitionProcessor.js.map +1 -1
- package/dist/production/src/acl/schemaUtils.cjs.map +1 -1
- package/dist/production/src/acl/schemaUtils.js.map +1 -1
- package/dist/production/src/dataUtils.cjs.map +1 -1
- package/dist/production/src/dataUtils.js.map +1 -1
- package/dist/production/src/definition-generator/AclDefinitionCodeGenerator.cjs +1 -2
- package/dist/production/src/definition-generator/AclDefinitionCodeGenerator.cjs.map +1 -1
- package/dist/production/src/definition-generator/AclDefinitionCodeGenerator.js +1 -2
- package/dist/production/src/definition-generator/AclDefinitionCodeGenerator.js.map +1 -1
- package/dist/production/src/definition-generator/DefinitionCodeGenerator.cjs +5 -9
- package/dist/production/src/definition-generator/DefinitionCodeGenerator.cjs.map +1 -1
- package/dist/production/src/definition-generator/DefinitionCodeGenerator.js +5 -9
- package/dist/production/src/definition-generator/DefinitionCodeGenerator.js.map +1 -1
- package/dist/production/src/definition-generator/DefinitionNamingConventions.cjs.map +1 -1
- package/dist/production/src/definition-generator/DefinitionNamingConventions.js.map +1 -1
- package/dist/production/src/definition-generator/TsDefinitionGenerator.cjs.map +1 -1
- package/dist/production/src/definition-generator/TsDefinitionGenerator.js.map +1 -1
- package/dist/production/src/lax/LaxSchemaConverter.cjs.map +1 -1
- package/dist/production/src/lax/LaxSchemaConverter.js.map +1 -1
- package/dist/production/src/lax/schema.cjs.map +1 -1
- package/dist/production/src/lax/schema.js.map +1 -1
- package/dist/production/src/model/NamingConventions.cjs.map +1 -1
- package/dist/production/src/model/NamingConventions.js.map +1 -1
- package/dist/production/src/model/modelUtils.cjs.map +1 -1
- package/dist/production/src/model/modelUtils.js.map +1 -1
- package/dist/production/src/model/resolveDefaultColumnType.cjs.map +1 -1
- package/dist/production/src/model/resolveDefaultColumnType.js.map +1 -1
- package/dist/production/src/schemaChecksum.cjs +9 -0
- package/dist/production/src/schemaChecksum.cjs.map +1 -0
- package/dist/production/src/schemaChecksum.js +9 -0
- package/dist/production/src/schemaChecksum.js.map +1 -0
- package/dist/production/src/schemaFilter.cjs.map +1 -1
- package/dist/production/src/schemaFilter.js.map +1 -1
- package/dist/production/src/schemaNormalizer.cjs.map +1 -1
- package/dist/production/src/schemaNormalizer.js.map +1 -1
- package/dist/production/src/type-schema/acl.cjs.map +1 -1
- package/dist/production/src/type-schema/acl.js.map +1 -1
- package/dist/production/src/type-schema/actions.cjs.map +1 -1
- package/dist/production/src/type-schema/actions.js.map +1 -1
- package/dist/production/src/type-schema/condition.cjs.map +1 -1
- package/dist/production/src/type-schema/condition.js.map +1 -1
- package/dist/production/src/type-schema/model.cjs +6 -1
- package/dist/production/src/type-schema/model.cjs.map +1 -1
- package/dist/production/src/type-schema/model.js +7 -1
- package/dist/production/src/type-schema/model.js.map +1 -1
- package/dist/production/src/type-schema/settings.cjs +1 -0
- package/dist/production/src/type-schema/settings.cjs.map +1 -1
- package/dist/production/src/type-schema/settings.js +1 -0
- package/dist/production/src/type-schema/settings.js.map +1 -1
- package/dist/production/src/type-schema/validation.cjs.map +1 -1
- package/dist/production/src/type-schema/validation.js.map +1 -1
- package/dist/production/src/type-schema/where.cjs.map +1 -1
- package/dist/production/src/type-schema/where.js.map +1 -1
- package/dist/production/src/utils/deepCompare.cjs.map +1 -1
- package/dist/production/src/utils/deepCompare.js.map +1 -1
- package/dist/production/src/utils/printJsValue.cjs.map +1 -1
- package/dist/production/src/utils/printJsValue.js.map +1 -1
- package/dist/production/src/validation/AclValidator.cjs.map +1 -1
- package/dist/production/src/validation/AclValidator.js.map +1 -1
- package/dist/production/src/validation/ActionsValidator.cjs.map +1 -1
- package/dist/production/src/validation/ActionsValidator.js.map +1 -1
- package/dist/production/src/validation/MembershipResolver.cjs.map +1 -1
- package/dist/production/src/validation/MembershipResolver.js.map +1 -1
- package/dist/production/src/validation/ModelValidator.cjs.map +1 -1
- package/dist/production/src/validation/ModelValidator.js.map +1 -1
- package/dist/production/src/validation/SchemaValidator.cjs.map +1 -1
- package/dist/production/src/validation/SchemaValidator.js.map +1 -1
- package/dist/production/src/validation/ValidationValidator.cjs.map +1 -1
- package/dist/production/src/validation/ValidationValidator.js.map +1 -1
- package/dist/production/src/validation/errors.cjs.map +1 -1
- package/dist/production/src/validation/errors.js.map +1 -1
- package/dist/tests/cases/unit/modelSchema.test.d.ts +2 -0
- package/dist/tests/cases/unit/modelSchema.test.d.ts.map +1 -0
- package/dist/tests/cases/unit/schemas/acl.d.ts +7 -7
- package/dist/tests/cases/unit/schemas/acl.d.ts.map +1 -1
- package/dist/tests/cases/unit/schemas/basic.d.ts +1 -1
- package/dist/tests/cases/unit/schemas/basic.d.ts.map +1 -1
- package/dist/tests/cases/unit/schemas/complex.d.ts +12 -0
- package/dist/tests/cases/unit/schemas/complex.d.ts.map +1 -0
- package/dist/tests/cases/unit/schemas/enum.d.ts +3 -3
- package/dist/tests/cases/unit/schemas/enum.d.ts.map +1 -1
- package/dist/tests/cases/unit/schemas/relations.d.ts +7 -7
- package/dist/tests/cases/unit/schemas/relations.d.ts.map +1 -1
- package/dist/tests/cases/unit/schemas/unique.d.ts +1 -1
- package/dist/tests/cases/unit/schemas/unique.d.ts.map +1 -1
- package/dist/tests/cases/unit/schemas/view.d.ts +4 -0
- package/dist/tests/cases/unit/schemas/view.d.ts.map +1 -0
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/dist/types/dataUtils.d.ts +1 -1
- package/dist/types/dataUtils.d.ts.map +1 -1
- package/dist/types/definition-generator/DefinitionCodeGenerator.d.ts.map +1 -1
- package/dist/types/index.d.ts +1 -0
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/schemaChecksum.d.ts +3 -0
- package/dist/types/schemaChecksum.d.ts.map +1 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dist/types/type-schema/model.d.ts.map +1 -1
- package/dist/types/type-schema/settings.d.ts +20 -28
- package/dist/types/type-schema/settings.d.ts.map +1 -1
- package/package.json +6 -6
- package/src/dataUtils.ts +2 -2
- package/src/definition-generator/AclDefinitionCodeGenerator.ts +1 -1
- package/src/definition-generator/DefinitionCodeGenerator.ts +10 -18
- package/src/index.ts +1 -0
- package/src/schemaChecksum.ts +12 -0
- package/src/type-schema/model.ts +7 -1
- package/src/type-schema/settings.ts +1 -0
- package/tests/cases/unit/conditionSchema.test.ts +8 -8
- package/tests/cases/unit/deepCompare.test.ts +4 -4
- package/tests/cases/unit/laxSchemaConverter.test.ts +4 -4
- package/tests/cases/unit/membershipResolver.test.ts +17 -17
- package/tests/cases/unit/modelSchema.test.ts +88 -0
- package/tests/cases/unit/modelValidator.test.ts +3 -3
- package/tests/cases/unit/printJsvalue.test.ts +49 -61
- package/tests/cases/unit/schemas/acl.ts +7 -9
- package/tests/cases/unit/schemas/complex.ts +38 -0
- package/tests/cases/unit/schemas/view.ts +6 -0
- package/tests/cases/unit/tsDefinitionGenerator.test.ts +5 -1
- package/tests/cases/unit/whereSchema.test.ts +10 -10
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { Schema } from '@contember/schema'
|
|
2
|
+
import crypto from 'node:crypto'
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
export const calculateSchemaChecksum = (schema: Schema): string => {
|
|
6
|
+
const jsonSchema = JSON.stringify(schema)
|
|
7
|
+
|
|
8
|
+
return crypto
|
|
9
|
+
.createHash('md5')
|
|
10
|
+
.update(jsonSchema)
|
|
11
|
+
.digest('hex')
|
|
12
|
+
}
|
package/src/type-schema/model.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import * as Typesafe from '@contember/typesafe'
|
|
2
2
|
import { Model } from '@contember/schema'
|
|
3
|
+
import { ParseError } from '@contember/typesafe'
|
|
3
4
|
|
|
4
5
|
const orderBySchema = Typesafe.array(Typesafe.object({
|
|
5
6
|
path: Typesafe.array(Typesafe.string),
|
|
@@ -118,7 +119,12 @@ const columnSchema = Typesafe.intersection(
|
|
|
118
119
|
Typesafe.object({
|
|
119
120
|
name: Typesafe.string,
|
|
120
121
|
columnName: Typesafe.string,
|
|
121
|
-
columnType: Typesafe.string,
|
|
122
|
+
columnType: Typesafe.transform(Typesafe.string, (it, raw, path) => {
|
|
123
|
+
if (!it.replaceAll(/\s+/g, '').match(/^[\w_]+(?:\(\w+(?:,\w+)*\))?\w*(?:"[^"]+")?(\[])*$/)) {
|
|
124
|
+
throw ParseError.format(it, path, 'valid column type')
|
|
125
|
+
}
|
|
126
|
+
return it
|
|
127
|
+
}),
|
|
122
128
|
nullable: Typesafe.boolean,
|
|
123
129
|
type: Typesafe.enumeration<Model.ColumnType>(...Object.values(Model.ColumnType)),
|
|
124
130
|
}),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { expect, test, describe } from 'bun:test'
|
|
2
2
|
import { conditionSchema } from '../../../src/type-schema'
|
|
3
3
|
import { Model } from '@contember/schema'
|
|
4
4
|
|
|
@@ -7,28 +7,28 @@ describe('condition schema', () => {
|
|
|
7
7
|
const condition = {
|
|
8
8
|
and: [{ isNull: true }, { not: { isNull: false } }],
|
|
9
9
|
}
|
|
10
|
-
|
|
10
|
+
expect(conditionSchema()(condition)).toStrictEqual(condition)
|
|
11
11
|
})
|
|
12
12
|
|
|
13
13
|
test('accept string-only condition for unknown type', () => {
|
|
14
14
|
const condition = {
|
|
15
15
|
containsCI: 'foo',
|
|
16
16
|
}
|
|
17
|
-
|
|
17
|
+
expect(conditionSchema()(condition)).toStrictEqual(condition)
|
|
18
18
|
})
|
|
19
19
|
|
|
20
20
|
test('accept string-only condition for string type', () => {
|
|
21
21
|
const condition = {
|
|
22
22
|
containsCI: 'foo',
|
|
23
23
|
}
|
|
24
|
-
|
|
24
|
+
expect(conditionSchema(Model.ColumnType.String)(condition)).toStrictEqual(condition)
|
|
25
25
|
})
|
|
26
26
|
|
|
27
27
|
test('reject string-only condition for int type', () => {
|
|
28
28
|
const condition = {
|
|
29
29
|
containsCI: 'foo',
|
|
30
30
|
}
|
|
31
|
-
|
|
31
|
+
expect(() => conditionSchema(Model.ColumnType.Int)(condition)).toThrow('value at root: extra property containsCI found')
|
|
32
32
|
})
|
|
33
33
|
|
|
34
34
|
|
|
@@ -36,20 +36,20 @@ describe('condition schema', () => {
|
|
|
36
36
|
const condition = {
|
|
37
37
|
eq: 'foo',
|
|
38
38
|
}
|
|
39
|
-
|
|
39
|
+
expect(conditionSchema()(condition)).toStrictEqual(condition)
|
|
40
40
|
})
|
|
41
41
|
|
|
42
42
|
test('accept non-json condition for string type', () => {
|
|
43
43
|
const condition = {
|
|
44
44
|
eq: 'foo',
|
|
45
45
|
}
|
|
46
|
-
|
|
46
|
+
expect(conditionSchema(Model.ColumnType.String)(condition)).toStrictEqual(condition)
|
|
47
47
|
})
|
|
48
48
|
|
|
49
49
|
test('reject non-json condition for json type', () => {
|
|
50
50
|
const condition = {
|
|
51
51
|
eq: 'foo',
|
|
52
52
|
}
|
|
53
|
-
|
|
53
|
+
expect(() => conditionSchema(Model.ColumnType.Json)(condition)).toThrow('value at root: extra property eq found')
|
|
54
54
|
})
|
|
55
55
|
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { expect, describe, test } from 'bun:test'
|
|
2
2
|
import { compareArraysIgnoreOrder } from '../../../src'
|
|
3
3
|
|
|
4
4
|
describe('deep compare', () => {
|
|
@@ -10,7 +10,7 @@ describe('deep compare', () => {
|
|
|
10
10
|
{ lorem: 'ipsum' },
|
|
11
11
|
{ foo: 'bar' },
|
|
12
12
|
], [])
|
|
13
|
-
|
|
13
|
+
expect(actual).toStrictEqual([])
|
|
14
14
|
})
|
|
15
15
|
|
|
16
16
|
test('compare array ignore order - missing in A', () => {
|
|
@@ -21,7 +21,7 @@ describe('deep compare', () => {
|
|
|
21
21
|
{ lorem: 'ipsum' },
|
|
22
22
|
{ foo: 'bar' },
|
|
23
23
|
], [])
|
|
24
|
-
|
|
24
|
+
expect(actual).toStrictEqual([{
|
|
25
25
|
path: [],
|
|
26
26
|
message: 'Array item: {"lorem":"ipsum"} not found in [{"foo":"bar"}]',
|
|
27
27
|
}])
|
|
@@ -35,7 +35,7 @@ describe('deep compare', () => {
|
|
|
35
35
|
{ lorem: 'ipsum' },
|
|
36
36
|
{ lorem: 'ipsum' },
|
|
37
37
|
], [])
|
|
38
|
-
|
|
38
|
+
expect(actual).toStrictEqual([{
|
|
39
39
|
path: [],
|
|
40
40
|
message: 'Array item: {"foo":"bar"} not found in [{"lorem":"ipsum"},{"lorem":"ipsum"}]',
|
|
41
41
|
}],
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { expect, test } from '
|
|
1
|
+
import { expect, test } from 'bun:test'
|
|
2
2
|
import { LaxSchemaConverter } from '../../../src'
|
|
3
3
|
|
|
4
4
|
test('lax schema converter basic', () => {
|
|
@@ -54,7 +54,7 @@ test('lax schema converter one-has-many', () => {
|
|
|
54
54
|
},
|
|
55
55
|
},
|
|
56
56
|
)
|
|
57
|
-
expect(converter2.convert()).
|
|
57
|
+
expect(converter2.convert()).toStrictEqual(schema1)
|
|
58
58
|
})
|
|
59
59
|
|
|
60
60
|
|
|
@@ -93,7 +93,7 @@ test('lax schema converter many-has-many', () => {
|
|
|
93
93
|
},
|
|
94
94
|
},
|
|
95
95
|
)
|
|
96
|
-
expect(converter2.convert()).
|
|
96
|
+
expect(converter2.convert()).toStrictEqual(schema1)
|
|
97
97
|
})
|
|
98
98
|
|
|
99
99
|
|
|
@@ -132,6 +132,6 @@ test('lax schema converter one-has-one', () => {
|
|
|
132
132
|
},
|
|
133
133
|
},
|
|
134
134
|
)
|
|
135
|
-
expect(converter2.convert()).
|
|
135
|
+
expect(converter2.convert()).toStrictEqual(schema1)
|
|
136
136
|
})
|
|
137
137
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { expect, test } from 'bun:test'
|
|
2
2
|
import { MembershipResolver, MembershipValidationErrorType } from '../../../src'
|
|
3
3
|
import { Acl } from '@contember/schema'
|
|
4
4
|
|
|
@@ -17,8 +17,8 @@ test('read membership with entity variable', () => {
|
|
|
17
17
|
}, [
|
|
18
18
|
{ role: 'editor', variables: [{ name: 'localeID', values: [id1] }] },
|
|
19
19
|
], MembershipResolver.UnknownIdentity)
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
expect(result.errors).toStrictEqual([])
|
|
21
|
+
expect(result.memberships).toStrictEqual([
|
|
22
22
|
{ role: 'editor', variables: [{ name: 'localeID', condition: { in: [id1] } }] },
|
|
23
23
|
])
|
|
24
24
|
})
|
|
@@ -37,13 +37,13 @@ test('read fails when variable is not provided', () => {
|
|
|
37
37
|
}, [
|
|
38
38
|
{ role: 'editor', variables: [] },
|
|
39
39
|
], MembershipResolver.UnknownIdentity)
|
|
40
|
-
|
|
40
|
+
expect(result.errors).toEqual([{
|
|
41
41
|
error: MembershipValidationErrorType.VARIABLE_EMPTY,
|
|
42
42
|
role: 'editor',
|
|
43
43
|
variable: 'localeID',
|
|
44
44
|
}])
|
|
45
45
|
|
|
46
|
-
|
|
46
|
+
expect(result.memberships).toStrictEqual([
|
|
47
47
|
{ role: 'editor', variables: [{ name: 'localeID', condition: { never: true } }] },
|
|
48
48
|
])
|
|
49
49
|
})
|
|
@@ -64,8 +64,8 @@ test('read membership with predefined variable', () => {
|
|
|
64
64
|
], {
|
|
65
65
|
identityId: id1,
|
|
66
66
|
})
|
|
67
|
-
|
|
68
|
-
|
|
67
|
+
expect(result.errors).toStrictEqual([])
|
|
68
|
+
expect(result.memberships).toStrictEqual([
|
|
69
69
|
{ role: 'editor', variables: [{ name: 'self', condition: { in: [id1] } }] },
|
|
70
70
|
])
|
|
71
71
|
})
|
|
@@ -84,8 +84,8 @@ test('read membership with condition variable', () => {
|
|
|
84
84
|
}, [
|
|
85
85
|
{ role: 'editor', variables: [{ name: 'cond', values: [JSON.stringify({ eq: 'foo' })] }] },
|
|
86
86
|
], MembershipResolver.UnknownIdentity)
|
|
87
|
-
|
|
88
|
-
|
|
87
|
+
expect(result.errors).toStrictEqual([])
|
|
88
|
+
expect(result.memberships).toStrictEqual([
|
|
89
89
|
{ role: 'editor', variables: [{ name: 'cond', condition: { eq: 'foo' } }] },
|
|
90
90
|
])
|
|
91
91
|
})
|
|
@@ -105,13 +105,13 @@ test('fails on invalid condition', () => {
|
|
|
105
105
|
{ role: 'editor', variables: [{ name: 'cond', values: [JSON.stringify('abcd')] }] },
|
|
106
106
|
], MembershipResolver.UnknownIdentity)
|
|
107
107
|
|
|
108
|
-
|
|
108
|
+
expect(result.errors).toEqual([{
|
|
109
109
|
error: MembershipValidationErrorType.VARIABLE_INVALID,
|
|
110
110
|
role: 'editor',
|
|
111
111
|
variable: 'cond',
|
|
112
112
|
}])
|
|
113
113
|
|
|
114
|
-
|
|
114
|
+
expect(result.memberships).toStrictEqual([
|
|
115
115
|
{ role: 'editor', variables: [{ name: 'cond', condition: { never: true } }] },
|
|
116
116
|
])
|
|
117
117
|
})
|
|
@@ -127,13 +127,13 @@ test('fails on undefined role', () => {
|
|
|
127
127
|
identityId: id1,
|
|
128
128
|
})
|
|
129
129
|
|
|
130
|
-
|
|
130
|
+
expect(result.errors).toEqual([{
|
|
131
131
|
error: MembershipValidationErrorType.ROLE_NOT_FOUND,
|
|
132
132
|
role: 'editor',
|
|
133
133
|
variable: undefined,
|
|
134
134
|
}])
|
|
135
135
|
|
|
136
|
-
|
|
136
|
+
expect(result.memberships).toStrictEqual([])
|
|
137
137
|
})
|
|
138
138
|
|
|
139
139
|
test('fails on undefined variable', () => {
|
|
@@ -149,13 +149,13 @@ test('fails on undefined variable', () => {
|
|
|
149
149
|
{ role: 'editor', variables: [{ name: 'cond', values: [JSON.stringify('abcd')] }] },
|
|
150
150
|
], MembershipResolver.UnknownIdentity)
|
|
151
151
|
|
|
152
|
-
|
|
152
|
+
expect(result.errors).toEqual([{
|
|
153
153
|
error: MembershipValidationErrorType.VARIABLE_NOT_FOUND,
|
|
154
154
|
role: 'editor',
|
|
155
155
|
variable: 'cond',
|
|
156
156
|
}])
|
|
157
157
|
|
|
158
|
-
|
|
158
|
+
expect(result.memberships).toStrictEqual([
|
|
159
159
|
{ role: 'editor', variables: [] },
|
|
160
160
|
])
|
|
161
161
|
})
|
|
@@ -175,9 +175,9 @@ test('use fallback value', () => {
|
|
|
175
175
|
}, [
|
|
176
176
|
{ role: 'editor', variables: [] },
|
|
177
177
|
], MembershipResolver.UnknownIdentity)
|
|
178
|
-
|
|
178
|
+
expect(result.errors).toStrictEqual([])
|
|
179
179
|
|
|
180
|
-
|
|
180
|
+
expect(result.memberships).toStrictEqual([
|
|
181
181
|
{ role: 'editor', variables: [{ name: 'localeID', condition: { always: true } }] },
|
|
182
182
|
])
|
|
183
183
|
})
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { expect, describe, test } from 'bun:test'
|
|
2
|
+
import { modelSchema } from '../../../src/type-schema'
|
|
3
|
+
import { Model } from '@contember/schema'
|
|
4
|
+
|
|
5
|
+
describe('model schema', () => {
|
|
6
|
+
const validDataTypes = [
|
|
7
|
+
'integer',
|
|
8
|
+
'double precision',
|
|
9
|
+
'character varying(255)',
|
|
10
|
+
'numeric(10, 2)',
|
|
11
|
+
'timestamp(3) with time zone',
|
|
12
|
+
'geometry(Point, 4326)',
|
|
13
|
+
'character(10)[]',
|
|
14
|
+
'bit varying(5)',
|
|
15
|
+
'VARCHAR(255) COLLATE "de_DE"',
|
|
16
|
+
]
|
|
17
|
+
|
|
18
|
+
// Array of invalid PostgreSQL data type examples
|
|
19
|
+
const invalidDataTypes = [
|
|
20
|
+
'varchar(255', // Missing closing parenthesis
|
|
21
|
+
'character(10))', // Extra closing parenthesis
|
|
22
|
+
'numeric(,2)', // Missing first parameter
|
|
23
|
+
'geometry(Point,4326))', // Extra closing parenthesis
|
|
24
|
+
'VARCHAR(255) COLLATE "de_DE" (extra text)', // Extra text outside the valid pattern
|
|
25
|
+
'VARCHAR(255) COLLATE "de_DE', // Missing closing quote
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
for (const dataType of validDataTypes) {
|
|
29
|
+
test(`accept valid data type ${dataType}`, () => {
|
|
30
|
+
const column: Model.AnyColumn = {
|
|
31
|
+
type: Model.ColumnType.String,
|
|
32
|
+
columnName: 'column',
|
|
33
|
+
name: 'column',
|
|
34
|
+
columnType: dataType,
|
|
35
|
+
nullable: false,
|
|
36
|
+
}
|
|
37
|
+
const model: Model.Schema = {
|
|
38
|
+
entities: {
|
|
39
|
+
Test: {
|
|
40
|
+
tableName: 'test',
|
|
41
|
+
primary: 'id',
|
|
42
|
+
primaryColumn: 'id',
|
|
43
|
+
unique: [],
|
|
44
|
+
indexes: [],
|
|
45
|
+
eventLog: { enabled: false },
|
|
46
|
+
name: 'Test',
|
|
47
|
+
fields: {
|
|
48
|
+
column,
|
|
49
|
+
},
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
enums: {},
|
|
53
|
+
}
|
|
54
|
+
expect(modelSchema(model)).toStrictEqual(model)
|
|
55
|
+
})
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
for (const dataType of invalidDataTypes) {
|
|
59
|
+
test(`reject invalid data type ${dataType}`, () => {
|
|
60
|
+
const column: Model.AnyColumn = {
|
|
61
|
+
type: Model.ColumnType.String,
|
|
62
|
+
columnName: 'column',
|
|
63
|
+
name: 'column',
|
|
64
|
+
columnType: dataType,
|
|
65
|
+
nullable: false,
|
|
66
|
+
}
|
|
67
|
+
const model: Model.Schema = {
|
|
68
|
+
entities: {
|
|
69
|
+
Test: {
|
|
70
|
+
tableName: 'test',
|
|
71
|
+
primary: 'id',
|
|
72
|
+
primaryColumn: 'id',
|
|
73
|
+
unique: [],
|
|
74
|
+
indexes: [],
|
|
75
|
+
eventLog: { enabled: false },
|
|
76
|
+
name: 'Test',
|
|
77
|
+
fields: {
|
|
78
|
+
column,
|
|
79
|
+
},
|
|
80
|
+
},
|
|
81
|
+
},
|
|
82
|
+
enums: {},
|
|
83
|
+
}
|
|
84
|
+
expect(() => modelSchema(model)).toThrow(`value at path /entities/Test/fields/column: all variants of union has failed:
|
|
85
|
+
value at path /entities/Test/fields/column/columnType: must be valid column type, "${dataType.replaceAll('"', '\\"')}" given`)
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
})
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { expect, test } from 'bun:test'
|
|
2
2
|
import { Model } from '@contember/schema'
|
|
3
3
|
import { ModelValidator } from '../../../src'
|
|
4
4
|
import { c, createSchema } from '@contember/schema-definition'
|
|
@@ -64,7 +64,7 @@ test('"meta" collision', () => {
|
|
|
64
64
|
},
|
|
65
65
|
}
|
|
66
66
|
const validator = new ModelValidator(model)
|
|
67
|
-
|
|
67
|
+
expect(validator.validate()).toStrictEqual([
|
|
68
68
|
{
|
|
69
69
|
code: 'MODEL_NAME_COLLISION',
|
|
70
70
|
message: 'entity FooMeta collides with entity Foo, because a GraphQL type with "Meta" suffix is created for every entity',
|
|
@@ -83,7 +83,7 @@ namespace ColumnNameCollision {
|
|
|
83
83
|
test('column name collision', () => {
|
|
84
84
|
const schema = createSchema(ColumnNameCollision)
|
|
85
85
|
const validator = new ModelValidator(schema.model)
|
|
86
|
-
|
|
86
|
+
expect(validator.validate()).toStrictEqual([
|
|
87
87
|
{
|
|
88
88
|
code: 'MODEL_NAME_COLLISION',
|
|
89
89
|
message: 'Column name "rel_id" on field "relId" collides with a column name on field "rel".',
|
|
@@ -1,100 +1,88 @@
|
|
|
1
|
-
import { beforeAll, describe, expect, test } from '
|
|
1
|
+
import { beforeAll, describe, expect, test } from 'bun:test'
|
|
2
2
|
import { printJsValue } from '../../../src/utils/printJsValue'
|
|
3
3
|
|
|
4
|
-
beforeAll(() => {
|
|
5
|
-
expect.addSnapshotSerializer({
|
|
6
|
-
test: val => typeof val === 'string',
|
|
7
|
-
print: val => String(val),
|
|
8
|
-
})
|
|
9
|
-
})
|
|
10
|
-
|
|
11
4
|
describe('printJsValue', () => {
|
|
12
5
|
test('string', () => {
|
|
13
|
-
expect(printJsValue('foobar')).
|
|
6
|
+
expect(printJsValue('foobar')).toEqual(`'foobar'`)
|
|
14
7
|
})
|
|
15
8
|
|
|
16
9
|
test('string escape', () => {
|
|
17
|
-
expect(printJsValue('foo\'bar')).
|
|
10
|
+
expect(printJsValue('foo\'bar')).toEqual(`'foo\\'bar'`)
|
|
18
11
|
})
|
|
19
12
|
|
|
20
13
|
test('number', () => {
|
|
21
|
-
expect(printJsValue(11)).
|
|
14
|
+
expect(printJsValue(11)).toEqual(`11`)
|
|
22
15
|
})
|
|
23
16
|
|
|
24
17
|
test('boolean', () => {
|
|
25
|
-
expect(printJsValue(true)).
|
|
18
|
+
expect(printJsValue(true)).toEqual(`true`)
|
|
26
19
|
})
|
|
27
20
|
|
|
28
21
|
test('null', () => {
|
|
29
|
-
expect(printJsValue(null)).
|
|
22
|
+
expect(printJsValue(null)).toEqual(`null`)
|
|
30
23
|
})
|
|
31
24
|
|
|
32
25
|
test('inline array', () => {
|
|
33
|
-
expect(printJsValue([1, 2, 3])).
|
|
26
|
+
expect(printJsValue([1, 2, 3])).toEqual(`[1, 2, 3]`)
|
|
34
27
|
})
|
|
35
28
|
test('block array', () => {
|
|
36
|
-
expect(printJsValue([1, 2, 3], () => true)).
|
|
37
|
-
[
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
`)
|
|
29
|
+
expect(printJsValue([1, 2, 3], () => true)).toEqual(
|
|
30
|
+
`[
|
|
31
|
+
1,
|
|
32
|
+
2,
|
|
33
|
+
3,
|
|
34
|
+
]`)
|
|
43
35
|
})
|
|
44
36
|
|
|
45
37
|
test('inline object', () => {
|
|
46
|
-
expect(printJsValue({ a: 1, b: 2 })).
|
|
38
|
+
expect(printJsValue({ a: 1, b: 2 })).toEqual('{ a: 1, b: 2 }')
|
|
47
39
|
})
|
|
48
40
|
|
|
49
41
|
test('block object', () => {
|
|
50
|
-
expect(printJsValue({ a: 1, b: 2 }, () => true)).
|
|
51
|
-
{
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
`)
|
|
42
|
+
expect(printJsValue({ a: 1, b: 2 }, () => true)).toEqual(
|
|
43
|
+
`{
|
|
44
|
+
a: 1,
|
|
45
|
+
b: 2,
|
|
46
|
+
}`)
|
|
56
47
|
})
|
|
57
48
|
|
|
58
49
|
test('nested block object', () => {
|
|
59
|
-
expect(printJsValue({ a: 1, b: { c: { d: { e: 1 } } } }, () => true)).
|
|
60
|
-
{
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
`)
|
|
50
|
+
expect(printJsValue({ a: 1, b: { c: { d: { e: 1 } } } }, () => true)).toEqual(
|
|
51
|
+
`{
|
|
52
|
+
a: 1,
|
|
53
|
+
b: {
|
|
54
|
+
c: {
|
|
55
|
+
d: {
|
|
56
|
+
e: 1,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
}`)
|
|
71
61
|
})
|
|
72
62
|
|
|
73
63
|
|
|
74
64
|
test('one level nested block object', () => {
|
|
75
|
-
expect(printJsValue({ a: 1, b: { c: { d: { e: 1 } } } }, (_, path) => path.length === 0)).
|
|
76
|
-
{
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
`)
|
|
65
|
+
expect(printJsValue({ a: 1, b: { c: { d: { e: 1 } } } }, (_, path) => path.length === 0)).toEqual(
|
|
66
|
+
`{
|
|
67
|
+
a: 1,
|
|
68
|
+
b: { c: { d: { e: 1 } } },
|
|
69
|
+
}`)
|
|
81
70
|
})
|
|
82
71
|
|
|
83
72
|
test('nested block object and arr', () => {
|
|
84
|
-
expect(printJsValue({ a: 1, b: [2, { c: 4 }, [5, 6]] }, () => true)).
|
|
85
|
-
{
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
`)
|
|
73
|
+
expect(printJsValue({ a: 1, b: [2, { c: 4 }, [5, 6]] }, () => true)).toEqual(
|
|
74
|
+
`{
|
|
75
|
+
a: 1,
|
|
76
|
+
b: [
|
|
77
|
+
2,
|
|
78
|
+
{
|
|
79
|
+
c: 4,
|
|
80
|
+
},
|
|
81
|
+
[
|
|
82
|
+
5,
|
|
83
|
+
6,
|
|
84
|
+
],
|
|
85
|
+
],
|
|
86
|
+
}`)
|
|
99
87
|
})
|
|
100
88
|
})
|
|
@@ -1,32 +1,30 @@
|
|
|
1
1
|
import { c } from '@contember/schema-definition'
|
|
2
2
|
|
|
3
|
-
export const readerRole = c.createRole('reader', { stages: '*' })
|
|
4
|
-
|
|
5
3
|
export const editorRole = c.createRole('editor', { stages: '*' })
|
|
6
4
|
|
|
7
|
-
export const
|
|
5
|
+
export const readerRole = c.createRole('reader', { stages: '*' })
|
|
8
6
|
|
|
7
|
+
export const categoryEditorVariable = c.createEntityVariable('category', 'Category', editorRole)
|
|
9
8
|
|
|
10
|
-
@c.Allow(readerRole, {
|
|
11
|
-
read: true,
|
|
12
|
-
})
|
|
13
9
|
@c.Allow(editorRole, {
|
|
14
10
|
when: { category: { id: categoryEditorVariable } },
|
|
15
11
|
read: true,
|
|
16
12
|
create: ['title', 'category'],
|
|
17
13
|
update: ['title', 'category'],
|
|
18
14
|
})
|
|
15
|
+
@c.Allow(readerRole, {
|
|
16
|
+
read: true,
|
|
17
|
+
})
|
|
19
18
|
export class Article {
|
|
20
19
|
title = c.stringColumn()
|
|
21
20
|
deletedAt = c.dateTimeColumn()
|
|
22
21
|
category = c.manyHasOne(Category)
|
|
23
22
|
}
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
@c.Allow(readerRole, {
|
|
24
|
+
@c.Allow(editorRole, {
|
|
27
25
|
read: true,
|
|
28
26
|
})
|
|
29
|
-
@c.Allow(
|
|
27
|
+
@c.Allow(readerRole, {
|
|
30
28
|
read: true,
|
|
31
29
|
})
|
|
32
30
|
export class Category {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import { c } from '@contember/schema-definition'
|
|
2
|
+
|
|
3
|
+
export const editorRole = c.createRole('editor', { stages: '*' })
|
|
4
|
+
|
|
5
|
+
export const readerRole = c.createRole('reader', { stages: '*' })
|
|
6
|
+
|
|
7
|
+
export const categoryEditorVariable = c.createEntityVariable('category', 'Category', editorRole)
|
|
8
|
+
|
|
9
|
+
@c.Unique('title')
|
|
10
|
+
@c.View(`SELECT * FROM article`)
|
|
11
|
+
@c.Allow(editorRole, {
|
|
12
|
+
when: { category: { id: categoryEditorVariable } },
|
|
13
|
+
read: true,
|
|
14
|
+
create: ['title', 'category'],
|
|
15
|
+
update: ['title', 'category'],
|
|
16
|
+
})
|
|
17
|
+
@c.Allow(readerRole, {
|
|
18
|
+
read: true,
|
|
19
|
+
})
|
|
20
|
+
export class Article {
|
|
21
|
+
title = c.stringColumn()
|
|
22
|
+
deletedAt = c.dateTimeColumn()
|
|
23
|
+
category = c.manyHasOne(Category)
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
@c.View(`
|
|
27
|
+
SELECT * FROM article
|
|
28
|
+
|
|
29
|
+
`)
|
|
30
|
+
@c.Allow(editorRole, {
|
|
31
|
+
read: true,
|
|
32
|
+
})
|
|
33
|
+
@c.Allow(readerRole, {
|
|
34
|
+
read: true,
|
|
35
|
+
})
|
|
36
|
+
export class Category {
|
|
37
|
+
name = c.stringColumn()
|
|
38
|
+
}
|
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { createSchema } from '@contember/schema-definition'
|
|
2
|
-
import { expect, test } from '
|
|
2
|
+
import { expect, test } from 'bun:test'
|
|
3
3
|
import * as basic from './schemas/basic'
|
|
4
|
+
import * as complex from './schemas/complex'
|
|
4
5
|
import * as relations from './schemas/relations'
|
|
5
6
|
import * as unique from './schemas/unique'
|
|
6
7
|
import * as enum_ from './schemas/enum'
|
|
7
8
|
import * as acl from './schemas/acl'
|
|
9
|
+
import * as view from './schemas/view'
|
|
8
10
|
import { readFile, writeFile } from 'fs/promises'
|
|
9
11
|
import { join } from 'path'
|
|
10
12
|
import { DefinitionCodeGenerator } from '../../../src/definition-generator/DefinitionCodeGenerator'
|
|
@@ -13,10 +15,12 @@ import { fileURLToPath } from 'node:url'
|
|
|
13
15
|
|
|
14
16
|
const tests = [
|
|
15
17
|
['basic', basic],
|
|
18
|
+
['complex', complex],
|
|
16
19
|
['relations', relations],
|
|
17
20
|
['unique', unique],
|
|
18
21
|
['enum', enum_],
|
|
19
22
|
['acl', acl],
|
|
23
|
+
['view', view],
|
|
20
24
|
] as const
|
|
21
25
|
for (const [name, def] of tests) {
|
|
22
26
|
test(`generate schema: ${name}`, async () => {
|