@nestledjs/api 2.9.1 → 2.9.2
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/package.json
CHANGED
|
@@ -112,12 +112,12 @@ function generateRelationHandling(model, operation) {
|
|
|
112
112
|
|
|
113
113
|
// Add virtual relation fields to the mapping
|
|
114
114
|
virtualRelationFields.forEach(field => {
|
|
115
|
-
code += ` ${field.relatedField}: { ids: ${field.name}, isVirtual: true, isList: ${field.isList} },\n`;
|
|
115
|
+
code += ` ${field.relatedField}: { ids: ${field.name}, isVirtual: true, isList: ${field.isList}, isRequired: false },\n`;
|
|
116
116
|
});
|
|
117
|
-
|
|
117
|
+
|
|
118
118
|
// Add foreign key fields to the mapping
|
|
119
119
|
foreignKeyFields.forEach(field => {
|
|
120
|
-
code += ` ${field.relationName}: { ids: ${field.fieldName}, isVirtual: false, isList: ${field.isList || false} },\n`;
|
|
120
|
+
code += ` ${field.relationName}: { ids: ${field.fieldName}, isVirtual: false, isList: ${field.isList || false}, isRequired: ${field.isRequired} },\n`;
|
|
121
121
|
});
|
|
122
122
|
|
|
123
123
|
code += ' };\n\n';
|
|
@@ -139,10 +139,21 @@ function generateRelationHandling(model, operation) {
|
|
|
139
139
|
|
|
140
140
|
code += ' data[relationName] = { [relationOperation]: ids };\n';
|
|
141
141
|
code += ' } else {\n';
|
|
142
|
-
|
|
142
|
+
if (operation === 'update') {
|
|
143
|
+
code += ' // Single relationship - connect when an id is provided; disconnect when null on update\n';
|
|
144
|
+
} else {
|
|
145
|
+
code += ' // Single relationship - always use connect\n';
|
|
146
|
+
}
|
|
143
147
|
code += ' data[relationName] = { connect: { id: config.ids } };\n';
|
|
144
148
|
code += ' }\n';
|
|
145
|
-
|
|
149
|
+
if (operation === 'update') {
|
|
150
|
+
code += ' } else if (config.ids === null && !config.isList && !config.isRequired) {\n';
|
|
151
|
+
code += ' // Explicitly null - disconnect the optional single relationship\n';
|
|
152
|
+
code += ' data[relationName] = { disconnect: true };\n';
|
|
153
|
+
code += ' }\n';
|
|
154
|
+
} else {
|
|
155
|
+
code += ' }\n';
|
|
156
|
+
}
|
|
146
157
|
code += ' }\n';
|
|
147
158
|
|
|
148
159
|
return code;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Relation handling code generation for CRUD services.
|
|
3
|
+
*
|
|
4
|
+
* These functions are the canonical source of truth for the relation-mapping
|
|
5
|
+
* logic used in the EJS template (api-crud-data-access.service.ts__tmpl__).
|
|
6
|
+
* The template contains identical copies of these functions so EJS can
|
|
7
|
+
* execute them without external imports. Any change here MUST be mirrored
|
|
8
|
+
* in the template, and vice versa.
|
|
9
|
+
*/
|
|
10
|
+
export interface ModelField {
|
|
11
|
+
name: string;
|
|
12
|
+
type: string;
|
|
13
|
+
kind?: string;
|
|
14
|
+
isId?: boolean;
|
|
15
|
+
isList: boolean;
|
|
16
|
+
isOptional: boolean;
|
|
17
|
+
isVirtual?: boolean;
|
|
18
|
+
isReadOnly?: boolean;
|
|
19
|
+
hasDefaultValue?: boolean;
|
|
20
|
+
default?: unknown;
|
|
21
|
+
relationName?: string;
|
|
22
|
+
relationFromFields?: string[];
|
|
23
|
+
relationToFields?: string[];
|
|
24
|
+
relationOnDelete?: string;
|
|
25
|
+
relationOnUpdate?: string;
|
|
26
|
+
isGenerated?: boolean;
|
|
27
|
+
isUpdatedAt?: boolean;
|
|
28
|
+
documentation?: string;
|
|
29
|
+
}
|
|
30
|
+
export interface ModelLike {
|
|
31
|
+
fields: ModelField[];
|
|
32
|
+
}
|
|
33
|
+
export interface VirtualRelationField {
|
|
34
|
+
name: string;
|
|
35
|
+
type: string;
|
|
36
|
+
isList: boolean;
|
|
37
|
+
isOptional: boolean;
|
|
38
|
+
isVirtual: boolean;
|
|
39
|
+
relationName: string;
|
|
40
|
+
relatedField: string;
|
|
41
|
+
}
|
|
42
|
+
export interface ForeignKeyRelationField {
|
|
43
|
+
fieldName: string;
|
|
44
|
+
relationName: string;
|
|
45
|
+
isRequired: boolean;
|
|
46
|
+
isList: boolean;
|
|
47
|
+
}
|
|
48
|
+
export declare function getRelationFields(model: ModelLike): ModelField[];
|
|
49
|
+
export declare function getVirtualRelationFields(model: ModelLike): VirtualRelationField[];
|
|
50
|
+
export declare function getForeignKeyRelationFields(model: ModelLike): ForeignKeyRelationField[];
|
|
51
|
+
export declare function generateRelationHandling(model: ModelLike, operation: 'create' | 'update'): string;
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Relation handling code generation for CRUD services.
|
|
4
|
+
*
|
|
5
|
+
* These functions are the canonical source of truth for the relation-mapping
|
|
6
|
+
* logic used in the EJS template (api-crud-data-access.service.ts__tmpl__).
|
|
7
|
+
* The template contains identical copies of these functions so EJS can
|
|
8
|
+
* execute them without external imports. Any change here MUST be mirrored
|
|
9
|
+
* in the template, and vice versa.
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.getRelationFields = getRelationFields;
|
|
13
|
+
exports.getVirtualRelationFields = getVirtualRelationFields;
|
|
14
|
+
exports.getForeignKeyRelationFields = getForeignKeyRelationFields;
|
|
15
|
+
exports.generateRelationHandling = generateRelationHandling;
|
|
16
|
+
function getRelationFields(model) {
|
|
17
|
+
return model.fields.filter((field) => field.relationName && field.relationName.length > 0);
|
|
18
|
+
}
|
|
19
|
+
function getVirtualRelationFields(model) {
|
|
20
|
+
const relationFields = getRelationFields(model);
|
|
21
|
+
const virtualFields = [];
|
|
22
|
+
relationFields.forEach((relationField) => {
|
|
23
|
+
if (!relationField.relationFromFields || relationField.relationFromFields.length === 0) {
|
|
24
|
+
if (relationField.isList) {
|
|
25
|
+
const virtualFieldName = relationField.name + 'Ids';
|
|
26
|
+
const existingField = model.fields.find((f) => f.name === virtualFieldName && (!f.relationName || f.relationName.length === 0));
|
|
27
|
+
if (!existingField) {
|
|
28
|
+
virtualFields.push({
|
|
29
|
+
name: virtualFieldName,
|
|
30
|
+
type: 'String',
|
|
31
|
+
isList: true,
|
|
32
|
+
isOptional: true,
|
|
33
|
+
isVirtual: true,
|
|
34
|
+
relationName: relationField.relationName,
|
|
35
|
+
relatedField: relationField.name,
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
const virtualFieldName = relationField.name + 'Id';
|
|
41
|
+
const existingField = model.fields.find((f) => f.name === virtualFieldName && (!f.relationName || f.relationName.length === 0));
|
|
42
|
+
if (!existingField) {
|
|
43
|
+
virtualFields.push({
|
|
44
|
+
name: virtualFieldName,
|
|
45
|
+
type: 'String',
|
|
46
|
+
isList: false,
|
|
47
|
+
isOptional: true,
|
|
48
|
+
isVirtual: true,
|
|
49
|
+
relationName: relationField.relationName,
|
|
50
|
+
relatedField: relationField.name,
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
return virtualFields;
|
|
57
|
+
}
|
|
58
|
+
function getForeignKeyRelationFields(model) {
|
|
59
|
+
const relationFields = getRelationFields(model);
|
|
60
|
+
const foreignKeyFields = [];
|
|
61
|
+
relationFields.forEach((relationField) => {
|
|
62
|
+
if (relationField.relationFromFields && relationField.relationFromFields.length > 0) {
|
|
63
|
+
relationField.relationFromFields.forEach((fkFieldName) => {
|
|
64
|
+
const fkField = model.fields.find((f) => f.name === fkFieldName);
|
|
65
|
+
if (fkField) {
|
|
66
|
+
foreignKeyFields.push({
|
|
67
|
+
fieldName: fkFieldName,
|
|
68
|
+
relationName: relationField.name,
|
|
69
|
+
isRequired: !fkField.isOptional,
|
|
70
|
+
isList: relationField.isList,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
return foreignKeyFields;
|
|
77
|
+
}
|
|
78
|
+
function generateRelationHandling(model, operation) {
|
|
79
|
+
const virtualRelationFields = getVirtualRelationFields(model);
|
|
80
|
+
const foreignKeyFields = getForeignKeyRelationFields(model);
|
|
81
|
+
const allRelationFields = [...virtualRelationFields, ...foreignKeyFields];
|
|
82
|
+
if (allRelationFields.length === 0) {
|
|
83
|
+
return ' const data = input;';
|
|
84
|
+
}
|
|
85
|
+
let code = ' const { ';
|
|
86
|
+
code += virtualRelationFields.map((field) => field.name).join(', ');
|
|
87
|
+
if (foreignKeyFields.length > 0) {
|
|
88
|
+
if (virtualRelationFields.length > 0)
|
|
89
|
+
code += ', ';
|
|
90
|
+
code += foreignKeyFields.map((field) => field.fieldName).join(', ');
|
|
91
|
+
}
|
|
92
|
+
code += ', ...regularFields } = input;\n';
|
|
93
|
+
code += ' const data: any = regularFields;\n\n';
|
|
94
|
+
// Create relation mapping object with field type metadata
|
|
95
|
+
code += ' const relationMappings = {\n';
|
|
96
|
+
// Add virtual relation fields to the mapping
|
|
97
|
+
virtualRelationFields.forEach((field) => {
|
|
98
|
+
code += ` ${field.relatedField}: { ids: ${field.name}, isVirtual: true, isList: ${field.isList}, isRequired: false },\n`;
|
|
99
|
+
});
|
|
100
|
+
// Add foreign key fields to the mapping
|
|
101
|
+
foreignKeyFields.forEach((field) => {
|
|
102
|
+
code += ` ${field.relationName}: { ids: ${field.fieldName}, isVirtual: false, isList: ${field.isList || false}, isRequired: ${field.isRequired} },\n`;
|
|
103
|
+
});
|
|
104
|
+
code += ' };\n\n';
|
|
105
|
+
// Generate the improved iteration logic
|
|
106
|
+
code += ' for (const [relationName, config] of Object.entries(relationMappings)) {\n';
|
|
107
|
+
code += ' if (config.ids !== undefined && config.ids !== null) {\n';
|
|
108
|
+
code += ' const ids = Array.isArray(config.ids) ? config.ids.map(id => ({ id })) : [{ id: config.ids }];\n';
|
|
109
|
+
code += ' \n';
|
|
110
|
+
code += ' if (config.isList) {\n';
|
|
111
|
+
if (operation === 'update') {
|
|
112
|
+
code += ' // List relationships: use set for updates on virtual relations, connect for foreign key relations\n';
|
|
113
|
+
code += " const relationOperation = config.isVirtual ? 'set' : 'connect';\n";
|
|
114
|
+
}
|
|
115
|
+
else {
|
|
116
|
+
code += ' // List relationships: always use connect for creates\n';
|
|
117
|
+
code += " const relationOperation = 'connect';\n";
|
|
118
|
+
}
|
|
119
|
+
code += ' data[relationName] = { [relationOperation]: ids };\n';
|
|
120
|
+
code += ' } else {\n';
|
|
121
|
+
if (operation === 'update') {
|
|
122
|
+
code += ' // Single relationship - connect when an id is provided; disconnect when null on update\n';
|
|
123
|
+
}
|
|
124
|
+
else {
|
|
125
|
+
code += ' // Single relationship - always use connect\n';
|
|
126
|
+
}
|
|
127
|
+
code += ' data[relationName] = { connect: { id: config.ids } };\n';
|
|
128
|
+
code += ' }\n';
|
|
129
|
+
if (operation === 'update') {
|
|
130
|
+
code += ' } else if (config.ids === null && !config.isList && !config.isRequired) {\n';
|
|
131
|
+
code += ' // Explicitly null - disconnect the optional single relationship\n';
|
|
132
|
+
code += ' data[relationName] = { disconnect: true };\n';
|
|
133
|
+
code += ' }\n';
|
|
134
|
+
}
|
|
135
|
+
else {
|
|
136
|
+
code += ' }\n';
|
|
137
|
+
}
|
|
138
|
+
code += ' }\n';
|
|
139
|
+
return code;
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=relation-handling.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"relation-handling.js","sourceRoot":"","sources":["../../../../../generators/api/src/generate-crud/relation-handling.ts"],"names":[],"mappings":"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"}
|