@postxl/generator 0.74.1 → 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,302 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
-
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
-
};
|
|
5
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
-
exports.generateModelBusinessLogicUpdate = void 0;
|
|
7
|
-
const assert_1 = __importDefault(require("assert"));
|
|
8
|
-
const imports_1 = require("../../../lib/imports");
|
|
9
|
-
const meta_1 = require("../../../lib/meta");
|
|
10
|
-
const fields_1 = require("../../../lib/schema/fields");
|
|
11
|
-
const types_1 = require("../../../lib/schema/types");
|
|
12
|
-
const types_2 = require("../../../lib/types");
|
|
13
|
-
const typescript_1 = require("../../../lib/typescript");
|
|
14
|
-
const jsdoc_1 = require("../../../lib/utils/jsdoc");
|
|
15
|
-
const zod_1 = require("../../../lib/zod");
|
|
16
|
-
/**
|
|
17
|
-
* Generates update business logic for a given model.
|
|
18
|
-
* The update logic handles all Create/Update/Delete/Upsert operations. See template's readme for more info.
|
|
19
|
-
*/
|
|
20
|
-
function generateModelBusinessLogicUpdate({ model, meta }) {
|
|
21
|
-
const schemaMeta = (0, meta_1.getSchemaMetadata)({ config: model.schemaConfig });
|
|
22
|
-
const { view, update, types, data } = meta;
|
|
23
|
-
const imports = imports_1.ImportsGenerator.from(meta.update.serviceClassLocation.path).addImports({
|
|
24
|
-
[data.repository.location.import]: data.repository.className,
|
|
25
|
-
[types.importPath]: [model.brandedIdType, types.typeName, types.toBrandedIdTypeFnName, (0, types_1.toTypeName)('User')],
|
|
26
|
-
[view.serviceLocation.import]: [view.serviceClassName],
|
|
27
|
-
[schemaMeta.actions.execution.interfaceLocation.import]: [schemaMeta.actions.execution.interface],
|
|
28
|
-
[schemaMeta.actions.dispatcher.definitionLocation.import]: [schemaMeta.actions.dispatcher.definition],
|
|
29
|
-
[schemaMeta.update.serviceLocation.path]: schemaMeta.update.serviceClassName,
|
|
30
|
-
[schemaMeta.view.serviceLocation.import]: schemaMeta.view.serviceClassName,
|
|
31
|
-
});
|
|
32
|
-
for (const field of (0, fields_1.getRelationFields)(model)) {
|
|
33
|
-
// NOTE: We add `toBrandedType` functions for foreign models for decoders.
|
|
34
|
-
if (field.relationToModel.typeName === model.typeName) {
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
const refModelMeta = (0, meta_1.getModelMetadata)({ model: field.relationToModel });
|
|
38
|
-
imports.addImport({
|
|
39
|
-
from: refModelMeta.types.importPath,
|
|
40
|
-
items: [refModelMeta.types.toBrandedIdTypeFnName],
|
|
41
|
-
});
|
|
42
|
-
}
|
|
43
|
-
const cloneFn = generateCloneFn({ model, meta, imports });
|
|
44
|
-
return /* ts */ `
|
|
45
|
-
import { Inject, Injectable, forwardRef } from '@nestjs/common'
|
|
46
|
-
import { z } from 'zod'
|
|
47
|
-
|
|
48
|
-
${imports.generate()}
|
|
49
|
-
|
|
50
|
-
import { TRPCError } from '@trpc/server'
|
|
51
|
-
|
|
52
|
-
export type Scope = "${meta.actions.actionScopeConstType}"
|
|
53
|
-
|
|
54
|
-
export type Actions = {
|
|
55
|
-
${(0, jsdoc_1.toJsDocComment)([`Creates a new ${meta.userFriendlyName} and returns it.`])}
|
|
56
|
-
create: {
|
|
57
|
-
payload: CreatePayload
|
|
58
|
-
result: ${types.typeName}
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
${(0, jsdoc_1.toJsDocComment)([`Updates a ${meta.userFriendlyName} and returns it.`])}
|
|
62
|
-
update: {
|
|
63
|
-
payload: UpdatePayload
|
|
64
|
-
result: ${types.typeName}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
${(0, jsdoc_1.toJsDocComment)([`Creates or updates a ${meta.userFriendlyName} and returns it.`])}
|
|
68
|
-
upsert: {
|
|
69
|
-
payload: UpsertPayload
|
|
70
|
-
result: ${types.typeName}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
${(0, jsdoc_1.toJsDocComment)([`Deletes a ${meta.userFriendlyName} and returns its id.`])}
|
|
74
|
-
delete: {
|
|
75
|
-
payload: ${model.brandedIdType}
|
|
76
|
-
result: ${model.brandedIdType}
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
/**
|
|
81
|
-
* Zod decoder for validating the create input of a ${meta.userFriendlyName}.
|
|
82
|
-
*/
|
|
83
|
-
export const ${meta.update.createInputDecoder} = z.object({
|
|
84
|
-
${model.fields
|
|
85
|
-
.filter((f) => !f.attributes.isReadonly)
|
|
86
|
-
.map((f) => `${f.name}: z.${(0, zod_1.getZodDecoderDefinition)({ field: f })}`)
|
|
87
|
-
.join(',')}
|
|
88
|
-
})
|
|
89
|
-
|
|
90
|
-
type CreatePayload = z.infer<typeof ${meta.update.createInputDecoder}>
|
|
91
|
-
|
|
92
|
-
/**
|
|
93
|
-
* Zod decoder for validating the update input of a ${meta.userFriendlyName} .
|
|
94
|
-
*/
|
|
95
|
-
export const ${meta.update.updateInputDecoder} = z.object({
|
|
96
|
-
${model.fields
|
|
97
|
-
.filter((f) => !f.attributes.isReadonly || f.kind === 'id')
|
|
98
|
-
.map((f) => `${f.name}: z.${(0, zod_1.getZodDecoderDefinition)({ field: f, allowAnyOptionalField: f.kind !== 'id' })}`)
|
|
99
|
-
.join(',')}
|
|
100
|
-
})
|
|
101
|
-
|
|
102
|
-
type UpdatePayload = z.infer<typeof ${meta.update.updateInputDecoder}>
|
|
103
|
-
|
|
104
|
-
/**
|
|
105
|
-
* Zod decoder for validating the upsert input of a ${meta.userFriendlyName} .
|
|
106
|
-
*/
|
|
107
|
-
export const ${meta.update.upsertInputDecoder} = z.union([
|
|
108
|
-
${meta.update.updateInputDecoder},
|
|
109
|
-
${meta.update.createInputDecoder}
|
|
110
|
-
])
|
|
111
|
-
|
|
112
|
-
type UpsertPayload = z.infer<typeof ${meta.update.upsertInputDecoder}>
|
|
113
|
-
|
|
114
|
-
export type ${update.serviceInterfaceName} = ${schemaMeta.actions.dispatcher.definition}<Actions>
|
|
115
|
-
|
|
116
|
-
@Injectable()
|
|
117
|
-
export class ${update.serviceClassName} implements ${update.serviceInterfaceName} {
|
|
118
|
-
|
|
119
|
-
/**
|
|
120
|
-
* Instance of the ${meta.userFriendlyName} view service for convenience.
|
|
121
|
-
*/
|
|
122
|
-
private view: ${view.serviceClassName}
|
|
123
|
-
|
|
124
|
-
constructor(
|
|
125
|
-
private readonly data: ${data.repository.className},
|
|
126
|
-
|
|
127
|
-
@Inject(forwardRef(() => ${schemaMeta.update.serviceClassName}))
|
|
128
|
-
private readonly updateService: ${schemaMeta.update.serviceClassName},
|
|
129
|
-
|
|
130
|
-
@Inject(forwardRef(() => ${schemaMeta.view.serviceClassName}))
|
|
131
|
-
private readonly viewService: ${schemaMeta.view.serviceClassName}
|
|
132
|
-
) {
|
|
133
|
-
this.view = this.viewService.${view.serviceVariableName}
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
${(0, jsdoc_1.toJsDocComment)([`Creates a new ${meta.userFriendlyName} and returns it.`])}
|
|
137
|
-
public async create({ data, execution }: {
|
|
138
|
-
data: CreatePayload;
|
|
139
|
-
execution: ${schemaMeta.actions.execution.interface}
|
|
140
|
-
}): Promise<${types.typeName}> {
|
|
141
|
-
// NOTE: User from execution.user should be authorized to create this item.
|
|
142
|
-
// eslint-disable-next-line no-constant-condition
|
|
143
|
-
if (false) {
|
|
144
|
-
throw new TRPCError({
|
|
145
|
-
code: 'UNAUTHORIZED',
|
|
146
|
-
message: \`You are not authorized to create a ${meta.userFriendlyName}\`,
|
|
147
|
-
})
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
return this.data.create({ item: data, execution })
|
|
151
|
-
}
|
|
152
|
-
|
|
153
|
-
${(0, jsdoc_1.toJsDocComment)([`Updates a ${meta.userFriendlyName} and returns it.`])}
|
|
154
|
-
public async update({ data, execution }: {
|
|
155
|
-
data: UpdatePayload;
|
|
156
|
-
execution: ${schemaMeta.actions.execution.interface}
|
|
157
|
-
}): Promise<${types.typeName}> {
|
|
158
|
-
// NOTE: We need to make sure that the user is authorized to access the item
|
|
159
|
-
await this.authorize(data.id, execution.user)
|
|
160
|
-
|
|
161
|
-
return this.data.update({ item: data, execution })
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
${(0, jsdoc_1.toJsDocComment)([`Creates or updates a ${meta.userFriendlyName} and returns it.`])}
|
|
165
|
-
public async upsert({ data, execution }: {
|
|
166
|
-
data: UpsertPayload;
|
|
167
|
-
execution: ${schemaMeta.actions.execution.interface}
|
|
168
|
-
}): Promise<${types.typeName}> {
|
|
169
|
-
if ('id' in data) {
|
|
170
|
-
await this.authorize(data.id, execution.user)
|
|
171
|
-
} else {
|
|
172
|
-
// eslint-disable-next-line no-constant-condition
|
|
173
|
-
if (false) {
|
|
174
|
-
throw new TRPCError({
|
|
175
|
-
code: 'UNAUTHORIZED',
|
|
176
|
-
message: \`You are not authorized to create a ${meta.userFriendlyName}\`,
|
|
177
|
-
})
|
|
178
|
-
}
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return this.data.upsert({ item: data, execution })
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
${(0, jsdoc_1.toJsDocComment)([`Deletes a ${meta.userFriendlyName} instance and returns its id.`])}
|
|
185
|
-
public async delete({ data, execution }: {
|
|
186
|
-
data: ${model.brandedIdType};
|
|
187
|
-
execution: ${schemaMeta.actions.execution.interface}
|
|
188
|
-
}): Promise<${model.brandedIdType}> {
|
|
189
|
-
// NOTE: We need to make sure that the user is authorized to access the item
|
|
190
|
-
await this.authorize(data, execution.user)
|
|
191
|
-
|
|
192
|
-
return this.data.delete({ id: data, execution })
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
${cloneFn}
|
|
196
|
-
|
|
197
|
-
/**
|
|
198
|
-
* Authorizes access to ${meta.userFriendlyName}.
|
|
199
|
-
*/
|
|
200
|
-
public async authorize(id: ${model.brandedIdType}, user: User): Promise<void> {
|
|
201
|
-
// NOTE: Root user is always authorized.
|
|
202
|
-
if (this.viewService.users.data.rootUser.id === user.id) {
|
|
203
|
-
return
|
|
204
|
-
}
|
|
205
|
-
const item = await this.data.get(id)
|
|
206
|
-
if (!item) {
|
|
207
|
-
throw new Error(\`${meta.userFriendlyName} with id \${id} not found\`)
|
|
208
|
-
}
|
|
209
|
-
// eslint-disable-next-line no-constant-condition
|
|
210
|
-
if (false) {
|
|
211
|
-
throw new TRPCError({
|
|
212
|
-
code: 'UNAUTHORIZED',
|
|
213
|
-
message: \`You are not authorized to access ${meta.userFriendlyName} with id \${id}\`,
|
|
214
|
-
})
|
|
215
|
-
}
|
|
216
|
-
}
|
|
217
|
-
}
|
|
218
|
-
`;
|
|
219
|
-
}
|
|
220
|
-
exports.generateModelBusinessLogicUpdate = generateModelBusinessLogicUpdate;
|
|
221
|
-
function generateCloneFn({ model, meta, imports }) {
|
|
222
|
-
const schemaMeta = (0, meta_1.getSchemaMetadata)({ config: model.schemaConfig });
|
|
223
|
-
for (const enumField of (0, fields_1.getEnumFields)(model)) {
|
|
224
|
-
const enumMeta = (0, meta_1.getEnumMetadata)(enumField);
|
|
225
|
-
imports.addTypeImport({
|
|
226
|
-
from: enumMeta.types.importPath,
|
|
227
|
-
items: [enumField.typeName],
|
|
228
|
-
});
|
|
229
|
-
}
|
|
230
|
-
const fnInputFields = model.fields
|
|
231
|
-
.filter((f) => {
|
|
232
|
-
switch (f.kind) {
|
|
233
|
-
case 'id':
|
|
234
|
-
case 'scalar':
|
|
235
|
-
case 'enum':
|
|
236
|
-
return true;
|
|
237
|
-
case 'relation':
|
|
238
|
-
return false;
|
|
239
|
-
default:
|
|
240
|
-
throw new types_2.ExhaustiveSwitchCheck(f);
|
|
241
|
-
}
|
|
242
|
-
})
|
|
243
|
-
.map((f) => {
|
|
244
|
-
const type = (0, typescript_1.getFieldType)(f);
|
|
245
|
-
switch (f.kind) {
|
|
246
|
-
case 'id':
|
|
247
|
-
return `${f.name}: ${type}`;
|
|
248
|
-
case 'scalar':
|
|
249
|
-
case 'enum':
|
|
250
|
-
if (f.isUnique) {
|
|
251
|
-
// NOTE: `unique` fields require a new value.
|
|
252
|
-
if (f.isRequired) {
|
|
253
|
-
return `${f.name}: ${type}`;
|
|
254
|
-
}
|
|
255
|
-
return `${f.name}: ${type} | null`;
|
|
256
|
-
}
|
|
257
|
-
// NOTE: Non-unique fields can be copied from the source.
|
|
258
|
-
if (f.isRequired) {
|
|
259
|
-
return `${f.name}?: ${type}`;
|
|
260
|
-
}
|
|
261
|
-
return `${f.name}?: ${type} | null`;
|
|
262
|
-
case 'relation':
|
|
263
|
-
(0, assert_1.default)(false);
|
|
264
|
-
break;
|
|
265
|
-
default:
|
|
266
|
-
throw new types_2.ExhaustiveSwitchCheck(f);
|
|
267
|
-
}
|
|
268
|
-
});
|
|
269
|
-
const foreignKeyMappings = (0, fields_1.getRelationFields)(model).map((f) => {
|
|
270
|
-
if (f.isRequired) {
|
|
271
|
-
return `${f.name}: mappings.get({ model: '${f.relationToModel.typeName}', id: item.${f.name} })`;
|
|
272
|
-
}
|
|
273
|
-
return `${f.name}: item.${f.name} ? mappings.get({ model: '${f.relationToModel.typeName}', id: item.${f.name} }) : null`;
|
|
274
|
-
});
|
|
275
|
-
if (foreignKeyMappings.length > 0) {
|
|
276
|
-
imports.addImports({
|
|
277
|
-
[schemaMeta.types.importPath]: [schemaMeta.types.idTypesIndex],
|
|
278
|
-
[(0, types_1.toPackageName)('@postxl/runtime')]: [(0, types_1.toClassName)('TypedMapping')],
|
|
279
|
-
});
|
|
280
|
-
}
|
|
281
|
-
return `
|
|
282
|
-
${(0, jsdoc_1.toJsDocComment)([`Clones a ${meta.userFriendlyName} with mapped foreign ids.`])}
|
|
283
|
-
public async clone(
|
|
284
|
-
{ data, execution }: {
|
|
285
|
-
data: { ${fnInputFields.join('; ')} },
|
|
286
|
-
execution: ${schemaMeta.actions.execution.interface}
|
|
287
|
-
},
|
|
288
|
-
${foreignKeyMappings.length > 0 ? `mappings = new TypedMapping<${schemaMeta.types.idTypesIndex}>()` : ''}
|
|
289
|
-
): Promise<${meta.types.typeName}> {
|
|
290
|
-
const clone = await this.data.clone({
|
|
291
|
-
id: data.id,
|
|
292
|
-
item: (${foreignKeyMappings.length > 0 ? 'item' : ''}) => ({
|
|
293
|
-
...data,
|
|
294
|
-
${foreignKeyMappings.join(',\n')}
|
|
295
|
-
}),
|
|
296
|
-
execution
|
|
297
|
-
})
|
|
298
|
-
|
|
299
|
-
return clone
|
|
300
|
-
}
|
|
301
|
-
`;
|
|
302
|
-
}
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
import { ModelMetaData } from '../../../lib/meta';
|
|
2
|
-
import { Model } from '../../../lib/schema/schema';
|
|
3
|
-
/**
|
|
4
|
-
* Generates view business logic for a given model.
|
|
5
|
-
* The view logic exposes all information and links of a model. See template's readme for more info.
|
|
6
|
-
*/
|
|
7
|
-
export declare function generateModelBusinessLogicView({ model, meta }: {
|
|
8
|
-
model: Model;
|
|
9
|
-
meta: ModelMetaData;
|
|
10
|
-
}): string;
|
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generateModelBusinessLogicView = void 0;
|
|
4
|
-
const imports_1 = require("../../../lib/imports");
|
|
5
|
-
const meta_1 = require("../../../lib/meta");
|
|
6
|
-
const fields_1 = require("../../../lib/schema/fields");
|
|
7
|
-
const types_1 = require("../../../lib/schema/types");
|
|
8
|
-
const ast_1 = require("../../../lib/utils/ast");
|
|
9
|
-
/**
|
|
10
|
-
* Generates view business logic for a given model.
|
|
11
|
-
* The view logic exposes all information and links of a model. See template's readme for more info.
|
|
12
|
-
*/
|
|
13
|
-
function generateModelBusinessLogicView({ model, meta }) {
|
|
14
|
-
const schemaMeta = (0, meta_1.getSchemaMetadata)({ config: model.schemaConfig });
|
|
15
|
-
const imports = imports_1.ImportsGenerator.from(meta.view.serviceLocation.path);
|
|
16
|
-
imports.addImports({
|
|
17
|
-
[meta.data.repository.location.import]: meta.data.repository.className,
|
|
18
|
-
[meta.types.importPath]: [
|
|
19
|
-
(0, types_1.toAnnotatedTypeName)(model.brandedIdType),
|
|
20
|
-
(0, types_1.toAnnotatedTypeName)(meta.types.typeName),
|
|
21
|
-
(0, types_1.toAnnotatedTypeName)((0, types_1.toTypeName)('User')),
|
|
22
|
-
],
|
|
23
|
-
[schemaMeta.view.serviceLocation.path]: schemaMeta.view.serviceClassName,
|
|
24
|
-
});
|
|
25
|
-
const compareFnBlock = (0, ast_1.createSwitchStatement)({
|
|
26
|
-
field: 'field',
|
|
27
|
-
cases: (0, fields_1.getScalarFields)({ fields: model.fields, tsTypeName: 'string' }).map((f) => ({
|
|
28
|
-
match: `"${f.name}"`,
|
|
29
|
-
block: `return (a[field] || '').localeCompare(b[field] || '')`,
|
|
30
|
-
})),
|
|
31
|
-
defaultBlock: 'return 0',
|
|
32
|
-
});
|
|
33
|
-
const stringFieldFilters = (0, fields_1.getScalarFields)({ fields: model.fields, tsTypeName: 'string' }).map((f) => {
|
|
34
|
-
return {
|
|
35
|
-
match: `"${f.name}"`,
|
|
36
|
-
block: `
|
|
37
|
-
if (typeof value !== 'string') {
|
|
38
|
-
return false
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
switch (operator) {
|
|
42
|
-
case 'contains': {
|
|
43
|
-
return (item[field] || '').toLowerCase().includes(value.toLowerCase())
|
|
44
|
-
}
|
|
45
|
-
default: {
|
|
46
|
-
return false
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
`,
|
|
50
|
-
};
|
|
51
|
-
});
|
|
52
|
-
const numberFieldsFilters = (0, fields_1.getScalarFields)({ fields: model.fields, tsTypeName: 'number' }).map((f) => {
|
|
53
|
-
return {
|
|
54
|
-
match: `"${f.name}"`,
|
|
55
|
-
block: `
|
|
56
|
-
const toCompare = item[field]
|
|
57
|
-
if (typeof value !== 'number' || toCompare === null) {
|
|
58
|
-
return false
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
switch (operator) {
|
|
62
|
-
case 'eq': {
|
|
63
|
-
return item[field] === value
|
|
64
|
-
}
|
|
65
|
-
case 'gt': {
|
|
66
|
-
return toCompare > value
|
|
67
|
-
}
|
|
68
|
-
case 'lt': {
|
|
69
|
-
return toCompare < value
|
|
70
|
-
}
|
|
71
|
-
default: {
|
|
72
|
-
return false
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
`,
|
|
76
|
-
};
|
|
77
|
-
});
|
|
78
|
-
const filterFnBlock = (0, ast_1.createSwitchStatement)({
|
|
79
|
-
field: 'field',
|
|
80
|
-
cases: [...stringFieldFilters, ...numberFieldsFilters],
|
|
81
|
-
defaultBlock: 'return false',
|
|
82
|
-
});
|
|
83
|
-
return /* ts */ `
|
|
84
|
-
/* eslint-disable @typescript-eslint/no-unused-vars */
|
|
85
|
-
import z from 'zod'
|
|
86
|
-
|
|
87
|
-
import { Inject, Injectable, forwardRef } from '@nestjs/common'
|
|
88
|
-
|
|
89
|
-
${imports.generate()}
|
|
90
|
-
|
|
91
|
-
import { TRPCError } from '@trpc/server'
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
/**
|
|
95
|
-
* Cursor decoder.
|
|
96
|
-
*/
|
|
97
|
-
export const ${meta.view.cursorDecoder} = z.object({ startRow: z.number(), endRow: z.number() })
|
|
98
|
-
|
|
99
|
-
type Cursor = z.infer<typeof ${meta.view.cursorDecoder}>
|
|
100
|
-
|
|
101
|
-
/**
|
|
102
|
-
* Filter operator decoder.
|
|
103
|
-
*/
|
|
104
|
-
export const ${meta.view.filterOperatorDecoder} = z.enum([
|
|
105
|
-
'eq',
|
|
106
|
-
'neq',
|
|
107
|
-
'gt',
|
|
108
|
-
'gte',
|
|
109
|
-
'lt',
|
|
110
|
-
'lte',
|
|
111
|
-
'in',
|
|
112
|
-
'nin',
|
|
113
|
-
'contains',
|
|
114
|
-
'ncontains',
|
|
115
|
-
'starts',
|
|
116
|
-
'ends',
|
|
117
|
-
])
|
|
118
|
-
|
|
119
|
-
type FilterOperator = z.infer<typeof ${meta.view.filterOperatorDecoder}>
|
|
120
|
-
|
|
121
|
-
@Injectable()
|
|
122
|
-
export class ${meta.view.serviceClassName} {
|
|
123
|
-
constructor(
|
|
124
|
-
public readonly data: ${meta.data.repository.className},
|
|
125
|
-
@Inject(forwardRef(() => ${schemaMeta.view.serviceClassName}))
|
|
126
|
-
private readonly viewService: ${schemaMeta.view.serviceClassName}
|
|
127
|
-
) {}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Returns the raw ${meta.userFriendlyName} with the given id or null if it does not exist.
|
|
131
|
-
* Raw: The ${meta.userFriendlyName} only contains linked Ids, not the linked items themselves.
|
|
132
|
-
*/
|
|
133
|
-
public async get({ id, user }: { id: ${model.brandedIdType}, user: User }): Promise<${meta.types.typeName} | null> {
|
|
134
|
-
const item = await this.data.get(id)
|
|
135
|
-
if (!item) {
|
|
136
|
-
return null
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
// NOTE: Authorizing user to access the item.
|
|
140
|
-
await this.authorize({ item, user })
|
|
141
|
-
|
|
142
|
-
return item
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
/**
|
|
146
|
-
* Returns a map of all ${meta.userFriendlyNamePlural}.
|
|
147
|
-
*/
|
|
148
|
-
public async getAll(user: User): Promise<Map<${meta.types.brandedIdType}, ${model.typeName}>> {
|
|
149
|
-
const result = await this.data.getAll()
|
|
150
|
-
|
|
151
|
-
// NOTE: Removing non-authorized items from the result.
|
|
152
|
-
for (const [key, value] of result.entries()) {
|
|
153
|
-
try {
|
|
154
|
-
await this.authorize({ item: value, user })
|
|
155
|
-
} catch (e) {
|
|
156
|
-
result.delete(key)
|
|
157
|
-
}
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return result
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Returns a list of filtered, sorted and paginated ${meta.userFriendlyNamePlural}.
|
|
165
|
-
*/
|
|
166
|
-
public async getList({
|
|
167
|
-
filter,
|
|
168
|
-
sort,
|
|
169
|
-
cursor,
|
|
170
|
-
user,
|
|
171
|
-
}: {
|
|
172
|
-
filter?: { field: keyof ${model.typeName}; operator: FilterOperator; value: string | number }
|
|
173
|
-
sort?: { field: keyof ${model.typeName}; ascending: boolean }
|
|
174
|
-
cursor?: Cursor
|
|
175
|
-
user: User,
|
|
176
|
-
},
|
|
177
|
-
) {
|
|
178
|
-
const items = await this.data.getAll()
|
|
179
|
-
|
|
180
|
-
// NOTE: Removing non-authorized items from the result.
|
|
181
|
-
for (const [key, value] of items.entries()) {
|
|
182
|
-
try {
|
|
183
|
-
await this.authorize({ item: value, user })
|
|
184
|
-
} catch (e) {
|
|
185
|
-
items.delete(key)
|
|
186
|
-
}
|
|
187
|
-
}
|
|
188
|
-
const authorized = [...items.values()]
|
|
189
|
-
|
|
190
|
-
const filtered = !filter
|
|
191
|
-
? authorized
|
|
192
|
-
: authorized.filter((item) => filterFn(item, filter.field, filter.operator, filter.value))
|
|
193
|
-
|
|
194
|
-
const filteredAndSorted = !sort
|
|
195
|
-
? filtered
|
|
196
|
-
: filtered.sort((a, b) => (sort.ascending ? compare(a, b, sort.field) : -compare(a, b, sort.field)))
|
|
197
|
-
|
|
198
|
-
const paginated = !cursor ? filteredAndSorted : filteredAndSorted.slice(cursor.startRow, cursor.endRow)
|
|
199
|
-
return { rows: paginated, count: authorized.length }
|
|
200
|
-
}
|
|
201
|
-
|
|
202
|
-
/**
|
|
203
|
-
* Authorizes access to ${meta.userFriendlyName}.
|
|
204
|
-
*/
|
|
205
|
-
// eslint-disable-next-line @typescript-eslint/require-await
|
|
206
|
-
public async authorize({ item, user}: { item: ${model.typeName}, user: User }): Promise<void> {
|
|
207
|
-
// eslint-disable-next-line no-constant-condition
|
|
208
|
-
if (false) {
|
|
209
|
-
throw new TRPCError({
|
|
210
|
-
code: 'UNAUTHORIZED',
|
|
211
|
-
message: \`You are not authorized to access ${meta.userFriendlyName} with id \${item.id}\`,
|
|
212
|
-
})
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
}
|
|
216
|
-
|
|
217
|
-
// Utility Functions
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* Compares two ${model.typeName} instances by the given field.
|
|
221
|
-
*/
|
|
222
|
-
function compare(a: ${model.typeName}, b: ${model.typeName}, field: keyof ${model.typeName}) {
|
|
223
|
-
${compareFnBlock}
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
/**
|
|
227
|
-
* Filters the given ${model.typeName} by the given field, using provided operator and value.
|
|
228
|
-
*/
|
|
229
|
-
function filterFn(
|
|
230
|
-
item: ${model.typeName},
|
|
231
|
-
field: keyof ${model.typeName},
|
|
232
|
-
operator: FilterOperator,
|
|
233
|
-
value: string | number
|
|
234
|
-
): boolean {
|
|
235
|
-
${filterFnBlock}
|
|
236
|
-
}
|
|
237
|
-
`;
|
|
238
|
-
}
|
|
239
|
-
exports.generateModelBusinessLogicView = generateModelBusinessLogicView;
|
package/dist/lib/attributes.d.ts
DELETED
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
export type AttributeValue = unknown;
|
|
2
|
-
export type Attributes = Record<string, AttributeValue>;
|
|
3
|
-
export type ModelAttributes = {
|
|
4
|
-
/**
|
|
5
|
-
* Schema tag: ´@@Ignore()`
|
|
6
|
-
*/
|
|
7
|
-
ignore: boolean;
|
|
8
|
-
/**
|
|
9
|
-
* Schema tag: ´@@Description("Description of the model")`
|
|
10
|
-
*/
|
|
11
|
-
description?: string;
|
|
12
|
-
/**
|
|
13
|
-
* Schema tag: ´@@Schema("Configuration")`
|
|
14
|
-
* The database schema that the model belongs to.
|
|
15
|
-
* @internal
|
|
16
|
-
* Note: Prisma has it's own schema attribute - but does not expose it in the DMMF.
|
|
17
|
-
*/
|
|
18
|
-
databaseSchema: string;
|
|
19
|
-
/**
|
|
20
|
-
* Schema tag: ´@@Index()`
|
|
21
|
-
* Creates an index on the given fields.
|
|
22
|
-
*/
|
|
23
|
-
index?: string[];
|
|
24
|
-
/**
|
|
25
|
-
* Schema tag: ´@@Seed()`
|
|
26
|
-
* Seed to use for random generation.
|
|
27
|
-
*/
|
|
28
|
-
randomSeed?: number;
|
|
29
|
-
/**
|
|
30
|
-
* Schema tag: ´@@SystemUser()`
|
|
31
|
-
* The user that is used for system actions.
|
|
32
|
-
*/
|
|
33
|
-
systemUser?: object;
|
|
34
|
-
};
|
|
35
|
-
export type FieldAttributes = {
|
|
36
|
-
/**
|
|
37
|
-
* Schema tag: ´@@Ignore()`
|
|
38
|
-
*
|
|
39
|
-
* Field will be ignored by the generator and not be exposed from the database.
|
|
40
|
-
*/
|
|
41
|
-
ignore: boolean;
|
|
42
|
-
/**
|
|
43
|
-
* Schema tag: ´@@Readonly()`
|
|
44
|
-
*
|
|
45
|
-
* Field is generated by the database and shall not be edited by the user. It is readable though.
|
|
46
|
-
*/
|
|
47
|
-
isReadonly: boolean;
|
|
48
|
-
/**
|
|
49
|
-
* Derived from Prisma's @updatedAt attribute.
|
|
50
|
-
*
|
|
51
|
-
* Field represents the last time the record was updated.
|
|
52
|
-
*/
|
|
53
|
-
isUpdatedAt: boolean;
|
|
54
|
-
/**
|
|
55
|
-
* Automatically set is field name is "createdAt".
|
|
56
|
-
* Field represents the time the record was created.
|
|
57
|
-
*/
|
|
58
|
-
isCreatedAt: boolean;
|
|
59
|
-
/**
|
|
60
|
-
* Schema tag: ´@@Description("Description of the field")`
|
|
61
|
-
*
|
|
62
|
-
* The description that is generated as a JSDoc comment in the code.
|
|
63
|
-
*/
|
|
64
|
-
description?: string;
|
|
65
|
-
/**
|
|
66
|
-
* Schema tag: ´@@Examples("Example1", "Example2")` or `@@Example("Example1")`
|
|
67
|
-
*
|
|
68
|
-
* Examples that are generated as a JSDoc comment in the code and used as seed/test data.
|
|
69
|
-
*/
|
|
70
|
-
examples?: (string | number | boolean | null)[];
|
|
71
|
-
/**
|
|
72
|
-
* Schema tag: ´@@DefaultField()`
|
|
73
|
-
* The property of the model that identifies the default row.
|
|
74
|
-
*
|
|
75
|
-
* If this is set, the repository will verify that exactly one record has this field set to true - and use it as the default record.
|
|
76
|
-
*/
|
|
77
|
-
isDefaultField?: boolean;
|
|
78
|
-
/**
|
|
79
|
-
* Schema tag: `@@MaxLength(int)`
|
|
80
|
-
* The maximum length of a string.
|
|
81
|
-
*/
|
|
82
|
-
maxLength?: number;
|
|
83
|
-
/**
|
|
84
|
-
* Schema tag: `@@IsNameField()`
|
|
85
|
-
* The field that should be used as the default label for the model.
|
|
86
|
-
*
|
|
87
|
-
* If this is set, the repository will verify that exactly one record has this field set to true - and use it as the default label.
|
|
88
|
-
*
|
|
89
|
-
* If this attribute is set, this field will be used in the code/UI as the field that specifies the model's name. If not provided, we check for the existence of the`name` field. If that is not found, we use the `id` field as the name field.
|
|
90
|
-
*/
|
|
91
|
-
isNameField?: boolean;
|
|
92
|
-
/**
|
|
93
|
-
* Schema tag: `@@Label("Label")`
|
|
94
|
-
* The human readable label/name of the field.
|
|
95
|
-
*
|
|
96
|
-
* If not provided, we use the field name.
|
|
97
|
-
*/
|
|
98
|
-
label: string;
|
|
99
|
-
};
|
|
100
|
-
export type EnumAttributes = {
|
|
101
|
-
/**
|
|
102
|
-
* The description of the enum.
|
|
103
|
-
* Schema tag: ´@@Description("Description of the model")`
|
|
104
|
-
*/
|
|
105
|
-
description?: string;
|
|
106
|
-
/**
|
|
107
|
-
* A dictionary of value descriptions.
|
|
108
|
-
*
|
|
109
|
-
* Note: Unfortunately, the DMMF does not support attributes for Enum values. So we use an attribute on the enum itself to define the descriptions.
|
|
110
|
-
*
|
|
111
|
-
* Schema tag: ´@@Schema("ValueDescription")`
|
|
112
|
-
*/
|
|
113
|
-
valueDescription?: Record<string, string>;
|
|
114
|
-
};
|
package/dist/lib/attributes.js
DELETED