@nest-yalc-2/omnikernel-module 2.2.1 → 2.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/package.json +22 -14
  2. package/src/__tests__/omni-collection.entity.spec.ts +49 -49
  3. package/src/__tests__/omni-collection.service.spec.ts +83 -83
  4. package/src/__tests__/omni-document.entity.spec.ts +55 -55
  5. package/src/__tests__/omni-document.service.spec.ts +83 -83
  6. package/src/__tests__/omni-extension-projection-constraints.spec.ts +518 -518
  7. package/src/__tests__/omni-extension-projection.registration.spec.ts +947 -946
  8. package/src/__tests__/omni-extension-projection.service.spec.ts +806 -806
  9. package/src/__tests__/omni-external-ref.entity.spec.ts +36 -36
  10. package/src/__tests__/omni-external-ref.service.spec.ts +252 -252
  11. package/src/__tests__/omni-named.entity.spec.ts +33 -33
  12. package/src/__tests__/omni-record.entity.spec.ts +32 -32
  13. package/src/__tests__/omni-record.service.spec.ts +107 -107
  14. package/src/__tests__/omni-relation-semantics.spec.ts +102 -102
  15. package/src/__tests__/omni-relation.entity.spec.ts +38 -38
  16. package/src/__tests__/omni-scope-substrate.spec.ts +81 -81
  17. package/src/__tests__/omni-scoped.backend.spec.ts +115 -115
  18. package/src/__tests__/omni-scoped.service.spec.ts +354 -354
  19. package/src/__tests__/omnikernel.diagnostics.spec.ts +94 -94
  20. package/src/__tests__/omnikernel.module.spec.ts +38 -40
  21. package/src/__tests__/omnikernel.persistence.spec.ts +154 -154
  22. package/src/__tests__/omnikernel.public-api.spec.ts +238 -238
  23. package/src/__tests__/omnikernel.query.service.spec.ts +155 -155
  24. package/src/base/omni-base.entity.ts +41 -41
  25. package/src/base/omni-external-ref.entity.ts +53 -53
  26. package/src/base/omni-named.entity.ts +16 -16
  27. package/src/base/omni-record.entity.ts +51 -51
  28. package/src/base/omni-relation.entity.ts +72 -72
  29. package/src/index.ts +49 -49
  30. package/src/omni-collection-kind.enum.ts +10 -10
  31. package/src/omni-collection.backend.ts +16 -16
  32. package/src/omni-collection.dto.ts +170 -170
  33. package/src/omni-collection.entity.ts +21 -21
  34. package/src/omni-collection.service.ts +75 -75
  35. package/src/omni-document-kind.enum.ts +12 -12
  36. package/src/omni-document.backend.ts +16 -16
  37. package/src/omni-document.dto.ts +198 -198
  38. package/src/omni-document.entity.ts +30 -30
  39. package/src/omni-document.service.ts +75 -75
  40. package/src/omni-dto.helpers.ts +21 -21
  41. package/src/omni-extension-projection.definition.ts +294 -294
  42. package/src/omni-extension-projection.resource.ts +274 -274
  43. package/src/omni-extension-projection.service.ts +452 -452
  44. package/src/omni-external-ref-binding.validator.ts +53 -53
  45. package/src/omni-external-ref-internal-type.enum.ts +11 -11
  46. package/src/omni-external-ref.backend.ts +25 -25
  47. package/src/omni-external-ref.dto.ts +128 -128
  48. package/src/omni-external-ref.service.ts +255 -255
  49. package/src/omni-migration.ts +365 -365
  50. package/src/omni-named.backend.ts +11 -11
  51. package/src/omni-named.dto.ts +86 -86
  52. package/src/omni-projection.catalog.ts +345 -345
  53. package/src/omni-projection.lifecycle.ts +53 -53
  54. package/src/omni-record-status.enum.ts +11 -11
  55. package/src/omni-record.backend.ts +19 -19
  56. package/src/omni-record.dto.ts +157 -157
  57. package/src/omni-record.service.ts +113 -113
  58. package/src/omni-relation-kind.contract.ts +49 -49
  59. package/src/omni-relation-kind.enum.ts +12 -12
  60. package/src/omni-relation-projection.definition.ts +166 -166
  61. package/src/omni-relation-projection.resource.ts +360 -360
  62. package/src/omni-relation-projection.service.ts +610 -610
  63. package/src/omni-relation-semantics.ts +52 -52
  64. package/src/omni-relation-status.enum.ts +11 -11
  65. package/src/omni-relation.backend.ts +21 -21
  66. package/src/omni-relation.dto.ts +142 -142
  67. package/src/omni-relation.service.ts +159 -159
  68. package/src/omni-scope.ts +161 -161
  69. package/src/omni-scoped.backend.ts +110 -110
  70. package/src/omni-scoped.repository.ts +34 -34
  71. package/src/omni-scoped.service.ts +338 -338
  72. package/src/omnikernel.diagnostics.ts +83 -83
  73. package/src/omnikernel.module.ts +97 -97
  74. package/src/omnikernel.query.service.ts +108 -108
@@ -1,294 +1,294 @@
1
- import {
2
- compileProjectionUniqueConstraintPredicate,
3
- createProjectionSchemaOptions,
4
- defineProjectionResource,
5
- getProjectionReferenceColumnNames,
6
- getProjectionReferenceIndexName,
7
- getProjectionReferenceTargetColumnNames,
8
- getProjectionUniqueConstraintColumnNames,
9
- type ProjectionDialect,
10
- type ProjectionResourceDefinition,
11
- } from '@nest-yalc-2/crud-gen';
12
- import {
13
- Column,
14
- Entity,
15
- ForeignKey,
16
- Index,
17
- PrimaryColumn,
18
- Table,
19
- type EntityTarget,
20
- type EntitySchemaColumnOptions,
21
- type ObjectLiteral,
22
- } from 'typeorm';
23
- import { OmniRecordEntity } from './base/omni-record.entity.js';
24
- import { OmniRecordStatus } from './omni-record-status.enum.js';
25
-
26
- export interface OmniExtensionProjectionDefinition extends ProjectionResourceDefinition {
27
- /**
28
- * Immutable metadata written only to the Omni record that owns every
29
- * extension row. The extension table never mirrors these values.
30
- */
31
- owner: {
32
- kind: string;
33
- title: string;
34
- status: OmniRecordStatus;
35
- schema: {
36
- id: string;
37
- version: number;
38
- };
39
- };
40
- }
41
-
42
- function assertNonEmptyString(
43
- value: unknown,
44
- label: string,
45
- max: number,
46
- ): void {
47
- if (
48
- typeof value !== 'string' ||
49
- value.trim().length === 0 ||
50
- value.length > max
51
- ) {
52
- throw new TypeError(
53
- `${label} must be a non-empty string up to ${max} characters.`,
54
- );
55
- }
56
- }
57
-
58
- /**
59
- * Defines an owner-extension projection. The inherited projection metadata
60
- * remains the single source for public fields, codecs, JSON paths, and query
61
- * capabilities; the extra owner block fixes Omni record metadata server-side.
62
- */
63
- export function defineOmniExtensionProjection<
64
- TDefinition extends OmniExtensionProjectionDefinition,
65
- >(definition: TDefinition): Readonly<TDefinition> {
66
- assertNonEmptyString(definition.owner?.kind, 'Omni extension owner kind', 64);
67
- assertNonEmptyString(
68
- definition.owner?.title,
69
- 'Omni extension owner title',
70
- 255,
71
- );
72
- assertNonEmptyString(
73
- definition.owner?.schema?.id,
74
- 'Omni extension owner schema id',
75
- 128,
76
- );
77
- if (
78
- !Number.isInteger(definition.owner?.schema?.version) ||
79
- definition.owner.schema.version < 1 ||
80
- definition.owner.schema.version > 2_147_483_647
81
- ) {
82
- throw new TypeError(
83
- 'Omni extension owner schema version must be a positive signed 32-bit integer.',
84
- );
85
- }
86
- if (!Object.values(OmniRecordStatus).includes(definition.owner.status)) {
87
- throw new TypeError(
88
- 'Omni extension owner status must be an Omni record status.',
89
- );
90
- }
91
-
92
- return defineProjectionResource(definition);
93
- }
94
-
95
- function extensionSchema(
96
- definition: OmniExtensionProjectionDefinition,
97
- dialect: ProjectionDialect,
98
- ): {
99
- columns: Record<string, EntitySchemaColumnOptions>;
100
- indices: ReturnType<typeof createProjectionSchemaOptions>['indices'];
101
- foreignKeys: Array<{
102
- name: string;
103
- columnNames: string[];
104
- referencedTableName: string;
105
- referencedColumnNames: string[];
106
- onDelete: 'RESTRICT' | 'NO ACTION';
107
- }>;
108
- } {
109
- const projectionSchema = createProjectionSchemaOptions(definition, dialect);
110
- const { [definition.revision.column]: _ownerRevision, ...columns } =
111
- projectionSchema.columns;
112
- const scopeColumn = definition.scope.column;
113
- const identityColumn = definition.identity.column;
114
-
115
- columns[scopeColumn] = {
116
- ...columns[scopeColumn],
117
- primary: true,
118
- nullable: false,
119
- };
120
- columns[identityColumn] = {
121
- ...columns[identityColumn],
122
- primary: true,
123
- nullable: false,
124
- length: 36,
125
- };
126
-
127
- const references = definition.references ?? [];
128
- const uniqueConstraints = definition.uniqueConstraints ?? [];
129
- return {
130
- columns,
131
- indices: [
132
- ...projectionSchema.indices,
133
- ...references.map((reference) => ({
134
- name: getProjectionReferenceIndexName(reference),
135
- columns: getProjectionReferenceColumnNames(definition, reference),
136
- unique: false,
137
- })),
138
- ...uniqueConstraints.map((constraint) => ({
139
- name: constraint.name,
140
- columns: getProjectionUniqueConstraintColumnNames(
141
- definition,
142
- constraint,
143
- ),
144
- unique: true,
145
- where: compileProjectionUniqueConstraintPredicate(
146
- definition,
147
- constraint,
148
- dialect.name,
149
- ),
150
- })),
151
- ],
152
- foreignKeys: references.map((reference) => ({
153
- name: reference.name,
154
- columnNames: getProjectionReferenceColumnNames(definition, reference),
155
- referencedTableName: reference.target.tableName,
156
- referencedColumnNames: getProjectionReferenceTargetColumnNames(reference),
157
- onDelete: reference.onDelete,
158
- })),
159
- };
160
- }
161
-
162
- function migrationColumnType(type: EntitySchemaColumnOptions['type']): string {
163
- if (type === String) return 'varchar';
164
- if (type === Number) return 'integer';
165
- if (type === Boolean) return 'boolean';
166
- if (type === 'simple-json') return 'text';
167
- if (typeof type === 'string') return type;
168
- throw new TypeError('Omni extension projection column type is unsupported.');
169
- }
170
-
171
- /**
172
- * Builds a TypeORM entity target for one extension table. This is deliberately
173
- * a decorated class, rather than an EntitySchema: TypeORM builds EntitySchema
174
- * metadata separately and cannot resolve an EntitySchema foreign key to the
175
- * decorated OmniRecordEntity. The generated class keeps both sides in the
176
- * same metadata pass, allowing the composite FK to be synchronized normally.
177
- */
178
- export function createOmniExtensionProjectionEntity<
179
- Extension extends ObjectLiteral,
180
- >(
181
- definition: OmniExtensionProjectionDefinition,
182
- dialect: ProjectionDialect,
183
- ): EntityTarget<Extension> {
184
- const { columns, indices, foreignKeys } = extensionSchema(
185
- definition,
186
- dialect,
187
- );
188
- const scopeColumn = definition.scope.column;
189
- const identityColumn = definition.identity.column;
190
-
191
- class OmniExtensionProjectionEntity {}
192
-
193
- Entity(definition.tableName)(OmniExtensionProjectionEntity);
194
- for (const [columnName, declared] of Object.entries(columns)) {
195
- const options = { ...declared };
196
- const primary = options.primary === true;
197
- delete options.primary;
198
- if (primary) {
199
- PrimaryColumn(options.type as never, options as never)(
200
- OmniExtensionProjectionEntity.prototype,
201
- columnName,
202
- );
203
- } else if (typeof options.type === 'function') {
204
- Column(options as never)(
205
- OmniExtensionProjectionEntity.prototype,
206
- columnName,
207
- );
208
- } else {
209
- Column(options.type as never, options as never)(
210
- OmniExtensionProjectionEntity.prototype,
211
- columnName,
212
- );
213
- }
214
- }
215
- for (const index of indices) {
216
- if (!index.name || !Array.isArray(index.columns)) {
217
- throw new TypeError(
218
- 'Omni extension projection indexes require a name and column list.',
219
- );
220
- }
221
- Index(index.name, index.columns, {
222
- unique: index.unique,
223
- ...(index.where ? { where: index.where } : {}),
224
- })(OmniExtensionProjectionEntity);
225
- }
226
- for (const foreignKey of foreignKeys) {
227
- ForeignKey(
228
- foreignKey.referencedTableName,
229
- foreignKey.columnNames as never,
230
- foreignKey.referencedColumnNames as never,
231
- { name: foreignKey.name, onDelete: foreignKey.onDelete },
232
- )(OmniExtensionProjectionEntity);
233
- }
234
- ForeignKey(
235
- () => OmniRecordEntity,
236
- [scopeColumn, identityColumn],
237
- ['scopeId', 'guid'],
238
- { onDelete: 'CASCADE' },
239
- )(OmniExtensionProjectionEntity);
240
-
241
- return OmniExtensionProjectionEntity as unknown as EntityTarget<Extension>;
242
- }
243
-
244
- /**
245
- * Creates reviewed-migration DDL for an extension table. Applications pass
246
- * the returned Table to QueryRunner.createTable; runtime CRUD never creates
247
- * schema objects. JSON storage remains a ProjectionDialect concern.
248
- */
249
- export function createOmniExtensionProjectionTable(
250
- definition: OmniExtensionProjectionDefinition,
251
- dialect: ProjectionDialect,
252
- ): Table {
253
- const { columns, indices, foreignKeys } = extensionSchema(
254
- definition,
255
- dialect,
256
- );
257
- const scopeColumn = definition.scope.column;
258
- const identityColumn = definition.identity.column;
259
-
260
- return new Table({
261
- name: definition.tableName,
262
- columns: Object.entries(columns).map(([name, options]) => ({
263
- name,
264
- type: migrationColumnType(options.type),
265
- isPrimary: options.primary === true,
266
- isNullable: options.nullable === true,
267
- ...(options.length !== undefined
268
- ? { length: String(options.length) }
269
- : {}),
270
- })),
271
- indices: indices.map((index) => {
272
- if (!index.name || !Array.isArray(index.columns)) {
273
- throw new TypeError(
274
- 'Omni extension projection indexes require a name and column list.',
275
- );
276
- }
277
- return {
278
- name: index.name,
279
- columnNames: index.columns,
280
- isUnique: index.unique === true,
281
- ...(index.where ? { where: index.where } : {}),
282
- };
283
- }),
284
- foreignKeys: [
285
- {
286
- columnNames: [scopeColumn, identityColumn],
287
- referencedTableName: 'omni-record',
288
- referencedColumnNames: ['scopeId', 'guid'],
289
- onDelete: 'CASCADE',
290
- },
291
- ...foreignKeys,
292
- ],
293
- });
294
- }
1
+ import {
2
+ compileProjectionUniqueConstraintPredicate,
3
+ createProjectionSchemaOptions,
4
+ defineProjectionResource,
5
+ getProjectionReferenceColumnNames,
6
+ getProjectionReferenceIndexName,
7
+ getProjectionReferenceTargetColumnNames,
8
+ getProjectionUniqueConstraintColumnNames,
9
+ type ProjectionDialect,
10
+ type ProjectionResourceDefinition,
11
+ } from '@nest-yalc-2/crud-gen';
12
+ import {
13
+ Column,
14
+ Entity,
15
+ ForeignKey,
16
+ Index,
17
+ PrimaryColumn,
18
+ Table,
19
+ type EntityTarget,
20
+ type EntitySchemaColumnOptions,
21
+ type ObjectLiteral,
22
+ } from 'typeorm';
23
+ import { OmniRecordEntity } from './base/omni-record.entity.js';
24
+ import { OmniRecordStatus } from './omni-record-status.enum.js';
25
+
26
+ export interface OmniExtensionProjectionDefinition extends ProjectionResourceDefinition {
27
+ /**
28
+ * Immutable metadata written only to the Omni record that owns every
29
+ * extension row. The extension table never mirrors these values.
30
+ */
31
+ owner: {
32
+ kind: string;
33
+ title: string;
34
+ status: OmniRecordStatus;
35
+ schema: {
36
+ id: string;
37
+ version: number;
38
+ };
39
+ };
40
+ }
41
+
42
+ function assertNonEmptyString(
43
+ value: unknown,
44
+ label: string,
45
+ max: number,
46
+ ): void {
47
+ if (
48
+ typeof value !== 'string' ||
49
+ value.trim().length === 0 ||
50
+ value.length > max
51
+ ) {
52
+ throw new TypeError(
53
+ `${label} must be a non-empty string up to ${max} characters.`,
54
+ );
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Defines an owner-extension projection. The inherited projection metadata
60
+ * remains the single source for public fields, codecs, JSON paths, and query
61
+ * capabilities; the extra owner block fixes Omni record metadata server-side.
62
+ */
63
+ export function defineOmniExtensionProjection<
64
+ TDefinition extends OmniExtensionProjectionDefinition,
65
+ >(definition: TDefinition): Readonly<TDefinition> {
66
+ assertNonEmptyString(definition.owner?.kind, 'Omni extension owner kind', 64);
67
+ assertNonEmptyString(
68
+ definition.owner?.title,
69
+ 'Omni extension owner title',
70
+ 255,
71
+ );
72
+ assertNonEmptyString(
73
+ definition.owner?.schema?.id,
74
+ 'Omni extension owner schema id',
75
+ 128,
76
+ );
77
+ if (
78
+ !Number.isInteger(definition.owner?.schema?.version) ||
79
+ definition.owner.schema.version < 1 ||
80
+ definition.owner.schema.version > 2_147_483_647
81
+ ) {
82
+ throw new TypeError(
83
+ 'Omni extension owner schema version must be a positive signed 32-bit integer.',
84
+ );
85
+ }
86
+ if (!Object.values(OmniRecordStatus).includes(definition.owner.status)) {
87
+ throw new TypeError(
88
+ 'Omni extension owner status must be an Omni record status.',
89
+ );
90
+ }
91
+
92
+ return defineProjectionResource(definition);
93
+ }
94
+
95
+ function extensionSchema(
96
+ definition: OmniExtensionProjectionDefinition,
97
+ dialect: ProjectionDialect,
98
+ ): {
99
+ columns: Record<string, EntitySchemaColumnOptions>;
100
+ indices: ReturnType<typeof createProjectionSchemaOptions>['indices'];
101
+ foreignKeys: Array<{
102
+ name: string;
103
+ columnNames: string[];
104
+ referencedTableName: string;
105
+ referencedColumnNames: string[];
106
+ onDelete: 'RESTRICT' | 'NO ACTION';
107
+ }>;
108
+ } {
109
+ const projectionSchema = createProjectionSchemaOptions(definition, dialect);
110
+ const { [definition.revision.column]: _ownerRevision, ...columns } =
111
+ projectionSchema.columns;
112
+ const scopeColumn = definition.scope.column;
113
+ const identityColumn = definition.identity.column;
114
+
115
+ columns[scopeColumn] = {
116
+ ...columns[scopeColumn],
117
+ primary: true,
118
+ nullable: false,
119
+ };
120
+ columns[identityColumn] = {
121
+ ...columns[identityColumn],
122
+ primary: true,
123
+ nullable: false,
124
+ length: 36,
125
+ };
126
+
127
+ const references = definition.references ?? [];
128
+ const uniqueConstraints = definition.uniqueConstraints ?? [];
129
+ return {
130
+ columns,
131
+ indices: [
132
+ ...projectionSchema.indices,
133
+ ...references.map((reference) => ({
134
+ name: getProjectionReferenceIndexName(reference),
135
+ columns: getProjectionReferenceColumnNames(definition, reference),
136
+ unique: false,
137
+ })),
138
+ ...uniqueConstraints.map((constraint) => ({
139
+ name: constraint.name,
140
+ columns: getProjectionUniqueConstraintColumnNames(
141
+ definition,
142
+ constraint,
143
+ ),
144
+ unique: true,
145
+ where: compileProjectionUniqueConstraintPredicate(
146
+ definition,
147
+ constraint,
148
+ dialect.name,
149
+ ),
150
+ })),
151
+ ],
152
+ foreignKeys: references.map((reference) => ({
153
+ name: reference.name,
154
+ columnNames: getProjectionReferenceColumnNames(definition, reference),
155
+ referencedTableName: reference.target.tableName,
156
+ referencedColumnNames: getProjectionReferenceTargetColumnNames(reference),
157
+ onDelete: reference.onDelete,
158
+ })),
159
+ };
160
+ }
161
+
162
+ function migrationColumnType(type: EntitySchemaColumnOptions['type']): string {
163
+ if (type === String) return 'varchar';
164
+ if (type === Number) return 'integer';
165
+ if (type === Boolean) return 'boolean';
166
+ if (type === 'simple-json') return 'text';
167
+ if (typeof type === 'string') return type;
168
+ throw new TypeError('Omni extension projection column type is unsupported.');
169
+ }
170
+
171
+ /**
172
+ * Builds a TypeORM entity target for one extension table. This is deliberately
173
+ * a decorated class, rather than an EntitySchema: TypeORM builds EntitySchema
174
+ * metadata separately and cannot resolve an EntitySchema foreign key to the
175
+ * decorated OmniRecordEntity. The generated class keeps both sides in the
176
+ * same metadata pass, allowing the composite FK to be synchronized normally.
177
+ */
178
+ export function createOmniExtensionProjectionEntity<
179
+ Extension extends ObjectLiteral,
180
+ >(
181
+ definition: OmniExtensionProjectionDefinition,
182
+ dialect: ProjectionDialect,
183
+ ): EntityTarget<Extension> {
184
+ const { columns, indices, foreignKeys } = extensionSchema(
185
+ definition,
186
+ dialect,
187
+ );
188
+ const scopeColumn = definition.scope.column;
189
+ const identityColumn = definition.identity.column;
190
+
191
+ class OmniExtensionProjectionEntity {}
192
+
193
+ Entity(definition.tableName)(OmniExtensionProjectionEntity);
194
+ for (const [columnName, declared] of Object.entries(columns)) {
195
+ const options = { ...declared };
196
+ const primary = options.primary === true;
197
+ delete options.primary;
198
+ if (primary) {
199
+ PrimaryColumn(options.type as never, options as never)(
200
+ OmniExtensionProjectionEntity.prototype,
201
+ columnName,
202
+ );
203
+ } else if (typeof options.type === 'function') {
204
+ Column(options as never)(
205
+ OmniExtensionProjectionEntity.prototype,
206
+ columnName,
207
+ );
208
+ } else {
209
+ Column(options.type as never, options as never)(
210
+ OmniExtensionProjectionEntity.prototype,
211
+ columnName,
212
+ );
213
+ }
214
+ }
215
+ for (const index of indices) {
216
+ if (!index.name || !Array.isArray(index.columns)) {
217
+ throw new TypeError(
218
+ 'Omni extension projection indexes require a name and column list.',
219
+ );
220
+ }
221
+ Index(index.name, index.columns, {
222
+ unique: index.unique,
223
+ ...(index.where ? { where: index.where } : {}),
224
+ })(OmniExtensionProjectionEntity);
225
+ }
226
+ for (const foreignKey of foreignKeys) {
227
+ ForeignKey(
228
+ foreignKey.referencedTableName,
229
+ foreignKey.columnNames as never,
230
+ foreignKey.referencedColumnNames as never,
231
+ { name: foreignKey.name, onDelete: foreignKey.onDelete },
232
+ )(OmniExtensionProjectionEntity);
233
+ }
234
+ ForeignKey(
235
+ () => OmniRecordEntity,
236
+ [scopeColumn, identityColumn],
237
+ ['scopeId', 'guid'],
238
+ { onDelete: 'CASCADE' },
239
+ )(OmniExtensionProjectionEntity);
240
+
241
+ return OmniExtensionProjectionEntity as unknown as EntityTarget<Extension>;
242
+ }
243
+
244
+ /**
245
+ * Creates reviewed-migration DDL for an extension table. Applications pass
246
+ * the returned Table to QueryRunner.createTable; runtime CRUD never creates
247
+ * schema objects. JSON storage remains a ProjectionDialect concern.
248
+ */
249
+ export function createOmniExtensionProjectionTable(
250
+ definition: OmniExtensionProjectionDefinition,
251
+ dialect: ProjectionDialect,
252
+ ): Table {
253
+ const { columns, indices, foreignKeys } = extensionSchema(
254
+ definition,
255
+ dialect,
256
+ );
257
+ const scopeColumn = definition.scope.column;
258
+ const identityColumn = definition.identity.column;
259
+
260
+ return new Table({
261
+ name: definition.tableName,
262
+ columns: Object.entries(columns).map(([name, options]) => ({
263
+ name,
264
+ type: migrationColumnType(options.type),
265
+ isPrimary: options.primary === true,
266
+ isNullable: options.nullable === true,
267
+ ...(options.length !== undefined
268
+ ? { length: String(options.length) }
269
+ : {}),
270
+ })),
271
+ indices: indices.map((index) => {
272
+ if (!index.name || !Array.isArray(index.columns)) {
273
+ throw new TypeError(
274
+ 'Omni extension projection indexes require a name and column list.',
275
+ );
276
+ }
277
+ return {
278
+ name: index.name,
279
+ columnNames: index.columns,
280
+ isUnique: index.unique === true,
281
+ ...(index.where ? { where: index.where } : {}),
282
+ };
283
+ }),
284
+ foreignKeys: [
285
+ {
286
+ columnNames: [scopeColumn, identityColumn],
287
+ referencedTableName: 'omni-record',
288
+ referencedColumnNames: ['scopeId', 'guid'],
289
+ onDelete: 'CASCADE',
290
+ },
291
+ ...foreignKeys,
292
+ ],
293
+ });
294
+ }