@travetto/model-sql 7.0.0-rc.1 → 7.0.0-rc.3

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/src/util.ts CHANGED
@@ -8,9 +8,9 @@ import { TableSymbol, VisitStack } from './types.ts';
8
8
 
9
9
  type FieldCacheEntry = {
10
10
  local: SchemaFieldConfig[];
11
- localMap: Record<string | symbol, SchemaFieldConfig>;
11
+ localMap: Record<string, SchemaFieldConfig>;
12
12
  foreign: SchemaFieldConfig[];
13
- foreignMap: Record<string | symbol, SchemaFieldConfig>;
13
+ foreignMap: Record<string, SchemaFieldConfig>;
14
14
  };
15
15
 
16
16
  /**
@@ -30,22 +30,22 @@ export class SQLModelUtil {
30
30
  /**
31
31
  * Clean results from db, by dropping internal fields
32
32
  */
33
- static cleanResults<T, U = T>(dct: DialectState, o: T[]): U[];
34
- static cleanResults<T, U = T>(dct: DialectState, o: T): U;
35
- static cleanResults<T, U = T>(dct: DialectState, o: T | T[]): U | U[] {
36
- if (Array.isArray(o)) {
37
- return o.filter(x => x !== null && x !== undefined).map(x => this.cleanResults(dct, x));
38
- } else if (!DataUtil.isSimpleValue(o)) {
39
- for (const k of TypedObject.keys(o)) {
40
- if (o[k] === null || o[k] === undefined || k === dct.parentPathField.name || k === dct.pathField.name || k === dct.idxField.name) {
41
- delete o[k];
33
+ static cleanResults<T, U = T>(state: DialectState, item: T[]): U[];
34
+ static cleanResults<T, U = T>(state: DialectState, item: T): U;
35
+ static cleanResults<T, U = T>(state: DialectState, item: T | T[]): U | U[] {
36
+ if (Array.isArray(item)) {
37
+ return item.filter(value => value !== null && value !== undefined).map(value => this.cleanResults(state, value));
38
+ } else if (!DataUtil.isSimpleValue(item)) {
39
+ for (const key of TypedObject.keys(item)) {
40
+ if (item[key] === null || item[key] === undefined || key === state.parentPathField.name || key === state.pathField.name || key === state.idxField.name) {
41
+ delete item[key];
42
42
  } else {
43
- o[k] = this.cleanResults(dct, o[k]);
43
+ item[key] = this.cleanResults(state, item[key]);
44
44
  }
45
45
  }
46
- return castTo({ ...o });
46
+ return castTo({ ...item });
47
47
  } else {
48
- return castTo(o);
48
+ return castTo(item);
49
49
  }
50
50
  }
51
51
 
@@ -54,13 +54,13 @@ export class SQLModelUtil {
54
54
  */
55
55
  static getFieldsByLocation(stack: VisitStack[]): FieldCacheEntry {
56
56
  const top = stack.at(-1)!;
57
- const conf = SchemaRegistryIndex.has(top.type) ? SchemaRegistryIndex.getConfig(top.type) : undefined;
57
+ const config = SchemaRegistryIndex.getOptional(top.type)?.get();
58
58
 
59
- if (conf && this.#schemaFieldsCache.has(conf.class)) {
60
- return this.#schemaFieldsCache.get(conf.class)!;
59
+ if (config && this.#schemaFieldsCache.has(config.class)) {
60
+ return this.#schemaFieldsCache.get(config.class)!;
61
61
  }
62
62
 
63
- if (!conf) { // If a simple type, it is it's own field
63
+ if (!config) { // If a simple type, it is it's own field
64
64
  const field: SchemaFieldConfig = castTo({ ...top });
65
65
  return {
66
66
  local: [field], localMap: { [field.name]: field },
@@ -68,15 +68,15 @@ export class SQLModelUtil {
68
68
  };
69
69
  }
70
70
 
71
- const hasModel = ModelRegistryIndex.has(conf.class)!;
72
- const fields = Object.values(conf.fields).map(field => ({ ...field }));
71
+ const hasModel = ModelRegistryIndex.has(config.class)!;
72
+ const fields = Object.values(config.fields).map(field => ({ ...field }));
73
73
 
74
74
  // Polymorphic
75
- if (hasModel && conf.discriminatedBase) {
76
- const fieldMap = new Set(fields.map(f => f.name));
77
- for (const type of SchemaRegistryIndex.getDiscriminatedClasses(conf.class)) {
78
- const typeConf = SchemaRegistryIndex.getConfig(type);
79
- for (const [fieldName, field] of Object.entries<SchemaFieldConfig>(typeConf.fields)) {
75
+ if (hasModel && config.discriminatedBase) {
76
+ const fieldMap = new Set(fields.map(field => field.name));
77
+ for (const type of SchemaRegistryIndex.getDiscriminatedClasses(config.class)) {
78
+ const typeConfig = SchemaRegistryIndex.getConfig(type);
79
+ for (const [fieldName, field] of Object.entries<SchemaFieldConfig>(typeConfig.fields)) {
80
80
  if (!fieldMap.has(fieldName)) {
81
81
  fieldMap.add(fieldName);
82
82
  fields.push({ ...field, required: { active: false } });
@@ -85,26 +85,26 @@ export class SQLModelUtil {
85
85
  }
86
86
  }
87
87
 
88
- const ret: FieldCacheEntry = {
88
+ const entry: FieldCacheEntry = {
89
89
  localMap: {},
90
90
  foreignMap: {},
91
- local: fields.filter(x => !SchemaRegistryIndex.has(x.type) && !x.array),
92
- foreign: fields.filter(x => SchemaRegistryIndex.has(x.type) || x.array)
91
+ local: fields.filter(field => !SchemaRegistryIndex.has(field.type) && !field.array),
92
+ foreign: fields.filter(field => SchemaRegistryIndex.has(field.type) || field.array)
93
93
  };
94
94
 
95
- ret.local.reduce((acc, f) => (acc[f.name] = f) && acc, ret.localMap);
96
- ret.foreign.reduce((acc, f) => (acc[f.name] = f) && acc, ret.foreignMap);
95
+ entry.local.reduce((map, field) => (map[field.name] = field) && map, entry.localMap);
96
+ entry.foreign.reduce((map, field) => (map[field.name] = field) && map, entry.foreignMap);
97
97
 
98
- this.#schemaFieldsCache.set(conf.class, ret);
98
+ this.#schemaFieldsCache.set(config.class, entry);
99
99
 
100
- return ret;
100
+ return entry;
101
101
  }
102
102
 
103
103
  /**
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 });
@@ -160,7 +160,7 @@ export class SQLModelUtil {
160
160
  * Process a schema instance by visiting it synchronously. This is synchronous to prevent concurrent calls from breaking
161
161
  */
162
162
  static visitSchemaInstance<T extends ModelType>(cls: Class<T>, instance: T | OptionalId<T>, handler: VisitHandler<unknown, VisitInstanceNode<unknown>>): void {
163
- const pathObj: unknown[] = [instance];
163
+ const pathStack: unknown[] = [instance];
164
164
  this.visitSchemaSync(SchemaRegistryIndex.getConfig(cls), {
165
165
  onRoot: (config) => {
166
166
  const { path } = config;
@@ -170,24 +170,24 @@ export class SQLModelUtil {
170
170
  },
171
171
  onSub: (config) => {
172
172
  const { config: field } = config;
173
- const topObj: Record<string | symbol, unknown> = castTo(pathObj.at(-1));
173
+ const topObject: Record<string, unknown> = castTo(pathStack.at(-1));
174
174
  const top = config.path.at(-1)!;
175
175
 
176
- if (field.name in topObj) {
177
- const value = topObj[field.name];
178
- const values = Array.isArray(value) ? value : [value];
176
+ if (field.name in topObject) {
177
+ const valuesInput = topObject[field.name];
178
+ const values = Array.isArray(valuesInput) ? valuesInput : [valuesInput];
179
179
 
180
180
  let i = 0;
181
- for (const val of values) {
181
+ for (const value of values) {
182
182
  try {
183
- pathObj.push(val);
183
+ pathStack.push(value);
184
184
  config.path[config.path.length - 1] = { ...top, index: i++ };
185
- handler.onSub({ ...config, value: val });
185
+ handler.onSub({ ...config, value });
186
186
  if (!field.array) {
187
187
  config.descend();
188
188
  }
189
189
  } finally {
190
- pathObj.pop();
190
+ pathStack.pop();
191
191
  }
192
192
  i += 1;
193
193
  }
@@ -198,8 +198,8 @@ export class SQLModelUtil {
198
198
  },
199
199
  onSimple: (config) => {
200
200
  const { config: field } = config;
201
- const topObj: Record<string | symbol, unknown> = castTo(pathObj.at(-1));
202
- const value = topObj[field.name];
201
+ const topObject: Record<string, unknown> = castTo(pathStack.at(-1));
202
+ const value = topObject[field.name];
203
203
  return handler.onSimple({ ...config, value });
204
204
  }
205
205
  });
@@ -210,26 +210,26 @@ 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));
217
217
 
218
218
  let toGet = new Set<string>();
219
219
 
220
- for (const [k, v] of TypedObject.entries(select)) {
221
- if (typeof k === 'string' && !DataUtil.isPlainObject(select[k]) && localMap[k]) {
222
- if (!v) {
220
+ for (const [key, value] of TypedObject.entries(select)) {
221
+ if (typeof key === 'string' && !DataUtil.isPlainObject(select[key]) && localMap[key]) {
222
+ if (!value) {
223
223
  if (toGet.size === 0) {
224
224
  toGet = new Set(Object.keys(SchemaRegistryIndex.getConfig(cls).fields));
225
225
  }
226
- toGet.delete(k);
226
+ toGet.delete(key);
227
227
  } else {
228
- toGet.add(k);
228
+ toGet.add(key);
229
229
  }
230
230
  }
231
231
  }
232
- return [...toGet].map(el => localMap[el]);
232
+ return [...toGet].map(field => localMap[field]);
233
233
  }
234
234
 
235
235
  /**
@@ -242,15 +242,15 @@ export class SQLModelUtil {
242
242
  let found: OrderBy | undefined;
243
243
  while (!found) {
244
244
  const key = Object.keys(cl)[0];
245
- const val = cl[key];
245
+ const value = cl[key];
246
246
  const field = { ...schema.fields[key] };
247
- if (DataUtil.isPrimitive(val)) {
247
+ if (DataUtil.isPrimitive(value)) {
248
248
  stack.push(field);
249
- found = { stack, asc: val === 1 };
249
+ found = { stack, asc: value === 1 };
250
250
  } else {
251
251
  stack.push(field);
252
252
  schema = SchemaRegistryIndex.getConfig(field.type);
253
- cl = castTo(val);
253
+ cl = castTo(value);
254
254
  }
255
255
  }
256
256
  return found;
@@ -260,30 +260,30 @@ export class SQLModelUtil {
260
260
  /**
261
261
  * Find all dependent fields via child tables
262
262
  */
263
- static collectDependents<T>(dct: DialectState, parent: unknown, v: T[], field?: SchemaFieldConfig): Record<string, T> {
263
+ static collectDependents<T>(state: DialectState, parent: unknown, items: T[], field?: SchemaFieldConfig): Record<string, T> {
264
264
  if (field) {
265
265
  const isSimple = SchemaRegistryIndex.has(field.type);
266
- for (const el of v) {
267
- const parentKey: string = castTo(el[castKey<T>(dct.parentPathField.name)]);
266
+ for (const item of items) {
267
+ const parentKey: string = castTo(item[castKey<T>(state.parentPathField.name)]);
268
268
  const root = castTo<Record<string, Record<string, unknown>>>(parent)[parentKey];
269
269
  const fieldKey = castKey<(typeof root) | T>(field.name);
270
270
  if (field.array) {
271
271
  if (!root[fieldKey]) {
272
- root[fieldKey] = [isSimple ? el : el[fieldKey]];
272
+ root[fieldKey] = [isSimple ? item : item[fieldKey]];
273
273
  } else if (Array.isArray(root[fieldKey])) {
274
- root[fieldKey].push(isSimple ? el : el[fieldKey]);
274
+ root[fieldKey].push(isSimple ? item : item[fieldKey]);
275
275
  }
276
276
  } else {
277
- root[fieldKey] = isSimple ? el : el[fieldKey];
277
+ root[fieldKey] = isSimple ? item : item[fieldKey];
278
278
  }
279
279
  }
280
280
  }
281
281
 
282
282
  const mapping: Record<string, T> = {};
283
- for (const el of v) {
284
- const key = el[castKey<T>(dct.pathField.name)];
283
+ for (const item of items) {
284
+ const key = item[castKey<T>(state.pathField.name)];
285
285
  if (typeof key === 'string') {
286
- mapping[key] = el;
286
+ mapping[key] = item;
287
287
  }
288
288
  }
289
289
  return mapping;
@@ -295,7 +295,7 @@ export class SQLModelUtil {
295
295
  static buildTable(list: VisitStack[]): string {
296
296
  const top = list.at(-1)!;
297
297
  if (!top[TableSymbol]) {
298
- top[TableSymbol] = list.map((el, i) => i === 0 ? ModelRegistryIndex.getStoreName(el.type) : el.name).join('_');
298
+ top[TableSymbol] = list.map((item, i) => i === 0 ? ModelRegistryIndex.getStoreName(item.type) : item.name).join('_');
299
299
  }
300
300
  return top[TableSymbol]!;
301
301
  }
@@ -304,22 +304,22 @@ export class SQLModelUtil {
304
304
  * Build property path for a table/field given the current stack
305
305
  */
306
306
  static buildPath(list: VisitStack[]): string {
307
- return list.map((el) => `${el.name.toString()}${el.index ? `[${el.index}]` : ''}`).join('.');
307
+ return list.map((item) => `${item.name}${item.index ? `[${item.index}]` : ''}`).join('.');
308
308
  }
309
309
 
310
310
  /**
311
311
  * Get insert statements for a given class, and its child tables
312
312
  */
313
- static async getInserts<T extends ModelType>(cls: Class<T>, els: (T | OptionalId<T>)[]): Promise<InsertWrapper[]> {
314
- const ins: Record<string, InsertWrapper> = {};
313
+ static async getInserts<T extends ModelType>(cls: Class<T>, items: (T | OptionalId<T>)[]): Promise<InsertWrapper[]> {
314
+ const wrappers: Record<string, InsertWrapper> = {};
315
315
 
316
316
  const track = (stack: VisitStack[], value: unknown): void => {
317
317
  const key = this.buildTable(stack);
318
- (ins[key] = ins[key] ?? { stack, records: [] }).records.push({ stack, value });
318
+ (wrappers[key] ??= { stack, records: [] }).records.push({ stack, value });
319
319
  };
320
320
 
321
- const all = els.map(el =>
322
- this.visitSchemaInstance(cls, el, {
321
+ const all = items.map(item =>
322
+ this.visitSchemaInstance(cls, item, {
323
323
  onRoot: ({ path, value }) => track(path, value),
324
324
  onSub: ({ path, value }) => track(path, value),
325
325
  onSimple: ({ path, value }) => track(path, value)
@@ -327,7 +327,7 @@ export class SQLModelUtil {
327
327
 
328
328
  await Promise.all(all);
329
329
 
330
- const result = [...Object.values(ins)].toSorted((a, b) => a.stack.length - b.stack.length);
330
+ const result = [...Object.values(wrappers)].toSorted((a, b) => a.stack.length - b.stack.length);
331
331
  return result;
332
332
  }
333
333
  }
@@ -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, {