@travetto/model-sql 7.0.0-rc.2 → 7.0.0-rc.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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/model-sql",
3
- "version": "7.0.0-rc.2",
3
+ "version": "7.0.0-rc.4",
4
4
  "description": "SQL backing for the travetto model module, with real-time modeling support for SQL schemas.",
5
5
  "keywords": [
6
6
  "sql",
@@ -27,14 +27,14 @@
27
27
  "directory": "module/model-sql"
28
28
  },
29
29
  "dependencies": {
30
- "@travetto/cli": "^7.0.0-rc.2",
31
- "@travetto/config": "^7.0.0-rc.2",
32
- "@travetto/context": "^7.0.0-rc.2",
33
- "@travetto/model": "^7.0.0-rc.2",
34
- "@travetto/model-query": "^7.0.0-rc.2"
30
+ "@travetto/cli": "^7.0.0-rc.4",
31
+ "@travetto/config": "^7.0.0-rc.4",
32
+ "@travetto/context": "^7.0.0-rc.4",
33
+ "@travetto/model": "^7.0.0-rc.4",
34
+ "@travetto/model-query": "^7.0.0-rc.4"
35
35
  },
36
36
  "peerDependencies": {
37
- "@travetto/test": "^7.0.0-rc.2"
37
+ "@travetto/test": "^7.0.0-rc.4"
38
38
  },
39
39
  "peerDependenciesMeta": {
40
40
  "@travetto/test": {
package/src/config.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { Config } from '@travetto/config';
2
- import { asFull } from '@travetto/runtime';
2
+ import { asFull, Runtime } from '@travetto/runtime';
3
3
 
4
4
  /**
5
5
  * SQL Model Config
@@ -17,11 +17,11 @@ export class SQLModelConfig<T extends {} = {}> {
17
17
  /**
18
18
  * Username
19
19
  */
20
- user = '';
20
+ user = Runtime.production ? '' : 'travetto';
21
21
  /**
22
22
  * Password
23
23
  */
24
- password = '';
24
+ password = Runtime.production ? '' : 'travetto';
25
25
  /**
26
26
  * Table prefix
27
27
  */
@@ -31,9 +31,9 @@ export class SQLModelConfig<T extends {} = {}> {
31
31
  */
32
32
  database = 'app';
33
33
  /**
34
- * Auto schema creation
34
+ * Allow storage modification at runtime
35
35
  */
36
- autoCreate?: boolean;
36
+ modifyStorage?: boolean;
37
37
  /**
38
38
  * Db version
39
39
  */
@@ -16,6 +16,12 @@ interface Alias {
16
16
  path: VisitStack[];
17
17
  }
18
18
 
19
+ export type SQLTableDescription = {
20
+ columns: { name: string, type: string, is_notnull: boolean }[];
21
+ foreignKeys: { name: string, from_column: string, to_column: string, to_table: string }[];
22
+ indices: { name: string, columns: { name: string, desc: boolean }[], is_unique: boolean }[];
23
+ };
24
+
19
25
  @Schema()
20
26
  class Total {
21
27
  total: number;
@@ -24,7 +30,7 @@ class Total {
24
30
  function makeField(name: string, type: Class, required: boolean, extra: Partial<SchemaFieldConfig>): SchemaFieldConfig {
25
31
  return {
26
32
  name,
27
- owner: null!,
33
+ class: null!,
28
34
  type,
29
35
  array: false,
30
36
  ...(required ? { required: { active: true } } : {}),
@@ -105,8 +111,8 @@ export abstract class SQLDialect implements DialectState {
105
111
  * Generate an id field
106
112
  */
107
113
  idField = makeField('id', String, true, {
108
- maxlength: { n: this.ID_LENGTH },
109
- minlength: { n: this.ID_LENGTH }
114
+ maxlength: { limit: this.ID_LENGTH },
115
+ minlength: { limit: this.ID_LENGTH }
110
116
  });
111
117
 
112
118
  /**
@@ -118,8 +124,8 @@ export abstract class SQLDialect implements DialectState {
118
124
  * Parent path reference
119
125
  */
120
126
  parentPathField = makeField('__parent_path', String, true, {
121
- maxlength: { n: this.HASH_LENGTH },
122
- minlength: { n: this.HASH_LENGTH },
127
+ maxlength: { limit: this.HASH_LENGTH },
128
+ minlength: { limit: this.HASH_LENGTH },
123
129
  required: { active: true }
124
130
  });
125
131
 
@@ -127,8 +133,8 @@ export abstract class SQLDialect implements DialectState {
127
133
  * Path reference
128
134
  */
129
135
  pathField = makeField('__path', String, true, {
130
- maxlength: { n: this.HASH_LENGTH },
131
- minlength: { n: this.HASH_LENGTH },
136
+ maxlength: { limit: this.HASH_LENGTH },
137
+ minlength: { limit: this.HASH_LENGTH },
132
138
  required: { active: true }
133
139
  });
134
140
 
@@ -156,6 +162,11 @@ export abstract class SQLDialect implements DialectState {
156
162
  */
157
163
  abstract hash(input: string): string;
158
164
 
165
+ /**
166
+ * Describe a table structure
167
+ */
168
+ abstract describeTable(table: string): Promise<SQLTableDescription | undefined>;
169
+
159
170
  executeSQL<T>(sql: string): Promise<{ records: T[], count: number }> {
160
171
  return this.connection.execute<T>(this.connection.active, sql);
161
172
  }
@@ -253,7 +264,7 @@ export abstract class SQLDialect implements DialectState {
253
264
  if (config.specifiers?.includes('text')) {
254
265
  type = this.COLUMN_TYPES.TEXT;
255
266
  } else {
256
- type = this.PARAMETERIZED_COLUMN_TYPES.VARCHAR(config.maxlength ? config.maxlength.n : this.DEFAULT_STRING_LENGTH);
267
+ type = this.PARAMETERIZED_COLUMN_TYPES.VARCHAR(config.maxlength?.limit ?? this.DEFAULT_STRING_LENGTH);
257
268
  }
258
269
  } else if (config.type === PointConcrete) {
259
270
  type = this.COLUMN_TYPES.POINT;
@@ -267,12 +278,13 @@ export abstract class SQLDialect implements DialectState {
267
278
  /**
268
279
  * FieldConfig to Column definition
269
280
  */
270
- getColumnDefinition(config: SchemaFieldConfig): string | undefined {
281
+ getColumnDefinition(config: SchemaFieldConfig, overrideRequired?: boolean): string | undefined {
271
282
  const type = this.getColumnType(config);
272
283
  if (!type) {
273
284
  return;
274
285
  }
275
- return `${this.identifier(config)} ${type} ${(config.required?.active !== false) ? 'NOT NULL' : 'DEFAULT NULL'}`;
286
+ const required = overrideRequired ? true : (config.required?.active ?? false);
287
+ return `${this.identifier(config)} ${type} ${required ? 'NOT NULL' : ''}`;
276
288
  }
277
289
 
278
290
  /**
@@ -420,7 +432,7 @@ export abstract class SQLDialect implements DialectState {
420
432
  // If dealing with simple external
421
433
  sStack.push({
422
434
  name: field.name,
423
- owner: null!,
435
+ class: null!,
424
436
  type: field.type
425
437
  });
426
438
  }
@@ -652,17 +664,11 @@ ${this.getLimitSQL(cls, query)}`;
652
664
  let idField = fields.find(field => field.name === this.idField.name);
653
665
  if (!idField) {
654
666
  fields.push(idField = this.idField);
655
- } else {
656
- idField.maxlength = { n: this.ID_LENGTH };
657
667
  }
658
668
  }
659
669
 
660
670
  const fieldSql = fields
661
- .map(field => {
662
- const def = this.getColumnDefinition(field) || '';
663
- return field.name === this.idField.name && !parent ?
664
- def.replace('DEFAULT NULL', 'NOT NULL') : def;
665
- })
671
+ .map(field => this.getColumnDefinition(field, field.name === this.idField.name && !parent) || '')
666
672
  .filter(line => !!line.trim())
667
673
  .join(',\n ');
668
674
 
@@ -714,6 +720,14 @@ CREATE TABLE IF NOT EXISTS ${this.table(stack)} (
714
720
  return indices.map(idx => this.getCreateIndexSQL(cls, idx));
715
721
  }
716
722
 
723
+ /**
724
+ * Get index name
725
+ */
726
+ getIndexName<T extends ModelType>(cls: Class<T>, idx: IndexConfig<ModelType>): string {
727
+ const table = this.namespace(SQLModelUtil.classToStack(cls));
728
+ return ['idx', table, idx.name.toLowerCase().replaceAll('-', '_')].join('_');
729
+ }
730
+
717
731
  /**
718
732
  * Get CREATE INDEX sql
719
733
  */
@@ -727,12 +741,20 @@ CREATE TABLE IF NOT EXISTS ${this.table(stack)} (
727
741
  }
728
742
  return [castTo(key), typeof value === 'number' ? value === 1 : (!!value)];
729
743
  });
730
- const constraint = `idx_${table}_${fields.map(([field]) => field).join('_')}`;
744
+ const constraint = this.getIndexName(cls, idx);
731
745
  return `CREATE ${idx.type === 'unique' ? 'UNIQUE ' : ''}INDEX ${constraint} ON ${this.identifier(table)} (${fields
732
746
  .map(([name, sel]) => `${this.identifier(name)} ${sel ? 'ASC' : 'DESC'}`)
733
747
  .join(', ')});`;
734
748
  }
735
749
 
750
+ /**
751
+ * Get DROP INDEX sql
752
+ */
753
+ getDropIndexSQL<T extends ModelType>(cls: Class<T>, idx: IndexConfig<T> | string): string {
754
+ const constraint = typeof idx === 'string' ? idx : this.getIndexName(cls, idx);
755
+ return `DROP INDEX ${this.identifier(constraint)} ;`;
756
+ }
757
+
736
758
  /**
737
759
  * Drop all tables for a given class
738
760
  */
@@ -869,8 +891,8 @@ ${this.getWhereSQL(type, where)};`;
869
891
  }
870
892
 
871
893
  /**
872
- * Get elements by ids
873
- */
894
+ * Get elements by ids
895
+ */
874
896
  getSelectRowsByIdsSQL(stack: VisitStack[], ids: string[], select: SchemaFieldConfig[] = []): string {
875
897
  const config = stack.at(-1)!;
876
898
  const orderBy = !config.array ?
@@ -1035,4 +1057,45 @@ ${this.getWhereSQL(cls, where!)}`;
1035
1057
 
1036
1058
  return out;
1037
1059
  }
1060
+
1061
+ /**
1062
+ * Determine if a column has changed
1063
+ */
1064
+ isColumnChanged(requested: SchemaFieldConfig, existing: SQLTableDescription['columns'][number],): boolean {
1065
+ const requestedColumnType = this.getColumnType(requested);
1066
+ const result =
1067
+ (requested.name !== this.idField.name && !!requested.required?.active !== !!existing.is_notnull)
1068
+ || (requestedColumnType.toUpperCase() !== existing.type.toUpperCase());
1069
+
1070
+ return result;
1071
+ }
1072
+
1073
+ /**
1074
+ * Determine if an index has changed
1075
+ */
1076
+ isIndexChanged(requested: IndexConfig<ModelType>, existing: SQLTableDescription['indices'][number]): boolean {
1077
+ let result =
1078
+ (existing.is_unique && requested.type !== 'unique')
1079
+ || requested.fields.length !== existing.columns.length;
1080
+
1081
+ for (let i = 0; i < requested.fields.length && !result; i++) {
1082
+ const [[key, value]] = Object.entries(requested.fields[i]);
1083
+ const desc = value === -1;
1084
+ result ||= key !== existing.columns[i].name && desc !== existing.columns[i].desc;
1085
+ }
1086
+
1087
+ return result;
1088
+ }
1089
+
1090
+ /**
1091
+ * Enforce the dialect specific id length
1092
+ */
1093
+ enforceIdLength(cls: Class<ModelType>): void {
1094
+ const config = SchemaRegistryIndex.getConfig(cls);
1095
+ const idField = config.fields[this.idField.name];
1096
+ if (idField) {
1097
+ idField.maxlength = { limit: this.ID_LENGTH };
1098
+ idField.minlength = { limit: this.ID_LENGTH };
1099
+ }
1100
+ }
1038
1101
  }
package/src/service.ts CHANGED
@@ -5,7 +5,7 @@ import {
5
5
  ModelExpiryUtil, ModelCrudUtil, ModelStorageUtil, ModelBulkUtil,
6
6
  } from '@travetto/model';
7
7
  import { castTo, Class } from '@travetto/runtime';
8
- import { DataUtil, SchemaChange } from '@travetto/schema';
8
+ import { DataUtil } from '@travetto/schema';
9
9
  import { AsyncContext } from '@travetto/context';
10
10
  import { Injectable } from '@travetto/di';
11
11
  import {
@@ -99,15 +99,11 @@ export class SQLModelService implements
99
99
  }
100
100
 
101
101
  async postConstruct(): Promise<void> {
102
- if (this.#dialect) {
103
- if (this.#dialect.connection.init) {
104
- await this.#dialect.connection.init();
105
- }
106
- this.idSource = ModelCrudUtil.uuidSource(this.#dialect.ID_LENGTH);
107
- this.#manager = new TableManager(this.#context, this.#dialect);
108
- await ModelStorageUtil.registerModelChangeListener(this);
109
- ModelExpiryUtil.registerCull(this);
110
- }
102
+ await this.#dialect.connection.init?.();
103
+ this.idSource = ModelCrudUtil.uuidSource(this.#dialect.ID_LENGTH);
104
+ this.#manager = new TableManager(this.#context, this.#dialect);
105
+ await ModelStorageUtil.storageInitialization(this);
106
+ ModelExpiryUtil.registerCull(this);
111
107
  }
112
108
 
113
109
  get connection(): Connection {
@@ -118,12 +114,8 @@ export class SQLModelService implements
118
114
  return (await this.#manager.exportTables(cls)).join('\n');
119
115
  }
120
116
 
121
- async changeSchema(cls: Class, change: SchemaChange): Promise<void> {
122
- await this.#manager.changeSchema(cls, change);
123
- }
124
-
125
- async createModel(cls: Class): Promise<void> {
126
- await this.#manager.createTables(cls);
117
+ async upsertModel(cls: Class): Promise<void> {
118
+ await this.#manager.upsertTables(cls);
127
119
  }
128
120
 
129
121
  async deleteModel(cls: Class): Promise<void> {
@@ -1,8 +1,7 @@
1
1
  import { AsyncContext, WithAsyncContext } from '@travetto/context';
2
2
  import { ModelRegistryIndex } from '@travetto/model';
3
3
  import { Class } from '@travetto/runtime';
4
- import { ChangeEvent } from '@travetto/registry';
5
- import { SchemaChange } from '@travetto/schema';
4
+ import { SchemaRegistryIndex, type SchemaFieldConfig } from '@travetto/schema';
6
5
 
7
6
  import { Connected, Transactional } from './connection/decorator.ts';
8
7
  import { SQLDialect } from './dialect/base.ts';
@@ -10,6 +9,10 @@ import { SQLModelUtil } from './util.ts';
10
9
  import { Connection } from './connection/base.ts';
11
10
  import { VisitStack } from './types.ts';
12
11
 
12
+ type UpsertStructure = { dropIndex: string[], createIndex: string[], table: string[] };
13
+ const isSimpleField = (input: VisitStack | undefined): input is SchemaFieldConfig =>
14
+ !!input && (!('type' in input) || (input.type && !SchemaRegistryIndex.has(input.type)));
15
+
13
16
  /**
14
17
  * Manage creation/updating of all tables
15
18
  */
@@ -27,6 +30,13 @@ export class TableManager {
27
30
  return this.#dialect.executeSQL<T>(sql);
28
31
  }
29
32
 
33
+ /**
34
+ * Get a valid connection
35
+ */
36
+ get connection(): Connection {
37
+ return this.#dialect.connection;
38
+ }
39
+
30
40
  /**
31
41
  * Create all needed tables for a given class
32
42
  */
@@ -44,30 +54,84 @@ export class TableManager {
44
54
  return out;
45
55
  }
46
56
 
47
- /**
48
- * Create all needed tables for a given class
49
- */
50
57
  @WithAsyncContext()
51
58
  @Connected()
52
- @Transactional()
53
- async createTables(cls: Class): Promise<void> {
54
- for (const command of this.#dialect.getCreateAllTablesSQL(cls)) {
55
- await this.#exec(command);
56
- }
57
- const indices = ModelRegistryIndex.getConfig(cls).indices;
58
- if (indices) {
59
- for (const command of this.#dialect.getCreateAllIndicesSQL(cls, indices)) {
60
- try {
61
- await this.#exec(command);
62
- } catch (error) {
63
- if (!(error instanceof Error)) {
64
- throw error;
59
+ async getUpsertTablesSQL(cls: Class): Promise<UpsertStructure> {
60
+ const sqlCommands: UpsertStructure = { dropIndex: [], createIndex: [], table: [] };
61
+
62
+ const onVisit = async (type: Class, fields: SchemaFieldConfig[], path: VisitStack[]): Promise<void> => {
63
+ const found = await this.#dialect.describeTable(this.#dialect.namespace(path));
64
+ const existingFields = new Map(found?.columns.map(column => [column.name, column]) ?? []);
65
+ const existingIndices = new Map(found?.indices.map(index => [index.name, index]) ?? []);
66
+ const model = path.length === 1 ? ModelRegistryIndex.getConfig(type) : undefined;
67
+ const requestedIndices = new Map((model?.indices ?? []).map(index => [this.#dialect.getIndexName(type, index), index]) ?? []);
68
+
69
+
70
+ // Manage fields
71
+ if (!existingFields.size) {
72
+ sqlCommands.table.push(this.#dialect.getCreateTableSQL(path));
73
+ } else { // Existing
74
+ // Fields
75
+ const requestedFields = new Map(fields.map(field => [field.name, field]));
76
+ const top = path.at(-1);
77
+
78
+ if (isSimpleField(top)) {
79
+ requestedFields.set(top.name, top);
80
+ }
81
+
82
+ for (const [column, field] of requestedFields.entries()) {
83
+ if (!existingFields.has(column)) {
84
+ sqlCommands.table.push(this.#dialect.getAddColumnSQL([...path, field]));
85
+ } else if (this.#dialect.isColumnChanged(field, existingFields.get(column)!)) {
86
+ sqlCommands.table.push(this.#dialect.getModifyColumnSQL([...path, field]));
65
87
  }
66
- if (!/\bexists|duplicate\b/i.test(error.message)) {
67
- throw error;
88
+ }
89
+
90
+ // TODO: Handle dropping tables that are FK'd when no longer in use
91
+
92
+ for (const column of existingFields.keys()) {
93
+ if (!requestedFields.has(column)) {
94
+ sqlCommands.table.push(this.#dialect.getDropColumnSQL([...path, { name: column, type: undefined!, array: false }]));
68
95
  }
69
96
  }
70
97
  }
98
+
99
+ // Manage indices
100
+ for (const index of requestedIndices.keys()) {
101
+ if (!existingIndices.has(index)) {
102
+ sqlCommands.createIndex.push(this.#dialect.getCreateIndexSQL(type, requestedIndices.get(index)!));
103
+ } else if (this.#dialect.isIndexChanged(requestedIndices.get(index)!, existingIndices.get(index)!)) {
104
+ sqlCommands.dropIndex.push(this.#dialect.getDropIndexSQL(type, existingIndices.get(index)!.name));
105
+ sqlCommands.createIndex.push(this.#dialect.getCreateIndexSQL(type, requestedIndices.get(index)!));
106
+ }
107
+ }
108
+
109
+ for (const index of existingIndices.keys()) {
110
+ if (!requestedIndices.has(index)) {
111
+ sqlCommands.dropIndex.push(this.#dialect.getDropIndexSQL(type, existingIndices.get(index)!.name));
112
+ }
113
+ }
114
+ };
115
+
116
+ const schema = SchemaRegistryIndex.getConfig(cls);
117
+ await SQLModelUtil.visitSchema(schema, {
118
+ onRoot: async ({ config, path, fields, descend }) => { await onVisit(config.class, fields, path); return descend(); },
119
+ onSub: async ({ config, path, fields, descend }) => { await onVisit(config.type, fields, path); return descend(); },
120
+ onSimple: async ({ config, path, fields }) => { await onVisit(config.type, fields, path); }
121
+ });
122
+ return sqlCommands;
123
+ }
124
+
125
+ @WithAsyncContext()
126
+ @Connected()
127
+ @Transactional()
128
+ async upsertTables(cls: Class): Promise<void> {
129
+ // Enforce id length
130
+ this.#dialect.enforceIdLength(cls);
131
+
132
+ const sqlCommands = await this.getUpsertTablesSQL(cls);
133
+ for (const key of ['dropIndex', 'table', 'createIndex'] as const) {
134
+ await Promise.all(sqlCommands[key].map(command => this.#exec(command)));
71
135
  }
72
136
  }
73
137
 
@@ -94,38 +158,4 @@ export class TableManager {
94
158
  await this.#exec(command);
95
159
  }
96
160
  }
97
-
98
- /**
99
- * Get a valid connection
100
- */
101
- get connection(): Connection {
102
- return this.#dialect.connection;
103
- }
104
-
105
- /**
106
- * When the schema changes, update SQL
107
- */
108
- @WithAsyncContext()
109
- @Transactional()
110
- @Connected()
111
- async changeSchema(cls: Class, change: SchemaChange): Promise<void> {
112
- try {
113
- const rootStack = SQLModelUtil.classToStack(cls);
114
-
115
- const changes = change.subs.reduce<Record<ChangeEvent<unknown>['type'], VisitStack[][]>>((result, value) => {
116
- const path = value.path.map(field => ({ ...field }));
117
- for (const event of value.fields) {
118
- result[event.type].push([...rootStack, ...path, { ...(event.type === 'removing' ? event.previous : event.current)! }]);
119
- }
120
- return result;
121
- }, { added: [], changed: [], removing: [] });
122
-
123
- await Promise.all(changes.added.map(value => this.#dialect.executeSQL(this.#dialect.getAddColumnSQL(value))));
124
- await Promise.all(changes.changed.map(value => this.#dialect.executeSQL(this.#dialect.getModifyColumnSQL(value))));
125
- await Promise.all(changes.removing.map(value => this.#dialect.executeSQL(this.#dialect.getDropColumnSQL(value))));
126
- } catch (error) {
127
- // Failed to change
128
- console.error('Unable to change field', { error });
129
- }
130
- }
131
161
  }
package/src/util.ts CHANGED
@@ -104,7 +104,7 @@ export class SQLModelUtil {
104
104
  * Process a schema structure, synchronously
105
105
  */
106
106
  static visitSchemaSync(config: SchemaClassConfig | SchemaFieldConfig, handler: VisitHandler<void>, state: VisitState = { path: [] }): void {
107
- const path = 'class' in config ? this.classToStack(config.class) : [...state.path, config];
107
+ const path = 'fields' in config ? this.classToStack(config.class) : [...state.path, config];
108
108
  const { local: fields, foreign } = this.getFieldsByLocation(path);
109
109
 
110
110
  const descend = (): void => {
@@ -121,7 +121,7 @@ export class SQLModelUtil {
121
121
  }
122
122
  };
123
123
 
124
- if ('class' in config) {
124
+ if ('fields' in config) {
125
125
  return handler.onRoot({ config, fields, descend, path });
126
126
  } else {
127
127
  return handler.onSub({ config, fields, descend, path });
@@ -132,7 +132,7 @@ export class SQLModelUtil {
132
132
  * Visit a Schema structure
133
133
  */
134
134
  static async visitSchema(config: SchemaClassConfig | SchemaFieldConfig, handler: VisitHandler<Promise<void>>, state: VisitState = { path: [] }): Promise<void> {
135
- const path = 'class' in config ? this.classToStack(config.class) : [...state.path, config];
135
+ const path = 'fields' in config ? this.classToStack(config.class) : [...state.path, config];
136
136
  const { local: fields, foreign } = this.getFieldsByLocation(path);
137
137
 
138
138
  const descend = async (): Promise<void> => {
@@ -149,7 +149,7 @@ export class SQLModelUtil {
149
149
  }
150
150
  };
151
151
 
152
- if ('class' in config) {
152
+ if ('fields' in config) {
153
153
  return handler.onRoot({ config, fields, descend, path });
154
154
  } else {
155
155
  return handler.onSub({ config, fields, descend, path });
@@ -210,7 +210,7 @@ export class SQLModelUtil {
210
210
  */
211
211
  static select<T>(cls: Class<T>, select?: SelectClause<T>): SchemaFieldConfig[] {
212
212
  if (!select || Object.keys(select).length === 0) {
213
- return [{ type: cls, name: '*', owner: cls, array: false }];
213
+ return [{ type: cls, name: '*', class: cls, array: false }];
214
214
  }
215
215
 
216
216
  const { localMap } = this.getFieldsByLocation(this.classToStack(cls));
@@ -69,7 +69,7 @@ export abstract class BaseSQLTest extends BaseModelSuite<SQLModelService> {
69
69
  dct.resolveName = (stack: VisitStack[]) => {
70
70
  const field: SchemaFieldConfig = castTo(stack.at(-1));
71
71
  const parent: SchemaFieldConfig = castTo(stack.at(-2));
72
- return `${field.owner ? field.owner.name.toString() : parent.name.toString()}.${field.name.toString()}`;
72
+ return `${field.class ? field.class.name.toString() : parent.name.toString()}.${field.name.toString()}`;
73
73
  };
74
74
 
75
75
  const qryStr = dct.getWhereGroupingSQL(WhereType, qry);
@@ -81,7 +81,7 @@ export abstract class BaseSQLTest extends BaseModelSuite<SQLModelService> {
81
81
  const dct = await this.dialect;
82
82
  dct.resolveName = (stack: VisitStack[]) => {
83
83
  const field: SchemaFieldConfig = castTo(stack.at(-1));
84
- return `${field.owner?.name}.${field.name.toString()}`;
84
+ return `${field.class?.name}.${field.name.toString()}`;
85
85
  };
86
86
 
87
87
  const out = dct.getWhereGroupingSQL(User, {