@postxl/generator 0.56.8 → 0.57.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/dist/generator.js +7 -0
- package/dist/generators/indices/businesslogic-update-clonecontext.generator.d.ts +9 -0
- package/dist/generators/indices/businesslogic-update-clonecontext.generator.js +39 -0
- package/dist/generators/indices/businesslogic-update-index.generator.js +1 -0
- package/dist/generators/models/admin.page.generator.d.ts +7 -0
- package/dist/generators/models/admin.page.generator.js +73 -0
- package/dist/generators/models/businesslogic-update.generator.js +60 -28
- package/dist/generators/models/route.generator.js +9 -9
- package/dist/lib/attributes.d.ts +5 -0
- package/dist/lib/meta.d.ts +78 -35
- package/dist/lib/meta.js +17 -4
- package/dist/lib/schema/schema.d.ts +4 -0
- package/dist/prisma/attributes.js +3 -1
- package/package.json +1 -1
package/dist/generator.js
CHANGED
|
@@ -42,6 +42,7 @@ const lock_1 = require("@postxl/lock");
|
|
|
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");
|
|
45
46
|
const businesslogic_update_index_generator_1 = require("./generators/indices/businesslogic-update-index.generator");
|
|
46
47
|
const businesslogic_update_module_generator_1 = require("./generators/indices/businesslogic-update-module.generator");
|
|
47
48
|
const businesslogic_update_service_generator_1 = require("./generators/indices/businesslogic-update-service.generator");
|
|
@@ -67,6 +68,7 @@ const selectors_generator_1 = require("./generators/indices/selectors.generator"
|
|
|
67
68
|
const stubs_generator_1 = require("./generators/indices/stubs.generator");
|
|
68
69
|
const testdata_service_generator_1 = require("./generators/indices/testdata-service.generator");
|
|
69
70
|
const types_generator_2 = require("./generators/indices/types.generator");
|
|
71
|
+
const admin_page_generator_1 = require("./generators/models/admin.page.generator");
|
|
70
72
|
const businesslogic_update_generator_1 = require("./generators/models/businesslogic-update.generator");
|
|
71
73
|
const businesslogic_view_generator_1 = require("./generators/models/businesslogic-view.generator");
|
|
72
74
|
const importexport_decoder_generator_1 = require("./generators/models/importexport-decoder.generator");
|
|
@@ -98,6 +100,7 @@ const CONFIG_SCHEMA = zod_1.z
|
|
|
98
100
|
trpcRoutesFolder: zod_1.z.string().optional(),
|
|
99
101
|
reactFolderOutput: zod_1.z.string().optional(),
|
|
100
102
|
prismaMigrationsFolder: zod_1.z.string().optional(),
|
|
103
|
+
pathToAdminPages: zod_1.z.string().optional(),
|
|
101
104
|
randomSeed: zod_1.z
|
|
102
105
|
.string()
|
|
103
106
|
.optional()
|
|
@@ -123,6 +126,7 @@ const CONFIG_SCHEMA = zod_1.z
|
|
|
123
126
|
seedDataPath: (0, types_1.toPath)(s.pathToSeedData || './backend/seed-data/src/'),
|
|
124
127
|
seedLibPath: (0, types_1.toPath)(s.pathToSeedLib || './backend/libs/seed/src/'),
|
|
125
128
|
trpcRoutesFolderPath: (0, types_1.toPath)(s.trpcRoutesFolder || './backend/libs/trpc/src/routes/'),
|
|
129
|
+
adminPagesFolderPath: (0, types_1.toPath)(s.pathToAdminPages || './web/src/pages/admin/'),
|
|
126
130
|
},
|
|
127
131
|
randomSeed: s.randomSeed,
|
|
128
132
|
force: s.force,
|
|
@@ -191,6 +195,8 @@ function generate({ models, enums, config, prismaClientPath, logger, }) {
|
|
|
191
195
|
generated.write(`/${meta.trpc.routerFilePath}.ts`, (0, route_generator_1.generateRoute)({ model, meta }));
|
|
192
196
|
// React
|
|
193
197
|
yield generated.copy((0, react_generator_2.generateReactComponentsForModel)({ model, meta }), meta.react.folderPath);
|
|
198
|
+
// Admin
|
|
199
|
+
generated.write(`/${meta.admin.filePath}.tsx`, (0, admin_page_generator_1.generateAdminPage)({ meta }));
|
|
194
200
|
logger.log(`- ${model.name} processed`);
|
|
195
201
|
}
|
|
196
202
|
// Generate Enums
|
|
@@ -228,6 +234,7 @@ function generate({ models, enums, config, prismaClientPath, logger, }) {
|
|
|
228
234
|
generated.write(`/${meta.businessLogic.view.moduleFilePath}.ts`, (0, businesslogic_view_module_generator_1.generateBusinessLogicViewModule)({ models, meta }));
|
|
229
235
|
generated.write(`/${meta.businessLogic.view.serviceFilePath}.ts`, (0, businesslogic_view_service_generator_1.generateBusinessLogicViewService)({ models, meta }));
|
|
230
236
|
generated.write(`/${meta.businessLogic.update.indexFilePath}.ts`, (0, businesslogic_update_index_generator_1.generateBusinessLogicUpdateIndex)({ models, meta }));
|
|
237
|
+
generated.write(`/${meta.businessLogic.update.cloneContextFilePath}.ts`, (0, businesslogic_update_clonecontext_generator_1.generateBusinessLogicCloneContext)({ models, meta }));
|
|
231
238
|
generated.write(`/${meta.businessLogic.update.moduleFilePath}.ts`, (0, businesslogic_update_module_generator_1.generateBusinessLogicUpdateModule)({ models, meta }));
|
|
232
239
|
generated.write(`/${meta.businessLogic.update.serviceFilePath}.ts`, (0, businesslogic_update_service_generator_1.generateBusinessLogicUpdateService)({ models, meta }));
|
|
233
240
|
generated.write(`/${meta.businessLogic.update.actionTypesFilePath}.ts`, (0, businesslogic_actiontypes_generator_1.generateBusinessLogicActionTypes)({ models, meta }));
|
|
@@ -0,0 +1,9 @@
|
|
|
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;
|
|
@@ -0,0 +1,39 @@
|
|
|
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.businessLogic.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.businessLogic.update.cloneContextMap}: Map<${modelMeta.types.brandedIdType}, ${modelMeta.types.typeName}>`);
|
|
19
|
+
mapAssignments.push(`${modelMeta.businessLogic.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;
|
|
@@ -15,6 +15,7 @@ function generateBusinessLogicUpdateIndex({ models, meta }) {
|
|
|
15
15
|
const meta = (0, meta_1.getModelMetadata)({ model });
|
|
16
16
|
exports.exportSelectionFromPath(meta.businessLogic.update.serviceFilePath, [
|
|
17
17
|
meta.businessLogic.update.serviceClassName,
|
|
18
|
+
meta.businessLogic.update.decoders.name,
|
|
18
19
|
]);
|
|
19
20
|
}
|
|
20
21
|
return exports.generate();
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.generateAdminPage = void 0;
|
|
4
|
+
const imports_1 = require("../../lib/imports");
|
|
5
|
+
/**
|
|
6
|
+
* returns an admin page for a given model.
|
|
7
|
+
*/
|
|
8
|
+
function generateAdminPage({ meta }) {
|
|
9
|
+
const { react } = meta;
|
|
10
|
+
const imports = imports_1.ImportsGenerator.from(meta.admin.filePath).addImport({
|
|
11
|
+
items: [react.components.libraryComponentName, react.components.modals.createComponentName],
|
|
12
|
+
from: meta.react.importPath,
|
|
13
|
+
});
|
|
14
|
+
return `
|
|
15
|
+
import styled from 'styled-components'
|
|
16
|
+
|
|
17
|
+
import { ActionWrapper, ActionsBarWrapper, Search, Spacer } from '@components/atoms/ActionsBar'
|
|
18
|
+
import { Button } from '@components/atoms/Button'
|
|
19
|
+
import { Headline } from '@components/atoms/Headline'
|
|
20
|
+
|
|
21
|
+
${imports.generate()}
|
|
22
|
+
|
|
23
|
+
import { Content, Layout } from '@components/shared/Layout'
|
|
24
|
+
import { t } from '@i18n/translation'
|
|
25
|
+
import { useState } from 'react'
|
|
26
|
+
|
|
27
|
+
export default function Admin${meta.internalSingularNameCapitalized}Page() {
|
|
28
|
+
const [query, setQuery] = useState('')
|
|
29
|
+
const [isCreateModalOpen, setIsCreateModalOpen] = useState(false)
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<Layout>
|
|
33
|
+
<Header>
|
|
34
|
+
<Headline label="${meta.userFriendlyName}" />
|
|
35
|
+
<ActionsBarWrapper>
|
|
36
|
+
<Search
|
|
37
|
+
key="Search"
|
|
38
|
+
placeholder="Search ${meta.userFriendlyNamePlural}"
|
|
39
|
+
icon="magnifying-glass"
|
|
40
|
+
value={query}
|
|
41
|
+
onChange={(e) => setQuery(e.target.value)}
|
|
42
|
+
/>
|
|
43
|
+
|
|
44
|
+
<Spacer key="Spacer" />
|
|
45
|
+
|
|
46
|
+
<ActionWrapper key="GlobalFilter">
|
|
47
|
+
<Button label={t['Create']} icon="plus" fill="fill" __cypress_selector__="indexPage-buttons-create" onClick={() => setIsCreateModalOpen(true)}/>
|
|
48
|
+
</ActionWrapper>
|
|
49
|
+
</ActionsBarWrapper>
|
|
50
|
+
</Header>
|
|
51
|
+
|
|
52
|
+
<Content>
|
|
53
|
+
<${meta.react.components.libraryComponentName} />
|
|
54
|
+
</Content>
|
|
55
|
+
|
|
56
|
+
<${meta.react.components.modals.createComponentName}
|
|
57
|
+
show={isCreateModalOpen}
|
|
58
|
+
onHide={() => setIsCreateModalOpen(false)}
|
|
59
|
+
/>
|
|
60
|
+
</Layout>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const Header = styled.header\`
|
|
65
|
+
display: flex;
|
|
66
|
+
flex-direction: column;
|
|
67
|
+
align-items: stretch;
|
|
68
|
+
|
|
69
|
+
gap: var(--headline-spacing);
|
|
70
|
+
\`
|
|
71
|
+
`;
|
|
72
|
+
}
|
|
73
|
+
exports.generateAdminPage = generateAdminPage;
|
|
@@ -41,10 +41,18 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
|
|
|
41
41
|
iExecution: schemaMeta.actions.execution.interface,
|
|
42
42
|
typeName: meta.types.typeName,
|
|
43
43
|
brandedId: model.brandedIdType,
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
44
|
+
decoders: {
|
|
45
|
+
name: meta.businessLogic.update.decoders.name,
|
|
46
|
+
createType: `Create${meta.internalSingularNameCapitalized}`,
|
|
47
|
+
updateType: `Update${meta.internalSingularNameCapitalized}`,
|
|
48
|
+
upsertType: `Upsert${meta.internalSingularNameCapitalized}`,
|
|
49
|
+
cloneType: `Clone${meta.internalSingularNameCapitalized}`,
|
|
50
|
+
},
|
|
51
|
+
cloneContext: {
|
|
52
|
+
type: schemaMeta.businessLogic.update.cloneContextType,
|
|
53
|
+
createMethod: schemaMeta.businessLogic.update.cloneContextCreateMethod,
|
|
54
|
+
map: meta.businessLogic.update.cloneContextMap,
|
|
55
|
+
},
|
|
48
56
|
};
|
|
49
57
|
const imports = imports_1.ImportsGenerator.from(meta.businessLogic.update.serviceFilePath);
|
|
50
58
|
imports.addImports({
|
|
@@ -58,6 +66,10 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
|
|
|
58
66
|
[meta.businessLogic.view.serviceFilePath]: [meta.businessLogic.view.serviceClassName],
|
|
59
67
|
[schemaMeta.actions.importPath]: [schemaMeta.actions.execution.interface, schemaMeta.actions.dispatcher.definition],
|
|
60
68
|
[schemaMeta.businessLogic.update.serviceFilePath]: schemaMeta.businessLogic.update.serviceClassName,
|
|
69
|
+
[schemaMeta.businessLogic.update.cloneContextFilePath]: [
|
|
70
|
+
schemaMeta.businessLogic.update.cloneContextType,
|
|
71
|
+
schemaMeta.businessLogic.update.cloneContextCreateMethod,
|
|
72
|
+
],
|
|
61
73
|
[schemaMeta.businessLogic.view.serviceFilePath]: schemaMeta.businessLogic.view.serviceClassName,
|
|
62
74
|
});
|
|
63
75
|
for (const relation of (0, fields_1.getRelationFields)(model)) {
|
|
@@ -85,7 +97,7 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
|
|
|
85
97
|
`@Inject(forwardRef(() => ${schemaMeta.businessLogic.update.serviceClassName})) private readonly updateService: ${schemaMeta.businessLogic.update.serviceClassName}`,
|
|
86
98
|
`@Inject(forwardRef(() => ${schemaMeta.businessLogic.view.serviceClassName})) private readonly viewService: ${schemaMeta.businessLogic.view.serviceClassName}`,
|
|
87
99
|
];
|
|
88
|
-
const
|
|
100
|
+
const decoders = meta.businessLogic.update.decoders;
|
|
89
101
|
const { view, update } = meta.businessLogic;
|
|
90
102
|
/* prettier-ignore */
|
|
91
103
|
return /* ts */ `
|
|
@@ -99,37 +111,37 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
|
|
|
99
111
|
export type Actions = {
|
|
100
112
|
${(0, jsdoc_1.toJsDocComment)([`Creates a new ${meta.userFriendlyName} and returns it.`])}
|
|
101
113
|
create: {
|
|
102
|
-
payload: ${m.createType}
|
|
114
|
+
payload: ${m.decoders.createType}
|
|
103
115
|
result: ${m.typeName}
|
|
104
116
|
}
|
|
105
117
|
|
|
106
118
|
${(0, jsdoc_1.toJsDocComment)([`Creates multiple new ${meta.userFriendlyNamePlural} and returns them.`])}
|
|
107
119
|
createMany: {
|
|
108
|
-
payload: ${m.createType}[]
|
|
120
|
+
payload: ${m.decoders.createType}[]
|
|
109
121
|
result: ${m.typeName}[]
|
|
110
122
|
}
|
|
111
123
|
|
|
112
124
|
${(0, jsdoc_1.toJsDocComment)([`Updates a ${meta.userFriendlyName} and returns it.`])}
|
|
113
125
|
update: {
|
|
114
|
-
payload: ${m.updateType}
|
|
126
|
+
payload: ${m.decoders.updateType}
|
|
115
127
|
result: ${m.typeName}
|
|
116
128
|
}
|
|
117
129
|
|
|
118
130
|
${(0, jsdoc_1.toJsDocComment)([`Updates multiple ${meta.userFriendlyNamePlural} and returns them.`])}
|
|
119
131
|
updateMany: {
|
|
120
|
-
payload: ${m.updateType}[]
|
|
132
|
+
payload: ${m.decoders.updateType}[]
|
|
121
133
|
result: ${m.typeName}[]
|
|
122
134
|
}
|
|
123
135
|
|
|
124
136
|
${(0, jsdoc_1.toJsDocComment)([`Creates or updates a ${meta.userFriendlyName} and returns it.`])}
|
|
125
137
|
upsert: {
|
|
126
|
-
payload: ${m.upsertType}
|
|
138
|
+
payload: ${m.decoders.upsertType}
|
|
127
139
|
result: ${m.typeName}
|
|
128
140
|
}
|
|
129
141
|
|
|
130
142
|
${(0, jsdoc_1.toJsDocComment)([`Creates or updates multiple ${meta.userFriendlyNamePlural} and returns them.`])}
|
|
131
143
|
upsertMany: {
|
|
132
|
-
payload: ${m.upsertType}[]
|
|
144
|
+
payload: ${m.decoders.upsertType}[]
|
|
133
145
|
result: ${m.typeName}[]
|
|
134
146
|
}
|
|
135
147
|
|
|
@@ -147,7 +159,7 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
|
|
|
147
159
|
|
|
148
160
|
${(0, jsdoc_1.toJsDocComment)([`Clones a ${meta.userFriendlyName} and returns the clone.`])}
|
|
149
161
|
clone: {
|
|
150
|
-
payload: ${m.cloneType}
|
|
162
|
+
payload: ${m.decoders.cloneType}
|
|
151
163
|
result: ${m.typeName}
|
|
152
164
|
}
|
|
153
165
|
}
|
|
@@ -155,46 +167,53 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
|
|
|
155
167
|
/**
|
|
156
168
|
* Zod decoder for validating the create input of a ${meta.userFriendlyName}.
|
|
157
169
|
*/
|
|
158
|
-
export const ${
|
|
170
|
+
export const ${decoders.create} = z.object({
|
|
159
171
|
${model.fields
|
|
160
172
|
.filter((f) => !f.attributes.isReadonly)
|
|
161
173
|
.map((f) => `${f.name}: z.${(0, zod_1.getZodDecoderDefinition)({ field: f })}`)
|
|
162
174
|
.join(',')}
|
|
163
175
|
})
|
|
164
176
|
|
|
165
|
-
type ${m.createType} = z.infer<typeof ${
|
|
177
|
+
type ${m.decoders.createType} = z.infer<typeof ${decoders.create}>
|
|
166
178
|
|
|
167
179
|
/**
|
|
168
180
|
* Zod decoder for validating the update input of a ${meta.userFriendlyName} .
|
|
169
181
|
*/
|
|
170
|
-
export const ${
|
|
182
|
+
export const ${decoders.update} = z.object({
|
|
171
183
|
${model.fields
|
|
172
184
|
.filter((f) => !f.attributes.isReadonly || f.kind === 'id')
|
|
173
185
|
.map((f) => `${f.name}: z.${(0, zod_1.getZodDecoderDefinition)({ field: f, allowAnyOptionalField: f.kind !== 'id' })}`)
|
|
174
186
|
.join(',')}
|
|
175
187
|
})
|
|
176
188
|
|
|
177
|
-
type ${m.updateType} = z.infer<typeof ${
|
|
189
|
+
type ${m.decoders.updateType} = z.infer<typeof ${decoders.update}>
|
|
178
190
|
|
|
179
191
|
/**
|
|
180
192
|
* Zod decoder for validating the upsert input of a ${meta.userFriendlyName} .
|
|
181
193
|
*/
|
|
182
|
-
export const ${
|
|
194
|
+
export const ${decoders.upsert} = z.union([${decoders.update}, ${decoders.create}])
|
|
183
195
|
|
|
184
|
-
type ${m.upsertType} = z.infer<typeof ${
|
|
196
|
+
type ${m.decoders.upsertType} = z.infer<typeof ${decoders.upsert}>
|
|
185
197
|
|
|
186
198
|
/**
|
|
187
199
|
* Zod decoder for validating the clone input of a ${meta.userFriendlyName} .
|
|
188
200
|
*/
|
|
189
|
-
export const ${
|
|
201
|
+
export const ${decoders.clone} = z.object({
|
|
190
202
|
${model.fields
|
|
191
203
|
.filter((f) => !f.attributes.isReadonly || f.kind === "id")
|
|
192
204
|
.map((f) => `${f.name}: z.${(0, zod_1.getZodDecoderDefinition)({ field: f, allowAnyOptionalField: f.kind !== 'id' })}`)
|
|
193
205
|
.join(',')}
|
|
194
206
|
})
|
|
195
207
|
|
|
196
|
-
type ${m.cloneType} = z.infer<typeof ${
|
|
208
|
+
type ${m.decoders.cloneType} = z.infer<typeof ${decoders.clone}>
|
|
197
209
|
|
|
210
|
+
export const ${decoders.name} = {
|
|
211
|
+
create: ${decoders.create},
|
|
212
|
+
update: ${decoders.update},
|
|
213
|
+
upsert: ${decoders.upsert},
|
|
214
|
+
clone: ${decoders.clone},
|
|
215
|
+
}
|
|
216
|
+
|
|
198
217
|
export type ${update.serviceInterfaceName} = ${schemaMeta.actions.dispatcher.definition}<Actions>
|
|
199
218
|
|
|
200
219
|
@Injectable()
|
|
@@ -210,32 +229,32 @@ function generateModelBusinessLogicUpdate({ model, meta }) {
|
|
|
210
229
|
}
|
|
211
230
|
|
|
212
231
|
${(0, jsdoc_1.toJsDocComment)([`Creates a new ${meta.userFriendlyName} and returns it.`])}
|
|
213
|
-
public async create({ data, execution }: { data: ${m.createType}; execution: ${m.iExecution} }): Promise<${m.typeName}> {
|
|
232
|
+
public async create({ data, execution }: { data: ${m.decoders.createType}; execution: ${m.iExecution} }): Promise<${m.typeName}> {
|
|
214
233
|
return this.data.create({ item: data, execution })
|
|
215
234
|
}
|
|
216
235
|
|
|
217
236
|
${(0, jsdoc_1.toJsDocComment)([`Creates multiple new ${meta.userFriendlyNamePlural} and returns them.`])}
|
|
218
|
-
public async createMany({ data, execution }: { data: ${m.createType}[]; execution: ${m.iExecution} }): Promise<${m.typeName}[]> {
|
|
237
|
+
public async createMany({ data, execution }: { data: ${m.decoders.createType}[]; execution: ${m.iExecution} }): Promise<${m.typeName}[]> {
|
|
219
238
|
return this.data.createMany({ items: data, execution })
|
|
220
239
|
}
|
|
221
240
|
|
|
222
241
|
${(0, jsdoc_1.toJsDocComment)([`Updates a ${meta.userFriendlyName} and returns it.`])}
|
|
223
|
-
public async update({ data, execution }: { data: ${m.updateType}; execution: ${m.iExecution} }): Promise<${m.typeName}> {
|
|
242
|
+
public async update({ data, execution }: { data: ${m.decoders.updateType}; execution: ${m.iExecution} }): Promise<${m.typeName}> {
|
|
224
243
|
return this.data.update({ item: data, execution })
|
|
225
244
|
}
|
|
226
245
|
|
|
227
246
|
${(0, jsdoc_1.toJsDocComment)([`Updates multiple ${meta.userFriendlyNamePlural} and returns them.`])}
|
|
228
|
-
public async updateMany({ data, execution }: { data: ${m.updateType}[]; execution: ${m.iExecution} }): Promise<${m.typeName}[]> {
|
|
247
|
+
public async updateMany({ data, execution }: { data: ${m.decoders.updateType}[]; execution: ${m.iExecution} }): Promise<${m.typeName}[]> {
|
|
229
248
|
return this.data.updateMany({ items: data, execution })
|
|
230
249
|
}
|
|
231
250
|
|
|
232
251
|
${(0, jsdoc_1.toJsDocComment)([`Creates or updates a ${meta.userFriendlyName} and returns it.`])}
|
|
233
|
-
public async upsert({ data, execution }: { data: ${m.upsertType}; execution: ${m.iExecution} }): Promise<${m.typeName}> {
|
|
252
|
+
public async upsert({ data, execution }: { data: ${m.decoders.upsertType}; execution: ${m.iExecution} }): Promise<${m.typeName}> {
|
|
234
253
|
return this.data.upsert({ item: data, execution })
|
|
235
254
|
}
|
|
236
255
|
|
|
237
256
|
${(0, jsdoc_1.toJsDocComment)([`Creates or updates multiple ${meta.userFriendlyNamePlural} and returns them.`])}
|
|
238
|
-
public async upsertMany({ data, execution }: { data: ${m.upsertType}[]; execution: ${m.iExecution} }): Promise<${m.typeName}[]> {
|
|
257
|
+
public async upsertMany({ data, execution }: { data: ${m.decoders.upsertType}[]; execution: ${m.iExecution} }): Promise<${m.typeName}[]> {
|
|
239
258
|
return this.data.upsertMany({ items: data, execution })
|
|
240
259
|
}
|
|
241
260
|
|
|
@@ -330,6 +349,10 @@ function generateCloneMethod({ model, meta, m }) {
|
|
|
330
349
|
const backReferenceCloning = [];
|
|
331
350
|
const backReferenceNames = [];
|
|
332
351
|
for (const { referencingField, referencingModel } of model.references) {
|
|
352
|
+
// We only clone back references that are marked as cloneWithParent.
|
|
353
|
+
if (!referencingField.attributes.cloneWithParent) {
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
333
356
|
const refModelMeta = (0, meta_1.getModelMetadata)({ model: referencingModel });
|
|
334
357
|
const refFieldMeta = (0, meta_1.getFieldMetadata)({ field: referencingField });
|
|
335
358
|
backReferenceNames.push(`${refModelMeta.userFriendlyNamePlural}.${referencingField.name}`);
|
|
@@ -337,15 +360,22 @@ function generateCloneMethod({ model, meta, m }) {
|
|
|
337
360
|
backReferenceCloning.push(`
|
|
338
361
|
// ${referencingModel.name}.${referencingField.name}
|
|
339
362
|
for (const childId of await this.viewService.${view.serviceVariableName}.data.${refFieldMeta.getByForeignKeyIdsMethodFnName}(id)) {
|
|
340
|
-
await this.updateService.${update.serviceVariableName}.clone({ data: { id: childId, ${referencingField.name}: clone.id }, execution })
|
|
363
|
+
await this.updateService.${update.serviceVariableName}.clone({ data: { id: childId, ${referencingField.name}: clone.id }, execution, context })
|
|
341
364
|
}
|
|
342
365
|
`);
|
|
343
366
|
}
|
|
344
367
|
return `
|
|
345
368
|
${(0, jsdoc_1.toJsDocComment)([`Creates a new ${meta.userFriendlyName} deep clone and returns it.`])}
|
|
346
369
|
public async clone(
|
|
347
|
-
{ data: { id, ...data }, execution
|
|
370
|
+
{ data: { id, ...data }, execution, context = ${m.cloneContext.createMethod}() }:
|
|
371
|
+
{ data: ${m.decoders.cloneType}; execution: ${m.iExecution}; context?: ${m.cloneContext.type} }
|
|
348
372
|
): Promise<${m.typeName}> {
|
|
373
|
+
const alreadyCloned = context.${m.cloneContext.map}.get(id)
|
|
374
|
+
if (alreadyCloned) {
|
|
375
|
+
// We already cloned this item before, so we return the cloned item.
|
|
376
|
+
return alreadyCloned
|
|
377
|
+
}
|
|
378
|
+
|
|
349
379
|
const source = await this.view.get(id)
|
|
350
380
|
if (!source) {
|
|
351
381
|
throw new Error(\`${meta.userFriendlyName} with id \${id} not found\`)
|
|
@@ -353,6 +383,8 @@ function generateCloneMethod({ model, meta, m }) {
|
|
|
353
383
|
|
|
354
384
|
const clone = await this.data.create({ item: { ...omitId(source), ...data }, execution })
|
|
355
385
|
|
|
386
|
+
context.${m.cloneContext.map}.set(id, clone)
|
|
387
|
+
|
|
356
388
|
${backReferenceCloning.join('\n')}
|
|
357
389
|
|
|
358
390
|
return clone
|
|
@@ -12,14 +12,14 @@ function generateRoute({ model, meta }) {
|
|
|
12
12
|
const defaultValueMethod = `
|
|
13
13
|
getDefault: procedure.query(({ ctx }) => ctx.view.${meta.data.dataServiceName}.${dataRepositoryVariableName}.defaultValue),
|
|
14
14
|
`;
|
|
15
|
-
const
|
|
15
|
+
const decoders = meta.businessLogic.update.decoders;
|
|
16
16
|
const imports = imports_1.ImportsGenerator.from(meta.trpc.routerFilePath).addImports({
|
|
17
17
|
[meta.types.importPath]: [
|
|
18
18
|
(0, types_1.toAnnotatedTypeName)(model.typeName),
|
|
19
19
|
meta.types.toBrandedIdTypeFnName,
|
|
20
20
|
meta.types.zodDecoderFnNames.id,
|
|
21
21
|
],
|
|
22
|
-
[meta.businessLogic.update.
|
|
22
|
+
[meta.businessLogic.update.importPath]: [decoders.name],
|
|
23
23
|
});
|
|
24
24
|
return /* ts */ `
|
|
25
25
|
import { z } from 'zod'
|
|
@@ -61,27 +61,27 @@ export const ${meta.trpc.routerName} = router({
|
|
|
61
61
|
}),
|
|
62
62
|
|
|
63
63
|
create: procedure
|
|
64
|
-
.input(${
|
|
64
|
+
.input(${decoders.name}.create)
|
|
65
65
|
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "create", payload: input})),
|
|
66
66
|
|
|
67
67
|
createMany: procedure
|
|
68
|
-
.input(z.array(${
|
|
68
|
+
.input(z.array(${decoders.name}.create))
|
|
69
69
|
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "createMany", payload: input})),
|
|
70
70
|
|
|
71
71
|
update: procedure
|
|
72
|
-
.input(${
|
|
72
|
+
.input(${decoders.name}.update)
|
|
73
73
|
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "update", payload: input})),
|
|
74
74
|
|
|
75
75
|
updateMany: procedure
|
|
76
|
-
.input(z.array(${
|
|
76
|
+
.input(z.array(${decoders.name}.update))
|
|
77
77
|
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "updateMany", payload: input})),
|
|
78
78
|
|
|
79
79
|
upsert: procedure
|
|
80
|
-
.input(${
|
|
80
|
+
.input(${decoders.name}.upsert)
|
|
81
81
|
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "upsert", payload: input})),
|
|
82
82
|
|
|
83
83
|
upsertMany: procedure
|
|
84
|
-
.input(z.array(${
|
|
84
|
+
.input(z.array(${decoders.name}.upsert))
|
|
85
85
|
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "upsertMany", payload: input})),
|
|
86
86
|
|
|
87
87
|
delete: procedure
|
|
@@ -93,7 +93,7 @@ export const ${meta.trpc.routerName} = router({
|
|
|
93
93
|
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "deleteMany", payload: input})),
|
|
94
94
|
|
|
95
95
|
clone: procedure
|
|
96
|
-
.input(${
|
|
96
|
+
.input(${decoders.name}.clone)
|
|
97
97
|
.mutation(({ input, ctx }) => ctx.dispatch({scope: "${scopeName}", type: "clone", payload: input})),
|
|
98
98
|
})
|
|
99
99
|
`;
|
package/dist/lib/attributes.d.ts
CHANGED
|
@@ -90,6 +90,11 @@ 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;
|
|
93
98
|
};
|
|
94
99
|
export type EnumAttributes = {
|
|
95
100
|
/**
|
package/dist/lib/meta.d.ts
CHANGED
|
@@ -568,6 +568,18 @@ export type SchemaMetaData = {
|
|
|
568
568
|
* Path to the file containing the overall action types
|
|
569
569
|
*/
|
|
570
570
|
actionTypesFilePath: Types.FilePath;
|
|
571
|
+
/**
|
|
572
|
+
* Path to the file containing the clone context
|
|
573
|
+
*/
|
|
574
|
+
cloneContextFilePath: Types.FilePath;
|
|
575
|
+
/**
|
|
576
|
+
* The name of the clone context type
|
|
577
|
+
*/
|
|
578
|
+
cloneContextType: Types.TypeName;
|
|
579
|
+
/**
|
|
580
|
+
* The name of the function that creates a clone context
|
|
581
|
+
*/
|
|
582
|
+
cloneContextCreateMethod: Types.FunctionName;
|
|
571
583
|
};
|
|
572
584
|
};
|
|
573
585
|
seedData: {
|
|
@@ -788,11 +800,11 @@ export type ModelMetaData = {
|
|
|
788
800
|
*/
|
|
789
801
|
className: Types.ClassName;
|
|
790
802
|
/**
|
|
791
|
-
* The name of the function that decodes a source (database) object to a fully typed object
|
|
803
|
+
* The name of the function that decodes a source (database) object to a fully typed object (e.g. `toAggregation`.)
|
|
792
804
|
*/
|
|
793
805
|
decoderFnName: Types.FunctionName;
|
|
794
806
|
/**
|
|
795
|
-
* The name of the method that should be used to get objects from the database
|
|
807
|
+
* The name of the method that should be used to get objects from the database (e.g. `aggregations`.)
|
|
796
808
|
*/
|
|
797
809
|
getMethodFnName: Types.FunctionName;
|
|
798
810
|
};
|
|
@@ -834,7 +846,7 @@ export type ModelMetaData = {
|
|
|
834
846
|
*/
|
|
835
847
|
exportDataTypeName: Types.TypeName;
|
|
836
848
|
/**
|
|
837
|
-
* Name of the function that adds an instance of this model to the exporter
|
|
849
|
+
* Name of the function that adds an instance of this model to the exporter (e.g. `addAggregation`.)
|
|
838
850
|
*/
|
|
839
851
|
exportAddFunctionName: Types.FunctionName;
|
|
840
852
|
/**
|
|
@@ -858,23 +870,23 @@ export type ModelMetaData = {
|
|
|
858
870
|
*/
|
|
859
871
|
filePath: Types.FilePath;
|
|
860
872
|
/**
|
|
861
|
-
* Name of the type that represents the model in Excel import/export
|
|
873
|
+
* Name of the type that represents the model in Excel import/export (e.g. `Aggregation_EncodedExcelData`.)
|
|
862
874
|
*/
|
|
863
875
|
encodedExcelType: Types.TypeName;
|
|
864
876
|
/**
|
|
865
|
-
* Name of the decoder function that represents the Excel table import type
|
|
877
|
+
* Name of the decoder function that represents the Excel table import type (e.g. `aggregationExcelTableDecoder`.)
|
|
866
878
|
*/
|
|
867
879
|
tableDecoder: Types.FunctionName;
|
|
868
880
|
/**
|
|
869
|
-
* Name of the function that converts a model item to the Excel format
|
|
881
|
+
* Name of the function that converts a model item to the Excel format (e.g. `encodeAggregation`.)
|
|
870
882
|
*/
|
|
871
883
|
itemEncoderFunctionName: Types.FunctionName;
|
|
872
884
|
/**
|
|
873
|
-
* Name of the function that converts an array of model items to the Excel format
|
|
885
|
+
* Name of the function that converts an array of model items to the Excel format (e.g. `encodeAggregations`.)
|
|
874
886
|
*/
|
|
875
887
|
arrayEncoderFunctionName: Types.FunctionName;
|
|
876
888
|
/**
|
|
877
|
-
* Name of the array in the decoded data containing all entities of this model
|
|
889
|
+
* Name of the array in the decoded data containing all entities of this model (e.g. `aggregations`.)
|
|
878
890
|
*/
|
|
879
891
|
decodedModelArrayName: Types.VariableName;
|
|
880
892
|
};
|
|
@@ -897,6 +909,10 @@ export type ModelMetaData = {
|
|
|
897
909
|
* The definitions for the view service of a model
|
|
898
910
|
*/
|
|
899
911
|
view: {
|
|
912
|
+
/**
|
|
913
|
+
* Path that may be used to import the types of this model.
|
|
914
|
+
*/
|
|
915
|
+
importPath: Types.BackendModulePath;
|
|
900
916
|
/**
|
|
901
917
|
* The name by which the model's view class is exposed in the viewService/context. (e.g. aggregations)
|
|
902
918
|
*/
|
|
@@ -918,6 +934,10 @@ export type ModelMetaData = {
|
|
|
918
934
|
* The definitions for the update service of a model
|
|
919
935
|
*/
|
|
920
936
|
update: {
|
|
937
|
+
/**
|
|
938
|
+
* Path that may be used to import the types of this model.
|
|
939
|
+
*/
|
|
940
|
+
importPath: Types.BackendModulePath;
|
|
921
941
|
/**
|
|
922
942
|
* The name by which the model's update class is exposed in the updateService/context. (e.g. AggregationUpdateService)
|
|
923
943
|
*/
|
|
@@ -942,22 +962,32 @@ export type ModelMetaData = {
|
|
|
942
962
|
* The name of the model used as a discriminant for the action execution. (e.g. `aggregation`)
|
|
943
963
|
*/
|
|
944
964
|
actionModelDiscriminantName: Types.VariableName;
|
|
965
|
+
decoders: {
|
|
966
|
+
/**
|
|
967
|
+
* The name of the variable that holds the decoders for the model. (e.g. `aggregationDecoders`)
|
|
968
|
+
*/
|
|
969
|
+
name: Types.VariableName;
|
|
970
|
+
/**
|
|
971
|
+
* The name of the function that decodes a Create object to a fully typed object (e.g. `aggregationCreateDecoder`.)
|
|
972
|
+
*/
|
|
973
|
+
create: Types.FunctionName;
|
|
974
|
+
/**
|
|
975
|
+
* The name of the function that decodes an Update object to a fully typed object (e.g. `aggregationUpdateDecoder`.)
|
|
976
|
+
*/
|
|
977
|
+
update: Types.FunctionName;
|
|
978
|
+
/**
|
|
979
|
+
* The name of the function that decodes an Upsert object to a fully typed object (e.g. `aggregationUpsertDecoder`.)
|
|
980
|
+
*/
|
|
981
|
+
upsert: Types.FunctionName;
|
|
982
|
+
/**
|
|
983
|
+
* The name of the function that clones an object (e.g. `aggregationCloneDecoder`.)
|
|
984
|
+
*/
|
|
985
|
+
clone: Types.FunctionName;
|
|
986
|
+
};
|
|
945
987
|
/**
|
|
946
|
-
* The name of the
|
|
947
|
-
*/
|
|
948
|
-
zodCreateObject: Types.FunctionName;
|
|
949
|
-
/**
|
|
950
|
-
* The name of the function that decodes an Update object to a fully typed object, e.g. `aggregationUpdateDecoder`.
|
|
951
|
-
*/
|
|
952
|
-
zodUpdateObject: Types.FunctionName;
|
|
953
|
-
/**
|
|
954
|
-
* The name of the function that decodes an Upsert object to a fully typed object, e.g. `aggregationUpsertDecoder`.
|
|
955
|
-
*/
|
|
956
|
-
zodUpsertObject: Types.FunctionName;
|
|
957
|
-
/**
|
|
958
|
-
* The name of the function that clones an object, e.g. `aggregationCloneDecoder`.
|
|
988
|
+
* The name of the map variable in the clone context that holds the cloned items of this model (e.g. `aggregation`)
|
|
959
989
|
*/
|
|
960
|
-
|
|
990
|
+
cloneContextMap: Types.VariableName;
|
|
961
991
|
};
|
|
962
992
|
/**
|
|
963
993
|
* Name by which the business logic service exposes the data service.
|
|
@@ -993,6 +1023,10 @@ export type ModelMetaData = {
|
|
|
993
1023
|
* The path to the folder that contains React components for this model.
|
|
994
1024
|
*/
|
|
995
1025
|
folderPath: Types.FilePath;
|
|
1026
|
+
/**
|
|
1027
|
+
* Globally accessible import path for the model's React components.
|
|
1028
|
+
*/
|
|
1029
|
+
importPath: Types.FilePath;
|
|
996
1030
|
context: {
|
|
997
1031
|
/**
|
|
998
1032
|
* Name of the function that should be used as React hook (e.g. `useAggregationContext`).
|
|
@@ -1087,6 +1121,15 @@ export type ModelMetaData = {
|
|
|
1087
1121
|
reactQueryMethod: Types.FunctionName;
|
|
1088
1122
|
};
|
|
1089
1123
|
};
|
|
1124
|
+
/**
|
|
1125
|
+
* Properties provided by the `admin.page` generators.
|
|
1126
|
+
*/
|
|
1127
|
+
admin: {
|
|
1128
|
+
/**
|
|
1129
|
+
* The absolute file path of the admin page for this model.
|
|
1130
|
+
*/
|
|
1131
|
+
filePath: Types.FilePath;
|
|
1132
|
+
};
|
|
1090
1133
|
/**
|
|
1091
1134
|
* Properties provided by the `types` generators.
|
|
1092
1135
|
*/
|
|
@@ -1100,7 +1143,7 @@ export type ModelMetaData = {
|
|
|
1100
1143
|
*/
|
|
1101
1144
|
importPath: Types.BackendModulePath;
|
|
1102
1145
|
/**
|
|
1103
|
-
* The name of the type that represents a branded ID
|
|
1146
|
+
* The name of the type that represents a branded ID (e.g. `AggregationId`.)
|
|
1104
1147
|
*/
|
|
1105
1148
|
brandedIdType: Types.TypeName;
|
|
1106
1149
|
/**
|
|
@@ -1110,11 +1153,11 @@ export type ModelMetaData = {
|
|
|
1110
1153
|
toBrandedIdTypeFnName: Types.FunctionName;
|
|
1111
1154
|
zodDecoderFnNames: {
|
|
1112
1155
|
/**
|
|
1113
|
-
* The name of the function that decodes a scalar value to a branded ID type
|
|
1156
|
+
* The name of the function that decodes a scalar value to a branded ID type (e.g. `aggregationIdDecoder`.)
|
|
1114
1157
|
*/
|
|
1115
1158
|
id: Types.FunctionName;
|
|
1116
1159
|
/**
|
|
1117
|
-
* The name of the function that decodes a source (database) object to a fully typed object
|
|
1160
|
+
* The name of the function that decodes a source (database) object to a fully typed object (e.g. `aggregationDatabaseDecoder`.)
|
|
1118
1161
|
*/
|
|
1119
1162
|
fromDatabase: Types.FunctionName;
|
|
1120
1163
|
};
|
|
@@ -1123,15 +1166,15 @@ export type ModelMetaData = {
|
|
|
1123
1166
|
*/
|
|
1124
1167
|
dto: {
|
|
1125
1168
|
/**
|
|
1126
|
-
* The name of the type that represents a DTO for creating a new object
|
|
1169
|
+
* The name of the type that represents a DTO for creating a new object (e.g. `AggregationCreateDTO`.)
|
|
1127
1170
|
*/
|
|
1128
1171
|
create: Types.TypeName;
|
|
1129
1172
|
/**
|
|
1130
|
-
* The name of the type that represents a DTO for updating an existing object
|
|
1173
|
+
* The name of the type that represents a DTO for updating an existing object (e.g. `AggregationUpdateDTO`.)
|
|
1131
1174
|
*/
|
|
1132
1175
|
update: Types.TypeName;
|
|
1133
1176
|
/**
|
|
1134
|
-
* The name of the type that represents a DTO for upserting an existing object
|
|
1177
|
+
* The name of the type that represents a DTO for upserting an existing object (e.g. `AggregationUpsertDTO`.)
|
|
1135
1178
|
*/
|
|
1136
1179
|
upsert: Types.TypeName;
|
|
1137
1180
|
};
|
|
@@ -1140,17 +1183,17 @@ export type ModelMetaData = {
|
|
|
1140
1183
|
*/
|
|
1141
1184
|
typeDefFileName: Types.FileName;
|
|
1142
1185
|
/**
|
|
1143
|
-
* The name of the type that represents a fully typed, flat object
|
|
1186
|
+
* The name of the type that represents a fully typed, flat object (e.g. `Aggregation`.)
|
|
1144
1187
|
* This type only refers to related types by their branded ID.
|
|
1145
1188
|
*/
|
|
1146
1189
|
typeName: Types.TypeName;
|
|
1147
1190
|
/**
|
|
1148
|
-
* The name of the type that represents a fully typed object
|
|
1191
|
+
* The name of the type that represents a fully typed object (e.g. `AggregationFull`.)
|
|
1149
1192
|
* This type refers to relations by linking to the (flat) types.
|
|
1150
1193
|
*/
|
|
1151
1194
|
linkedTypeName: Types.TypeName;
|
|
1152
1195
|
/**
|
|
1153
|
-
* The name of the type that represents a source (i.e. database) object
|
|
1196
|
+
* The name of the type that represents a source (i.e. database) object (e.g. `Aggregation`.)
|
|
1154
1197
|
*/
|
|
1155
1198
|
sourceType: Types.TypeName;
|
|
1156
1199
|
};
|
|
@@ -1167,15 +1210,15 @@ export type FieldMetaData = {
|
|
|
1167
1210
|
*/
|
|
1168
1211
|
tsFieldName: Types.VariableName;
|
|
1169
1212
|
/**
|
|
1170
|
-
* The name of the method that should be used to get all child objects for a given item
|
|
1213
|
+
* The name of the method that should be used to get all child objects for a given item (e.g. `getItemsForAggregation`.)
|
|
1171
1214
|
*/
|
|
1172
1215
|
getByForeignKeyMethodFnName: Types.FunctionName;
|
|
1173
1216
|
/**
|
|
1174
|
-
* The name of the method that should be used to get all child Ids for a given item
|
|
1217
|
+
* The name of the method that should be used to get all child Ids for a given item (e.g. `getIdsForAggregation`.)
|
|
1175
1218
|
*/
|
|
1176
1219
|
getByForeignKeyIdsMethodFnName: Types.FunctionName;
|
|
1177
1220
|
/**
|
|
1178
|
-
* The name of the column in the seed Excel table
|
|
1221
|
+
* The name of the column in the seed Excel table (e.g. `Aggregation`.)
|
|
1179
1222
|
*/
|
|
1180
1223
|
excelColumnName: string;
|
|
1181
1224
|
};
|
|
@@ -1216,7 +1259,7 @@ export type EnumMetaData = {
|
|
|
1216
1259
|
*/
|
|
1217
1260
|
membersMap: Types.VariableName;
|
|
1218
1261
|
/**
|
|
1219
|
-
* Relative path to the file that contains the enum's types
|
|
1262
|
+
* Relative path to the file that contains the enum's types (e.g. `./aggregation.type`.)
|
|
1220
1263
|
*/
|
|
1221
1264
|
filePath: Types.FilePath;
|
|
1222
1265
|
/**
|
package/dist/lib/meta.js
CHANGED
|
@@ -119,6 +119,9 @@ function getSchemaMetadata({ config }) {
|
|
|
119
119
|
serviceClassName: Types.toClassName(`UpdateService`),
|
|
120
120
|
serviceFilePath: Types.toPath(`${config.paths.businessLogicPath}update/update.service`),
|
|
121
121
|
actionTypesFilePath: Types.toPath(`${config.paths.businessLogicPath}update/actions`),
|
|
122
|
+
cloneContextFilePath: Types.toPath(`${config.paths.businessLogicPath}update/clone.context`),
|
|
123
|
+
cloneContextType: Types.toTypeName(`CloneContext`),
|
|
124
|
+
cloneContextCreateMethod: Types.toFunctionName(`createCloneContext`),
|
|
122
125
|
},
|
|
123
126
|
},
|
|
124
127
|
data: {
|
|
@@ -331,22 +334,28 @@ function getModelMetadata({ model }) {
|
|
|
331
334
|
scopeName: Types.toVariableName(`${camelCase}`),
|
|
332
335
|
importPath: Types.toBackendModulePath(`@backend/business-logic`),
|
|
333
336
|
view: {
|
|
337
|
+
importPath: Types.toBackendModulePath(`@backend/business-logic/view`),
|
|
334
338
|
serviceClassName: Types.toClassName(`${PascalCase}ViewService`),
|
|
335
339
|
serviceVariableName: Types.toVariableName(`${uncapitalizedPlural}`),
|
|
336
340
|
serviceFileName: Types.toFileName(`${camelCase}.view.service`),
|
|
337
341
|
serviceFilePath: Types.toPath(`${config.paths.businessLogicPath}view/${camelCase}.view.service`),
|
|
338
342
|
},
|
|
339
343
|
update: {
|
|
344
|
+
importPath: Types.toBackendModulePath(`@backend/business-logic/update`),
|
|
340
345
|
serviceClassName: Types.toClassName(`${PascalCase}UpdateService`),
|
|
341
346
|
serviceInterfaceName: Types.toTypeName(`I${PascalCase}UpdateService`),
|
|
342
347
|
serviceVariableName: Types.toVariableName(`${uncapitalizedPlural}`),
|
|
343
348
|
serviceFileName: Types.toFileName(`${camelCase}.update.service`),
|
|
344
349
|
serviceFilePath: Types.toPath(`${config.paths.businessLogicPath}update/${camelCase}.update.service`),
|
|
345
350
|
actionModelDiscriminantName: Types.toVariableName(`${camelCase}`),
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
351
|
+
decoders: {
|
|
352
|
+
name: Types.toVariableName(`${camelCase}Decoders`),
|
|
353
|
+
create: Types.toFunctionName(`${camelCase}CreateDecoder`),
|
|
354
|
+
update: Types.toFunctionName(`${camelCase}UpdateDecoder`),
|
|
355
|
+
upsert: Types.toFunctionName(`${camelCase}UpsertDecoder`),
|
|
356
|
+
clone: Types.toFunctionName(`${camelCase}CloneDecoder`),
|
|
357
|
+
},
|
|
358
|
+
cloneContextMap: Types.toVariableName(`${camelCase}`),
|
|
350
359
|
},
|
|
351
360
|
dataRepositoryVariableName: Types.toVariableName(`data`),
|
|
352
361
|
},
|
|
@@ -358,6 +367,7 @@ function getModelMetadata({ model }) {
|
|
|
358
367
|
react: {
|
|
359
368
|
folderName: Types.toFolderName(`${PascalCase}`),
|
|
360
369
|
folderPath: Types.toPath(`${config.paths.reactFolderPath}models/${PascalCase}/`),
|
|
370
|
+
importPath: Types.toPath(`@components/models/${PascalCase}`),
|
|
361
371
|
context: {
|
|
362
372
|
hookFnName: Types.toFunctionName(`use${PascalCase}Context`),
|
|
363
373
|
instanceGetterHookFnName: Types.toFunctionName(`use${PascalCase}`),
|
|
@@ -402,6 +412,9 @@ function getModelMetadata({ model }) {
|
|
|
402
412
|
reactQueryMethod: Types.toFunctionName(`${uncapitalizedPlural}.delete`),
|
|
403
413
|
},
|
|
404
414
|
},
|
|
415
|
+
admin: {
|
|
416
|
+
filePath: Types.toPath(`${config.paths.adminPagesFolderPath}/${uncapitalized}`),
|
|
417
|
+
},
|
|
405
418
|
types: {
|
|
406
419
|
importPath: Types.toBackendModulePath(`@backend/types`),
|
|
407
420
|
filePath: Types.toPath(`${config.paths.modelTypeDefinitionsPath}${camelCase}.type`),
|
|
@@ -87,6 +87,10 @@ export type SchemaConfig = {
|
|
|
87
87
|
* Path to the directory containing trpc routes.
|
|
88
88
|
*/
|
|
89
89
|
trpcRoutesFolderPath: Types.FilePath;
|
|
90
|
+
/**
|
|
91
|
+
* Path to the directory containing admin pages.
|
|
92
|
+
*/
|
|
93
|
+
adminPagesFolderPath: Types.FilePath;
|
|
90
94
|
};
|
|
91
95
|
/**
|
|
92
96
|
* Whether the generator should overwrite existing files.
|
|
@@ -144,9 +144,10 @@ function getFieldAttributes(field) {
|
|
|
144
144
|
.or(zod_1.default.string().transform((s) => parseInt(s, 10)))
|
|
145
145
|
.optional(),
|
|
146
146
|
readonly: blankStringBooleanDecoder,
|
|
147
|
+
cloneWithParent: blankStringBooleanDecoder,
|
|
147
148
|
})
|
|
148
149
|
.transform((obj) => {
|
|
149
|
-
var _a;
|
|
150
|
+
var _a, _b;
|
|
150
151
|
if (isPrismaIgnored && !obj.ignore) {
|
|
151
152
|
throw new Error(`Field ${field.name} is ignored by Prisma, but is missing the "ignore" PostXL attribute!`);
|
|
152
153
|
}
|
|
@@ -160,6 +161,7 @@ function getFieldAttributes(field) {
|
|
|
160
161
|
isReadonly: obj.readonly || field.isGenerated || field.isUpdatedAt || field.name === 'createdAt' || field.isId,
|
|
161
162
|
isUpdatedAt: (_a = field.isUpdatedAt) !== null && _a !== void 0 ? _a : false,
|
|
162
163
|
isCreatedAt: field.name === 'createdAt',
|
|
164
|
+
cloneWithParent: (_b = obj.cloneWithParent) !== null && _b !== void 0 ? _b : false,
|
|
163
165
|
};
|
|
164
166
|
});
|
|
165
167
|
const result = decoder.safeParse(attributes);
|