@contember/schema-utils 2.1.0-beta.2 → 2.2.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.
- package/dist/development/index.cjs +11 -0
- package/dist/development/index.cjs.map +1 -1
- package/dist/development/index.js +11 -0
- package/dist/development/index.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/dataUtils.cjs +1 -0
- package/dist/development/src/dataUtils.cjs.map +1 -1
- package/dist/development/src/dataUtils.js +1 -0
- package/dist/development/src/dataUtils.js.map +1 -1
- package/dist/development/src/definition-generator/AclDefinitionCodeGenerator.cjs.map +1 -1
- package/dist/development/src/definition-generator/AclDefinitionCodeGenerator.js.map +1 -1
- package/dist/development/src/definition-generator/DefinitionCodeGenerator.cjs +37 -2
- package/dist/development/src/definition-generator/DefinitionCodeGenerator.cjs.map +1 -1
- package/dist/development/src/definition-generator/DefinitionCodeGenerator.js +37 -2
- package/dist/development/src/definition-generator/DefinitionCodeGenerator.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/json-schema/collectUnsupportedKeywords.cjs +45 -0
- package/dist/development/src/json-schema/collectUnsupportedKeywords.cjs.map +1 -0
- package/dist/development/src/json-schema/collectUnsupportedKeywords.js +45 -0
- package/dist/development/src/json-schema/collectUnsupportedKeywords.js.map +1 -0
- package/dist/development/src/json-schema/jsonSchemaToTsType.cjs +138 -0
- package/dist/development/src/json-schema/jsonSchemaToTsType.cjs.map +1 -0
- package/dist/development/src/json-schema/jsonSchemaToTsType.js +138 -0
- package/dist/development/src/json-schema/jsonSchemaToTsType.js.map +1 -0
- package/dist/development/src/json-schema/keywords.cjs +57 -0
- package/dist/development/src/json-schema/keywords.cjs.map +1 -0
- package/dist/development/src/json-schema/keywords.js +57 -0
- package/dist/development/src/json-schema/keywords.js.map +1 -0
- package/dist/development/src/lax/LaxSchemaConverter.cjs.map +1 -1
- package/dist/development/src/lax/LaxSchemaConverter.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 +2 -0
- package/dist/development/src/model/resolveDefaultColumnType.cjs.map +1 -1
- package/dist/development/src/model/resolveDefaultColumnType.js +2 -0
- package/dist/development/src/model/resolveDefaultColumnType.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/condition.cjs +6 -1
- package/dist/development/src/type-schema/condition.cjs.map +1 -1
- package/dist/development/src/type-schema/condition.js +6 -1
- package/dist/development/src/type-schema/condition.js.map +1 -1
- package/dist/development/src/type-schema/model.cjs +14 -2
- package/dist/development/src/type-schema/model.cjs.map +1 -1
- package/dist/development/src/type-schema/model.js +14 -2
- 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/where.cjs.map +1 -1
- package/dist/development/src/type-schema/where.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 +66 -0
- package/dist/development/src/validation/ModelValidator.cjs.map +1 -1
- package/dist/development/src/validation/ModelValidator.js +66 -0
- 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 +11 -0
- package/dist/production/index.cjs.map +1 -1
- package/dist/production/index.js +11 -0
- package/dist/production/index.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/dataUtils.cjs +1 -0
- package/dist/production/src/dataUtils.cjs.map +1 -1
- package/dist/production/src/dataUtils.js +1 -0
- package/dist/production/src/dataUtils.js.map +1 -1
- package/dist/production/src/definition-generator/AclDefinitionCodeGenerator.cjs.map +1 -1
- package/dist/production/src/definition-generator/AclDefinitionCodeGenerator.js.map +1 -1
- package/dist/production/src/definition-generator/DefinitionCodeGenerator.cjs +37 -2
- package/dist/production/src/definition-generator/DefinitionCodeGenerator.cjs.map +1 -1
- package/dist/production/src/definition-generator/DefinitionCodeGenerator.js +37 -2
- package/dist/production/src/definition-generator/DefinitionCodeGenerator.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/json-schema/collectUnsupportedKeywords.cjs +45 -0
- package/dist/production/src/json-schema/collectUnsupportedKeywords.cjs.map +1 -0
- package/dist/production/src/json-schema/collectUnsupportedKeywords.js +45 -0
- package/dist/production/src/json-schema/collectUnsupportedKeywords.js.map +1 -0
- package/dist/production/src/json-schema/jsonSchemaToTsType.cjs +138 -0
- package/dist/production/src/json-schema/jsonSchemaToTsType.cjs.map +1 -0
- package/dist/production/src/json-schema/jsonSchemaToTsType.js +138 -0
- package/dist/production/src/json-schema/jsonSchemaToTsType.js.map +1 -0
- package/dist/production/src/json-schema/keywords.cjs +57 -0
- package/dist/production/src/json-schema/keywords.cjs.map +1 -0
- package/dist/production/src/json-schema/keywords.js +57 -0
- package/dist/production/src/json-schema/keywords.js.map +1 -0
- package/dist/production/src/lax/LaxSchemaConverter.cjs.map +1 -1
- package/dist/production/src/lax/LaxSchemaConverter.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 +2 -0
- package/dist/production/src/model/resolveDefaultColumnType.cjs.map +1 -1
- package/dist/production/src/model/resolveDefaultColumnType.js +2 -0
- package/dist/production/src/model/resolveDefaultColumnType.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/condition.cjs +6 -1
- package/dist/production/src/type-schema/condition.cjs.map +1 -1
- package/dist/production/src/type-schema/condition.js +6 -1
- package/dist/production/src/type-schema/condition.js.map +1 -1
- package/dist/production/src/type-schema/model.cjs +14 -2
- package/dist/production/src/type-schema/model.cjs.map +1 -1
- package/dist/production/src/type-schema/model.js +14 -2
- 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/where.cjs.map +1 -1
- package/dist/production/src/type-schema/where.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 +66 -0
- package/dist/production/src/validation/ModelValidator.cjs.map +1 -1
- package/dist/production/src/validation/ModelValidator.js +66 -0
- 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/jsonSchemaKeywords.test.d.ts +2 -0
- package/dist/tests/cases/unit/jsonSchemaKeywords.test.d.ts.map +1 -0
- package/dist/tests/cases/unit/jsonSchemaToTsType.test.d.ts +2 -0
- package/dist/tests/cases/unit/jsonSchemaToTsType.test.d.ts.map +1 -0
- package/dist/tests/cases/unit/numericColumnCodeGenerator.test.d.ts +2 -0
- package/dist/tests/cases/unit/numericColumnCodeGenerator.test.d.ts.map +1 -0
- package/dist/tests/tsconfig.tsbuildinfo +1 -1
- package/dist/types/acl/index.d.ts +3 -3
- package/dist/types/acl/index.d.ts.map +1 -1
- package/dist/types/dataUtils.d.ts.map +1 -1
- package/dist/types/definition-generator/AclDefinitionCodeGenerator.d.ts +1 -1
- package/dist/types/definition-generator/AclDefinitionCodeGenerator.d.ts.map +1 -1
- package/dist/types/definition-generator/DefinitionCodeGenerator.d.ts +3 -3
- package/dist/types/definition-generator/DefinitionCodeGenerator.d.ts.map +1 -1
- package/dist/types/definition-generator/TsDefinitionGenerator.d.ts +1 -1
- package/dist/types/definition-generator/TsDefinitionGenerator.d.ts.map +1 -1
- package/dist/types/definition-generator/index.d.ts +4 -4
- package/dist/types/definition-generator/index.d.ts.map +1 -1
- package/dist/types/index.d.ts +11 -10
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/json-schema/collectUnsupportedKeywords.d.ts +20 -0
- package/dist/types/json-schema/collectUnsupportedKeywords.d.ts.map +1 -0
- package/dist/types/json-schema/index.d.ts +4 -0
- package/dist/types/json-schema/index.d.ts.map +1 -0
- package/dist/types/json-schema/jsonSchemaToTsType.d.ts +24 -0
- package/dist/types/json-schema/jsonSchemaToTsType.d.ts.map +1 -0
- package/dist/types/json-schema/keywords.d.ts +28 -0
- package/dist/types/json-schema/keywords.d.ts.map +1 -0
- package/dist/types/lax/LaxSchemaConverter.d.ts +2 -2
- package/dist/types/lax/LaxSchemaConverter.d.ts.map +1 -1
- package/dist/types/lax/index.d.ts +2 -2
- package/dist/types/lax/index.d.ts.map +1 -1
- package/dist/types/model/index.d.ts +3 -3
- package/dist/types/model/index.d.ts.map +1 -1
- package/dist/types/model/resolveDefaultColumnType.d.ts.map +1 -1
- package/dist/types/tsconfig.tsbuildinfo +1 -1
- package/dist/types/type-schema/index.d.ts +5 -5
- package/dist/types/type-schema/index.d.ts.map +1 -1
- package/dist/types/type-schema/model.d.ts.map +1 -1
- package/dist/types/type-schema/settings.d.ts +3 -0
- package/dist/types/type-schema/settings.d.ts.map +1 -1
- package/dist/types/utils/index.d.ts +3 -3
- package/dist/types/utils/index.d.ts.map +1 -1
- package/dist/types/validation/AclValidator.d.ts +1 -1
- package/dist/types/validation/AclValidator.d.ts.map +1 -1
- package/dist/types/validation/ActionsValidator.d.ts +1 -1
- package/dist/types/validation/ActionsValidator.d.ts.map +1 -1
- package/dist/types/validation/ModelValidator.d.ts +3 -1
- package/dist/types/validation/ModelValidator.d.ts.map +1 -1
- package/dist/types/validation/SchemaValidator.d.ts +1 -1
- package/dist/types/validation/SchemaValidator.d.ts.map +1 -1
- package/dist/types/validation/ValidationValidator.d.ts +1 -1
- package/dist/types/validation/ValidationValidator.d.ts.map +1 -1
- package/dist/types/validation/errors.d.ts +1 -1
- package/dist/types/validation/errors.d.ts.map +1 -1
- package/dist/types/validation/index.d.ts +6 -6
- package/dist/types/validation/index.d.ts.map +1 -1
- package/package.json +4 -4
- package/src/acl/PredicateDefinitionProcessor.ts +1 -1
- package/src/acl/index.ts +3 -3
- package/src/dataUtils.ts +1 -0
- package/src/definition-generator/AclDefinitionCodeGenerator.ts +3 -3
- package/src/definition-generator/DefinitionCodeGenerator.ts +44 -7
- package/src/definition-generator/TsDefinitionGenerator.ts +2 -2
- package/src/definition-generator/index.ts +4 -4
- package/src/index.ts +14 -13
- package/src/json-schema/collectUnsupportedKeywords.ts +74 -0
- package/src/json-schema/index.ts +3 -0
- package/src/json-schema/jsonSchemaToTsType.ts +188 -0
- package/src/json-schema/keywords.ts +79 -0
- package/src/lax/LaxSchemaConverter.ts +3 -3
- package/src/lax/index.ts +2 -2
- package/src/model/index.ts +3 -3
- package/src/model/modelUtils.ts +1 -1
- package/src/model/resolveDefaultColumnType.ts +3 -1
- package/src/schemaNormalizer.ts +1 -1
- package/src/type-schema/acl.ts +1 -1
- package/src/type-schema/condition.ts +5 -0
- package/src/type-schema/index.ts +5 -5
- package/src/type-schema/model.ts +12 -0
- package/src/type-schema/settings.ts +1 -0
- package/src/type-schema/where.ts +2 -2
- package/src/utils/index.ts +3 -3
- package/src/validation/AclValidator.ts +4 -4
- package/src/validation/ActionsValidator.ts +4 -4
- package/src/validation/MembershipResolver.ts +3 -3
- package/src/validation/ModelValidator.ts +80 -2
- package/src/validation/SchemaValidator.ts +5 -5
- package/src/validation/ValidationValidator.ts +2 -2
- package/src/validation/errors.ts +2 -0
- package/src/validation/index.ts +6 -6
- package/tests/cases/unit/conditionSchema.test.ts +1 -1
- package/tests/cases/unit/deepCompare.test.ts +1 -1
- package/tests/cases/unit/jsonSchemaKeywords.test.ts +91 -0
- package/tests/cases/unit/jsonSchemaToTsType.test.ts +55 -0
- package/tests/cases/unit/laxSchemaConverter.test.ts +1 -1
- package/tests/cases/unit/membershipResolver.test.ts +1 -1
- package/tests/cases/unit/modelSchema.test.ts +1 -1
- package/tests/cases/unit/modelValidator.test.ts +246 -1
- package/tests/cases/unit/numericColumnCodeGenerator.test.ts +69 -0
- package/tests/cases/unit/printJsvalue.test.ts +1 -1
- package/tests/cases/unit/tsDefinitionGenerator.test.ts +46 -9
- package/tests/cases/unit/whereSchema.test.ts +2 -2
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test'
|
|
2
|
+
import { collectUnsupportedJsonSchemaKeywords } from '../../../src/index.js'
|
|
3
|
+
|
|
4
|
+
describe('collectUnsupportedJsonSchemaKeywords', () => {
|
|
5
|
+
test('accepts a fully supported schema', () => {
|
|
6
|
+
expect(collectUnsupportedJsonSchemaKeywords({
|
|
7
|
+
type: 'object',
|
|
8
|
+
properties: {
|
|
9
|
+
name: { type: 'string', minLength: 1, maxLength: 10, pattern: '^.+$' },
|
|
10
|
+
age: { type: 'integer', minimum: 0, maximum: 120 },
|
|
11
|
+
tags: { type: 'array', items: { type: 'string' }, minItems: 1, maxItems: 5, uniqueItems: true },
|
|
12
|
+
kind: { enum: ['a', 'b'] },
|
|
13
|
+
flag: { const: true },
|
|
14
|
+
},
|
|
15
|
+
required: ['name'],
|
|
16
|
+
additionalProperties: false,
|
|
17
|
+
minProperties: 1,
|
|
18
|
+
maxProperties: 10,
|
|
19
|
+
})).toStrictEqual([])
|
|
20
|
+
})
|
|
21
|
+
|
|
22
|
+
test('accepts combinators', () => {
|
|
23
|
+
expect(collectUnsupportedJsonSchemaKeywords({
|
|
24
|
+
allOf: [{ type: 'object' }],
|
|
25
|
+
anyOf: [{ type: 'string' }, { type: 'number' }],
|
|
26
|
+
oneOf: [{ const: 1 }, { const: 2 }],
|
|
27
|
+
not: { type: 'null' },
|
|
28
|
+
})).toStrictEqual([])
|
|
29
|
+
})
|
|
30
|
+
|
|
31
|
+
test('accepts annotation keywords', () => {
|
|
32
|
+
expect(collectUnsupportedJsonSchemaKeywords({
|
|
33
|
+
$schema: 'https://json-schema.org/draft/2020-12/schema',
|
|
34
|
+
$id: 'https://example.com/x',
|
|
35
|
+
$comment: 'note',
|
|
36
|
+
title: 'Title',
|
|
37
|
+
description: 'Desc',
|
|
38
|
+
examples: [1, 2],
|
|
39
|
+
default: 0,
|
|
40
|
+
readOnly: true,
|
|
41
|
+
writeOnly: false,
|
|
42
|
+
deprecated: false,
|
|
43
|
+
type: 'integer',
|
|
44
|
+
})).toStrictEqual([])
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
test.each([
|
|
48
|
+
'$ref',
|
|
49
|
+
'$defs',
|
|
50
|
+
'format',
|
|
51
|
+
'patternProperties',
|
|
52
|
+
'propertyNames',
|
|
53
|
+
'dependentRequired',
|
|
54
|
+
'dependentSchemas',
|
|
55
|
+
'if',
|
|
56
|
+
'then',
|
|
57
|
+
'else',
|
|
58
|
+
'contains',
|
|
59
|
+
'prefixItems',
|
|
60
|
+
])('rejects unsupported keyword %s at the root', keyword => {
|
|
61
|
+
expect(collectUnsupportedJsonSchemaKeywords({ [keyword]: {} })).toStrictEqual([{ keyword, path: '' }])
|
|
62
|
+
})
|
|
63
|
+
|
|
64
|
+
test('descends into properties, items, additionalProperties and reports a path', () => {
|
|
65
|
+
expect(collectUnsupportedJsonSchemaKeywords({
|
|
66
|
+
type: 'object',
|
|
67
|
+
properties: {
|
|
68
|
+
a: { type: 'string', format: 'email' },
|
|
69
|
+
},
|
|
70
|
+
additionalProperties: { type: 'array', items: { contains: { type: 'number' } } },
|
|
71
|
+
})).toStrictEqual([
|
|
72
|
+
{ keyword: 'format', path: '/properties/a' },
|
|
73
|
+
{ keyword: 'contains', path: '/additionalProperties/items' },
|
|
74
|
+
])
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
test('descends into combinators', () => {
|
|
78
|
+
expect(collectUnsupportedJsonSchemaKeywords({
|
|
79
|
+
anyOf: [{ type: 'string' }, { type: 'object', propertyNames: { pattern: '^x' } }],
|
|
80
|
+
not: { $ref: '#/x' },
|
|
81
|
+
})).toStrictEqual([
|
|
82
|
+
{ keyword: 'propertyNames', path: '/anyOf/1' },
|
|
83
|
+
{ keyword: '$ref', path: '/not' },
|
|
84
|
+
])
|
|
85
|
+
})
|
|
86
|
+
|
|
87
|
+
test('boolean schema is valid', () => {
|
|
88
|
+
expect(collectUnsupportedJsonSchemaKeywords(true)).toStrictEqual([])
|
|
89
|
+
expect(collectUnsupportedJsonSchemaKeywords(false)).toStrictEqual([])
|
|
90
|
+
})
|
|
91
|
+
})
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { describe, expect, test } from 'bun:test'
|
|
2
|
+
import { jsonSchemaToTsType } from '../../../src/index.js'
|
|
3
|
+
|
|
4
|
+
describe('jsonSchemaToTsType', () => {
|
|
5
|
+
test('scalars', () => {
|
|
6
|
+
expect(jsonSchemaToTsType({ type: 'string' })).toBe('string')
|
|
7
|
+
expect(jsonSchemaToTsType({ type: 'integer' })).toBe('number')
|
|
8
|
+
expect(jsonSchemaToTsType({ type: 'number' })).toBe('number')
|
|
9
|
+
expect(jsonSchemaToTsType({ type: 'boolean' })).toBe('boolean')
|
|
10
|
+
expect(jsonSchemaToTsType({ type: 'null' })).toBe('null')
|
|
11
|
+
})
|
|
12
|
+
|
|
13
|
+
test('type union', () => {
|
|
14
|
+
expect(jsonSchemaToTsType({ type: ['string', 'null'] })).toBe('string | null')
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
test('const and enum', () => {
|
|
18
|
+
expect(jsonSchemaToTsType({ const: 'x' })).toBe('"x"')
|
|
19
|
+
expect(jsonSchemaToTsType({ const: 5 })).toBe('5')
|
|
20
|
+
expect(jsonSchemaToTsType({ enum: ['a', 'b', 1] })).toBe('"a" | "b" | 1')
|
|
21
|
+
})
|
|
22
|
+
|
|
23
|
+
test('object with required and optional properties', () => {
|
|
24
|
+
expect(jsonSchemaToTsType({
|
|
25
|
+
type: 'object',
|
|
26
|
+
properties: {
|
|
27
|
+
name: { type: 'string' },
|
|
28
|
+
age: { type: 'integer' },
|
|
29
|
+
},
|
|
30
|
+
required: ['name'],
|
|
31
|
+
})).toBe('{ name: string; age?: number }')
|
|
32
|
+
})
|
|
33
|
+
|
|
34
|
+
test('array of strings', () => {
|
|
35
|
+
expect(jsonSchemaToTsType({ type: 'array', items: { type: 'string' } })).toBe('readonly (string)[]')
|
|
36
|
+
})
|
|
37
|
+
|
|
38
|
+
test('combinators', () => {
|
|
39
|
+
expect(jsonSchemaToTsType({ anyOf: [{ type: 'string' }, { type: 'number' }] })).toBe('string | number')
|
|
40
|
+
expect(jsonSchemaToTsType({ allOf: [{ type: 'object', properties: { a: { type: 'string' } }, required: ['a'] }] }))
|
|
41
|
+
.toBe('{ a: string }')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('falls back to JSONValue for unexpressible constructs', () => {
|
|
45
|
+
expect(jsonSchemaToTsType({})).toBe('JSONValue')
|
|
46
|
+
expect(jsonSchemaToTsType(true)).toBe('JSONValue')
|
|
47
|
+
expect(jsonSchemaToTsType({ not: { type: 'string' } })).toBe('JSONValue')
|
|
48
|
+
// object with no declared properties stays JSONValue rather than emitting `{}`
|
|
49
|
+
expect(jsonSchemaToTsType({ type: 'object' })).toBe('JSONValue')
|
|
50
|
+
// const of a non-primitive
|
|
51
|
+
expect(jsonSchemaToTsType({ const: { a: 1 } })).toBe('JSONValue')
|
|
52
|
+
// unsupported nested item type degrades to JSONValue element rather than failing whole array
|
|
53
|
+
expect(jsonSchemaToTsType({ type: 'array', items: { not: {} } })).toBe('readonly (JSONValue)[]')
|
|
54
|
+
})
|
|
55
|
+
})
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { expect, test } from 'bun:test'
|
|
2
|
-
import { MembershipResolver, MembershipValidationErrorType } from '../../../src'
|
|
2
|
+
import { MembershipResolver, MembershipValidationErrorType } from '../../../src/index.js'
|
|
3
3
|
import { Acl } from '@contember/schema'
|
|
4
4
|
|
|
5
5
|
const id1 = 'bff057b3-11f7-4bc7-abe3-1f2ef266824d'
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { expect, test } from 'bun:test'
|
|
2
2
|
import { Model } from '@contember/schema'
|
|
3
|
-
import { ModelValidator } from '../../../src'
|
|
3
|
+
import { ModelValidator } from '../../../src/index.js'
|
|
4
4
|
import { c, createSchema } from '@contember/schema-definition'
|
|
5
5
|
|
|
6
6
|
test('"meta" collision', () => {
|
|
@@ -92,6 +92,167 @@ test('column name collision', () => {
|
|
|
92
92
|
])
|
|
93
93
|
})
|
|
94
94
|
|
|
95
|
+
namespace CoveringIndexKeyOverlap {
|
|
96
|
+
@c.Index({ fields: ['title'], include: ['title'] })
|
|
97
|
+
export class Article {
|
|
98
|
+
title = c.stringColumn()
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
test('covering index include column overlaps key column', () => {
|
|
103
|
+
const schema = createSchema(CoveringIndexKeyOverlap)
|
|
104
|
+
const validator = new ModelValidator(schema.model)
|
|
105
|
+
expect(validator.validate()).toStrictEqual([
|
|
106
|
+
{
|
|
107
|
+
code: 'MODEL_INVALID_INDEX',
|
|
108
|
+
message: 'Field title cannot be both an index key and an included (covering) column',
|
|
109
|
+
path: ['entities', 'Article', 'indexes'],
|
|
110
|
+
},
|
|
111
|
+
])
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
namespace IndexColumnOptionsNonKey {
|
|
115
|
+
@c.Index('title')
|
|
116
|
+
export class Article {
|
|
117
|
+
title = c.stringColumn()
|
|
118
|
+
rank = c.intColumn()
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
test('index column options reference a non-key column', () => {
|
|
123
|
+
const schema = createSchema(IndexColumnOptionsNonKey)
|
|
124
|
+
const article = schema.model.entities.Article
|
|
125
|
+
// `columnOptions` keys are always index key fields when built through the DSL; inject an invalid
|
|
126
|
+
// one directly to exercise the guard against hand-written/imported models.
|
|
127
|
+
const model: Model.Schema = {
|
|
128
|
+
...schema.model,
|
|
129
|
+
entities: {
|
|
130
|
+
...schema.model.entities,
|
|
131
|
+
Article: {
|
|
132
|
+
...article,
|
|
133
|
+
indexes: [{ fields: ['title'], columnOptions: { rank: { order: 'desc' } } }],
|
|
134
|
+
},
|
|
135
|
+
},
|
|
136
|
+
}
|
|
137
|
+
const validator = new ModelValidator(model)
|
|
138
|
+
expect(validator.validate()).toStrictEqual([
|
|
139
|
+
{
|
|
140
|
+
code: 'MODEL_INVALID_INDEX',
|
|
141
|
+
message: 'Column options reference field rank, which is not a key column of the index',
|
|
142
|
+
path: ['entities', 'Article', 'indexes'],
|
|
143
|
+
},
|
|
144
|
+
])
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
namespace IndexDuplicateKeyColumn {
|
|
148
|
+
@c.Index({ fields: [{ field: 'title' }, { field: 'title', order: 'desc' }] })
|
|
149
|
+
export class Article {
|
|
150
|
+
title = c.stringColumn()
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
test('index lists a key column more than once', () => {
|
|
155
|
+
const schema = createSchema(IndexDuplicateKeyColumn)
|
|
156
|
+
const validator = new ModelValidator(schema.model)
|
|
157
|
+
expect(validator.validate()).toStrictEqual([
|
|
158
|
+
{
|
|
159
|
+
code: 'MODEL_INVALID_INDEX',
|
|
160
|
+
message: 'Field title is listed more than once as an index key column',
|
|
161
|
+
path: ['entities', 'Article', 'indexes'],
|
|
162
|
+
},
|
|
163
|
+
])
|
|
164
|
+
})
|
|
165
|
+
|
|
166
|
+
namespace IndexSortOptionsOnNonBtree {
|
|
167
|
+
@c.Index({ fields: [{ field: 'title', order: 'desc' }], method: 'gin' })
|
|
168
|
+
export class Article {
|
|
169
|
+
title = c.stringColumn()
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
test('index sort order on a non-btree method', () => {
|
|
174
|
+
const schema = createSchema(IndexSortOptionsOnNonBtree)
|
|
175
|
+
const validator = new ModelValidator(schema.model)
|
|
176
|
+
expect(validator.validate()).toStrictEqual([
|
|
177
|
+
{
|
|
178
|
+
code: 'MODEL_INVALID_INDEX',
|
|
179
|
+
message: 'Column options (order/nulls) on field title are only supported for btree indexes, not "gin"',
|
|
180
|
+
path: ['entities', 'Article', 'indexes'],
|
|
181
|
+
},
|
|
182
|
+
])
|
|
183
|
+
})
|
|
184
|
+
|
|
185
|
+
namespace IndexInvalidOpClass {
|
|
186
|
+
@c.Index({ fields: ['title'], opClass: 'gin_trgm_ops); DROP TABLE article; --' })
|
|
187
|
+
export class Article {
|
|
188
|
+
title = c.stringColumn()
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
test('index operator class with an invalid (injection-shaped) value', () => {
|
|
193
|
+
const schema = createSchema(IndexInvalidOpClass)
|
|
194
|
+
const validator = new ModelValidator(schema.model)
|
|
195
|
+
expect(validator.validate()).toStrictEqual([
|
|
196
|
+
{
|
|
197
|
+
code: 'MODEL_INVALID_INDEX',
|
|
198
|
+
message:
|
|
199
|
+
'Invalid index operator class "gin_trgm_ops); DROP TABLE article; --": expected an identifier, optionally schema-qualified (e.g. "public.gin_trgm_ops")',
|
|
200
|
+
path: ['entities', 'Article', 'indexes'],
|
|
201
|
+
},
|
|
202
|
+
])
|
|
203
|
+
})
|
|
204
|
+
|
|
205
|
+
namespace IndexSchemaQualifiedOpClass {
|
|
206
|
+
@c.Index({ fields: ['title'], method: 'gin', opClass: 'public.gin_trgm_ops' })
|
|
207
|
+
export class Article {
|
|
208
|
+
title = c.stringColumn()
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
test('index operator class may be schema-qualified', () => {
|
|
213
|
+
const schema = createSchema(IndexSchemaQualifiedOpClass)
|
|
214
|
+
const validator = new ModelValidator(schema.model)
|
|
215
|
+
expect(validator.validate()).toStrictEqual([])
|
|
216
|
+
})
|
|
217
|
+
|
|
218
|
+
namespace PartialIndexEmptyPredicate {
|
|
219
|
+
@c.Index({ fields: ['title'], where: ' ' })
|
|
220
|
+
export class Article {
|
|
221
|
+
title = c.stringColumn()
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
test('partial index with empty predicate', () => {
|
|
226
|
+
const schema = createSchema(PartialIndexEmptyPredicate)
|
|
227
|
+
const validator = new ModelValidator(schema.model)
|
|
228
|
+
expect(validator.validate()).toStrictEqual([
|
|
229
|
+
{
|
|
230
|
+
code: 'MODEL_INVALID_INDEX',
|
|
231
|
+
message: 'Index predicate (where) must not be empty.',
|
|
232
|
+
path: ['entities', 'Article', 'indexes'],
|
|
233
|
+
},
|
|
234
|
+
])
|
|
235
|
+
})
|
|
236
|
+
|
|
237
|
+
namespace PartialIndexSemicolonPredicate {
|
|
238
|
+
@c.Index({ fields: ['title'], where: 'title IS NOT NULL); DROP TABLE article; --' })
|
|
239
|
+
export class Article {
|
|
240
|
+
title = c.stringColumn()
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
test('partial index predicate with a statement terminator', () => {
|
|
245
|
+
const schema = createSchema(PartialIndexSemicolonPredicate)
|
|
246
|
+
const validator = new ModelValidator(schema.model)
|
|
247
|
+
expect(validator.validate()).toStrictEqual([
|
|
248
|
+
{
|
|
249
|
+
code: 'MODEL_INVALID_INDEX',
|
|
250
|
+
message: 'Index predicate (where) must not contain ";".',
|
|
251
|
+
path: ['entities', 'Article', 'indexes'],
|
|
252
|
+
},
|
|
253
|
+
])
|
|
254
|
+
})
|
|
255
|
+
|
|
95
256
|
namespace ViewRelations {
|
|
96
257
|
@c.View('SELECT 1')
|
|
97
258
|
export class Foo {
|
|
@@ -109,3 +270,87 @@ test('view relations', () => {
|
|
|
109
270
|
const validator = new ModelValidator(schema.model)
|
|
110
271
|
expect(validator.validate()).toStrictEqual([])
|
|
111
272
|
})
|
|
273
|
+
|
|
274
|
+
namespace SupportedJsonSchema {
|
|
275
|
+
export class Foo {
|
|
276
|
+
data = c.jsonColumn().schema({
|
|
277
|
+
type: 'object',
|
|
278
|
+
title: 'Some data',
|
|
279
|
+
description: 'annotation keywords are allowed',
|
|
280
|
+
properties: {
|
|
281
|
+
name: { type: 'string', minLength: 1 },
|
|
282
|
+
tags: { type: 'array', items: { type: 'string' }, uniqueItems: true },
|
|
283
|
+
},
|
|
284
|
+
required: ['name'],
|
|
285
|
+
additionalProperties: false,
|
|
286
|
+
})
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
test('json schema with supported keywords passes', () => {
|
|
291
|
+
const schema = createSchema(SupportedJsonSchema)
|
|
292
|
+
const validator = new ModelValidator(schema.model)
|
|
293
|
+
expect(validator.validate()).toStrictEqual([])
|
|
294
|
+
})
|
|
295
|
+
|
|
296
|
+
namespace UnsupportedJsonSchemaKeyword {
|
|
297
|
+
export class Foo {
|
|
298
|
+
data = c.jsonColumn().schema({
|
|
299
|
+
type: 'string',
|
|
300
|
+
format: 'email',
|
|
301
|
+
})
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
test('json schema with an unsupported keyword fails', () => {
|
|
306
|
+
const schema = createSchema(UnsupportedJsonSchemaKeyword)
|
|
307
|
+
const validator = new ModelValidator(schema.model)
|
|
308
|
+
const errors = validator.validate()
|
|
309
|
+
expect(errors).toHaveLength(1)
|
|
310
|
+
expect(errors[0].code).toBe('MODEL_INVALID_JSON_SCHEMA')
|
|
311
|
+
expect(errors[0].path).toStrictEqual(['entities', 'Foo', 'data'])
|
|
312
|
+
expect(errors[0].message).toContain('unsupported keyword "format"')
|
|
313
|
+
expect(errors[0].message).toContain('at the schema root')
|
|
314
|
+
})
|
|
315
|
+
|
|
316
|
+
namespace UnsupportedJsonSchemaKeywordNested {
|
|
317
|
+
export class Foo {
|
|
318
|
+
data = c.jsonColumn().schema({
|
|
319
|
+
type: 'object',
|
|
320
|
+
properties: {
|
|
321
|
+
ref: { $ref: '#/definitions/Bar' },
|
|
322
|
+
},
|
|
323
|
+
})
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
test('json schema reports unsupported keyword nested in properties with a path', () => {
|
|
328
|
+
const schema = createSchema(UnsupportedJsonSchemaKeywordNested)
|
|
329
|
+
const validator = new ModelValidator(schema.model)
|
|
330
|
+
const errors = validator.validate()
|
|
331
|
+
expect(errors).toHaveLength(1)
|
|
332
|
+
expect(errors[0].code).toBe('MODEL_INVALID_JSON_SCHEMA')
|
|
333
|
+
expect(errors[0].message).toContain('unsupported keyword "$ref"')
|
|
334
|
+
expect(errors[0].message).toContain('at "/properties/ref"')
|
|
335
|
+
})
|
|
336
|
+
|
|
337
|
+
namespace UnsupportedJsonSchemaKeywordInCombinator {
|
|
338
|
+
export class Foo {
|
|
339
|
+
data = c.jsonColumn().schema({
|
|
340
|
+
anyOf: [
|
|
341
|
+
{ type: 'string' },
|
|
342
|
+
{ type: 'object', patternProperties: { '^x': { type: 'number' } } },
|
|
343
|
+
],
|
|
344
|
+
})
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
test('json schema reports unsupported keyword inside a combinator', () => {
|
|
349
|
+
const schema = createSchema(UnsupportedJsonSchemaKeywordInCombinator)
|
|
350
|
+
const validator = new ModelValidator(schema.model)
|
|
351
|
+
const errors = validator.validate()
|
|
352
|
+
expect(errors).toHaveLength(1)
|
|
353
|
+
expect(errors[0].code).toBe('MODEL_INVALID_JSON_SCHEMA')
|
|
354
|
+
expect(errors[0].message).toContain('unsupported keyword "patternProperties"')
|
|
355
|
+
expect(errors[0].message).toContain('at "/anyOf/1"')
|
|
356
|
+
})
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { c, createSchema } from '@contember/schema-definition'
|
|
2
|
+
import { expect, test } from 'bun:test'
|
|
3
|
+
import { Model, Schema } from '@contember/schema'
|
|
4
|
+
import { DefinitionCodeGenerator } from '../../../src/definition-generator/DefinitionCodeGenerator.js'
|
|
5
|
+
|
|
6
|
+
namespace NumericModel {
|
|
7
|
+
export class Product {
|
|
8
|
+
price = c.numericColumn(20, 9).notNull()
|
|
9
|
+
discount = c.numericColumn(5, 2)
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
// Immutably overrides the stored columnType of a single Product column, so we can
|
|
14
|
+
// exercise the regex / fallback branches without writing to the readonly fields map.
|
|
15
|
+
const withColumnType = (schema: Schema, field: string, columnType: string): Schema => {
|
|
16
|
+
const entity = schema.model.entities.Product
|
|
17
|
+
const column = entity.fields[field] as Model.AnyColumn
|
|
18
|
+
return {
|
|
19
|
+
...schema,
|
|
20
|
+
model: {
|
|
21
|
+
...schema.model,
|
|
22
|
+
entities: {
|
|
23
|
+
...schema.model.entities,
|
|
24
|
+
Product: {
|
|
25
|
+
...entity,
|
|
26
|
+
fields: {
|
|
27
|
+
...entity.fields,
|
|
28
|
+
[field]: { ...column, columnType },
|
|
29
|
+
},
|
|
30
|
+
},
|
|
31
|
+
},
|
|
32
|
+
},
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
test('reverse codegen round-trips numericColumn(precision, scale)', () => {
|
|
37
|
+
const schema = createSchema(NumericModel)
|
|
38
|
+
const generated = new DefinitionCodeGenerator().generate(schema)
|
|
39
|
+
|
|
40
|
+
expect(generated).toContain('price = c.numericColumn(20, 9).notNull()')
|
|
41
|
+
expect(generated).toContain('discount = c.numericColumn(5, 2)')
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
test('reverse codegen parses arbitrary whitespace/casing in numeric(p, s)', () => {
|
|
45
|
+
// An equivalent-but-unusual form must still be parsed by the regex.
|
|
46
|
+
const schema = withColumnType(createSchema(NumericModel), 'price', 'NUMERIC ( 30 , 10 )')
|
|
47
|
+
|
|
48
|
+
const generated = new DefinitionCodeGenerator().generate(schema)
|
|
49
|
+
expect(generated).toContain('price = c.numericColumn(30, 10).notNull()')
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
test('reverse codegen falls back when columnType is not parseable', () => {
|
|
53
|
+
// An unparseable columnType (e.g. a domain type) must fall back to a default
|
|
54
|
+
// numericColumn(...) plus an explicit columnType(...).
|
|
55
|
+
const schema = withColumnType(createSchema(NumericModel), 'price', 'my_money_domain')
|
|
56
|
+
|
|
57
|
+
const generated = new DefinitionCodeGenerator().generate(schema)
|
|
58
|
+
expect(generated).toContain("price = c.numericColumn(30, 10).columnType('my_money_domain').notNull()")
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
test('reverse codegen fallback omits columnType when it equals the default', () => {
|
|
62
|
+
// A bare "numeric" is not matched by the precision/scale regex, but equals the default
|
|
63
|
+
// column type, so no redundant columnType(...) should be emitted.
|
|
64
|
+
const schema = withColumnType(createSchema(NumericModel), 'discount', 'numeric')
|
|
65
|
+
|
|
66
|
+
const generated = new DefinitionCodeGenerator().generate(schema)
|
|
67
|
+
expect(generated).toContain('discount = c.numericColumn(30, 10)')
|
|
68
|
+
expect(generated).not.toContain("columnType('numeric')")
|
|
69
|
+
})
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { createSchema } from '@contember/schema-definition'
|
|
1
|
+
import { c, createSchema } from '@contember/schema-definition'
|
|
2
2
|
import { expect, test } from 'bun:test'
|
|
3
|
-
import * as basic from './schemas/basic'
|
|
4
|
-
import * as complex from './schemas/complex'
|
|
5
|
-
import * as relations from './schemas/relations'
|
|
6
|
-
import * as unique from './schemas/unique'
|
|
7
|
-
import * as enum_ from './schemas/enum'
|
|
8
|
-
import * as acl from './schemas/acl'
|
|
9
|
-
import * as view from './schemas/view'
|
|
3
|
+
import * as basic from './schemas/basic.js'
|
|
4
|
+
import * as complex from './schemas/complex.js'
|
|
5
|
+
import * as relations from './schemas/relations.js'
|
|
6
|
+
import * as unique from './schemas/unique.js'
|
|
7
|
+
import * as enum_ from './schemas/enum.js'
|
|
8
|
+
import * as acl from './schemas/acl.js'
|
|
9
|
+
import * as view from './schemas/view.js'
|
|
10
10
|
import { readFile, writeFile } from 'fs/promises'
|
|
11
11
|
import { join } from 'path'
|
|
12
|
-
import { DefinitionCodeGenerator } from '../../../src/definition-generator/DefinitionCodeGenerator'
|
|
12
|
+
import { DefinitionCodeGenerator } from '../../../src/definition-generator/DefinitionCodeGenerator.js'
|
|
13
13
|
import { dirname } from 'node:path'
|
|
14
14
|
import { fileURLToPath } from 'node:url'
|
|
15
15
|
|
|
@@ -36,3 +36,40 @@ for (const [name, def] of tests) {
|
|
|
36
36
|
}
|
|
37
37
|
})
|
|
38
38
|
}
|
|
39
|
+
|
|
40
|
+
namespace IndexOptionsSchema {
|
|
41
|
+
@c.Index({ fields: ['title'], opClass: 'text_pattern_ops' })
|
|
42
|
+
@c.Index({ fields: ['title'], method: 'gin', opClass: 'gin_trgm_ops' })
|
|
43
|
+
@c.Index({ fields: ['title'], include: ['content'], where: 'content IS NOT NULL' })
|
|
44
|
+
export class Article {
|
|
45
|
+
title = c.stringColumn()
|
|
46
|
+
content = c.stringColumn()
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
test('definition generator preserves index opClass, include and where options', () => {
|
|
51
|
+
const generator = new DefinitionCodeGenerator()
|
|
52
|
+
const generated = generator.generate(createSchema(IndexOptionsSchema))
|
|
53
|
+
// regression (ARCH-1): opClass used to be dropped on regeneration, silently degrading e.g. trigram search
|
|
54
|
+
expect(generated).toContain(`@c.Index({ fields: ['title'], opClass: 'text_pattern_ops' })`)
|
|
55
|
+
expect(generated).toContain(`@c.Index({ fields: ['title'], method: 'gin', opClass: 'gin_trgm_ops' })`)
|
|
56
|
+
expect(generated).toContain(`@c.Index({ fields: ['title'], include: ['content'], where: 'content IS NOT NULL' })`)
|
|
57
|
+
// opClass alone must force the options form, never the positional short form that would drop it
|
|
58
|
+
expect(generated).not.toContain(`@c.Index('title')`)
|
|
59
|
+
})
|
|
60
|
+
|
|
61
|
+
namespace IndexColumnOptionsGenSchema {
|
|
62
|
+
@c.Index({ fields: ['title', { field: 'rank', order: 'desc', nulls: 'last' }] })
|
|
63
|
+
@c.Index({ fields: [{ field: 'title', opClass: 'text_pattern_ops' }] })
|
|
64
|
+
export class Article {
|
|
65
|
+
title = c.stringColumn()
|
|
66
|
+
rank = c.intColumn()
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
test('definition generator round-trips per-column index options', () => {
|
|
71
|
+
const generator = new DefinitionCodeGenerator()
|
|
72
|
+
const generated = generator.generate(createSchema(IndexColumnOptionsGenSchema))
|
|
73
|
+
expect(generated).toContain(`@c.Index({ fields: ['title', { field: 'rank', order: 'desc', nulls: 'last' }] })`)
|
|
74
|
+
expect(generated).toContain(`@c.Index({ fields: [{ field: 'title', opClass: 'text_pattern_ops' }] })`)
|
|
75
|
+
})
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { describe, expect, test } from 'bun:test'
|
|
2
|
-
import { conditionSchema } from '../../../src/type-schema'
|
|
2
|
+
import { conditionSchema } from '../../../src/type-schema/index.js'
|
|
3
3
|
import { Model } from '@contember/schema'
|
|
4
4
|
import { createSchema, SchemaDefinition as def } from '@contember/schema-definition'
|
|
5
|
-
import { whereSchema } from '../../../src/type-schema/where'
|
|
5
|
+
import { whereSchema } from '../../../src/type-schema/where.js'
|
|
6
6
|
|
|
7
7
|
namespace MyModel {
|
|
8
8
|
export class Article {
|