rads-db 3.0.3 → 3.0.6

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/index.cjs CHANGED
@@ -1017,7 +1017,7 @@ function generateMethods(schema, validators, options) {
1017
1017
  typeName: key,
1018
1018
  handle: schema[key].handle
1019
1019
  };
1020
- const driverInstance = getDriverInstance(schema, key, opts.driver, drivers);
1020
+ const driverInstance = getDriverInstance(schema, key, getDriverConstructor(opts, schema, key), drivers);
1021
1021
  db[handle] = getRadsDbMethods(key, computedContext, driverInstance);
1022
1022
  }
1023
1023
  for (const f of opts.features) {
@@ -1026,18 +1026,13 @@ function generateMethods(schema, validators, options) {
1026
1026
  }
1027
1027
  return db;
1028
1028
  }
1029
- function getDriverInstance(schema, key, driver, driverInstances) {
1029
+ function getDriverInstance(schema, key, driverConstructor, driverInstances) {
1030
1030
  if (!driverInstances[key]) {
1031
- driverInstances[key] = getDriverInstanceInner(schema, key, driver);
1031
+ driverInstances[key] = getDriverInstanceInner(schema, key, driverConstructor);
1032
1032
  }
1033
1033
  return driverInstances[key];
1034
1034
  }
1035
- function getDriverInstanceInner(schema, key, drivers) {
1036
- const driverName = schema[key].decorators.entity.driver || "default";
1037
- const driverConstructor = drivers[driverName];
1038
- if (!driverConstructor) {
1039
- throw new Error(`Missing driver "${driverName}" for entity "${key}"`);
1040
- }
1035
+ function getDriverInstanceInner(schema, key, driverConstructor) {
1041
1036
  const driverInstance = driverConstructor(schema, key);
1042
1037
  addDryRunSupport(driverInstance, key);
1043
1038
  async function getAll(args, ctx) {
@@ -1142,6 +1137,17 @@ function normalizeOptions(options) {
1142
1137
  driver = { default: driver };
1143
1138
  return { computed: {}, features: [], ...options, driver };
1144
1139
  }
1140
+ function getDriverConstructor(options, schema, key) {
1141
+ let driverName = "default";
1142
+ if (!options.noCustomDrivers) {
1143
+ driverName = schema[key].decorators.entity.driver || driverName;
1144
+ }
1145
+ const driverConstructor = options.driver[driverName];
1146
+ if (!driverConstructor) {
1147
+ throw new Error(`Missing driver "${driverName}" for entity "${key}"`);
1148
+ }
1149
+ return driverConstructor;
1150
+ }
1145
1151
 
1146
1152
  const restApi = (options) => (schema, entity) => {
1147
1153
  const opts = {
package/dist/index.d.ts CHANGED
@@ -86,6 +86,7 @@ interface EntityMethods<E, EN extends keyof EntityMeta, W> {
86
86
  }
87
87
 
88
88
  type MaybePromise<T> = Promise<T> | T;
89
+ type RequiredFields<T, K extends keyof T> = T & Required<Pick<T, K>>;
89
90
  type ValidateFieldDecoratorArgs<T> = T extends string ? ValidateStringDecoratorArgs : T extends number ? ValidateNumberDecoratorArgs : ValidateAnyDecoratorArgs;
90
91
  interface ValidateEntityDecoratorArgs {
91
92
  }
@@ -182,6 +183,9 @@ interface CreateRadsDbArgs {
182
183
  context?: Record<string, any> & Omit<RadsRequestContext, 'dryRun' | 'silent'>;
183
184
  features?: RadsFeature[];
184
185
  }
186
+ type CreateRadsDbArgsNormalized = RequiredFields<CreateRadsDbArgs, 'computed' | 'features'> & {
187
+ driver: CreateRadsArgsDrivers;
188
+ };
185
189
  type CreateRadsDbClientArgs = Omit<CreateRadsDbArgs, 'noComputed' | 'noCustomDrivers' | 'driver'> & {
186
190
  driver?: RestDriverOptions;
187
191
  };
@@ -359,7 +363,7 @@ declare function field(meta?: FieldDecoratorArgs): (a: any, b?: ClassFieldDecora
359
363
  declare function precomputed(meta?: ComputedDecoratorArgs): (a: any, b?: ClassFieldDecoratorContext | ClassDecoratorContext) => void;
360
364
  declare function computed(meta?: ComputedDecoratorArgs): (a: any, b?: ClassFieldDecoratorContext | ClassDecoratorContext) => void;
361
365
 
362
- declare function getDriverInstance(schema: Schema, key: string, driver: CreateRadsArgsDrivers, driverInstances: Record<string, Driver>): Driver;
366
+ declare function getDriverInstance(schema: Schema, key: string, driverConstructor: DriverConstructor, driverInstances: Record<string, Driver>): Driver;
363
367
 
364
368
  /**
365
369
  * Creates instance of rads db - object that provides access to all entities.
@@ -373,4 +377,4 @@ declare function createRadsDb(args?: CreateRadsDbArgs): RadsDb;
373
377
  */
374
378
  declare function createRadsDbClient(args?: CreateRadsDbClientArgs): RadsDb;
375
379
 
376
- export { Change, ComputedContext, ComputedContextGlobal, ComputedDecoratorArgs, CreateRadsArgsDrivers, CreateRadsDbArgs, CreateRadsDbClientArgs, DeepPartial, Driver, DriverConstructor, EntityDecoratorArgs, EntityMethods, FieldDecoratorArgs, FieldDefinition, FileSystemNode, FileUploadArgs, FileUploadDriver, GenerateClientNormalizedOptions, GenerateClientOptions, GetAggArgs, GetAggArgsAgg, GetAggArgsAny, GetAggResponse, GetArgs, GetArgsAny, GetArgsInclude, GetManyArgs, GetManyArgsAny, GetManyResponse, GetResponse, GetResponseInclude, GetResponseIncludeSelect, GetResponseNoInclude, GetRestRoutesArgs, GetRestRoutesOptions, GetRestRoutesResponse, MinimalDriver, PutArgs, PutEffect, RadsFeature, RadsRequestContext, RadsUiSlotDefinition, RadsUiSlotName, RadsVitePluginOptions, Relation, RestDriverOptions, RestFileUploadDriverOptions, Schema, SchemaValidators, TypeDefinition, UiDecoratorArgs, UiFieldDecoratorArgs, ValidateEntityDecoratorArgs, ValidateFieldDecoratorArgs, ValidateStringDecoratorArgs, VerifyManyArgs, VerifyManyArgsAny, VerifyManyResponse, computed, createRadsDb, createRadsDbClient, entity, field, getDriverInstance, precomputed, ui, validate };
380
+ export { Change, ComputedContext, ComputedContextGlobal, ComputedDecoratorArgs, CreateRadsArgsDrivers, CreateRadsDbArgs, CreateRadsDbArgsNormalized, CreateRadsDbClientArgs, DeepPartial, Driver, DriverConstructor, EntityDecoratorArgs, EntityMethods, FieldDecoratorArgs, FieldDefinition, FileSystemNode, FileUploadArgs, FileUploadDriver, GenerateClientNormalizedOptions, GenerateClientOptions, GetAggArgs, GetAggArgsAgg, GetAggArgsAny, GetAggResponse, GetArgs, GetArgsAny, GetArgsInclude, GetManyArgs, GetManyArgsAny, GetManyResponse, GetResponse, GetResponseInclude, GetResponseIncludeSelect, GetResponseNoInclude, GetRestRoutesArgs, GetRestRoutesOptions, GetRestRoutesResponse, MinimalDriver, PutArgs, PutEffect, RadsFeature, RadsRequestContext, RadsUiSlotDefinition, RadsUiSlotName, RadsVitePluginOptions, Relation, RequiredFields, RestDriverOptions, RestFileUploadDriverOptions, Schema, SchemaValidators, TypeDefinition, UiDecoratorArgs, UiFieldDecoratorArgs, ValidateEntityDecoratorArgs, ValidateFieldDecoratorArgs, ValidateStringDecoratorArgs, VerifyManyArgs, VerifyManyArgsAny, VerifyManyResponse, computed, createRadsDb, createRadsDbClient, entity, field, getDriverInstance, precomputed, ui, validate };
package/dist/index.mjs CHANGED
@@ -1009,7 +1009,7 @@ function generateMethods(schema, validators, options) {
1009
1009
  typeName: key,
1010
1010
  handle: schema[key].handle
1011
1011
  };
1012
- const driverInstance = getDriverInstance(schema, key, opts.driver, drivers);
1012
+ const driverInstance = getDriverInstance(schema, key, getDriverConstructor(opts, schema, key), drivers);
1013
1013
  db[handle] = getRadsDbMethods(key, computedContext, driverInstance);
1014
1014
  }
1015
1015
  for (const f of opts.features) {
@@ -1018,18 +1018,13 @@ function generateMethods(schema, validators, options) {
1018
1018
  }
1019
1019
  return db;
1020
1020
  }
1021
- function getDriverInstance(schema, key, driver, driverInstances) {
1021
+ function getDriverInstance(schema, key, driverConstructor, driverInstances) {
1022
1022
  if (!driverInstances[key]) {
1023
- driverInstances[key] = getDriverInstanceInner(schema, key, driver);
1023
+ driverInstances[key] = getDriverInstanceInner(schema, key, driverConstructor);
1024
1024
  }
1025
1025
  return driverInstances[key];
1026
1026
  }
1027
- function getDriverInstanceInner(schema, key, drivers) {
1028
- const driverName = schema[key].decorators.entity.driver || "default";
1029
- const driverConstructor = drivers[driverName];
1030
- if (!driverConstructor) {
1031
- throw new Error(`Missing driver "${driverName}" for entity "${key}"`);
1032
- }
1027
+ function getDriverInstanceInner(schema, key, driverConstructor) {
1033
1028
  const driverInstance = driverConstructor(schema, key);
1034
1029
  addDryRunSupport(driverInstance, key);
1035
1030
  async function getAll(args, ctx) {
@@ -1134,6 +1129,17 @@ function normalizeOptions(options) {
1134
1129
  driver = { default: driver };
1135
1130
  return { computed: {}, features: [], ...options, driver };
1136
1131
  }
1132
+ function getDriverConstructor(options, schema, key) {
1133
+ let driverName = "default";
1134
+ if (!options.noCustomDrivers) {
1135
+ driverName = schema[key].decorators.entity.driver || driverName;
1136
+ }
1137
+ const driverConstructor = options.driver[driverName];
1138
+ if (!driverConstructor) {
1139
+ throw new Error(`Missing driver "${driverName}" for entity "${key}"`);
1140
+ }
1141
+ return driverConstructor;
1142
+ }
1137
1143
 
1138
1144
  const restApi = (options) => (schema, entity) => {
1139
1145
  const opts = {
@@ -56,9 +56,7 @@ var _default = options => {
56
56
  handle: cacheEntityName,
57
57
  handlePlural: `${cacheEntityName}s`
58
58
  };
59
- cacheDrivers[handle] = (0, _radsDb.getDriverInstance)(schema, cacheEntityName, {
60
- default: normalizedOptions[typeName].driver
61
- }, drivers);
59
+ cacheDrivers[handle] = (0, _radsDb.getDriverInstance)(schema, cacheEntityName, normalizedOptions[typeName].driver, drivers);
62
60
  cacheStatus[handle] = {
63
61
  preloadStatus: normalizedOptions[typeName].preload ? "neverLoaded" : void 0
64
62
  };
@@ -38,12 +38,7 @@ export default (options) => {
38
38
  handle: cacheEntityName,
39
39
  handlePlural: `${cacheEntityName}s`
40
40
  };
41
- cacheDrivers[handle] = getDriverInstance(
42
- schema,
43
- cacheEntityName,
44
- { default: normalizedOptions[typeName].driver },
45
- drivers
46
- );
41
+ cacheDrivers[handle] = getDriverInstance(schema, cacheEntityName, normalizedOptions[typeName].driver, drivers);
47
42
  cacheStatus[handle] = { preloadStatus: normalizedOptions[typeName].preload ? "neverLoaded" : void 0 };
48
43
  }
49
44
  db.cache = {
@@ -114,6 +114,7 @@ function getOrder(f) {
114
114
  return decorator.order ?? defaultOrders[decorator.preset] ?? 0;
115
115
  }
116
116
  function parseType(typeDeclaration, typeName, ctx) {
117
+ if (ctx.result[typeName]) return ctx.result[typeName];
117
118
  const {
118
119
  modifiers
119
120
  } = typeDeclaration;
@@ -155,15 +156,27 @@ function parseType(typeDeclaration, typeName, ctx) {
155
156
  }
156
157
  if (typeDeclaration.kind === _typescript.SyntaxKind.TypeAliasDeclaration) {
157
158
  const typeAliasDeclaration = typeDeclaration;
158
- if (typeAliasDeclaration.type.kind !== _typescript.SyntaxKind.UnionType) throw new Error(`Unexpected type definition - ${typeDeclaration.getText(ctx.sourceFile)}. Did you mean 'class'?`);
159
- const typeAliasValue = typeAliasDeclaration.type;
160
- const enumValues = getEnumValues(typeAliasValue, typeDeclaration, ctx);
161
- if (typeDeclaration) return {
162
- name,
163
- decorators,
164
- enumValues,
165
- comment
166
- };
159
+ const typeAliasType = typeAliasDeclaration.type;
160
+ if (typeAliasType.kind === _typescript.SyntaxKind.UnionType) {
161
+ const typeAliasValue = typeAliasDeclaration.type;
162
+ const enumValues = getEnumValues(typeAliasValue, typeDeclaration, ctx);
163
+ return {
164
+ name,
165
+ decorators,
166
+ enumValues,
167
+ comment
168
+ };
169
+ }
170
+ if (typeAliasType.kind === _typescript.SyntaxKind.TypeOperator && typeAliasType.operator === _typescript.SyntaxKind.KeyOfKeyword) {
171
+ const enumValues = getEnumValuesFromKeyOf(typeAliasType, ctx);
172
+ return {
173
+ name,
174
+ decorators,
175
+ enumValues,
176
+ comment
177
+ };
178
+ }
179
+ throw new Error(`Unexpected type definition - ${typeDeclaration.getText(ctx.sourceFile)}. Did you mean 'class'?`);
167
180
  }
168
181
  throw new Error(`Unexpected type kind - "${name}"`);
169
182
  }
@@ -227,64 +240,132 @@ function parseClassMember(node, parentName, ctx) {
227
240
  return result;
228
241
  }
229
242
  function parseFieldType(ctx, parentName, fieldName, node, defaultValueDescription) {
230
- let isArray;
231
- let isRelation;
232
- let relationDenormFields;
233
- let nodeType = node?.type;
234
- if (nodeType?.kind === _typescript.SyntaxKind.ArrayType) {
235
- isArray = true;
236
- nodeType = nodeType.elementType;
237
- if (nodeType?.kind === _typescript.SyntaxKind.ParenthesizedType) {
238
- nodeType = nodeType.type;
239
- }
240
- if (nodeType?.kind === _typescript.SyntaxKind.ArrayType) {
241
- throw new Error(`Nested arrays are not supported (${parentName})`);
242
- }
243
- }
244
- if (nodeType?.kind === _typescript.SyntaxKind.TypeReference) {
245
- const nt = nodeType;
246
- if (nt.typeName.getText(ctx.sourceFile) === "Relation") {
247
- if (!nt.typeArguments?.length) throw new Error(`Missing type argument for Relation<>: '${parentName}'`);
248
- nodeType = nt.typeArguments[0];
249
- isRelation = true;
250
- if (nt.typeArguments[1]) {
251
- const ta = nt.typeArguments[1];
252
- relationDenormFields = getRelationDenormFields(ctx, ta);
253
- }
254
- }
255
- }
256
- let type;
257
- if (nodeType?.kind === _typescript.SyntaxKind.UnionType) {
258
- const newTypeName = `${parentName}_${_lodash.default.upperFirst(fieldName)}`;
259
- ctx.result[newTypeName] = {
260
- name: newTypeName,
261
- decorators: {},
262
- enumValues: getEnumValues(nodeType, node, ctx)
263
- };
264
- type = newTypeName;
265
- }
266
- type = type ?? nodeType?.getText(ctx.sourceFile) ?? defaultValueDescription?.type;
267
- if (!type) throw new Error(`Cannot detect property type: '${node.getText(ctx.sourceFile)}'`);
268
- let isChange;
269
- if (type.startsWith("Change<")) {
270
- type = type.slice(7, -1);
271
- if (!ctx.typesMap[type]) throw new Error(`Unexpected property type: '${type}'`);
272
- isChange = true;
243
+ const parsedType = {
244
+ isArray: false,
245
+ isRelation: false,
246
+ isChange: false,
247
+ relationDenormFields: void 0,
248
+ type: void 0,
249
+ nodeType: node.type,
250
+ node
251
+ };
252
+ parseFieldTypeArray(parsedType, parentName);
253
+ parseFieldTypeRelation(parsedType, parentName, ctx);
254
+ parseFieldTypeInlineEnum(parsedType, parentName, fieldName, ctx);
255
+ parseFieldTypeKeyofEnum(parsedType, parentName, fieldName, ctx);
256
+ parseFieldTypeRecordEnum(parsedType, parentName, fieldName, ctx);
257
+ parsedType.type = parsedType.type ?? parsedType.nodeType?.getText(ctx.sourceFile) ?? defaultValueDescription?.type;
258
+ if (!parsedType.type) throw new Error(`Cannot detect property type: '${node.getText(ctx.sourceFile)}'`);
259
+ if (parsedType.type.startsWith("Change<")) {
260
+ parsedType.type = parsedType.type.slice(7, -1);
261
+ if (!ctx.typesMap[parsedType.type]) throw new Error(`Unexpected property type: '${parsedType.type}'`);
262
+ parsedType.isChange = true;
273
263
  } else {
274
- if (!supportedPrimitiveTypes.includes(type) && !ctx.typesMap[type] && !ctx.result[type] && type !== "thisReference") {
275
- throw new Error(`Unexpected property type: '${type}'`);
264
+ if (!supportedPrimitiveTypes.includes(parsedType.type) && !ctx.typesMap[parsedType.type] && !ctx.result[parsedType.type] && parsedType.type !== "thisReference") {
265
+ throw new Error(`Unexpected property type: '${parsedType.type}'`);
276
266
  }
277
267
  }
278
268
  if (defaultValueDescription && defaultValueDescription.type !== "thisReference") {
279
- verifyDefaultValueType(isArray, defaultValueDescription, type, supportedPrimitiveTypes, ctx);
269
+ verifyDefaultValueType(parsedType.isArray, defaultValueDescription, parsedType.type, supportedPrimitiveTypes, ctx);
280
270
  }
281
271
  return {
282
- isArray,
283
- isRelation,
284
- isChange,
285
- relationDenormFields,
286
- type
272
+ isArray: parsedType.isArray || void 0,
273
+ isRelation: parsedType.isRelation || void 0,
274
+ isChange: parsedType.isChange || void 0,
275
+ relationDenormFields: parsedType.relationDenormFields,
276
+ type: parsedType.type
277
+ };
278
+ }
279
+ function parseFieldTypeRecordEnum(parsedType, parentName, fieldName, ctx) {
280
+ if (parsedType.nodeType?.kind !== _typescript.SyntaxKind.TypeReference) return;
281
+ const nt = parsedType.nodeType;
282
+ if (nt.typeName.getText(ctx.sourceFile) !== "Record") return;
283
+ if (nt.typeArguments?.length !== 2) return;
284
+ const keyTypeName = nt.typeArguments[0].getText(ctx.sourceFile);
285
+ const valueTypeName = nt.typeArguments[1].getText(ctx.sourceFile);
286
+ const keyType = ctx.typesMap[keyTypeName];
287
+ if (!keyType) return;
288
+ if (!ctx.result[keyTypeName]) ctx.result[keyTypeName] = parseType(keyType.node, keyTypeName, ctx);
289
+ const enumValues = ctx.result[keyTypeName].enumValues;
290
+ if (!enumValues) throw new Error(`Unexpected type - ${keyTypeName}`);
291
+ const newTypeName = `${parentName}_${_lodash.default.upperFirst(fieldName)}`;
292
+ const fieldsArray = enumValues.map(v => ({
293
+ name: v,
294
+ type: valueTypeName,
295
+ isRequired: true
296
+ }));
297
+ ctx.result[newTypeName] = {
298
+ name: newTypeName,
299
+ decorators: {},
300
+ fields: _lodash.default.keyBy(fieldsArray, "name")
287
301
  };
302
+ parsedType.type = newTypeName;
303
+ }
304
+ function parseFieldTypeArray(parsedType, parentName) {
305
+ if (parsedType.nodeType?.kind !== _typescript.SyntaxKind.ArrayType) return;
306
+ parsedType.isArray = true;
307
+ parsedType.nodeType = parsedType.nodeType.elementType;
308
+ if (parsedType.nodeType?.kind === _typescript.SyntaxKind.ParenthesizedType) {
309
+ parsedType.nodeType = parsedType.nodeType.type;
310
+ }
311
+ if (parsedType.nodeType?.kind === _typescript.SyntaxKind.ArrayType) {
312
+ throw new Error(`Nested arrays are not supported (${parentName})`);
313
+ }
314
+ }
315
+ function parseFieldTypeRelation(parsedType, parentName, ctx) {
316
+ if (parsedType.nodeType?.kind !== _typescript.SyntaxKind.TypeReference) return;
317
+ const nt = parsedType.nodeType;
318
+ if (nt.typeName.getText(ctx.sourceFile) === "Relation") {
319
+ if (!nt.typeArguments?.length) throw new Error(`Missing type argument for Relation<>: '${parentName}'`);
320
+ parsedType.nodeType = nt.typeArguments[0];
321
+ parsedType.isRelation = true;
322
+ if (nt.typeArguments[1]) {
323
+ const ta = nt.typeArguments[1];
324
+ parsedType.relationDenormFields = getRelationDenormFields(ctx, ta);
325
+ }
326
+ }
327
+ }
328
+ function parseFieldTypeInlineEnum(parsedType, parentName, fieldName, ctx) {
329
+ if (parsedType.nodeType?.kind !== _typescript.SyntaxKind.UnionType) return;
330
+ const nt = parsedType.nodeType;
331
+ const enumValues = getEnumValues(nt, parsedType.node, ctx);
332
+ const newTypeName = `${parentName}_${_lodash.default.upperFirst(fieldName)}`;
333
+ ctx.result[newTypeName] = {
334
+ name: newTypeName,
335
+ decorators: {},
336
+ enumValues
337
+ };
338
+ parsedType.type = newTypeName;
339
+ }
340
+ function parseFieldTypeKeyofEnum(parsedType, parentName, fieldName, ctx) {
341
+ if (parsedType.nodeType?.kind !== _typescript.SyntaxKind.TypeOperator) return;
342
+ const nt = parsedType.nodeType;
343
+ if (nt.operator !== _typescript.SyntaxKind.KeyOfKeyword) return;
344
+ const enumValues = getEnumValuesFromKeyOf(nt, ctx);
345
+ const newTypeName = `${parentName}_${_lodash.default.upperFirst(fieldName)}`;
346
+ ctx.result[newTypeName] = {
347
+ name: newTypeName,
348
+ decorators: {},
349
+ enumValues
350
+ };
351
+ parsedType.type = newTypeName;
352
+ }
353
+ function getEnumValuesFromKeyOf(nodeType, ctx) {
354
+ if (nodeType.type.kind !== _typescript.SyntaxKind.TypeReference) {
355
+ throw new Error(`Unexpected type - ${nodeType.type.getText(ctx.sourceFile)}`);
356
+ }
357
+ const typeReferenceNode = nodeType.type;
358
+ if (typeReferenceNode.typeName.kind !== _typescript.SyntaxKind.Identifier) {
359
+ throw new Error(`Unexpected type - ${typeReferenceNode.getText(ctx.sourceFile)}`);
360
+ }
361
+ const typeName = typeReferenceNode.typeName.text;
362
+ const type = ctx.typesMap[typeName];
363
+ if (!type) {
364
+ throw new Error(`Unexpected type - ${typeName}`);
365
+ }
366
+ if (!ctx.result[typeName]) ctx.result[typeName] = parseType(type.node, typeName, ctx);
367
+ if (!ctx.result[typeName].fields) throw new Error(`Unexpected type - ${typeName}`);
368
+ return Object.keys(ctx.result[typeName].fields);
288
369
  }
289
370
  function getRelationDenormFields(ctx, node) {
290
371
  if (node.kind === _typescript.SyntaxKind.LiteralType) {
@@ -309,9 +390,11 @@ function verifyDefaultValueType(isArray, defaultValueDescription, type, supporte
309
390
  if (supportedPrimitiveTypes2.includes(type) && defaultValueDescription.type !== type) {
310
391
  throw new Error(`Default value type is different from field type: '${type}'`);
311
392
  }
393
+ if (!ctx.result[type] && ctx.typesMap[type]) ctx.result[type] = parseType(ctx.typesMap[type].node, type, ctx);
312
394
  const enumValues = ctx.result[type]?.enumValues;
313
395
  if (enumValues && !enumValues.includes(defaultValueDescription.value)) {
314
- throw new Error(`Default value type is different from field type: '${type}'`);
396
+ const enumValuesStr = enumValues.map(x => `'x'`).join(", ");
397
+ throw new Error(`Default value must be one of: ${enumValuesStr}`);
315
398
  }
316
399
  }
317
400
  }
@@ -99,6 +99,8 @@ function getOrder(f) {
99
99
  return decorator.order ?? defaultOrders[decorator.preset] ?? 0;
100
100
  }
101
101
  function parseType(typeDeclaration, typeName, ctx) {
102
+ if (ctx.result[typeName])
103
+ return ctx.result[typeName];
102
104
  const { modifiers } = typeDeclaration;
103
105
  const nameNode = typeDeclaration.name;
104
106
  if (!nameNode || nameNode.kind !== SyntaxKind.Identifier)
@@ -136,12 +138,17 @@ function parseType(typeDeclaration, typeName, ctx) {
136
138
  }
137
139
  if (typeDeclaration.kind === SyntaxKind.TypeAliasDeclaration) {
138
140
  const typeAliasDeclaration = typeDeclaration;
139
- if (typeAliasDeclaration.type.kind !== SyntaxKind.UnionType)
140
- throw new Error(`Unexpected type definition - ${typeDeclaration.getText(ctx.sourceFile)}. Did you mean 'class'?`);
141
- const typeAliasValue = typeAliasDeclaration.type;
142
- const enumValues = getEnumValues(typeAliasValue, typeDeclaration, ctx);
143
- if (typeDeclaration)
141
+ const typeAliasType = typeAliasDeclaration.type;
142
+ if (typeAliasType.kind === SyntaxKind.UnionType) {
143
+ const typeAliasValue = typeAliasDeclaration.type;
144
+ const enumValues = getEnumValues(typeAliasValue, typeDeclaration, ctx);
144
145
  return { name, decorators, enumValues, comment };
146
+ }
147
+ if (typeAliasType.kind === SyntaxKind.TypeOperator && typeAliasType.operator === SyntaxKind.KeyOfKeyword) {
148
+ const enumValues = getEnumValuesFromKeyOf(typeAliasType, ctx);
149
+ return { name, decorators, enumValues, comment };
150
+ }
151
+ throw new Error(`Unexpected type definition - ${typeDeclaration.getText(ctx.sourceFile)}. Did you mean 'class'?`);
145
152
  }
146
153
  throw new Error(`Unexpected type kind - "${name}"`);
147
154
  }
@@ -206,61 +213,136 @@ function parseClassMember(node, parentName, ctx) {
206
213
  return result;
207
214
  }
208
215
  function parseFieldType(ctx, parentName, fieldName, node, defaultValueDescription) {
209
- let isArray;
210
- let isRelation;
211
- let relationDenormFields;
212
- let nodeType = node?.type;
213
- if (nodeType?.kind === SyntaxKind.ArrayType) {
214
- isArray = true;
215
- nodeType = nodeType.elementType;
216
- if (nodeType?.kind === SyntaxKind.ParenthesizedType) {
217
- nodeType = nodeType.type;
218
- }
219
- if (nodeType?.kind === SyntaxKind.ArrayType) {
220
- throw new Error(`Nested arrays are not supported (${parentName})`);
216
+ const parsedType = {
217
+ isArray: false,
218
+ isRelation: false,
219
+ isChange: false,
220
+ relationDenormFields: void 0,
221
+ type: void 0,
222
+ nodeType: node.type,
223
+ node
224
+ };
225
+ parseFieldTypeArray(parsedType, parentName);
226
+ parseFieldTypeRelation(parsedType, parentName, ctx);
227
+ parseFieldTypeInlineEnum(parsedType, parentName, fieldName, ctx);
228
+ parseFieldTypeKeyofEnum(parsedType, parentName, fieldName, ctx);
229
+ parseFieldTypeRecordEnum(parsedType, parentName, fieldName, ctx);
230
+ parsedType.type = parsedType.type ?? parsedType.nodeType?.getText(ctx.sourceFile) ?? defaultValueDescription?.type;
231
+ if (!parsedType.type)
232
+ throw new Error(`Cannot detect property type: '${node.getText(ctx.sourceFile)}'`);
233
+ if (parsedType.type.startsWith("Change<")) {
234
+ parsedType.type = parsedType.type.slice(7, -1);
235
+ if (!ctx.typesMap[parsedType.type])
236
+ throw new Error(`Unexpected property type: '${parsedType.type}'`);
237
+ parsedType.isChange = true;
238
+ } else {
239
+ if (!supportedPrimitiveTypes.includes(parsedType.type) && !ctx.typesMap[parsedType.type] && !ctx.result[parsedType.type] && parsedType.type !== "thisReference") {
240
+ throw new Error(`Unexpected property type: '${parsedType.type}'`);
221
241
  }
222
242
  }
223
- if (nodeType?.kind === SyntaxKind.TypeReference) {
224
- const nt = nodeType;
225
- if (nt.typeName.getText(ctx.sourceFile) === "Relation") {
226
- if (!nt.typeArguments?.length)
227
- throw new Error(`Missing type argument for Relation<>: '${parentName}'`);
228
- nodeType = nt.typeArguments[0];
229
- isRelation = true;
230
- if (nt.typeArguments[1]) {
231
- const ta = nt.typeArguments[1];
232
- relationDenormFields = getRelationDenormFields(ctx, ta);
233
- }
234
- }
243
+ if (defaultValueDescription && defaultValueDescription.type !== "thisReference") {
244
+ verifyDefaultValueType(parsedType.isArray, defaultValueDescription, parsedType.type, supportedPrimitiveTypes, ctx);
235
245
  }
236
- let type;
237
- if (nodeType?.kind === SyntaxKind.UnionType) {
238
- const newTypeName = `${parentName}_${_.upperFirst(fieldName)}`;
239
- ctx.result[newTypeName] = {
240
- name: newTypeName,
241
- decorators: {},
242
- enumValues: getEnumValues(nodeType, node, ctx)
243
- };
244
- type = newTypeName;
246
+ return {
247
+ isArray: parsedType.isArray || void 0,
248
+ isRelation: parsedType.isRelation || void 0,
249
+ isChange: parsedType.isChange || void 0,
250
+ relationDenormFields: parsedType.relationDenormFields,
251
+ type: parsedType.type
252
+ };
253
+ }
254
+ function parseFieldTypeRecordEnum(parsedType, parentName, fieldName, ctx) {
255
+ if (parsedType.nodeType?.kind !== SyntaxKind.TypeReference)
256
+ return;
257
+ const nt = parsedType.nodeType;
258
+ if (nt.typeName.getText(ctx.sourceFile) !== "Record")
259
+ return;
260
+ if (nt.typeArguments?.length !== 2)
261
+ return;
262
+ const keyTypeName = nt.typeArguments[0].getText(ctx.sourceFile);
263
+ const valueTypeName = nt.typeArguments[1].getText(ctx.sourceFile);
264
+ const keyType = ctx.typesMap[keyTypeName];
265
+ if (!keyType)
266
+ return;
267
+ if (!ctx.result[keyTypeName])
268
+ ctx.result[keyTypeName] = parseType(keyType.node, keyTypeName, ctx);
269
+ const enumValues = ctx.result[keyTypeName].enumValues;
270
+ if (!enumValues)
271
+ throw new Error(`Unexpected type - ${keyTypeName}`);
272
+ const newTypeName = `${parentName}_${_.upperFirst(fieldName)}`;
273
+ const fieldsArray = enumValues.map((v) => ({ name: v, type: valueTypeName, isRequired: true }));
274
+ ctx.result[newTypeName] = {
275
+ name: newTypeName,
276
+ decorators: {},
277
+ fields: _.keyBy(fieldsArray, "name")
278
+ };
279
+ parsedType.type = newTypeName;
280
+ }
281
+ function parseFieldTypeArray(parsedType, parentName) {
282
+ if (parsedType.nodeType?.kind !== SyntaxKind.ArrayType)
283
+ return;
284
+ parsedType.isArray = true;
285
+ parsedType.nodeType = parsedType.nodeType.elementType;
286
+ if (parsedType.nodeType?.kind === SyntaxKind.ParenthesizedType) {
287
+ parsedType.nodeType = parsedType.nodeType.type;
245
288
  }
246
- type = type ?? nodeType?.getText(ctx.sourceFile) ?? defaultValueDescription?.type;
247
- if (!type)
248
- throw new Error(`Cannot detect property type: '${node.getText(ctx.sourceFile)}'`);
249
- let isChange;
250
- if (type.startsWith("Change<")) {
251
- type = type.slice(7, -1);
252
- if (!ctx.typesMap[type])
253
- throw new Error(`Unexpected property type: '${type}'`);
254
- isChange = true;
255
- } else {
256
- if (!supportedPrimitiveTypes.includes(type) && !ctx.typesMap[type] && !ctx.result[type] && type !== "thisReference") {
257
- throw new Error(`Unexpected property type: '${type}'`);
289
+ if (parsedType.nodeType?.kind === SyntaxKind.ArrayType) {
290
+ throw new Error(`Nested arrays are not supported (${parentName})`);
291
+ }
292
+ }
293
+ function parseFieldTypeRelation(parsedType, parentName, ctx) {
294
+ if (parsedType.nodeType?.kind !== SyntaxKind.TypeReference)
295
+ return;
296
+ const nt = parsedType.nodeType;
297
+ if (nt.typeName.getText(ctx.sourceFile) === "Relation") {
298
+ if (!nt.typeArguments?.length)
299
+ throw new Error(`Missing type argument for Relation<>: '${parentName}'`);
300
+ parsedType.nodeType = nt.typeArguments[0];
301
+ parsedType.isRelation = true;
302
+ if (nt.typeArguments[1]) {
303
+ const ta = nt.typeArguments[1];
304
+ parsedType.relationDenormFields = getRelationDenormFields(ctx, ta);
258
305
  }
259
306
  }
260
- if (defaultValueDescription && defaultValueDescription.type !== "thisReference") {
261
- verifyDefaultValueType(isArray, defaultValueDescription, type, supportedPrimitiveTypes, ctx);
307
+ }
308
+ function parseFieldTypeInlineEnum(parsedType, parentName, fieldName, ctx) {
309
+ if (parsedType.nodeType?.kind !== SyntaxKind.UnionType)
310
+ return;
311
+ const nt = parsedType.nodeType;
312
+ const enumValues = getEnumValues(nt, parsedType.node, ctx);
313
+ const newTypeName = `${parentName}_${_.upperFirst(fieldName)}`;
314
+ ctx.result[newTypeName] = { name: newTypeName, decorators: {}, enumValues };
315
+ parsedType.type = newTypeName;
316
+ }
317
+ function parseFieldTypeKeyofEnum(parsedType, parentName, fieldName, ctx) {
318
+ if (parsedType.nodeType?.kind !== SyntaxKind.TypeOperator)
319
+ return;
320
+ const nt = parsedType.nodeType;
321
+ if (nt.operator !== SyntaxKind.KeyOfKeyword)
322
+ return;
323
+ const enumValues = getEnumValuesFromKeyOf(nt, ctx);
324
+ const newTypeName = `${parentName}_${_.upperFirst(fieldName)}`;
325
+ ctx.result[newTypeName] = { name: newTypeName, decorators: {}, enumValues };
326
+ parsedType.type = newTypeName;
327
+ }
328
+ function getEnumValuesFromKeyOf(nodeType, ctx) {
329
+ if (nodeType.type.kind !== SyntaxKind.TypeReference) {
330
+ throw new Error(`Unexpected type - ${nodeType.type.getText(ctx.sourceFile)}`);
262
331
  }
263
- return { isArray, isRelation, isChange, relationDenormFields, type };
332
+ const typeReferenceNode = nodeType.type;
333
+ if (typeReferenceNode.typeName.kind !== SyntaxKind.Identifier) {
334
+ throw new Error(`Unexpected type - ${typeReferenceNode.getText(ctx.sourceFile)}`);
335
+ }
336
+ const typeName = typeReferenceNode.typeName.text;
337
+ const type = ctx.typesMap[typeName];
338
+ if (!type) {
339
+ throw new Error(`Unexpected type - ${typeName}`);
340
+ }
341
+ if (!ctx.result[typeName])
342
+ ctx.result[typeName] = parseType(type.node, typeName, ctx);
343
+ if (!ctx.result[typeName].fields)
344
+ throw new Error(`Unexpected type - ${typeName}`);
345
+ return Object.keys(ctx.result[typeName].fields);
264
346
  }
265
347
  function getRelationDenormFields(ctx, node) {
266
348
  if (node.kind === SyntaxKind.LiteralType) {
@@ -285,9 +367,12 @@ function verifyDefaultValueType(isArray, defaultValueDescription, type, supporte
285
367
  if (supportedPrimitiveTypes2.includes(type) && defaultValueDescription.type !== type) {
286
368
  throw new Error(`Default value type is different from field type: '${type}'`);
287
369
  }
370
+ if (!ctx.result[type] && ctx.typesMap[type])
371
+ ctx.result[type] = parseType(ctx.typesMap[type].node, type, ctx);
288
372
  const enumValues = ctx.result[type]?.enumValues;
289
373
  if (enumValues && !enumValues.includes(defaultValueDescription.value)) {
290
- throw new Error(`Default value type is different from field type: '${type}'`);
374
+ const enumValuesStr = enumValues.map((x) => `'x'`).join(", ");
375
+ throw new Error(`Default value must be one of: ${enumValuesStr}`);
291
376
  }
292
377
  }
293
378
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "rads-db",
3
- "version": "3.0.3",
3
+ "version": "3.0.6",
4
4
  "files": [
5
5
  "dist",
6
6
  "drivers",