@postxl/generator 0.14.0 → 0.15.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (31) hide show
  1. package/dist/generator.js +16 -0
  2. package/dist/generators/indices/businesslogicindex.generator.d.ts +9 -0
  3. package/dist/generators/indices/businesslogicindex.generator.js +19 -0
  4. package/dist/generators/indices/businesslogicmodule.generator.d.ts +9 -0
  5. package/dist/generators/indices/businesslogicmodule.generator.js +43 -0
  6. package/dist/generators/indices/businesslogicservice.generator.d.ts +9 -0
  7. package/dist/generators/indices/businesslogicservice.generator.js +32 -0
  8. package/dist/generators/indices/datamockmodule.generator.js +1 -1
  9. package/dist/generators/indices/datamodule.generator.js +22 -21
  10. package/dist/generators/indices/dataservice.generator.js +1 -1
  11. package/dist/generators/indices/seed-template-decoder.generator.js +32 -11
  12. package/dist/generators/models/businesslogic.generator.d.ts +9 -0
  13. package/dist/generators/models/businesslogic.generator.js +172 -0
  14. package/dist/generators/models/react.generator/context.generator.js +5 -3
  15. package/dist/generators/models/react.generator/library.generator.js +1 -1
  16. package/dist/generators/models/react.generator/lookup.generator.js +1 -1
  17. package/dist/generators/models/react.generator/modals.generator.d.ts +1 -1
  18. package/dist/generators/models/react.generator/modals.generator.js +118 -60
  19. package/dist/generators/models/repository.generator.js +18 -2
  20. package/dist/generators/models/route.generator.js +6 -6
  21. package/dist/generators/models/seed.generator.js +5 -2
  22. package/dist/generators/models/stub.generator.js +11 -9
  23. package/dist/generators/models/types.generator.js +32 -2
  24. package/dist/lib/imports.js +12 -3
  25. package/dist/lib/meta.d.ts +101 -1
  26. package/dist/lib/meta.js +21 -0
  27. package/dist/lib/schema/fields.d.ts +5 -1
  28. package/dist/lib/schema/schema.d.ts +26 -1
  29. package/dist/lib/schema/schema.js +1 -1
  30. package/dist/prisma/parse.js +15 -3
  31. package/package.json +2 -2
@@ -5,6 +5,14 @@ import * as Types from './schema/types';
5
5
  */
6
6
  export type SchemaMetaData = {
7
7
  data: {
8
+ /**
9
+ * The name of the Module class
10
+ */
11
+ moduleName: Types.ClassName;
12
+ /**
13
+ * Path that may be used to import from the data module.
14
+ */
15
+ importPath: Types.Path;
8
16
  /**
9
17
  * Path to the file containing the data module class definition.
10
18
  */
@@ -34,6 +42,32 @@ export type SchemaMetaData = {
34
42
  */
35
43
  stubIndexFilePath: Types.Path;
36
44
  };
45
+ businessLogic: {
46
+ /**
47
+ * The name of the Module class
48
+ */
49
+ moduleName: Types.ClassName;
50
+ /**
51
+ * Path that may be used to import from the business logic module.
52
+ */
53
+ importPath: Types.Path;
54
+ /**
55
+ * Path to the file containing the business logic index.
56
+ */
57
+ indexFilePath: Types.Path;
58
+ /**
59
+ * Path to the file containing the business logic module definition.
60
+ */
61
+ moduleFilePath: Types.Path;
62
+ /**
63
+ * The name of the business logic service class.
64
+ */
65
+ serviceClassName: Types.ClassName;
66
+ /**
67
+ * Path to the file containing the business logic service class definition.
68
+ */
69
+ serviceFilePath: Types.Path;
70
+ };
37
71
  seed: {
38
72
  /**
39
73
  * Path to the index file for the seed package.
@@ -104,6 +138,25 @@ export type ModelMetaData = {
104
138
  * use a more specific name for your purposes (e.g. `reactCreateModalComponentName`).
105
139
  */
106
140
  userFriendlyName: string;
141
+ /**
142
+ * The name of the model in singular form.
143
+ *
144
+ * NOTE: This name is meant to be used in internal variables only.
145
+ * For any variables, class names, etc. that are exposed, please use a more specific name.
146
+ * (e.g. `reactCreateModalComponentName`)
147
+ */
148
+ internalSingularName: Types.VariableName;
149
+ /**
150
+ * The name of the model in plural form.
151
+ *
152
+ * NOTE: This name is meant to be used in internal variables only.
153
+ * For any variables, class names, etc. that are exposed, please use a more specific name.
154
+ * (e.g. `reactCreateModalComponentName`)
155
+ */
156
+ internalPluralName: Types.VariableName;
157
+ /**
158
+ * Properties provided by the `data` generators.
159
+ */
107
160
  data: {
108
161
  /**
109
162
  * Path that may be used to import definitions of this model.
@@ -168,6 +221,34 @@ export type ModelMetaData = {
168
221
  getMethodFnName: Types.Fnction;
169
222
  };
170
223
  };
224
+ /**
225
+ * Properties provided by the `business logic` generator.
226
+ */
227
+ businessLogic: {
228
+ /**
229
+ * Path that may be used to import definitions of this model.
230
+ */
231
+ importPath: Types.Path;
232
+ /**
233
+ * The name by which the model's class is exposed in the businessLogicService/context. (e.g. aggregations)
234
+ */
235
+ serviceClassName: Types.ClassName;
236
+ /**
237
+ * The name by which the model's class is exposed in the businessLogicService/context. (e.g. aggregations)
238
+ */
239
+ serviceVariableName: Types.VariableName;
240
+ /**
241
+ * Name of the file containing the service for this model.
242
+ */
243
+ serviceFileName: Types.FileName;
244
+ /**
245
+ * Path to the file containing the service.
246
+ */
247
+ serviceFilePath: Types.Path;
248
+ };
249
+ /**
250
+ * Properties provided by the `seed` generators.
251
+ */
171
252
  seed: {
172
253
  /**
173
254
  * The name of the constant containing seed data of this model (e.g. `aggregations`).
@@ -206,6 +287,9 @@ export type ModelMetaData = {
206
287
  dataName: Types.VariableName;
207
288
  };
208
289
  };
290
+ /**
291
+ * Properties provided by the `react` generators.
292
+ */
209
293
  react: {
210
294
  /**
211
295
  * Name of the folder that contains React components for this model.
@@ -264,6 +348,9 @@ export type ModelMetaData = {
264
348
  cardComponentName: Types.VariableName;
265
349
  };
266
350
  };
351
+ /**
352
+ * Properties provided by the `trpc` generators.
353
+ */
267
354
  trpc: {
268
355
  /**
269
356
  * The path to the file that contains the router definition for this model.
@@ -299,7 +386,7 @@ export type ModelMetaData = {
299
386
  };
300
387
  update: {
301
388
  /**
302
- * The name of the TRPC udpate method (e.g. `udpate` or `udpateAggregation`).
389
+ * The name of the TRPC update method (e.g. `update` or `updateAggregation`).
303
390
  */
304
391
  methodName: Types.VariableName;
305
392
  /**
@@ -318,6 +405,9 @@ export type ModelMetaData = {
318
405
  reactQueryMethod: Types.Fnction;
319
406
  };
320
407
  };
408
+ /**
409
+ * Properties provided by the `types` generators.
410
+ */
321
411
  types: {
322
412
  /**
323
413
  * The absolute path of the file that contains the type definition for this model.
@@ -344,6 +434,16 @@ export type ModelMetaData = {
344
434
  * The name of the file containing type definitions (e.g. `aggregation.type`).
345
435
  */
346
436
  typeDefFileName: Types.FileName;
437
+ /**
438
+ * The name of the type that represents a fully typed, flat object, e.g. `Aggregation`.
439
+ * This type only refers to related types by their branded ID.
440
+ */
441
+ typeName: Types.TypeName;
442
+ /**
443
+ * The name of the type that represents a fully typed object, e.g. `AggregationFull`.
444
+ * This type refers to relations by linking to the (flat) types.
445
+ */
446
+ linkedTypeName: Types.TypeName;
347
447
  /**
348
448
  * The name of the type that represents a source (i.e. database) object, e.g. `Aggregation`.
349
449
  */
package/dist/lib/meta.js CHANGED
@@ -32,6 +32,8 @@ const string_1 = require("./utils/string");
32
32
  function getSchemaMetadata({ config }) {
33
33
  return {
34
34
  data: {
35
+ moduleName: Types.toClassName(`DataModule`),
36
+ importPath: Types.toPath(`@${config.project}/data`),
35
37
  dataModuleFilePath: Types.toPath(`${config.paths.dataLibPath}data.module`),
36
38
  dataMockModuleFilePath: Types.toPath(`${config.paths.dataLibPath}data.mock.module`),
37
39
  testDataServiceFilePath: Types.toPath(`${config.paths.dataLibPath}test-data.service`),
@@ -40,6 +42,14 @@ function getSchemaMetadata({ config }) {
40
42
  repositoriesIndexFilePath: Types.toPath(`${config.paths.dataLibPath}repositories/index`),
41
43
  stubIndexFilePath: Types.toPath(`${config.paths.dataLibPath}stubs/index`),
42
44
  },
45
+ businessLogic: {
46
+ moduleName: Types.toClassName(`BusinessLogicModule`),
47
+ importPath: Types.toPath(`@${config.project}/business-logic`),
48
+ indexFilePath: Types.toPath(`${config.paths.businessLogicPath}index`),
49
+ moduleFilePath: Types.toPath(`${config.paths.businessLogicPath}business-logic.module`),
50
+ serviceClassName: Types.toClassName(`BusinessLogicService`),
51
+ serviceFilePath: Types.toPath(`${config.paths.businessLogicPath}business-logic.service`),
52
+ },
43
53
  trpc: {
44
54
  routesFilePath: Types.toPath(`${config.paths.trpcRoutesFolderPath}index`),
45
55
  importPath: Types.toPath(`@${config.project}/trpc`),
@@ -68,6 +78,8 @@ function getModelMetadata({ model }) {
68
78
  const { PascalCase, camelCase, pluralized, uncapitalizedPlural, capitalizedPlural } = (0, string_1.conjugateNames)(name);
69
79
  return {
70
80
  userFriendlyName: PascalCase,
81
+ internalSingularName: Types.toVariableName(camelCase),
82
+ internalPluralName: Types.toVariableName(uncapitalizedPlural),
71
83
  data: {
72
84
  mockDataPropertyName: Types.toVariableName(`${uncapitalizedPlural}`),
73
85
  defaultStubConstantName: Types.toVariableName(`${camelCase}DefaultStub`),
@@ -87,6 +99,13 @@ function getModelMetadata({ model }) {
87
99
  getMethodFnName: Types.toFunction(`${camelCase}`),
88
100
  },
89
101
  },
102
+ businessLogic: {
103
+ importPath: Types.toPath(`@${config.project}/businessLogic`),
104
+ serviceClassName: Types.toClassName(`${PascalCase}Service`),
105
+ serviceVariableName: Types.toVariableName(`${uncapitalizedPlural}`),
106
+ serviceFileName: Types.toFileName(`${camelCase}.service`),
107
+ serviceFilePath: Types.toPath(`${config.paths.businessLogicPath}${camelCase}.service`),
108
+ },
90
109
  seed: {
91
110
  filePath: Types.toPath(`${config.paths.seedPath}${uncapitalizedPlural}`),
92
111
  constantName: Types.toVariableName(`${uncapitalizedPlural}`),
@@ -157,6 +176,8 @@ function getModelMetadata({ model }) {
157
176
  brandedIdType: Types.toTypeName(`${PascalCase}Id`),
158
177
  toBrandedIdTypeFnName: Types.toFunction(`to${PascalCase}Id`),
159
178
  zodDecoderFnName: Types.toFunction(`${camelCase}Decoder`),
179
+ typeName: Types.toTypeName(`${PascalCase}`),
180
+ linkedTypeName: Types.toTypeName(`${PascalCase}Linked`),
160
181
  typeDefFileName: Types.toFileName(`${camelCase}.type`),
161
182
  sourceType: Types.toTypeName(`${PascalCase}`),
162
183
  },
@@ -36,4 +36,8 @@ export declare const isUniqueStringField: (f: Field) => boolean;
36
36
  /**
37
37
  * Returns true if the given field has a maxLength attribute.
38
38
  */
39
- export declare const isMaxLengthStringField: (f: Field) => boolean;
39
+ export declare const isMaxLengthStringField: (f: Field) => f is Field & {
40
+ attributes: {
41
+ maxLength: number;
42
+ };
43
+ };
@@ -23,6 +23,10 @@ export type SchemaConfig = {
23
23
  * If true, data module will not be generated.
24
24
  */
25
25
  data: boolean;
26
+ /**
27
+ * If true, business logic module will not be generated.
28
+ */
29
+ businessLogic: boolean;
26
30
  /**
27
31
  * If true, seed data will not be generated.
28
32
  */
@@ -51,6 +55,13 @@ export type SchemaConfig = {
51
55
  * may reference data library using `@project/data` import.
52
56
  */
53
57
  dataLibPath: Types.Path;
58
+ /**
59
+ * Path to the directory containing business logic.
60
+ *
61
+ * NOTE: Metadata assumes that project is set up so that certain parts of the code
62
+ * may reference mock data using `@project/business-logic` import.
63
+ */
64
+ businessLogicPath: Types.Path;
54
65
  /**
55
66
  * Path to the directory containing mock data samples.
56
67
  *
@@ -285,6 +296,13 @@ export type FieldRelation = Prettify<Omit<FieldCore, 'name'> & {
285
296
  * Name of the field and variable (e.g. aggregationId)
286
297
  */
287
298
  name: string;
299
+ /**
300
+ * Name of the field in the related model that references this model (e.g. `aggregation`).
301
+ *
302
+ * NOTE: This does not reference the database column name, but the field name
303
+ * in the model (e.g. not `aggregationId`, but `aggregation`).
304
+ */
305
+ relatedModelBacklinkFieldName: string;
288
306
  /**
289
307
  * Name of the unbranded TypeScript type of the field, e.g. string
290
308
  *
@@ -308,6 +326,13 @@ export declare const isFieldRelation: (field: Field) => field is Prettify<Omit<F
308
326
  * Name of the field and variable (e.g. aggregationId)
309
327
  */
310
328
  name: string;
329
+ /**
330
+ * Name of the field in the related model that references this model (e.g. `aggregation`).
331
+ *
332
+ * NOTE: This does not reference the database column name, but the field name
333
+ * in the model (e.g. not `aggregationId`, but `aggregation`).
334
+ */
335
+ relatedModelBacklinkFieldName: string;
311
336
  /**
312
337
  * Name of the unbranded TypeScript type of the field, e.g. string
313
338
  *
@@ -341,7 +366,7 @@ export type FieldEnum = Prettify<Omit<FieldCore, 'name'> & {
341
366
  enumerator: Enum;
342
367
  }>;
343
368
  /**
344
- * Utility function to check if a field is an enumid field.
369
+ * Utility function to check if a field is an enum field.
345
370
  */
346
371
  export declare const isFieldEnum: (field: Field) => field is Prettify<Omit<FieldCore, "name"> & {
347
372
  kind: 'enum';
@@ -12,7 +12,7 @@ exports.isFieldId = isFieldId;
12
12
  const isFieldRelation = (field) => field.kind === 'relation';
13
13
  exports.isFieldRelation = isFieldRelation;
14
14
  /**
15
- * Utility function to check if a field is an enumid field.
15
+ * Utility function to check if a field is an enum field.
16
16
  */
17
17
  const isFieldEnum = (field) => field.kind === 'enum';
18
18
  exports.isFieldEnum = isFieldEnum;
@@ -84,9 +84,17 @@ function parseModel({ dmmfModel, enums, models, config, }) {
84
84
  }
85
85
  relations[dmmfField.relationFromFields[0]] = referencedModel;
86
86
  }
87
+ const relationFields = dmmfModel.fields
88
+ .filter((f) => f.kind === 'object' && f.relationToFields && f.relationToFields.length === 1)
89
+ .reduce((acc, f) => {
90
+ if (f.relationFromFields && f.relationFromFields[0]) {
91
+ acc[f.relationFromFields[0]] = f;
92
+ }
93
+ return acc;
94
+ }, {});
87
95
  const fields = dmmfModel.fields
88
96
  .filter((dmmfField) =>
89
- // if field is a "backlink", i.e. the reciever of a relation, we ignore it
97
+ // if field is a "backlink", i.e. the receiver of a relation, we ignore it
90
98
  dmmfField.kind !== 'object')
91
99
  .map((dmmfField) => {
92
100
  const attributes = (0, attributes_1.getFieldAttributes)(dmmfField);
@@ -101,7 +109,11 @@ function parseModel({ dmmfModel, enums, models, config, }) {
101
109
  // NOTE: We mark scalar fields which are used in relations as relation fields by Purple Schema standards.
102
110
  if (dmmfField.name in relations) {
103
111
  const refModel = relations[dmmfField.name];
104
- return Object.assign(Object.assign({ kind: 'relation' }, shared), { typeName: Types.toTypeName(dmmfField.type), unbrandedTypeName: getTsTypeForId(dmmfField), relationToModel: refModel });
112
+ const refField = relationFields[dmmfField.name];
113
+ if (!refField) {
114
+ (0, error_1.throwError)(`Investigate: Relation field ${dmmfField.name} not found.`);
115
+ }
116
+ return Object.assign(Object.assign({ kind: 'relation' }, shared), { relatedModelBacklinkFieldName: refField.name, typeName: Types.toTypeName(dmmfField.type), unbrandedTypeName: getTsTypeForId(dmmfField), relationToModel: refModel });
105
117
  }
106
118
  if (dmmfField.isId) {
107
119
  return Object.assign(Object.assign({ kind: 'id' }, shared), { isUnique: isUniqueField(dmmfField), isGenerated: isAutoIncrementField(dmmfField), unbrandedTypeName: getTsTypeForId(dmmfField), model: core });
@@ -117,7 +129,7 @@ function parseModel({ dmmfModel, enums, models, config, }) {
117
129
  if (dmmfField.type === 'Float') {
118
130
  validation = { type: 'float' };
119
131
  }
120
- return Object.assign(Object.assign({ kind: 'scalar' }, shared), { isUnique: isUniqueField(dmmfField), isGenerated: isAutoIncrementField(dmmfField), typeName: getTsTypeForScalar(dmmfField) });
132
+ return Object.assign(Object.assign({ kind: 'scalar', validation }, shared), { isUnique: isUniqueField(dmmfField), isGenerated: isAutoIncrementField(dmmfField), typeName: getTsTypeForScalar(dmmfField) });
121
133
  }
122
134
  if (dmmfField.kind === 'enum') {
123
135
  const fieldEnumDef = enums.find((e) => e.sourceName === dmmfField.type);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@postxl/generator",
3
- "version": "0.14.0",
3
+ "version": "0.15.1",
4
4
  "main": "./dist/generator.js",
5
5
  "typings": "./dist/generator.d.ts",
6
6
  "bin": {
@@ -22,7 +22,7 @@
22
22
  "prettier": "^2.8.7",
23
23
  "remeda": "1.9.4",
24
24
  "zod": "3.21.4",
25
- "@postxl/lock": "0.3.2"
25
+ "@postxl/lock": "0.4.1"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@prisma/client": "4.12.0",