@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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nestledjs/api",
3
- "version": "2.9.1",
3
+ "version": "2.9.2",
4
4
  "generators": "./generators.json",
5
5
  "type": "commonjs",
6
6
  "main": "./src/index.js",
@@ -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
- code += ' // Single relationship - always use connect\n';
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
- code += ' }\n';
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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"}