@postxl/generator 0.65.2 → 0.67.0

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/generator.js CHANGED
@@ -42,7 +42,6 @@ const prettier = __importStar(require("@postxl/prettier"));
42
42
  const react_generator_1 = require("./generators/enums/react.generator");
43
43
  const types_generator_1 = require("./generators/enums/types.generator");
44
44
  const businesslogic_actiontypes_generator_1 = require("./generators/indices/businesslogic-actiontypes.generator");
45
- const businesslogic_update_clonecontext_generator_1 = require("./generators/indices/businesslogic-update-clonecontext.generator");
46
45
  const businesslogic_update_module_generator_1 = require("./generators/indices/businesslogic-update-module.generator");
47
46
  const businesslogic_update_service_generator_1 = require("./generators/indices/businesslogic-update-service.generator");
48
47
  const businesslogic_view_module_generator_1 = require("./generators/indices/businesslogic-view-module.generator");
@@ -220,7 +219,6 @@ function generate({ models, enums, config, prismaClientPath, logger, }) {
220
219
  // Business Logic
221
220
  generated.write(`/${meta.view.moduleLocation.path}.ts`, (0, businesslogic_view_module_generator_1.generateBusinessLogicViewModule)({ models, meta }));
222
221
  generated.write(`/${meta.view.serviceLocation.path}.ts`, (0, businesslogic_view_service_generator_1.generateBusinessLogicViewService)({ models, meta }));
223
- generated.write(`/${meta.update.cloneContextFilePath}.ts`, (0, businesslogic_update_clonecontext_generator_1.generateBusinessLogicCloneContext)({ models, meta }));
224
222
  generated.write(`/${meta.update.moduleLocation.path}.ts`, (0, businesslogic_update_module_generator_1.generateBusinessLogicUpdateModule)({ models, meta }));
225
223
  generated.write(`/${meta.update.serviceLocation.path}.ts`, (0, businesslogic_update_service_generator_1.generateBusinessLogicUpdateService)({ models, meta }));
226
224
  generated.write(`/${meta.update.actionTypesFilePath}.ts`, (0, businesslogic_actiontypes_generator_1.generateBusinessLogicActionTypes)({ models, meta }));
@@ -28,9 +28,10 @@ const imports_1 = require("../../lib/imports");
28
28
  const meta_1 = require("../../lib/meta");
29
29
  const fields_1 = require("../../lib/schema/fields");
30
30
  const Types = __importStar(require("../../lib/schema/types"));
31
- const zod_1 = require("../../lib/schema/zod");
31
+ const typescript_1 = require("../../lib/typescript");
32
32
  const jsdoc_1 = require("../../lib/utils/jsdoc");
33
33
  const string_1 = require("../../lib/utils/string");
34
+ const zod_1 = require("../../lib/zod");
34
35
  /**
35
36
  * Generates update business logic for a given model.
36
37
  * The update logic handles all Create/Update/Delete/Upsert operations. See template's readme for more info.
@@ -46,12 +47,6 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
46
47
  createType: `Create${meta.internalSingularNameCapitalized}`,
47
48
  updateType: `Update${meta.internalSingularNameCapitalized}`,
48
49
  upsertType: `Upsert${meta.internalSingularNameCapitalized}`,
49
- cloneType: `Clone${meta.internalSingularNameCapitalized}`,
50
- },
51
- cloneContext: {
52
- type: schemaMeta.update.cloneContextType,
53
- createMethod: schemaMeta.update.cloneContextCreateMethod,
54
- map: meta.update.cloneContextMap,
55
50
  },
56
51
  };
57
52
  const imports = imports_1.ImportsGenerator.from(meta.update.serviceClassLocation.path);
@@ -61,27 +56,33 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
61
56
  Types.toAnnotatedTypeName(m.brandedId),
62
57
  Types.toAnnotatedTypeName(m.typeName),
63
58
  meta.types.toBrandedIdTypeFnName,
64
- Types.toFunctionName(`omitId`),
65
59
  ],
66
60
  [meta.view.serviceLocation.import]: [meta.view.serviceClassName],
67
61
  [schemaMeta.actions.execution.interfaceLocation.import]: [schemaMeta.actions.execution.interface],
68
62
  [schemaMeta.actions.dispatcher.definitionLocation.import]: [schemaMeta.actions.dispatcher.definition],
69
63
  [schemaMeta.update.serviceLocation.path]: schemaMeta.update.serviceClassName,
70
- [schemaMeta.update.cloneContextFilePath]: [
71
- schemaMeta.update.cloneContextType,
72
- schemaMeta.update.cloneContextCreateMethod,
73
- ],
74
64
  [schemaMeta.view.serviceLocation.import]: schemaMeta.view.serviceClassName,
75
65
  });
76
- for (const relation of (0, fields_1.getRelationFields)(model)) {
66
+ for (const field of (0, fields_1.getRelationFields)(model)) {
77
67
  // NOTE: We add `toBrandedType` functions for foreign models for decoders.
78
- if (relation.relationToModel.typeName === model.typeName) {
68
+ if (field.relationToModel.typeName === model.typeName) {
79
69
  continue;
80
70
  }
81
- const refMeta = (0, meta_1.getModelMetadata)({ model: relation.relationToModel });
71
+ const refModelMeta = (0, meta_1.getModelMetadata)({ model: field.relationToModel });
82
72
  imports.addImport({
83
- items: [refMeta.types.toBrandedIdTypeFnName],
84
- from: refMeta.types.importPath,
73
+ from: refModelMeta.types.importPath,
74
+ items: [refModelMeta.types.toBrandedIdTypeFnName],
75
+ });
76
+ imports.addTypeImport({
77
+ from: refModelMeta.types.importPath,
78
+ items: [refModelMeta.types.brandedIdType],
79
+ });
80
+ }
81
+ for (const { enumerator } of (0, fields_1.getEnumFields)(model)) {
82
+ const enumMeta = (0, meta_1.getEnumMetadata)({ enumerator });
83
+ imports.addTypeImport({
84
+ from: enumMeta.types.importPath,
85
+ items: [enumerator.tsTypeName],
85
86
  });
86
87
  }
87
88
  /**
@@ -97,8 +98,9 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
97
98
  ];
98
99
  const decoders = meta.update.decoders;
99
100
  const { view, update } = meta;
100
- const deleteFn = generateDeleteFunction({ model, meta, m });
101
- const deleteManyFn = generateDeleteManyMethod({ imports, model, meta, m });
101
+ const deleteFn = generateDeleteFn({ model, meta, m });
102
+ const deleteManyFn = generateDeleteManyFn({ imports, model, meta, m });
103
+ const cloneFn = generateCloneFn({ model, meta, m });
102
104
  /* prettier-ignore */
103
105
  return /* ts */ `
104
106
  import { Inject, Injectable, forwardRef } from '@nestjs/common'
@@ -132,12 +134,6 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
132
134
  payload: ${m.brandedId}
133
135
  result: ${m.brandedId}
134
136
  }
135
-
136
- ${(0, jsdoc_1.toJsDocComment)([`Clones a ${meta.userFriendlyName} and returns the clone.`])}
137
- clone: {
138
- payload: ${m.decoders.cloneType}
139
- result: ${m.typeName}
140
- }
141
137
  }
142
138
 
143
139
  /**
@@ -171,23 +167,10 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
171
167
 
172
168
  type ${m.decoders.upsertType} = z.infer<typeof ${decoders.upsert}>
173
169
 
174
- /**
175
- * Zod decoder for validating the clone input of a ${meta.userFriendlyName} .
176
- */
177
- export const ${decoders.clone} = z.object({
178
- ${model.fields
179
- .filter((f) => !f.attributes.isReadonly || f.kind === "id")
180
- .map((f) => `${f.name}: z.${(0, zod_1.getZodDecoderDefinition)({ field: f, allowAnyOptionalField: f.kind !== 'id' })}`)
181
- .join(',')}
182
- })
183
-
184
- type ${m.decoders.cloneType} = z.infer<typeof ${decoders.clone}>
185
-
186
170
  export const ${decoders.name} = {
187
171
  create: ${decoders.create},
188
172
  update: ${decoders.update},
189
173
  upsert: ${decoders.upsert},
190
- clone: ${decoders.clone},
191
174
  }
192
175
 
193
176
  export type ${update.serviceInterfaceName} = ${schemaMeta.actions.dispatcher.definition}<Actions>
@@ -223,7 +206,7 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
223
206
 
224
207
  ${deleteManyFn}
225
208
 
226
- ${generateCloneMethod({ model, meta, m })}
209
+ ${cloneFn}
227
210
  }
228
211
  `;
229
212
  }
@@ -231,11 +214,12 @@ exports.generateModelBusinessLogicUpdate = generateModelBusinessLogicUpdate;
231
214
  /**
232
215
  * Returns a function implementation that deletes a single entity and all its related entities.
233
216
  */
234
- function generateDeleteFunction({ model, meta, m }) {
217
+ function generateDeleteFn({ model, meta, m }) {
235
218
  const backReferenceDelete = [];
236
219
  const backReferenceNames = [];
237
220
  for (const { referencingField, referencingModel } of model.references) {
238
- // NOTE: We only delete back references that are required references.
221
+ // NOTE: We only delete back references that are required references so that delete method
222
+ // doesn't fail on non-null constraints.
239
223
  if (!referencingField.isRequired) {
240
224
  continue;
241
225
  }
@@ -262,7 +246,7 @@ function generateDeleteFunction({ model, meta, m }) {
262
246
  /**
263
247
  * Returns a function that deletes multiple entities and all their related entities.
264
248
  */
265
- function generateDeleteManyMethod({ imports, model, meta, m, }) {
249
+ function generateDeleteManyFn({ imports, model, meta, m, }) {
266
250
  const idArrays = [];
267
251
  const idAssignments = [];
268
252
  const deleteCalls = [];
@@ -312,50 +296,42 @@ function generateDeleteManyMethod({ imports, model, meta, m, }) {
312
296
  }`;
313
297
  }
314
298
  /**
315
- * Returns a function that deep clones a given entity and all its related entities.
299
+ * Returns a function that shallow clones a given entity. Unique fields are required
300
+ * to generate a unique clone as skipping them would result in a non-unique clone.
316
301
  */
317
- function generateCloneMethod({ model, meta, m }) {
318
- const backReferenceCloning = [];
319
- const backReferenceNames = [];
320
- for (const { referencingField, referencingModel } of model.references) {
321
- // We only clone back references that are marked as cloneWithParent.
322
- if (!referencingField.attributes.cloneWithParent) {
323
- continue;
302
+ function generateCloneFn({ model, meta, m }) {
303
+ const inputFields = model.fields.map((f) => {
304
+ const type = (0, typescript_1.getFieldType)(f);
305
+ // NOTE: ID field is always required to resolve the source.
306
+ if (f.kind === 'id') {
307
+ return `${f.name}: ${type}`;
324
308
  }
325
- const refModelMeta = (0, meta_1.getModelMetadata)({ model: referencingModel });
326
- const refFieldMeta = (0, meta_1.getFieldMetadata)({ field: referencingField });
327
- backReferenceNames.push(`${refModelMeta.userFriendlyNamePlural}.${referencingField.name}`);
328
- const { view, update } = refModelMeta;
329
- backReferenceCloning.push(`
330
- // ${referencingModel.name}.${referencingField.name}
331
- for (const childId of await this.viewService.${view.serviceVariableName}.data.${refFieldMeta.getByForeignKeyIdsMethodFnName}(id)) {
332
- await this.updateService.${update.serviceVariableName}.clone({ data: { id: childId, ${referencingField.name}: clone.id }, execution, context })
333
- }
334
- `);
335
- }
309
+ if (f.isUnique) {
310
+ // NOTE: `unique` fields require a new value.
311
+ if (f.isRequired) {
312
+ return `${f.name}: ${type}`;
313
+ }
314
+ return `${f.name}: ${type} | null`;
315
+ }
316
+ // NOTE: Non-unique fields can be copied from the source.
317
+ if (f.isRequired) {
318
+ return `${f.name}?: ${type}`;
319
+ }
320
+ return `${f.name}?: ${type} | null`;
321
+ });
336
322
  return `
337
323
  ${(0, jsdoc_1.toJsDocComment)([`Creates a new ${meta.userFriendlyName} deep clone and returns it.`])}
338
324
  public async clone(
339
- { data: { id, ...data }, execution, context = ${m.cloneContext.createMethod}() }:
340
- { data: ${m.decoders.cloneType}; execution: ${m.iExecution}; context?: ${m.cloneContext.type} }
325
+ { data, execution }: { data: { ${inputFields.join(', ')} }; execution: ${m.iExecution} }
341
326
  ): Promise<${m.typeName}> {
342
- const alreadyCloned = context.${m.cloneContext.map}.get(id)
343
- if (alreadyCloned) {
344
- // We already cloned this item before, so we return the cloned item.
345
- return alreadyCloned
346
- }
347
-
348
- const source = await this.view.get(id)
327
+ const source = await this.view.get(data.id)
349
328
  if (!source) {
350
- throw new Error(\`${meta.userFriendlyName} with id \${id} not found\`)
329
+ throw new Error(\`${meta.userFriendlyName} with id \${data.id} not found\`)
351
330
  }
352
331
 
353
- const clone = await this.data.create({ item: { ...omitId(source), ...data }, execution })
354
-
355
- context.${m.cloneContext.map}.set(id, clone)
356
-
357
- ${backReferenceCloning.join('\n')}
332
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
333
+ const { id, ...duplicate } = { ...source, ...data } satisfies Actions['create']['payload']
358
334
 
359
- return clone
335
+ return await this.create({ data: duplicate, execution })
360
336
  }`;
361
337
  }
@@ -75,10 +75,6 @@ export const ${meta.trpc.routerName} = router({
75
75
  delete: procedure
76
76
  .input(${meta.types.zodDecoderFnNames.id})
77
77
  .mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "delete", payload: input})),
78
-
79
- clone: procedure
80
- .input(${decoders.name}.clone)
81
- .mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "clone", payload: input})),
82
78
  })
83
79
  `;
84
80
  }
@@ -4,9 +4,9 @@ exports.generateModelTypes = void 0;
4
4
  const imports_1 = require("../../lib/imports");
5
5
  const meta_1 = require("../../lib/meta");
6
6
  const fields_1 = require("../../lib/schema/fields");
7
- const zod_1 = require("../../lib/schema/zod");
8
- const types_1 = require("../../lib/types");
7
+ const typescript_1 = require("../../lib/typescript");
9
8
  const jsdoc_1 = require("../../lib/utils/jsdoc");
9
+ const zod_1 = require("../../lib/zod");
10
10
  /**
11
11
  * Generates types for a given model.
12
12
  */
@@ -47,7 +47,7 @@ export type ${meta.types.typeName} = {
47
47
  .map((f) => {
48
48
  return `
49
49
  ${(0, jsdoc_1.getFieldComment)(f)}
50
- ${f.name}: ${getFieldType(f)}${f.isRequired ? '' : ' | null'}
50
+ ${f.name}: ${(0, typescript_1.getFieldType)(f)}${f.isRequired ? '' : ' | null'}
51
51
  `;
52
52
  })
53
53
  .join('\n')}
@@ -98,20 +98,3 @@ export type ${meta.types.dto.upsert} = ${schemaMeta.types.dto.upsert}<${meta.typ
98
98
  `;
99
99
  }
100
100
  exports.generateModelTypes = generateModelTypes;
101
- /**
102
- * Converts a field to a TypeScript type definition.
103
- */
104
- function getFieldType(f) {
105
- switch (f.kind) {
106
- case 'enum':
107
- return f.typeName;
108
- case 'relation':
109
- return f.relationToModel.brandedIdType;
110
- case 'id':
111
- return f.model.brandedIdType;
112
- case 'scalar':
113
- return f.tsTypeName;
114
- default:
115
- throw new types_1.ExhaustiveSwitchCheck(f);
116
- }
117
- }
@@ -90,11 +90,6 @@ export type FieldAttributes = {
90
90
  * The field that should be used as the default label for the model.
91
91
  */
92
92
  isLabel?: boolean;
93
- /**
94
- * Schema tag: `@@CloneWithParent()`
95
- * If set, the all models that reference the parent that was cloned should also be cloned.
96
- */
97
- cloneWithParent?: boolean;
98
93
  };
99
94
  export type EnumAttributes = {
100
95
  /**
@@ -560,18 +560,6 @@ export type SchemaMetaData = {
560
560
  * Path to the file containing the overall action types
561
561
  */
562
562
  actionTypesFilePath: Types.FilePath;
563
- /**
564
- * Path to the file containing the clone context
565
- */
566
- cloneContextFilePath: Types.FilePath;
567
- /**
568
- * The name of the clone context type
569
- */
570
- cloneContextType: Types.TypeName;
571
- /**
572
- * The name of the function that creates a clone context
573
- */
574
- cloneContextCreateMethod: Types.FunctionName;
575
563
  };
576
564
  seedData: {
577
565
  /**
@@ -942,15 +930,7 @@ export type ModelMetaData = {
942
930
  * The name of the function that decodes an Upsert object to a fully typed object (e.g. `aggregationUpsertDecoder`.)
943
931
  */
944
932
  upsert: Types.FunctionName;
945
- /**
946
- * The name of the function that clones an object (e.g. `aggregationCloneDecoder`.)
947
- */
948
- clone: Types.FunctionName;
949
933
  };
950
- /**
951
- * The name of the map variable in the clone context that holds the cloned items of this model (e.g. `aggregation`)
952
- */
953
- cloneContextMap: Types.VariableName;
954
934
  /**
955
935
  * Name by which the business logic service exposes the data service.
956
936
  */
package/dist/lib/meta.js CHANGED
@@ -118,9 +118,6 @@ function getSchemaMetadata({ config }) {
118
118
  serviceClassName: Types.toClassName(`UpdateService`),
119
119
  serviceLocation: Types.toModuleLocation(`update`, `${config.paths.businessUpdateLogicPath}update.service`),
120
120
  actionTypesFilePath: Types.toPath(`${config.paths.businessUpdateLogicPath}actions`),
121
- cloneContextFilePath: Types.toPath(`${config.paths.businessUpdateLogicPath}clone.context`),
122
- cloneContextType: Types.toTypeName(`CloneContext`),
123
- cloneContextCreateMethod: Types.toFunctionName(`createCloneContext`),
124
121
  },
125
122
  data: {
126
123
  moduleName: Types.toClassName(`DataModule`),
@@ -342,9 +339,7 @@ function getModelMetadata({ model }) {
342
339
  create: Types.toFunctionName(`${camelCase}CreateDecoder`),
343
340
  update: Types.toFunctionName(`${camelCase}UpdateDecoder`),
344
341
  upsert: Types.toFunctionName(`${camelCase}UpsertDecoder`),
345
- clone: Types.toFunctionName(`${camelCase}CloneDecoder`),
346
342
  },
347
- cloneContextMap: Types.toVariableName(`${camelCase}`),
348
343
  dataRepositoryVariableName: Types.toVariableName(`data`),
349
344
  },
350
345
  seed: {
@@ -435,24 +430,6 @@ function getFieldMetadata({ field }) {
435
430
  getByForeignKeyIdsMethodFnName: Types.toFunctionName(`getIdsFor${PascalCase}`),
436
431
  excelColumnName: (0, string_1.toPascalCase)(field.name),
437
432
  };
438
- // switch (field.kind) {
439
- // case 'id':
440
- // return {
441
- // tsFieldName: Types.toVariableName(toCamelCase(field.name)),
442
- // }
443
- // case 'enum':
444
- // return {
445
- // tsFieldName: Types.toVariableName(toCamelCase(field.name)),
446
- // }
447
- // case 'relation':
448
- // return {
449
- // tsFieldName: Types.toVariableName(toCamelCase(field.name)),
450
- // }
451
- // case 'scalar':
452
- // return {
453
- // tsFieldName: Types.toVariableName(toCamelCase(field.name)),
454
- // }
455
- // }
456
433
  }
457
434
  exports.getFieldMetadata = getFieldMetadata;
458
435
  /**
@@ -215,9 +215,13 @@ export type FieldCore = {
215
215
  */
216
216
  description?: string;
217
217
  /**
218
- * True if the field is not nullable.
218
+ * Tells whether there's a NOT NULL constraint on the field.
219
219
  */
220
220
  isRequired: boolean;
221
+ /**
222
+ * Tells whether there's a unique constraint on the field.
223
+ */
224
+ isUnique: boolean;
221
225
  /**
222
226
  * A dictionary of potential attributes the field can have.
223
227
  */
@@ -0,0 +1,5 @@
1
+ import { Field } from './schema/schema';
2
+ /**
3
+ * Converts a field to a TypeScript type definition.
4
+ */
5
+ export declare function getFieldType(f: Field): string;
@@ -0,0 +1,22 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getFieldType = void 0;
4
+ const types_1 = require("./types");
5
+ /**
6
+ * Converts a field to a TypeScript type definition.
7
+ */
8
+ function getFieldType(f) {
9
+ switch (f.kind) {
10
+ case 'enum':
11
+ return f.typeName;
12
+ case 'relation':
13
+ return f.relationToModel.brandedIdType;
14
+ case 'id':
15
+ return f.model.brandedIdType;
16
+ case 'scalar':
17
+ return f.tsTypeName;
18
+ default:
19
+ throw new types_1.ExhaustiveSwitchCheck(f);
20
+ }
21
+ }
22
+ exports.getFieldType = getFieldType;
@@ -1,4 +1,4 @@
1
- import { Field } from './schema';
1
+ import { Field } from './schema/schema';
2
2
  /**
3
3
  * Returns the string defining the zod decoder for a given field.
4
4
  */
@@ -1,8 +1,8 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getZodDecoderDefinition = void 0;
4
- const meta_1 = require("../meta");
5
- const types_1 = require("../types");
4
+ const meta_1 = require("./meta");
5
+ const types_1 = require("./types");
6
6
  /**
7
7
  * Returns the string defining the zod decoder for a given field.
8
8
  */
@@ -25,6 +25,9 @@ const getZodDecoderDefinition = ({ field, allowAnyOptionalField, }) => {
25
25
  return definition;
26
26
  };
27
27
  exports.getZodDecoderDefinition = getZodDecoderDefinition;
28
+ /**
29
+ * Returns the string defining the type of the Zod decoder for a given field.
30
+ */
28
31
  function getZodTypeDefinition(field) {
29
32
  switch (field.kind) {
30
33
  case 'scalar':
@@ -148,10 +148,9 @@ function getFieldAttributes(field) {
148
148
  .or(zod_1.default.string().transform((s) => parseInt(s, 10)))
149
149
  .optional(),
150
150
  readonly: blankStringBooleanDecoder,
151
- cloneWithParent: blankStringBooleanDecoder,
152
151
  })
153
152
  .transform((obj) => {
154
- var _a, _b;
153
+ var _a;
155
154
  if (isPrismaIgnored && !obj.ignore) {
156
155
  throw new Error(`Field ${field.name} is ignored by Prisma, but is missing the "ignore" PostXL attribute!`);
157
156
  }
@@ -165,7 +164,6 @@ function getFieldAttributes(field) {
165
164
  isReadonly: obj.readonly || field.isGenerated || field.isUpdatedAt || field.name === 'createdAt' || field.isId,
166
165
  isUpdatedAt: (_a = field.isUpdatedAt) !== null && _a !== void 0 ? _a : false,
167
166
  isCreatedAt: field.name === 'createdAt',
168
- cloneWithParent: (_b = obj.cloneWithParent) !== null && _b !== void 0 ? _b : false,
169
167
  };
170
168
  });
171
169
  const result = decoder.safeParse(attributes);
@@ -29,15 +29,11 @@ const error_1 = require("../lib/utils/error");
29
29
  const logger_1 = require("../lib/utils/logger");
30
30
  const string_1 = require("../lib/utils/string");
31
31
  const attributes_1 = require("./attributes");
32
- /**
33
- * These models are required for the generators/backend to work.
34
- */
35
- const REQUIRED_MODELS = ['User', 'Config', 'File', 'Action', 'Mutation'];
36
32
  /**
37
33
  * Converts a Prisma schema (DMMF) document to a Schema that's passed around generators.
38
34
  */
39
35
  function parsePrismaSchema({ datamodel: { enums: enumsRaw, models: modelsRaw }, config, }) {
40
- ensureRequiredModelsExists(modelsRaw);
36
+ ensurePXLSystemModelsExist(modelsRaw);
41
37
  ensureConsistency({ models: modelsRaw, enums: enumsRaw });
42
38
  // NOTE: We preprocess models and enums so that we can populate relationships.
43
39
  const models = modelsRaw.map((dmmfModel) => parseModelCore({ dmmfModel, config }));
@@ -66,8 +62,12 @@ function parsePrismaSchema({ datamodel: { enums: enumsRaw, models: modelsRaw },
66
62
  return { models: modelsWithFields, enums };
67
63
  }
68
64
  exports.parsePrismaSchema = parsePrismaSchema;
69
- function ensureRequiredModelsExists(models) {
70
- for (const requiredModel of REQUIRED_MODELS) {
65
+ /**
66
+ * These models are required for the generators/backend to work.
67
+ */
68
+ const SYSTEM_MODELS = ['User', 'Config', 'File', 'Action', 'Mutation'];
69
+ function ensurePXLSystemModelsExist(models) {
70
+ for (const requiredModel of SYSTEM_MODELS) {
71
71
  if (!models.find((m) => m.name === requiredModel)) {
72
72
  (0, error_1.throwError)(`Required model ${(0, logger_1.highlight)(requiredModel)} not found in schema!`);
73
73
  }
@@ -209,6 +209,7 @@ function parseModel({ dmmfModel, enums, models, config, }) {
209
209
  description: attributes.description,
210
210
  sourceName: dmmfField.name,
211
211
  isRequired: dmmfField.isRequired,
212
+ isUnique: dmmfField.isUnique,
212
213
  attributes,
213
214
  schemaConfig: config,
214
215
  schemaType: dmmfField.type,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postxl/generator",
3
- "version": "0.65.2",
3
+ "version": "0.67.0",
4
4
  "main": "./dist/generator.js",
5
5
  "typings": "./dist/generator.d.ts",
6
6
  "bin": {
@@ -1,9 +0,0 @@
1
- import { SchemaMetaData } from '../../lib/meta';
2
- import { Model } from '../../lib/schema/schema';
3
- /**
4
- * Generates the clone context for the business logic update service.
5
- */
6
- export declare function generateBusinessLogicCloneContext({ models, meta: schemaMeta, }: {
7
- models: Model[];
8
- meta: SchemaMetaData;
9
- }): string;
@@ -1,39 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateBusinessLogicCloneContext = void 0;
4
- const imports_1 = require("../../lib/imports");
5
- const meta_1 = require("../../lib/meta");
6
- /**
7
- * Generates the clone context for the business logic update service.
8
- */
9
- function generateBusinessLogicCloneContext({ models, meta: schemaMeta, }) {
10
- const imports = imports_1.ImportsGenerator.from(schemaMeta.update.cloneContextFilePath);
11
- const typeDefinitions = [];
12
- const mapAssignments = [];
13
- for (const model of models) {
14
- const modelMeta = (0, meta_1.getModelMetadata)({ model });
15
- imports.addImports({
16
- [schemaMeta.types.importPath]: [modelMeta.types.brandedIdType, modelMeta.types.typeName],
17
- });
18
- typeDefinitions.push(`${modelMeta.update.cloneContextMap}: Map<${modelMeta.types.brandedIdType}, ${modelMeta.types.typeName}>`);
19
- mapAssignments.push(`${modelMeta.update.cloneContextMap}: new Map()`);
20
- }
21
- return /* ts */ `
22
- ${imports.generate()}
23
-
24
- /**
25
- * The context that is passed in a clone action.
26
- *
27
- * This context is used to track which items have already been cloned and link them to the cloned item.
28
- */
29
- export type CloneContext = {
30
- ${typeDefinitions.join('\n')}
31
- }
32
-
33
- export function createCloneContext(): CloneContext {
34
- return {
35
- ${mapAssignments.join(',\n')}
36
- }
37
- }`;
38
- }
39
- exports.generateBusinessLogicCloneContext = generateBusinessLogicCloneContext;