@postxl/generator 0.74.2 → 1.0.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.
- package/LICENSE +50 -0
- package/README.md +79 -1
- package/dist/generator-manager.class.d.ts +59 -0
- package/dist/generator-manager.class.js +221 -0
- package/dist/generator.class.d.ts +90 -0
- package/dist/generator.class.js +32 -0
- package/dist/generator.context.d.ts +174 -0
- package/dist/generator.context.js +125 -0
- package/dist/helpers/branded.types.d.ts +149 -0
- package/dist/helpers/branded.types.js +111 -0
- package/dist/helpers/config-builder.class.d.ts +27 -0
- package/dist/helpers/config-builder.class.js +54 -0
- package/dist/helpers/import-generator.class.d.ts +70 -0
- package/dist/helpers/import-generator.class.js +166 -0
- package/dist/helpers/importable.types.d.ts +52 -0
- package/dist/helpers/importable.types.js +15 -0
- package/dist/helpers/index-generator.class.d.ts +10 -0
- package/dist/helpers/index-generator.class.js +46 -0
- package/dist/helpers/index.d.ts +8 -0
- package/dist/helpers/index.js +24 -0
- package/dist/helpers/package-json.generator.d.ts +56 -0
- package/dist/helpers/package-json.generator.js +36 -0
- package/dist/helpers/tsconfig.generator.d.ts +1 -0
- package/dist/helpers/tsconfig.generator.js +14 -0
- package/dist/helpers/verify-context.d.ts +4 -0
- package/dist/helpers/verify-context.js +23 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +21 -0
- package/dist/utils/checksum.d.ts +10 -0
- package/dist/utils/checksum.js +132 -0
- package/dist/utils/fs-utils.d.ts +34 -0
- package/dist/utils/fs-utils.js +126 -0
- package/dist/utils/index.d.ts +10 -0
- package/dist/utils/index.js +26 -0
- package/dist/utils/jsdoc.d.ts +12 -0
- package/dist/utils/jsdoc.js +37 -0
- package/dist/utils/lint.d.ts +46 -0
- package/dist/utils/lint.js +154 -0
- package/dist/utils/lockfile.d.ts +7 -0
- package/dist/utils/lockfile.js +80 -0
- package/dist/utils/logger.class.d.ts +25 -0
- package/dist/utils/logger.class.js +55 -0
- package/dist/utils/merge-conflict.d.ts +55 -0
- package/dist/utils/merge-conflict.js +264 -0
- package/dist/utils/path.d.ts +52 -0
- package/dist/utils/path.js +183 -0
- package/dist/utils/prettier-config.d.ts +2 -0
- package/dist/utils/prettier-config.js +13 -0
- package/dist/utils/prettier.d.ts +5 -0
- package/dist/utils/prettier.js +67 -0
- package/dist/utils/prettier.skiptest.d.ts +1 -0
- package/dist/utils/prettier.skiptest.js +22 -0
- package/dist/utils/promise.d.ts +2 -0
- package/dist/utils/promise.js +10 -0
- package/dist/utils/string-functions.d.ts +9 -0
- package/dist/utils/string-functions.js +23 -0
- package/dist/utils/sync-log-result.d.ts +9 -0
- package/dist/utils/sync-log-result.js +90 -0
- package/dist/utils/sync.d.ts +143 -0
- package/dist/utils/sync.js +325 -0
- package/dist/utils/template.d.ts +66 -0
- package/dist/utils/template.js +159 -0
- package/dist/utils/vfs.class.d.ts +115 -0
- package/dist/utils/vfs.class.js +239 -0
- package/dist/utils/zip.d.ts +13 -0
- package/dist/utils/zip.js +40 -0
- package/package.json +57 -34
- package/dist/generator.d.ts +0 -13
- package/dist/generator.js +0 -455
- package/dist/generators/enums/react.generator.d.ts +0 -10
- package/dist/generators/enums/react.generator.js +0 -110
- package/dist/generators/enums/types.generator.d.ts +0 -10
- package/dist/generators/enums/types.generator.js +0 -39
- package/dist/generators/indices/data/module.generator.d.ts +0 -9
- package/dist/generators/indices/data/module.generator.js +0 -60
- package/dist/generators/indices/data/service.generator.d.ts +0 -9
- package/dist/generators/indices/data/service.generator.js +0 -249
- package/dist/generators/indices/data/types.generator.d.ts +0 -9
- package/dist/generators/indices/data/types.generator.js +0 -49
- package/dist/generators/indices/dispatcher-service.generator.d.ts +0 -9
- package/dist/generators/indices/dispatcher-service.generator.js +0 -107
- package/dist/generators/indices/export/class.generator.d.ts +0 -9
- package/dist/generators/indices/export/class.generator.js +0 -140
- package/dist/generators/indices/export/encoder.generator.d.ts +0 -9
- package/dist/generators/indices/export/encoder.generator.js +0 -50
- package/dist/generators/indices/import/convert-functions.generator.d.ts +0 -9
- package/dist/generators/indices/import/convert-functions.generator.js +0 -509
- package/dist/generators/indices/import/decoder.generator.d.ts +0 -9
- package/dist/generators/indices/import/decoder.generator.js +0 -40
- package/dist/generators/indices/import/service.generator.d.ts +0 -9
- package/dist/generators/indices/import/service.generator.js +0 -573
- package/dist/generators/indices/import/types.generator.d.ts +0 -9
- package/dist/generators/indices/import/types.generator.js +0 -242
- package/dist/generators/indices/repositories.generator.d.ts +0 -9
- package/dist/generators/indices/repositories.generator.js +0 -25
- package/dist/generators/indices/routes.generator.d.ts +0 -9
- package/dist/generators/indices/routes.generator.js +0 -29
- package/dist/generators/indices/seed-migration.generator.d.ts +0 -9
- package/dist/generators/indices/seed-migration.generator.js +0 -36
- package/dist/generators/indices/seed-template.generator.d.ts +0 -9
- package/dist/generators/indices/seed-template.generator.js +0 -80
- package/dist/generators/indices/testids.generator.d.ts +0 -7
- package/dist/generators/indices/testids.generator.js +0 -71
- package/dist/generators/indices/types.generator.d.ts +0 -10
- package/dist/generators/indices/types.generator.js +0 -35
- package/dist/generators/indices/update/actiontypes.generator.d.ts +0 -9
- package/dist/generators/indices/update/actiontypes.generator.js +0 -49
- package/dist/generators/indices/update/module.generator.d.ts +0 -9
- package/dist/generators/indices/update/module.generator.js +0 -41
- package/dist/generators/indices/update/service.generator.d.ts +0 -9
- package/dist/generators/indices/update/service.generator.js +0 -34
- package/dist/generators/indices/view/module.generator.d.ts +0 -9
- package/dist/generators/indices/view/module.generator.js +0 -39
- package/dist/generators/indices/view/service.generator.d.ts +0 -9
- package/dist/generators/indices/view/service.generator.js +0 -34
- package/dist/generators/models/admin.page.generator.d.ts +0 -7
- package/dist/generators/models/admin.page.generator.js +0 -74
- package/dist/generators/models/export/encoder.generator.d.ts +0 -9
- package/dist/generators/models/export/encoder.generator.js +0 -51
- package/dist/generators/models/import/decoder.generator.d.ts +0 -9
- package/dist/generators/models/import/decoder.generator.js +0 -148
- package/dist/generators/models/react/context.generator.d.ts +0 -9
- package/dist/generators/models/react/context.generator.js +0 -71
- package/dist/generators/models/react/index.d.ts +0 -10
- package/dist/generators/models/react/index.js +0 -31
- package/dist/generators/models/react/library.generator.d.ts +0 -10
- package/dist/generators/models/react/library.generator.js +0 -94
- package/dist/generators/models/react/lookup.generator.d.ts +0 -9
- package/dist/generators/models/react/lookup.generator.js +0 -175
- package/dist/generators/models/react/modals.generator.d.ts +0 -23
- package/dist/generators/models/react/modals.generator.js +0 -710
- package/dist/generators/models/repository.generator.d.ts +0 -9
- package/dist/generators/models/repository.generator.js +0 -955
- package/dist/generators/models/route.generator.d.ts +0 -9
- package/dist/generators/models/route.generator.js +0 -92
- package/dist/generators/models/seed.generator.d.ts +0 -21
- package/dist/generators/models/seed.generator.js +0 -285
- package/dist/generators/models/stub.generator.d.ts +0 -9
- package/dist/generators/models/stub.generator.js +0 -92
- package/dist/generators/models/types.generator.d.ts +0 -9
- package/dist/generators/models/types.generator.js +0 -125
- package/dist/generators/models/update/service.generator.d.ts +0 -10
- package/dist/generators/models/update/service.generator.js +0 -302
- package/dist/generators/models/view/service.generator.d.ts +0 -10
- package/dist/generators/models/view/service.generator.js +0 -239
- package/dist/lib/attributes.d.ts +0 -114
- package/dist/lib/attributes.js +0 -2
- package/dist/lib/exports.d.ts +0 -45
- package/dist/lib/exports.js +0 -90
- package/dist/lib/imports.d.ts +0 -65
- package/dist/lib/imports.js +0 -114
- package/dist/lib/meta.d.ts +0 -1191
- package/dist/lib/meta.js +0 -434
- package/dist/lib/schema/fields.d.ts +0 -46
- package/dist/lib/schema/fields.js +0 -62
- package/dist/lib/schema/schema.d.ts +0 -466
- package/dist/lib/schema/schema.js +0 -18
- package/dist/lib/schema/types.d.ts +0 -201
- package/dist/lib/schema/types.js +0 -112
- package/dist/lib/serializer.d.ts +0 -15
- package/dist/lib/serializer.js +0 -24
- package/dist/lib/test-id-collector.d.ts +0 -42
- package/dist/lib/test-id-collector.js +0 -53
- package/dist/lib/types.d.ts +0 -7
- package/dist/lib/types.js +0 -13
- package/dist/lib/typescript.d.ts +0 -5
- package/dist/lib/typescript.js +0 -22
- package/dist/lib/utils/ast.d.ts +0 -29
- package/dist/lib/utils/ast.js +0 -23
- package/dist/lib/utils/error.d.ts +0 -17
- package/dist/lib/utils/error.js +0 -52
- package/dist/lib/utils/file.d.ts +0 -10
- package/dist/lib/utils/file.js +0 -56
- package/dist/lib/utils/jsdoc.d.ts +0 -9
- package/dist/lib/utils/jsdoc.js +0 -37
- package/dist/lib/utils/logger.d.ts +0 -17
- package/dist/lib/utils/logger.js +0 -12
- package/dist/lib/utils/string.d.ts +0 -40
- package/dist/lib/utils/string.js +0 -187
- package/dist/lib/utils/types.d.ts +0 -12
- package/dist/lib/utils/types.js +0 -2
- package/dist/lib/zod.d.ts +0 -8
- package/dist/lib/zod.js +0 -60
- package/dist/prisma/attributes.d.ts +0 -21
- package/dist/prisma/attributes.js +0 -175
- package/dist/prisma/client-path.d.ts +0 -7
- package/dist/prisma/client-path.js +0 -29
- package/dist/prisma/parse.d.ts +0 -12
- package/dist/prisma/parse.js +0 -452
|
@@ -1,573 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generateImportService = void 0;
|
|
4
|
-
const imports_1 = require("../../../lib/imports");
|
|
5
|
-
const meta_1 = require("../../../lib/meta");
|
|
6
|
-
const types_1 = require("../../../lib/schema/types");
|
|
7
|
-
const string_1 = require("../../../lib/utils/string");
|
|
8
|
-
/**
|
|
9
|
-
* Generates the Import Service class for the Import module
|
|
10
|
-
*/
|
|
11
|
-
function generateImportService({ models, meta }) {
|
|
12
|
-
const imports = imports_1.ImportsGenerator.from(meta.import.importService.location.path);
|
|
13
|
-
const { types, decoder, converterFunctions } = meta.import;
|
|
14
|
-
const { delta_Fields, delta, delta_Model } = types;
|
|
15
|
-
const { create, errors, unchanged, update } = delta_Model;
|
|
16
|
-
const { nonUnique, invalidReference, invalidType, isRequiredDependency, missingField } = errors;
|
|
17
|
-
const { dto } = meta.types;
|
|
18
|
-
imports.addImports({
|
|
19
|
-
[meta.data.dataService.location.import]: [meta.data.dataService.class],
|
|
20
|
-
[meta.data.types.location.import]: [(0, types_1.toAnnotatedTypeName)(meta.data.types.bulkMutation)],
|
|
21
|
-
[meta.types.importPath]: [
|
|
22
|
-
(0, types_1.toAnnotatedTypeName)(dto.genericModel),
|
|
23
|
-
(0, types_1.toAnnotatedTypeName)(dto.idType),
|
|
24
|
-
(0, types_1.toAnnotatedTypeName)(dto.update),
|
|
25
|
-
],
|
|
26
|
-
[meta.actions.execution.interfaceLocation.import]: [meta.actions.execution.interface],
|
|
27
|
-
[meta.actions.dispatcher.classLocation.import]: [meta.actions.dispatcher.class],
|
|
28
|
-
[types.location.path]: [
|
|
29
|
-
(0, types_1.toAnnotatedTypeName)(delta),
|
|
30
|
-
(0, types_1.toAnnotatedTypeName)(delta_Fields),
|
|
31
|
-
(0, types_1.toAnnotatedTypeName)(delta_Model.type),
|
|
32
|
-
(0, types_1.toAnnotatedTypeName)(delta_Model.errors.invalidReference.type),
|
|
33
|
-
(0, types_1.toAnnotatedTypeName)(delta_Model.errors.isRequiredDependency.type),
|
|
34
|
-
],
|
|
35
|
-
[decoder.location.path]: [(0, types_1.toAnnotatedTypeName)(decoder.decodedPXLModelDataTypeName)],
|
|
36
|
-
[converterFunctions.location.path]: [converterFunctions.deltaToBulkMutations],
|
|
37
|
-
});
|
|
38
|
-
const resultAssignments = [];
|
|
39
|
-
const detectDeltaFunctions = [];
|
|
40
|
-
for (const model of models) {
|
|
41
|
-
const modelMeta = (0, meta_1.getModelMetadata)({ model });
|
|
42
|
-
imports.addTypeImport({
|
|
43
|
-
from: modelMeta.types.importPath,
|
|
44
|
-
items: [modelMeta.types.typeName, modelMeta.types.brandedIdType],
|
|
45
|
-
});
|
|
46
|
-
resultAssignments.push(`${modelMeta.seed.constantName}: await this.detect${modelMeta.internalSingularNameCapitalized}Delta(data.${modelMeta.seed.constantName}),`);
|
|
47
|
-
detectDeltaFunctions.push(generateDetectDeltaFunction({ model, modelMeta, models, schemaMeta: meta, imports }));
|
|
48
|
-
}
|
|
49
|
-
return /* ts */ `
|
|
50
|
-
import { Injectable } from '@nestjs/common'
|
|
51
|
-
import { ExhaustiveSwitchCheck } from '@postxl/runtime'
|
|
52
|
-
|
|
53
|
-
${imports.generate()}
|
|
54
|
-
|
|
55
|
-
import { Action_Import } from './actions'
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
type Delta_Result<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}> =
|
|
59
|
-
| { type: '${create.discriminant}' }
|
|
60
|
-
| { type: '${update.discriminant}'; delta: ${delta_Fields}<Model, ID>; existingItem: Model }
|
|
61
|
-
| { type: '${delta_Model.delete.discriminant}'; existingItem: Model }
|
|
62
|
-
| { type: '${unchanged.discriminant}' }
|
|
63
|
-
|
|
64
|
-
@Injectable()
|
|
65
|
-
export class ${meta.import.importService.name} {
|
|
66
|
-
constructor(
|
|
67
|
-
private readonly data: ${meta.data.dataService.class},
|
|
68
|
-
private readonly dispatcher: ${meta.actions.dispatcher.class},
|
|
69
|
-
) {
|
|
70
|
-
// We have a circular dependency between DispatcherService and ${meta.import.importService.name}.
|
|
71
|
-
// In order to avoid trouble, instead of using Nest's forwardRef(), we inject the dispatcher service here
|
|
72
|
-
// and set the dispatcher's ${meta.import.importService.sharedName} to this instance.
|
|
73
|
-
this.dispatcher.${meta.import.importService.sharedName} =this
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Will be called by the dispatcher service to dispatch the given action.
|
|
79
|
-
*/
|
|
80
|
-
public async dispatch({
|
|
81
|
-
action,
|
|
82
|
-
execution
|
|
83
|
-
}: {
|
|
84
|
-
action: Action_Import;
|
|
85
|
-
execution: ${meta.actions.execution.interface}
|
|
86
|
-
}) {
|
|
87
|
-
switch (action.type) {
|
|
88
|
-
case 'detect-delta':
|
|
89
|
-
return this.detectDelta(action.payload.data)
|
|
90
|
-
case 'execute-upsert':
|
|
91
|
-
return this.executeUpsert({ delta: action.payload, execution })
|
|
92
|
-
case 'execute-direct-upsert':
|
|
93
|
-
return this.executeDirectUpsert({ data: action.payload.data, execution })
|
|
94
|
-
|
|
95
|
-
default:
|
|
96
|
-
throw new ExhaustiveSwitchCheck(action)
|
|
97
|
-
}
|
|
98
|
-
}
|
|
99
|
-
|
|
100
|
-
public async detectDelta(data: ${decoder.decodedPXLModelDataTypeName}): Promise<{
|
|
101
|
-
bulkMutations: ${meta.data.types.bulkMutation}[]
|
|
102
|
-
upsertResult: ${delta}
|
|
103
|
-
}> {
|
|
104
|
-
const upsertResult: ${delta} = {
|
|
105
|
-
${resultAssignments.join('\n')}
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
const bulkMutations: ${meta.data.types.bulkMutation}[] = ${converterFunctions.deltaToBulkMutations}(upsertResult)
|
|
109
|
-
return { bulkMutations, upsertResult }
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
public async executeUpsert({
|
|
113
|
-
delta,
|
|
114
|
-
execution
|
|
115
|
-
}: {
|
|
116
|
-
delta: Delta;
|
|
117
|
-
execution: ${meta.actions.execution.interface}
|
|
118
|
-
}) {
|
|
119
|
-
const bulkMutations = ${converterFunctions.deltaToBulkMutations}(delta)
|
|
120
|
-
return this.data.${meta.data.dataService.executeBulkMutations}({ steps: bulkMutations, execution })
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
public async executeDirectUpsert({
|
|
124
|
-
data,
|
|
125
|
-
execution
|
|
126
|
-
}: {
|
|
127
|
-
data: ${meta.import.decoder.decodedPXLModelDataTypeName};
|
|
128
|
-
execution: ${meta.actions.execution.interface}
|
|
129
|
-
}) {
|
|
130
|
-
const { bulkMutations } = await this.detectDelta(data)
|
|
131
|
-
return this.data.${meta.data.dataService.executeBulkMutations}({ steps: bulkMutations, execution })
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
/**
|
|
135
|
-
* Generic function to determine what action (create/update/delete/unchanged) to take with an item
|
|
136
|
-
* In case the type is update it also includes the delta for a given item. In case of delete, it also includes
|
|
137
|
-
* the existing item.
|
|
138
|
-
*
|
|
139
|
-
* NOTE: The function does not implement any logic to automatically determine if an item should be deleted.
|
|
140
|
-
* Implement this logic based on the business requirements!
|
|
141
|
-
*/
|
|
142
|
-
private async determineDeltaResult<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}>({
|
|
143
|
-
item,
|
|
144
|
-
getId,
|
|
145
|
-
getDelta,
|
|
146
|
-
}: {
|
|
147
|
-
item: Model
|
|
148
|
-
getId: (id: ID) => Promise<Model | null>
|
|
149
|
-
getDelta: ({ item, existingItem }: { item: Model; existingItem: Model }) => ${delta_Fields}<Model, ID>
|
|
150
|
-
}): Promise<Delta_Result<Model, ID>> {
|
|
151
|
-
if (item.id === undefined || item.id === '') {
|
|
152
|
-
return { type: '${create.discriminant}' }
|
|
153
|
-
}
|
|
154
|
-
const existingItem = await getId(item.id)
|
|
155
|
-
|
|
156
|
-
if (!existingItem) {
|
|
157
|
-
return { type: '${create.discriminant}' }
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
const delta = getDelta({ item, existingItem })
|
|
161
|
-
|
|
162
|
-
if (Object.keys(delta).length > 0) {
|
|
163
|
-
return { type: '${update.discriminant}', delta, existingItem }
|
|
164
|
-
}
|
|
165
|
-
|
|
166
|
-
// We do not have a default logic to identify deletions. Implement it here, e.g. using a
|
|
167
|
-
// custom "Action" field in the Excel table. If it is set to "Delete", we can handle the delete here.
|
|
168
|
-
// return {type: '${delta_Model.delete.discriminant}', existingItem}
|
|
169
|
-
|
|
170
|
-
// If we reach this point, we assume the item has not changed
|
|
171
|
-
return { type: '${unchanged.discriminant}' }
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
private getDelta<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}>({
|
|
175
|
-
item,
|
|
176
|
-
existingItem,
|
|
177
|
-
properties,
|
|
178
|
-
}: {
|
|
179
|
-
item: Model
|
|
180
|
-
existingItem: Model
|
|
181
|
-
properties: (keyof Omit<Model, 'id'>)[]
|
|
182
|
-
}): ${delta_Fields}<Model, ID> {
|
|
183
|
-
const delta: ${delta_Fields}<Model, ID> = {}
|
|
184
|
-
|
|
185
|
-
for (const property of properties) {
|
|
186
|
-
addDelta({ delta, existingItem, item, property })
|
|
187
|
-
}
|
|
188
|
-
|
|
189
|
-
return delta
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
/**
|
|
193
|
-
* Detects changes for a model and returns the result as a Delta_Model object.
|
|
194
|
-
*/
|
|
195
|
-
private async detectModelDelta<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}, ModelErrors>({
|
|
196
|
-
items,
|
|
197
|
-
getId,
|
|
198
|
-
getDelta,
|
|
199
|
-
validateCreate,
|
|
200
|
-
validateUpdate,
|
|
201
|
-
validateDelete,
|
|
202
|
-
}: {
|
|
203
|
-
items?: Model[]
|
|
204
|
-
getId: (id: ID) => Promise<Model | null>
|
|
205
|
-
getDelta: (args: { item: Model; existingItem: Model }) => ${delta_Fields}<Model, ID>
|
|
206
|
-
validateCreate: (args: { item: Model }) => Promise<ModelErrors[]>
|
|
207
|
-
validateUpdate: (args: { item: Model; existingItem: Model }) => Promise<ModelErrors[]>
|
|
208
|
-
validateDelete: (args: { existingItem: Model }) => Promise<ModelErrors[]>
|
|
209
|
-
}): Promise<Delta_Model<Model, ID, ModelErrors>[]> {
|
|
210
|
-
const upsertResult: Delta_Model<Model, ID, ModelErrors>[] = []
|
|
211
|
-
|
|
212
|
-
if (items === undefined || items.length === 0) {
|
|
213
|
-
return upsertResult
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
for (const item of items) {
|
|
217
|
-
const deltaResult = await this.determineDeltaResult({ item, getId, getDelta })
|
|
218
|
-
|
|
219
|
-
switch (deltaResult.type) {
|
|
220
|
-
case 'create': {
|
|
221
|
-
const errors = await validateCreate({ item })
|
|
222
|
-
if (errors.length === 0) {
|
|
223
|
-
upsertResult.push({ type: '${create.discriminant}', input: item, createDTO: item })
|
|
224
|
-
} else {
|
|
225
|
-
upsertResult.push({ type: '${errors.discriminant}', input: item, errors })
|
|
226
|
-
}
|
|
227
|
-
break
|
|
228
|
-
}
|
|
229
|
-
|
|
230
|
-
case 'update': {
|
|
231
|
-
const errors = await validateUpdate({ item, existingItem: deltaResult.existingItem })
|
|
232
|
-
if (errors.length === 0) {
|
|
233
|
-
upsertResult.push({
|
|
234
|
-
type: '${update.discriminant}',
|
|
235
|
-
input: item,
|
|
236
|
-
delta: deltaResult.delta,
|
|
237
|
-
updateDTO: deltaToUpdateDtoFunction({ id: item.id, delta: deltaResult.delta }),
|
|
238
|
-
})
|
|
239
|
-
} else {
|
|
240
|
-
upsertResult.push({ type: '${errors.discriminant}', input: item, errors })
|
|
241
|
-
}
|
|
242
|
-
break
|
|
243
|
-
}
|
|
244
|
-
|
|
245
|
-
case 'delete': {
|
|
246
|
-
const errors = await validateDelete({ existingItem: deltaResult.existingItem })
|
|
247
|
-
if (errors.length === 0) {
|
|
248
|
-
upsertResult.push({ type: '${delta_Model.delete.discriminant}', input: item })
|
|
249
|
-
} else {
|
|
250
|
-
upsertResult.push({ type: '${errors.discriminant}', input: item, errors })
|
|
251
|
-
}
|
|
252
|
-
break
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
case 'unchanged': {
|
|
256
|
-
upsertResult.push({ type: '${unchanged.discriminant}', input: item })
|
|
257
|
-
break
|
|
258
|
-
}
|
|
259
|
-
|
|
260
|
-
default:
|
|
261
|
-
throw new ExhaustiveSwitchCheck(deltaResult)
|
|
262
|
-
}
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
return upsertResult
|
|
266
|
-
}
|
|
267
|
-
|
|
268
|
-
/**
|
|
269
|
-
* Internal helper function that removes undefined values from an array.
|
|
270
|
-
*/
|
|
271
|
-
private keepErrors<O, I extends O | undefined>(errors: I[]): O[] {
|
|
272
|
-
return errors.filter((error) => error !== undefined) as O[]
|
|
273
|
-
}
|
|
274
|
-
|
|
275
|
-
private validateRequiredFields<
|
|
276
|
-
Model extends ${dto.genericModel}<ID>,
|
|
277
|
-
ID extends ${dto.idType},
|
|
278
|
-
FieldName extends Extract<keyof Omit<Model, 'id'>, string>
|
|
279
|
-
>({
|
|
280
|
-
item,
|
|
281
|
-
fieldNames,
|
|
282
|
-
}: {
|
|
283
|
-
item: Model
|
|
284
|
-
fieldNames: FieldName[]
|
|
285
|
-
}): ${missingField.type}<FieldName>[] {
|
|
286
|
-
const errors: ${missingField.type}<FieldName>[] = []
|
|
287
|
-
for (const fieldName of fieldNames) {
|
|
288
|
-
if (item[fieldName] === undefined) {
|
|
289
|
-
errors.push({ error: '${missingField.discriminant}', fieldName })
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
if (errors.length > 0) {
|
|
293
|
-
return errors
|
|
294
|
-
} else {
|
|
295
|
-
return []
|
|
296
|
-
}
|
|
297
|
-
}
|
|
298
|
-
|
|
299
|
-
private async validateReferenceField<
|
|
300
|
-
Model extends ${dto.genericModel}<ID>,
|
|
301
|
-
ID extends ${dto.idType},
|
|
302
|
-
RelatedModel extends ${dto.genericModel}<RelatedID>,
|
|
303
|
-
RelatedID extends ${dto.idType},
|
|
304
|
-
FieldName extends keyof Omit<Model, 'id'> & string,
|
|
305
|
-
Value extends RelatedID,
|
|
306
|
-
RelatedModelName extends string,
|
|
307
|
-
>({
|
|
308
|
-
item,
|
|
309
|
-
fieldName,
|
|
310
|
-
relatedModel,
|
|
311
|
-
getExistingItem,
|
|
312
|
-
}: {
|
|
313
|
-
item: Partial<Model>
|
|
314
|
-
fieldName: FieldName
|
|
315
|
-
relatedModel: RelatedModelName
|
|
316
|
-
getExistingItem: (id: RelatedID) => Promise<RelatedModel | null>
|
|
317
|
-
}): Promise<${invalidReference.type}<RelatedModelName, FieldName, Value> | undefined> {
|
|
318
|
-
const value: Value | undefined = item[fieldName] as Value | undefined
|
|
319
|
-
if (value === undefined) {
|
|
320
|
-
return undefined
|
|
321
|
-
}
|
|
322
|
-
const existingItem = await getExistingItem(value)
|
|
323
|
-
if (!existingItem) {
|
|
324
|
-
return { error: '${invalidReference.discriminant}', relatedModel, fieldName, value }
|
|
325
|
-
}
|
|
326
|
-
return undefined
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
private async validateUniqueField<
|
|
330
|
-
Model extends ${dto.genericModel}<ID>,
|
|
331
|
-
ID extends ${dto.idType},
|
|
332
|
-
FieldName extends keyof Omit<Model, 'id'> & string,
|
|
333
|
-
Value extends Model[FieldName],
|
|
334
|
-
>({
|
|
335
|
-
item,
|
|
336
|
-
fieldName,
|
|
337
|
-
getExistingItem,
|
|
338
|
-
}: {
|
|
339
|
-
item: Partial<Model>
|
|
340
|
-
fieldName: FieldName
|
|
341
|
-
getExistingItem: (fieldValue: Value) => Promise<Model | undefined>
|
|
342
|
-
}): Promise<${nonUnique.type}<FieldName, Value> | undefined> {
|
|
343
|
-
const value: Value | undefined = item[fieldName] as Value | undefined
|
|
344
|
-
if (value === undefined) {
|
|
345
|
-
return undefined
|
|
346
|
-
}
|
|
347
|
-
const existingItem = await getExistingItem(value)
|
|
348
|
-
if (existingItem) {
|
|
349
|
-
return { error: '${nonUnique.discriminant}', fieldName, value }
|
|
350
|
-
}
|
|
351
|
-
return undefined
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
private validateInt<
|
|
355
|
-
Model extends ${dto.genericModel}<ID>,
|
|
356
|
-
ID extends ${dto.idType},
|
|
357
|
-
FieldName extends keyof Omit<Model, 'id'> & string,
|
|
358
|
-
>({
|
|
359
|
-
item,
|
|
360
|
-
fieldName,
|
|
361
|
-
}: {
|
|
362
|
-
item: Model
|
|
363
|
-
fieldName: FieldName
|
|
364
|
-
}): ${invalidType.type}<FieldName, 'Int', number> | undefined {
|
|
365
|
-
const value: number | undefined | null = item[fieldName] as number | undefined | null
|
|
366
|
-
//we handle undefined and null in other value checks so we can ignore them here
|
|
367
|
-
if (value === undefined || value === null) {
|
|
368
|
-
return undefined
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
if (value !== Math.floor(value)) {
|
|
372
|
-
return { error: '${invalidType.discriminant}', fieldName, typeExpected: 'Int', value }
|
|
373
|
-
}
|
|
374
|
-
return undefined
|
|
375
|
-
}
|
|
376
|
-
|
|
377
|
-
private async validateRequiredDependency<
|
|
378
|
-
Model extends ${dto.genericModel}<ID>,
|
|
379
|
-
ID extends ${dto.idType},
|
|
380
|
-
RelatedModelName extends string,
|
|
381
|
-
RelatedField extends string,
|
|
382
|
-
RelatedModel extends ${dto.genericModel}<RelatedID>,
|
|
383
|
-
RelatedID extends ${dto.idType},
|
|
384
|
-
>({
|
|
385
|
-
item,
|
|
386
|
-
relatedModel,
|
|
387
|
-
relatedField,
|
|
388
|
-
getReferencedItems,
|
|
389
|
-
}: {
|
|
390
|
-
item: Model
|
|
391
|
-
relatedModel: RelatedModelName
|
|
392
|
-
relatedField: RelatedField
|
|
393
|
-
getReferencedItems: (id: ID) => Promise<RelatedModel[]>
|
|
394
|
-
}): Promise<
|
|
395
|
-
${isRequiredDependency.type}<RelatedModelName, RelatedField, RelatedModel, RelatedID> | undefined
|
|
396
|
-
> {
|
|
397
|
-
const relatedItems = await getReferencedItems(item.id)
|
|
398
|
-
if (relatedItems.length > 0) {
|
|
399
|
-
return undefined
|
|
400
|
-
}
|
|
401
|
-
return { error: '${isRequiredDependency.discriminant}', relatedModel, relatedField, relatedItems }
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
${detectDeltaFunctions.join('\n')}
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
/**
|
|
408
|
-
* Adds a delta entry for a property to the given delta object if the property
|
|
409
|
-
* of the item is different from the existing item
|
|
410
|
-
*/
|
|
411
|
-
function addDelta<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}>({
|
|
412
|
-
delta,
|
|
413
|
-
existingItem,
|
|
414
|
-
item,
|
|
415
|
-
property,
|
|
416
|
-
}: {
|
|
417
|
-
delta: ${delta_Fields}<Model, ID>
|
|
418
|
-
existingItem: Model
|
|
419
|
-
item: Model
|
|
420
|
-
property: keyof Omit<Model, 'id'>
|
|
421
|
-
}): void {
|
|
422
|
-
if (existingItem[property] === item[property]) {
|
|
423
|
-
return
|
|
424
|
-
}
|
|
425
|
-
delta[property] = { old: existingItem[property], new: item[property] }
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
/**
|
|
429
|
-
* Converts a Delta to an UpdateDTO.
|
|
430
|
-
*/
|
|
431
|
-
function deltaToUpdateDtoFunction<Model extends ${dto.genericModel}<ID>, ID extends ${dto.idType}>({
|
|
432
|
-
id,
|
|
433
|
-
delta,
|
|
434
|
-
}: {
|
|
435
|
-
id: ID
|
|
436
|
-
delta: ${delta_Fields}<Model, ID>
|
|
437
|
-
}): ${dto.update}<Model, ID> {
|
|
438
|
-
const updateDTO = {
|
|
439
|
-
id: id,
|
|
440
|
-
} as UpdateDTO<Model, ID>
|
|
441
|
-
|
|
442
|
-
for (const [key, value] of Object.entries(delta)) {
|
|
443
|
-
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access
|
|
444
|
-
const updatedValue = value.new as Model[keyof Omit<Model, 'id'>]
|
|
445
|
-
updateDTO[key as keyof Omit<Model, 'id'>] = updatedValue
|
|
446
|
-
}
|
|
447
|
-
return updateDTO
|
|
448
|
-
}`;
|
|
449
|
-
}
|
|
450
|
-
exports.generateImportService = generateImportService;
|
|
451
|
-
function generateDetectDeltaFunction({ model, modelMeta, models, schemaMeta, imports, }) {
|
|
452
|
-
const { types } = schemaMeta.import;
|
|
453
|
-
const { delta_Model } = types;
|
|
454
|
-
imports.addTypeImport({
|
|
455
|
-
from: types.location.path,
|
|
456
|
-
items: [modelMeta.import.delta_Model_Errors],
|
|
457
|
-
});
|
|
458
|
-
const returnType = `${delta_Model.type}<${model.typeName}, ${modelMeta.types.brandedIdType}, ${modelMeta.import.delta_Model_Errors}>[]`;
|
|
459
|
-
const sharedValidations = [];
|
|
460
|
-
const requiredFields = [];
|
|
461
|
-
const fieldNames = [];
|
|
462
|
-
for (const field of model.fields) {
|
|
463
|
-
if (field.name === 'id' ||
|
|
464
|
-
field.attributes.isReadonly ||
|
|
465
|
-
field.attributes.isCreatedAt ||
|
|
466
|
-
field.attributes.isUpdatedAt) {
|
|
467
|
-
continue;
|
|
468
|
-
}
|
|
469
|
-
const fieldName = field.name;
|
|
470
|
-
fieldNames.push(`'${fieldName}'`);
|
|
471
|
-
if (field.isRequired) {
|
|
472
|
-
requiredFields.push(`'${fieldName}'`);
|
|
473
|
-
}
|
|
474
|
-
if (field.kind === 'scalar') {
|
|
475
|
-
if (field.isUnique) {
|
|
476
|
-
imports.addTypeImport({
|
|
477
|
-
from: schemaMeta.import.types.location.path,
|
|
478
|
-
items: [delta_Model.errors.nonUnique.type],
|
|
479
|
-
});
|
|
480
|
-
const getByName = `getBy${(0, string_1.toPascalCase)(fieldName)}`;
|
|
481
|
-
sharedValidations.push(`this.validateUniqueField({
|
|
482
|
-
item,
|
|
483
|
-
fieldName: '${fieldName}',
|
|
484
|
-
getExistingItem: (value) => this.data.${modelMeta.data.dataServiceName}.${getByName}(value)
|
|
485
|
-
})`);
|
|
486
|
-
}
|
|
487
|
-
if (field.validation && field.validation.type === 'int') {
|
|
488
|
-
imports.addTypeImport({
|
|
489
|
-
from: schemaMeta.import.types.location.path,
|
|
490
|
-
items: [delta_Model.errors.invalidType.type],
|
|
491
|
-
});
|
|
492
|
-
sharedValidations.push(`this.validateInt({item, fieldName: '${fieldName}'})`);
|
|
493
|
-
}
|
|
494
|
-
}
|
|
495
|
-
else if (field.kind === 'relation') {
|
|
496
|
-
const relatedModelMeta = (0, meta_1.getModelMetadata)({ model: field.relationToModel });
|
|
497
|
-
sharedValidations.push(`this.validateReferenceField({
|
|
498
|
-
item,
|
|
499
|
-
fieldName: '${fieldName}',
|
|
500
|
-
relatedModel: '${field.relationToModel.name}',
|
|
501
|
-
getExistingItem: (id: ${field.relationToModel.brandedIdType}) => this.data.${relatedModelMeta.data.dataServiceName}.get(id)
|
|
502
|
-
})`);
|
|
503
|
-
}
|
|
504
|
-
}
|
|
505
|
-
const deleteValidations = [];
|
|
506
|
-
for (const relatedModel of models) {
|
|
507
|
-
if (relatedModel.name === model.name) {
|
|
508
|
-
continue;
|
|
509
|
-
}
|
|
510
|
-
for (const relatedField of relatedModel.fields) {
|
|
511
|
-
if (relatedField.kind !== 'relation' ||
|
|
512
|
-
relatedField.relationToModel.name !== model.name ||
|
|
513
|
-
!relatedField.isRequired) {
|
|
514
|
-
continue;
|
|
515
|
-
}
|
|
516
|
-
const relatedModelMeta = (0, meta_1.getModelMetadata)({ model: relatedModel });
|
|
517
|
-
const relatedFieldName = (0, string_1.toPascalCase)(relatedField.name);
|
|
518
|
-
deleteValidations.push(`
|
|
519
|
-
await this.validateRequiredDependency({
|
|
520
|
-
item: existingItem,
|
|
521
|
-
relatedModel: '${relatedModel.name}',
|
|
522
|
-
relatedField: '${relatedField.name}',
|
|
523
|
-
getReferencedItems: async (id: ${modelMeta.types.brandedIdType}) => [
|
|
524
|
-
...(await this.data.${relatedModelMeta.data.dataServiceName}.getItemsFor${relatedFieldName}(id)).values()
|
|
525
|
-
]
|
|
526
|
-
})`);
|
|
527
|
-
}
|
|
528
|
-
}
|
|
529
|
-
if (requiredFields.length > 0) {
|
|
530
|
-
imports.addTypeImport({
|
|
531
|
-
from: schemaMeta.import.types.location.path,
|
|
532
|
-
items: [delta_Model.errors.missingField.type],
|
|
533
|
-
});
|
|
534
|
-
}
|
|
535
|
-
const requiredFieldsValidation = requiredFields.length > 0
|
|
536
|
-
? `...this.validateRequiredFields({item, fieldNames: [${requiredFields.join(',')}]}),`
|
|
537
|
-
: '';
|
|
538
|
-
const sharedValidationsFunction = sharedValidations.length > 0
|
|
539
|
-
? `(item: ${model.name}) => Promise.all([${sharedValidations.join(',\n')}])`
|
|
540
|
-
: 'async () => Promise.resolve([])';
|
|
541
|
-
const validateDelete = deleteValidations.length > 0
|
|
542
|
-
? `async ({ existingItem }) => this.keepErrors([${deleteValidations.join(',\n')}])`
|
|
543
|
-
: 'async () => Promise.resolve([])';
|
|
544
|
-
return /* ts */ `
|
|
545
|
-
/**
|
|
546
|
-
* Detects changes for ${modelMeta.userFriendlyName} and returns the result as a ${delta_Model.type} object.
|
|
547
|
-
*/
|
|
548
|
-
private async detect${modelMeta.internalSingularNameCapitalized}Delta(
|
|
549
|
-
items?: ${model.typeName}[]
|
|
550
|
-
): Promise<${returnType}> {
|
|
551
|
-
const sharedValidations: (item: ${model.name}) => Promise<(${modelMeta.import.delta_Model_Errors} | undefined)[]> =
|
|
552
|
-
${sharedValidationsFunction}
|
|
553
|
-
|
|
554
|
-
return this.detectModelDelta({
|
|
555
|
-
items,
|
|
556
|
-
getId: (id: ${model.brandedIdType}) => this.data.${modelMeta.data.dataServiceName}.get(id),
|
|
557
|
-
getDelta: ({ item, existingItem }: { item: ${model.name}; existingItem: ${model.name} }) =>
|
|
558
|
-
this.getDelta({
|
|
559
|
-
item,
|
|
560
|
-
existingItem,
|
|
561
|
-
properties: [${fieldNames.join(',')}],
|
|
562
|
-
}),
|
|
563
|
-
validateCreate: async ({ item }): Promise<${modelMeta.import.delta_Model_Errors}[]> =>
|
|
564
|
-
this.keepErrors([
|
|
565
|
-
${requiredFieldsValidation}
|
|
566
|
-
...(await sharedValidations(item)),
|
|
567
|
-
]),
|
|
568
|
-
validateUpdate: async ({ item }): Promise<${modelMeta.import.delta_Model_Errors}[]> =>
|
|
569
|
-
this.keepErrors(await sharedValidations(item)),
|
|
570
|
-
validateDelete: ${validateDelete},
|
|
571
|
-
})
|
|
572
|
-
}`;
|
|
573
|
-
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { SchemaMetaData } from '../../../lib/meta';
|
|
2
|
-
import { Model } from '../../../lib/schema/schema';
|
|
3
|
-
/**
|
|
4
|
-
* Generates types for import module.
|
|
5
|
-
*/
|
|
6
|
-
export declare function generateImportTypes({ models, meta }: {
|
|
7
|
-
models: Model[];
|
|
8
|
-
meta: SchemaMetaData;
|
|
9
|
-
}): string;
|