@bairock/lenz 0.0.15 → 0.0.16
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/README.md +88 -4
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +34 -8
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +0 -2
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/index.js +0 -2
- package/dist/cli/index.js.map +1 -1
- package/dist/config/index.d.ts +4 -6
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/index.js +24 -3
- package/dist/config/index.js.map +1 -1
- package/dist/engine/CodeGenerator.d.ts +7 -28
- package/dist/engine/CodeGenerator.d.ts.map +1 -1
- package/dist/engine/CodeGenerator.js +25 -1969
- package/dist/engine/CodeGenerator.js.map +1 -1
- package/dist/engine/GraphQLParseHelpers.d.ts +25 -0
- package/dist/engine/GraphQLParseHelpers.d.ts.map +1 -0
- package/dist/engine/GraphQLParseHelpers.js +128 -0
- package/dist/engine/GraphQLParseHelpers.js.map +1 -0
- package/dist/engine/GraphQLParser.d.ts +23 -10
- package/dist/engine/GraphQLParser.d.ts.map +1 -1
- package/dist/engine/GraphQLParser.js +154 -240
- package/dist/engine/GraphQLParser.js.map +1 -1
- package/dist/engine/GraphQLRelationAnalyzer.d.ts +10 -0
- package/dist/engine/GraphQLRelationAnalyzer.d.ts.map +1 -0
- package/dist/engine/GraphQLRelationAnalyzer.js +117 -0
- package/dist/engine/GraphQLRelationAnalyzer.js.map +1 -0
- package/dist/engine/LenzEngine.d.ts +1 -1
- package/dist/engine/LenzEngine.d.ts.map +1 -1
- package/dist/engine/LenzEngine.js +33 -13
- package/dist/engine/LenzEngine.js.map +1 -1
- package/dist/engine/SchemaRelationValidator.d.ts +15 -0
- package/dist/engine/SchemaRelationValidator.d.ts.map +1 -0
- package/dist/engine/SchemaRelationValidator.js +133 -0
- package/dist/engine/SchemaRelationValidator.js.map +1 -0
- package/dist/engine/SchemaValidator.d.ts +11 -10
- package/dist/engine/SchemaValidator.d.ts.map +1 -1
- package/dist/engine/SchemaValidator.js +151 -169
- package/dist/engine/SchemaValidator.js.map +1 -1
- package/dist/engine/directives.d.ts +10 -0
- package/dist/engine/directives.d.ts.map +1 -1
- package/dist/engine/directives.js +152 -6
- package/dist/engine/directives.js.map +1 -1
- package/dist/engine/generators/ClientGenerator.d.ts +7 -0
- package/dist/engine/generators/ClientGenerator.d.ts.map +1 -0
- package/dist/engine/generators/ClientGenerator.js +386 -0
- package/dist/engine/generators/ClientGenerator.js.map +1 -0
- package/dist/engine/generators/DelegateGenerator.d.ts +9 -0
- package/dist/engine/generators/DelegateGenerator.d.ts.map +1 -0
- package/dist/engine/generators/DelegateGenerator.js +453 -0
- package/dist/engine/generators/DelegateGenerator.js.map +1 -0
- package/dist/engine/generators/DelegateHelpers.d.ts +7 -0
- package/dist/engine/generators/DelegateHelpers.d.ts.map +1 -0
- package/dist/engine/generators/DelegateHelpers.js +144 -0
- package/dist/engine/generators/DelegateHelpers.js.map +1 -0
- package/dist/engine/generators/DelegateRelations.d.ts +11 -0
- package/dist/engine/generators/DelegateRelations.d.ts.map +1 -0
- package/dist/engine/generators/DelegateRelations.js +794 -0
- package/dist/engine/generators/DelegateRelations.js.map +1 -0
- package/dist/engine/generators/DelegateTemplateBody.d.ts +8 -0
- package/dist/engine/generators/DelegateTemplateBody.d.ts.map +1 -0
- package/dist/engine/generators/DelegateTemplateBody.js +776 -0
- package/dist/engine/generators/DelegateTemplateBody.js.map +1 -0
- package/dist/engine/generators/GenerateRuntimeErrors.d.ts +2 -0
- package/dist/engine/generators/GenerateRuntimeErrors.d.ts.map +1 -0
- package/dist/engine/generators/GenerateRuntimeErrors.js +140 -0
- package/dist/engine/generators/GenerateRuntimeErrors.js.map +1 -0
- package/dist/engine/generators/GenerateRuntimeIndex.d.ts +2 -0
- package/dist/engine/generators/GenerateRuntimeIndex.d.ts.map +1 -0
- package/dist/engine/generators/GenerateRuntimeIndex.js +21 -0
- package/dist/engine/generators/GenerateRuntimeIndex.js.map +1 -0
- package/dist/engine/generators/GenerateRuntimeLogger.d.ts +2 -0
- package/dist/engine/generators/GenerateRuntimeLogger.d.ts.map +1 -0
- package/dist/engine/generators/GenerateRuntimeLogger.js +125 -0
- package/dist/engine/generators/GenerateRuntimeLogger.js.map +1 -0
- package/dist/engine/generators/GenerateRuntimePagination.d.ts +2 -0
- package/dist/engine/generators/GenerateRuntimePagination.d.ts.map +1 -0
- package/dist/engine/generators/GenerateRuntimePagination.js +159 -0
- package/dist/engine/generators/GenerateRuntimePagination.js.map +1 -0
- package/dist/engine/generators/GenerateRuntimeQuery.d.ts +2 -0
- package/dist/engine/generators/GenerateRuntimeQuery.d.ts.map +1 -0
- package/dist/engine/generators/GenerateRuntimeQuery.js +427 -0
- package/dist/engine/generators/GenerateRuntimeQuery.js.map +1 -0
- package/dist/engine/generators/GenerateRuntimeRelations.d.ts +2 -0
- package/dist/engine/generators/GenerateRuntimeRelations.d.ts.map +1 -0
- package/dist/engine/generators/GenerateRuntimeRelations.js +130 -0
- package/dist/engine/generators/GenerateRuntimeRelations.js.map +1 -0
- package/dist/engine/generators/RuntimeGenerator.d.ts +16 -0
- package/dist/engine/generators/RuntimeGenerator.d.ts.map +1 -0
- package/dist/engine/generators/RuntimeGenerator.js +16 -0
- package/dist/engine/generators/RuntimeGenerator.js.map +1 -0
- package/dist/engine/generators/TypeFilterTypes.d.ts +2 -0
- package/dist/engine/generators/TypeFilterTypes.d.ts.map +1 -0
- package/dist/engine/generators/TypeFilterTypes.js +220 -0
- package/dist/engine/generators/TypeFilterTypes.js.map +1 -0
- package/dist/engine/generators/TypeGenerator.d.ts +16 -0
- package/dist/engine/generators/TypeGenerator.d.ts.map +1 -0
- package/dist/engine/generators/TypeGenerator.js +493 -0
- package/dist/engine/generators/TypeGenerator.js.map +1 -0
- package/dist/engine/generators/helpers.d.ts +13 -0
- package/dist/engine/generators/helpers.d.ts.map +1 -0
- package/dist/engine/generators/helpers.js +316 -0
- package/dist/engine/generators/helpers.js.map +1 -0
- package/dist/errors/index.d.ts +3 -0
- package/dist/errors/index.d.ts.map +1 -1
- package/dist/errors/index.js +11 -1
- package/dist/errors/index.js.map +1 -1
- package/dist/index.d.ts +0 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -3
- package/dist/index.js.map +1 -1
- package/package.json +5 -5
|
@@ -0,0 +1,776 @@
|
|
|
1
|
+
import { toCamelCase } from './helpers.js';
|
|
2
|
+
function genIdExpression(generator) {
|
|
3
|
+
switch (generator) {
|
|
4
|
+
case 'uuid': return 'crypto.randomUUID()';
|
|
5
|
+
case 'cuid': return "'cuid_' + crypto.randomUUID().slice(0, 8)";
|
|
6
|
+
case 'cuid2': return "'c' + crypto.randomUUID().replace(/-/g, '').toLowerCase().slice(0, 23)";
|
|
7
|
+
case 'ulid': return `(() => { const ENC = '0123456789ABCDEFGHJKMNPQRSTVWXYZ'; let ts = Date.now(); let r = ''; for (let i = 0; i < 10; i++) { r = ENC[ts % 32] + r; ts = Math.floor(ts / 32); } const rand = crypto.randomUUID().replace(/-/g, '').toUpperCase(); for (let i = 0; i < 16; i++) { r += ENC[parseInt(rand[i % rand.length], 16) % 32]; } return r; })()`;
|
|
8
|
+
case 'now': return 'new Date()';
|
|
9
|
+
default: return 'new ObjectId()';
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
export function genCreateMethods(model, validateCall, hasBigInt, customIdGenerator) {
|
|
13
|
+
const idExpr = genIdExpression(customIdGenerator);
|
|
14
|
+
return `
|
|
15
|
+
async create(args: ${model.name}CreateArgs): Promise<${model.name}> {
|
|
16
|
+
return this.execute('create', async () => {
|
|
17
|
+
const now = new Date()
|
|
18
|
+
const parentId = ${idExpr}
|
|
19
|
+
|
|
20
|
+
const relationFields = ['${model.relations.filter(r => !r.joinCollection).map(r => r.field).join("', '")}'] as const;
|
|
21
|
+
const nestedData: Record<string, any> = {};
|
|
22
|
+
const scalarData: Record<string, any> = {};
|
|
23
|
+
for (const [key, value] of Object.entries(args.data)) {
|
|
24
|
+
if (relationFields.includes(key as any) && typeof value === 'object' && value !== null && !Array.isArray(value) && !(value as any).equals) {
|
|
25
|
+
nestedData[key] = value;
|
|
26
|
+
} else if (relationFields.includes(key as any) && Array.isArray(value) && value.length > 0 && typeof value[0] === 'object' && !(value[0] as any)?.equals) {
|
|
27
|
+
nestedData[key] = value;
|
|
28
|
+
} else {
|
|
29
|
+
scalarData[key] = value;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
${validateCall}
|
|
34
|
+
${hasBigInt ? `this.convertBigIntFields(scalarData)\n` : ' '}const document = {
|
|
35
|
+
...this.defaultValues,
|
|
36
|
+
...scalarData,
|
|
37
|
+
_id: parentId,
|
|
38
|
+
createdAt: now,
|
|
39
|
+
updatedAt: now
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const result = await this.collection.insertOne(document, args.session ? { session: args.session } : {})
|
|
43
|
+
const parentDocId = result.insertedId.toString()
|
|
44
|
+
|
|
45
|
+
const postCreateSets: Record<string, any> = {};
|
|
46
|
+
const postCreatePushes: Record<string, any> = {};
|
|
47
|
+
${model.relations.filter(r => !r.joinCollection).map(rel => {
|
|
48
|
+
const delegate = `this.client.${toCamelCase(rel.target)}`;
|
|
49
|
+
const fkInSource = rel.foreignKeyLocation === 'source' || !rel.foreignKeyLocation;
|
|
50
|
+
const isArray = rel.isForeignKeyArray;
|
|
51
|
+
const childFkArg = (!fkInSource && rel.foreignKey) ? `, ${rel.foreignKey}: parentDocId` : '';
|
|
52
|
+
if (rel.type === 'oneToMany' || rel.type === 'manyToMany') {
|
|
53
|
+
return `
|
|
54
|
+
if (nestedData.${rel.field}) {
|
|
55
|
+
const ${rel.field}Data = nestedData.${rel.field};
|
|
56
|
+
if (${rel.field}Data.create) {
|
|
57
|
+
const created = await Promise.all(
|
|
58
|
+
(Array.isArray(${rel.field}Data.create) ? ${rel.field}Data.create : [${rel.field}Data.create]).map(data =>
|
|
59
|
+
${delegate}.create({ data: { ...data${childFkArg} } })
|
|
60
|
+
)
|
|
61
|
+
);
|
|
62
|
+
const ids = created.map(c => c.id);
|
|
63
|
+
${fkInSource ? (isArray ? `(postCreatePushes.${rel.foreignKey} || (postCreatePushes.${rel.foreignKey} = [])).push(...ids);` : `postCreateSets.${rel.foreignKey} = ids.length === 1 ? ids[0] : ids;`) : ''}
|
|
64
|
+
}
|
|
65
|
+
if (${rel.field}Data.connect) {
|
|
66
|
+
const connectIds = (Array.isArray(${rel.field}Data.connect) ? ${rel.field}Data.connect : [${rel.field}Data.connect]).map(c => c.id);
|
|
67
|
+
${fkInSource ? (isArray ? `(postCreatePushes.${rel.foreignKey} || (postCreatePushes.${rel.foreignKey} = [])).push(...connectIds);` : `postCreateSets.${rel.foreignKey} = connectIds.length === 1 ? connectIds[0] : connectIds;`) : ''}
|
|
68
|
+
}
|
|
69
|
+
if (${rel.field}Data.connectOrCreate) {
|
|
70
|
+
const items = Array.isArray(${rel.field}Data.connectOrCreate) ? ${rel.field}Data.connectOrCreate : [${rel.field}Data.connectOrCreate];
|
|
71
|
+
for (const item of items) {
|
|
72
|
+
const existing = await ${delegate}.findUnique({ where: item.where });
|
|
73
|
+
if (existing) {
|
|
74
|
+
${fkInSource ? (isArray ? `(postCreatePushes.${rel.foreignKey} || (postCreatePushes.${rel.foreignKey} = [])).push(existing.id);` : `postCreateSets.${rel.foreignKey} = existing.id;`) : ''}
|
|
75
|
+
} else {
|
|
76
|
+
const created = await ${delegate}.create({ data: { ...item.create${childFkArg} } });
|
|
77
|
+
${fkInSource ? (isArray ? `(postCreatePushes.${rel.foreignKey} || (postCreatePushes.${rel.foreignKey} = [])).push(created.id);` : `postCreateSets.${rel.foreignKey} = created.id;`) : ''}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}`;
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
return `
|
|
85
|
+
if (nestedData.${rel.field}) {
|
|
86
|
+
const ${rel.field}Data = nestedData.${rel.field};
|
|
87
|
+
if (${rel.field}Data.create) {
|
|
88
|
+
const created = await ${delegate}.create({ data: { ...${rel.field}Data.create${childFkArg} } });
|
|
89
|
+
${fkInSource ? (isArray ? `(postCreatePushes.${rel.foreignKey} || (postCreatePushes.${rel.foreignKey} = [])).push(created.id);` : `postCreateSets.${rel.foreignKey} = created.id;`) : ''}
|
|
90
|
+
}
|
|
91
|
+
if (${rel.field}Data.connect) {
|
|
92
|
+
${fkInSource ? `postCreateSets.${rel.foreignKey} = ${rel.field}Data.connect.id;` : ''}
|
|
93
|
+
}
|
|
94
|
+
if (${rel.field}Data.connectOrCreate) {
|
|
95
|
+
const existing = await ${delegate}.findUnique({ where: ${rel.field}Data.connectOrCreate.where });
|
|
96
|
+
if (existing) {
|
|
97
|
+
${fkInSource ? (isArray ? `(postCreatePushes.${rel.foreignKey} || (postCreatePushes.${rel.foreignKey} = [])).push(existing.id);` : `postCreateSets.${rel.foreignKey} = existing.id;`) : ''}
|
|
98
|
+
} else {
|
|
99
|
+
const created = await ${delegate}.create({ data: { ...${rel.field}Data.connectOrCreate.create${childFkArg} } });
|
|
100
|
+
${fkInSource ? (isArray ? `(postCreatePushes.${rel.foreignKey} || (postCreatePushes.${rel.foreignKey} = [])).push(created.id);` : `postCreateSets.${rel.foreignKey} = created.id;`) : ''}
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}`;
|
|
104
|
+
}
|
|
105
|
+
}).join('\n')}
|
|
106
|
+
|
|
107
|
+
${model.relations.filter(r => r.joinCollection).map(rel => {
|
|
108
|
+
const delegate = `this.client.${toCamelCase(rel.target)}`;
|
|
109
|
+
const sourceField = `${toCamelCase(model.name)}Id`;
|
|
110
|
+
const targetField = `${toCamelCase(rel.target)}Id`;
|
|
111
|
+
return `
|
|
112
|
+
if (nestedData.${rel.field}) {
|
|
113
|
+
const ${rel.field}Data = nestedData.${rel.field};
|
|
114
|
+
const joinCol = this.client.\\$db.collection('${rel.joinCollection}');
|
|
115
|
+
if (${rel.field}Data.create) {
|
|
116
|
+
const created = await Promise.all(
|
|
117
|
+
(Array.isArray(${rel.field}Data.create) ? ${rel.field}Data.create : [${rel.field}Data.create]).map(data =>
|
|
118
|
+
${delegate}.create({ data: { ...data } })
|
|
119
|
+
)
|
|
120
|
+
);
|
|
121
|
+
for (const c of created) {
|
|
122
|
+
await joinCol.insertOne({ ${sourceField}: parentDocId, ${targetField}: c.id }, args.session ? { session: args.session } : {});
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
if (${rel.field}Data.connect) {
|
|
126
|
+
const connectItems = Array.isArray(${rel.field}Data.connect) ? ${rel.field}Data.connect : [${rel.field}Data.connect];
|
|
127
|
+
for (const c of connectItems) {
|
|
128
|
+
await joinCol.insertOne({ ${sourceField}: parentDocId, ${targetField}: c.id }, args.session ? { session: args.session } : {});
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
if (${rel.field}Data.connectOrCreate) {
|
|
132
|
+
const items = Array.isArray(${rel.field}Data.connectOrCreate) ? ${rel.field}Data.connectOrCreate : [${rel.field}Data.connectOrCreate];
|
|
133
|
+
for (const item of items) {
|
|
134
|
+
const existing = await ${delegate}.findUnique({ where: item.where });
|
|
135
|
+
if (existing) {
|
|
136
|
+
await joinCol.insertOne({ ${sourceField}: parentDocId, ${targetField}: existing.id }, args.session ? { session: args.session } : {});
|
|
137
|
+
} else {
|
|
138
|
+
const created = await ${delegate}.create({ data: item.create });
|
|
139
|
+
await joinCol.insertOne({ ${sourceField}: parentDocId, ${targetField}: created.id }, args.session ? { session: args.session } : {});
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
}`;
|
|
144
|
+
}).join('\n')}
|
|
145
|
+
|
|
146
|
+
if (Object.keys(postCreateSets).length > 0 || Object.keys(postCreatePushes).length > 0) {
|
|
147
|
+
const postUpdate: Record<string, any> = {};
|
|
148
|
+
if (Object.keys(postCreateSets).length > 0) postUpdate.$set = postCreateSets;
|
|
149
|
+
if (Object.keys(postCreatePushes).length > 0) {
|
|
150
|
+
postUpdate.$push = {};
|
|
151
|
+
for (const [field, ids] of Object.entries(postCreatePushes)) {
|
|
152
|
+
postUpdate.$push[field] = { $each: ids as string[] };
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
await this.collection.updateOne(
|
|
156
|
+
{ _id: parentId },
|
|
157
|
+
postUpdate,
|
|
158
|
+
args.session ? { session: args.session } : {}
|
|
159
|
+
);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
const createdDoc = await this.collection.findOne(
|
|
163
|
+
{ _id: parentId },
|
|
164
|
+
args.session ? { session: args.session } : {}
|
|
165
|
+
)
|
|
166
|
+
|
|
167
|
+
if (!createdDoc) {
|
|
168
|
+
throw new Error('Failed to create document')
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const formatted = RelationResolver.formatDocument(createdDoc)
|
|
172
|
+
const omitted = this.applyOmit(formatted, args.omit)
|
|
173
|
+
|
|
174
|
+
if (args.include) {
|
|
175
|
+
return await this.includeRelations(omitted, args.include)
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
return omitted
|
|
179
|
+
})
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
async createMany(args: { data: ${model.name}CreateInput[]; session?: any; skipDuplicates?: boolean }): Promise<{ count: number }> {
|
|
183
|
+
return this.execute('createMany', async () => {
|
|
184
|
+
const now = new Date()
|
|
185
|
+
const relationFieldNames = ['${model.relations.filter(r => !r.joinCollection).map(r => r.field).join("', '")}'] as const;
|
|
186
|
+
const documents = args.data.map(data => {
|
|
187
|
+
const doc: Record<string, any> = { ...this.defaultValues, _id: ${idExpr}, createdAt: now, updatedAt: now };
|
|
188
|
+
for (const [key, value] of Object.entries(data)) {
|
|
189
|
+
if (!relationFieldNames.includes(key as any) || typeof value !== 'object' || value === null || (value as any).equals) {
|
|
190
|
+
doc[key] = value;
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
return doc;
|
|
194
|
+
})
|
|
195
|
+
${hasBigInt ? `
|
|
196
|
+
for (const doc of documents) {
|
|
197
|
+
this.convertBigIntFields(doc);
|
|
198
|
+
}` : ''}
|
|
199
|
+
|
|
200
|
+
const insertOptions: any = {}
|
|
201
|
+
if (args.session) insertOptions.session = args.session
|
|
202
|
+
if (args.skipDuplicates) {
|
|
203
|
+
insertOptions.ordered = false
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
try {
|
|
207
|
+
const result = await this.collection.insertMany(documents, insertOptions)
|
|
208
|
+
return { count: result.insertedCount }
|
|
209
|
+
} catch (error: any) {
|
|
210
|
+
if (args.skipDuplicates && error?.code === 11000) {
|
|
211
|
+
return { count: error?.insertedCount ?? error?.result?.nInserted ?? 0 }
|
|
212
|
+
}
|
|
213
|
+
throw error
|
|
214
|
+
}
|
|
215
|
+
})
|
|
216
|
+
}
|
|
217
|
+
`;
|
|
218
|
+
}
|
|
219
|
+
export function genUpdateMethods(model, hasBigInt, cascadeUpdateCall) {
|
|
220
|
+
return `
|
|
221
|
+
async update(args: ${model.name}UpdateArgs): Promise<${model.name}> {
|
|
222
|
+
return this.execute('update', async () => {
|
|
223
|
+
const whereForUpdate = await this.processRelationFilters(args.where)
|
|
224
|
+
const query = QueryBuilder.buildWhere(whereForUpdate)
|
|
225
|
+
|
|
226
|
+
const relationFields = ['${model.relations.filter(r => !r.joinCollection).map(r => r.field).join("', '")}'] as const;
|
|
227
|
+
const nestedUpdateData: Record<string, any> = {};
|
|
228
|
+
const scalarUpdateData: Record<string, any> = {};
|
|
229
|
+
for (const [key, value] of Object.entries(args.data)) {
|
|
230
|
+
if (relationFields.includes(key as any) && typeof value === 'object' && value !== null) {
|
|
231
|
+
nestedUpdateData[key] = value;
|
|
232
|
+
} else {
|
|
233
|
+
scalarUpdateData[key] = value;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
${hasBigInt ? `this.convertBigIntFields(scalarUpdateData)\n` : ''} const updateData = {
|
|
238
|
+
...scalarUpdateData,
|
|
239
|
+
updatedAt: new Date()
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const update = QueryBuilder.buildUpdate(updateData)
|
|
243
|
+
// Fetch pre-update document for cascade update diffing
|
|
244
|
+
const preUpdateDoc = await this.collection.findOne(
|
|
245
|
+
query,
|
|
246
|
+
args.session ? { session: args.session } : {}
|
|
247
|
+
)
|
|
248
|
+
const result = await this.collection.findOneAndUpdate(
|
|
249
|
+
query,
|
|
250
|
+
update,
|
|
251
|
+
{ returnDocument: 'after', ...(args.session ? { session: args.session } : {}) }
|
|
252
|
+
)
|
|
253
|
+
|
|
254
|
+
const updatedDoc = result && 'value' in result ? result.value : result
|
|
255
|
+
if (!updatedDoc) {
|
|
256
|
+
throw new Error('Document not found')
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
const updatedDocId = RelationResolver.formatDocument(updatedDoc).id;
|
|
260
|
+
const preRelationDoc = preUpdateDoc ? RelationResolver.formatDocument(preUpdateDoc) : null;
|
|
261
|
+
|
|
262
|
+
const postUpdateSets: Record<string, any> = {};
|
|
263
|
+
const postUpdatePushes: Record<string, any> = {};
|
|
264
|
+
const postUpdatePulls: Record<string, any> = {};
|
|
265
|
+
${model.relations.filter(r => !r.joinCollection).map(rel => {
|
|
266
|
+
const delegate = `this.client.${toCamelCase(rel.target)}`;
|
|
267
|
+
const fkInSource = rel.foreignKeyLocation === 'source' || !rel.foreignKeyLocation;
|
|
268
|
+
const isArray = rel.isForeignKeyArray;
|
|
269
|
+
const childFkArg = (!fkInSource && rel.foreignKey) ? `, ${rel.foreignKey}: updatedDocId` : '';
|
|
270
|
+
if (rel.type === 'oneToMany' || rel.type === 'manyToMany') {
|
|
271
|
+
return `
|
|
272
|
+
if (nestedUpdateData.${rel.field}) {
|
|
273
|
+
const ${rel.field}Data = nestedUpdateData.${rel.field};
|
|
274
|
+
if (${rel.field}Data.create) {
|
|
275
|
+
const created = await Promise.all(
|
|
276
|
+
(Array.isArray(${rel.field}Data.create) ? ${rel.field}Data.create : [${rel.field}Data.create]).map(data =>
|
|
277
|
+
${delegate}.create({ data: { ...data${childFkArg} } })
|
|
278
|
+
)
|
|
279
|
+
);
|
|
280
|
+
const ids = created.map(c => c.id);
|
|
281
|
+
${fkInSource ? (isArray ? `(postUpdatePushes.${rel.foreignKey} || (postUpdatePushes.${rel.foreignKey} = [])).push(...ids);` : `postUpdateSets.${rel.foreignKey} = ids.length === 1 ? ids[0] : ids;`) : ''}
|
|
282
|
+
}
|
|
283
|
+
if (${rel.field}Data.connect) {
|
|
284
|
+
const connectIds = (Array.isArray(${rel.field}Data.connect) ? ${rel.field}Data.connect : [${rel.field}Data.connect]).map(c => c.id);
|
|
285
|
+
${fkInSource ? (isArray ? `(postUpdatePushes.${rel.foreignKey} || (postUpdatePushes.${rel.foreignKey} = [])).push(...connectIds);` : `postUpdateSets.${rel.foreignKey} = connectIds.length === 1 ? connectIds[0] : connectIds;`) : ''}
|
|
286
|
+
}
|
|
287
|
+
if (${rel.field}Data.connectOrCreate) {
|
|
288
|
+
const items = Array.isArray(${rel.field}Data.connectOrCreate) ? ${rel.field}Data.connectOrCreate : [${rel.field}Data.connectOrCreate];
|
|
289
|
+
for (const item of items) {
|
|
290
|
+
const existing = await ${delegate}.findUnique({ where: item.where });
|
|
291
|
+
if (existing) {
|
|
292
|
+
${fkInSource ? (isArray ? `(postUpdatePushes.${rel.foreignKey} || (postUpdatePushes.${rel.foreignKey} = [])).push(existing.id);` : `postUpdateSets.${rel.foreignKey} = existing.id;`) : ''}
|
|
293
|
+
} else {
|
|
294
|
+
const created = await ${delegate}.create({ data: { ...item.create${childFkArg} } });
|
|
295
|
+
${fkInSource ? (isArray ? `(postUpdatePushes.${rel.foreignKey} || (postUpdatePushes.${rel.foreignKey} = [])).push(created.id);` : `postUpdateSets.${rel.foreignKey} = created.id;`) : ''}
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (${rel.field}Data.disconnect) {
|
|
300
|
+
const disconnectIds = (Array.isArray(${rel.field}Data.disconnect) ? ${rel.field}Data.disconnect : [${rel.field}Data.disconnect]).map(c => c.id);
|
|
301
|
+
${fkInSource && isArray ? `(postUpdatePulls.${rel.foreignKey} || (postUpdatePulls.${rel.foreignKey} = [])).push(...disconnectIds);` : fkInSource ? `postUpdateSets.${rel.foreignKey} = null;` : ''}
|
|
302
|
+
}
|
|
303
|
+
if (${rel.field}Data.set) {
|
|
304
|
+
const setIds = (Array.isArray(${rel.field}Data.set) ? ${rel.field}Data.set : [${rel.field}Data.set]).map(c => c.id);
|
|
305
|
+
${fkInSource ? (isArray ? `postUpdateSets.${rel.foreignKey} = setIds;` : `postUpdateSets.${rel.foreignKey} = setIds.length === 1 ? setIds[0] : setIds;`) : ''}
|
|
306
|
+
}
|
|
307
|
+
if (${rel.field}Data.update) {
|
|
308
|
+
const updateItems = Array.isArray(${rel.field}Data.update) ? ${rel.field}Data.update : [${rel.field}Data.update];
|
|
309
|
+
for (const item of updateItems) {
|
|
310
|
+
await ${delegate}.update({ where: item.where, data: item.data });
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
if (${rel.field}Data.delete) {
|
|
314
|
+
const deleteItems = Array.isArray(${rel.field}Data.delete) ? ${rel.field}Data.delete : [${rel.field}Data.delete];
|
|
315
|
+
for (const item of deleteItems) {
|
|
316
|
+
await ${delegate}.delete({ where: item });
|
|
317
|
+
}
|
|
318
|
+
}
|
|
319
|
+
if (${rel.field}Data.upsert) {
|
|
320
|
+
const upsertItems = Array.isArray(${rel.field}Data.upsert) ? ${rel.field}Data.upsert : [${rel.field}Data.upsert];
|
|
321
|
+
for (const item of upsertItems) {
|
|
322
|
+
await ${delegate}.upsert({ where: item.where, create: item.create, update: item.update });
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
if (${rel.field}Data.updateMany) {
|
|
326
|
+
await ${delegate}.updateMany({ where: ${rel.field}Data.updateMany.where, data: ${rel.field}Data.updateMany.data });
|
|
327
|
+
}
|
|
328
|
+
if (${rel.field}Data.deleteMany) {
|
|
329
|
+
await ${delegate}.deleteMany({ where: ${rel.field}Data.deleteMany });
|
|
330
|
+
}
|
|
331
|
+
}`;
|
|
332
|
+
}
|
|
333
|
+
else {
|
|
334
|
+
return `
|
|
335
|
+
if (nestedUpdateData.${rel.field}) {
|
|
336
|
+
const ${rel.field}Data = nestedUpdateData.${rel.field};
|
|
337
|
+
if (${rel.field}Data.create) {
|
|
338
|
+
const created = await ${delegate}.create({ data: { ...${rel.field}Data.create${childFkArg} } });
|
|
339
|
+
${fkInSource ? (isArray ? `(postUpdatePushes.${rel.foreignKey} || (postUpdatePushes.${rel.foreignKey} = [])).push(created.id);` : `postUpdateSets.${rel.foreignKey} = created.id;`) : ''}
|
|
340
|
+
}
|
|
341
|
+
if (${rel.field}Data.connect) {
|
|
342
|
+
${fkInSource ? `postUpdateSets.${rel.foreignKey} = ${rel.field}Data.connect.id;` : ''}
|
|
343
|
+
}
|
|
344
|
+
if (${rel.field}Data.connectOrCreate) {
|
|
345
|
+
const existing = await ${delegate}.findUnique({ where: ${rel.field}Data.connectOrCreate.where });
|
|
346
|
+
if (existing) {
|
|
347
|
+
${fkInSource ? (isArray ? `(postUpdatePushes.${rel.foreignKey} || (postUpdatePushes.${rel.foreignKey} = [])).push(existing.id);` : `postUpdateSets.${rel.foreignKey} = existing.id;`) : ''}
|
|
348
|
+
} else {
|
|
349
|
+
const created = await ${delegate}.create({ data: { ...${rel.field}Data.connectOrCreate.create${childFkArg} } });
|
|
350
|
+
${fkInSource ? (isArray ? `(postUpdatePushes.${rel.foreignKey} || (postUpdatePushes.${rel.foreignKey} = [])).push(created.id);` : `postUpdateSets.${rel.foreignKey} = created.id;`) : ''}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
if (${rel.field}Data.disconnect) {
|
|
354
|
+
${fkInSource && !isArray ? `postUpdateSets.${rel.foreignKey} = null;` : ''}
|
|
355
|
+
}
|
|
356
|
+
if (${rel.field}Data.update && updatedDoc.${rel.foreignKey}) {
|
|
357
|
+
await ${delegate}.update({ where: { id: String(updatedDoc.${rel.foreignKey}) }, data: ${rel.field}Data.update });
|
|
358
|
+
}
|
|
359
|
+
if (${rel.field}Data.delete && updatedDoc.${rel.foreignKey}) {
|
|
360
|
+
await ${delegate}.delete({ where: { id: String(updatedDoc.${rel.foreignKey}) } });
|
|
361
|
+
}
|
|
362
|
+
if (${rel.field}Data.upsert) {
|
|
363
|
+
await ${delegate}.upsert({ where: ${rel.field}Data.upsert.where, create: ${rel.field}Data.upsert.create, update: ${rel.field}Data.upsert.update });
|
|
364
|
+
}
|
|
365
|
+
}`;
|
|
366
|
+
}
|
|
367
|
+
}).join('\n')}
|
|
368
|
+
|
|
369
|
+
${model.relations.filter(r => r.joinCollection).map(rel => {
|
|
370
|
+
const delegate = `this.client.${toCamelCase(rel.target)}`;
|
|
371
|
+
const sourceField = `${toCamelCase(model.name)}Id`;
|
|
372
|
+
const targetField = `${toCamelCase(rel.target)}Id`;
|
|
373
|
+
return `
|
|
374
|
+
if (nestedUpdateData.${rel.field}) {
|
|
375
|
+
const ${rel.field}Data = nestedUpdateData.${rel.field};
|
|
376
|
+
const joinCol = this.client.\\$db.collection('${rel.joinCollection}');
|
|
377
|
+
if (${rel.field}Data.create) {
|
|
378
|
+
const created = await Promise.all(
|
|
379
|
+
(Array.isArray(${rel.field}Data.create) ? ${rel.field}Data.create : [${rel.field}Data.create]).map(data =>
|
|
380
|
+
${delegate}.create({ data: { ...data } })
|
|
381
|
+
)
|
|
382
|
+
);
|
|
383
|
+
for (const c of created) {
|
|
384
|
+
await joinCol.insertOne({ ${sourceField}: updatedDocId, ${targetField}: c.id }, args.session ? { session: args.session } : {});
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
if (${rel.field}Data.connect) {
|
|
388
|
+
const connectItems = Array.isArray(${rel.field}Data.connect) ? ${rel.field}Data.connect : [${rel.field}Data.connect];
|
|
389
|
+
for (const c of connectItems) {
|
|
390
|
+
await joinCol.insertOne({ ${sourceField}: updatedDocId, ${targetField}: c.id }, args.session ? { session: args.session } : {});
|
|
391
|
+
}
|
|
392
|
+
}
|
|
393
|
+
if (${rel.field}Data.disconnect) {
|
|
394
|
+
const disconnectItems = Array.isArray(${rel.field}Data.disconnect) ? ${rel.field}Data.disconnect : [${rel.field}Data.disconnect];
|
|
395
|
+
for (const c of disconnectItems) {
|
|
396
|
+
await joinCol.deleteOne({ ${sourceField}: updatedDocId, ${targetField}: c.id }, args.session ? { session: args.session } : {});
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
if (${rel.field}Data.set) {
|
|
400
|
+
await joinCol.deleteMany({ ${sourceField}: updatedDocId }, args.session ? { session: args.session } : {});
|
|
401
|
+
const setItems = Array.isArray(${rel.field}Data.set) ? ${rel.field}Data.set : [${rel.field}Data.set];
|
|
402
|
+
for (const c of setItems) {
|
|
403
|
+
await joinCol.insertOne({ ${sourceField}: updatedDocId, ${targetField}: c.id }, args.session ? { session: args.session } : {});
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
if (${rel.field}Data.connectOrCreate) {
|
|
407
|
+
const items = Array.isArray(${rel.field}Data.connectOrCreate) ? ${rel.field}Data.connectOrCreate : [${rel.field}Data.connectOrCreate];
|
|
408
|
+
for (const item of items) {
|
|
409
|
+
const existing = await ${delegate}.findUnique({ where: item.where });
|
|
410
|
+
if (existing) {
|
|
411
|
+
await joinCol.insertOne({ ${sourceField}: updatedDocId, ${targetField}: existing.id }, args.session ? { session: args.session } : {});
|
|
412
|
+
} else {
|
|
413
|
+
const created = await ${delegate}.create({ data: item.create });
|
|
414
|
+
await joinCol.insertOne({ ${sourceField}: updatedDocId, ${targetField}: created.id }, args.session ? { session: args.session } : {});
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
if (${rel.field}Data.update) {
|
|
419
|
+
const updateItems = Array.isArray(${rel.field}Data.update) ? ${rel.field}Data.update : [${rel.field}Data.update];
|
|
420
|
+
for (const item of updateItems) {
|
|
421
|
+
await ${delegate}.update({ where: item.where, data: item.data });
|
|
422
|
+
}
|
|
423
|
+
}
|
|
424
|
+
if (${rel.field}Data.delete) {
|
|
425
|
+
const deleteItems = Array.isArray(${rel.field}Data.delete) ? ${rel.field}Data.delete : [${rel.field}Data.delete];
|
|
426
|
+
for (const item of deleteItems) {
|
|
427
|
+
const del = await ${delegate}.delete({ where: item });
|
|
428
|
+
if (del) {
|
|
429
|
+
await joinCol.deleteOne({ ${sourceField}: updatedDocId, ${targetField}: del.id }, args.session ? { session: args.session } : {});
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
if (${rel.field}Data.updateMany) {
|
|
434
|
+
await ${delegate}.updateMany({ where: ${rel.field}Data.updateMany.where, data: ${rel.field}Data.updateMany.data });
|
|
435
|
+
}
|
|
436
|
+
if (${rel.field}Data.deleteMany) {
|
|
437
|
+
await ${delegate}.deleteMany({ where: ${rel.field}Data.deleteMany });
|
|
438
|
+
}
|
|
439
|
+
if (${rel.field}Data.upsert) {
|
|
440
|
+
const upsertItems = Array.isArray(${rel.field}Data.upsert) ? ${rel.field}Data.upsert : [${rel.field}Data.upsert];
|
|
441
|
+
for (const item of upsertItems) {
|
|
442
|
+
await ${delegate}.upsert({ where: item.where, create: item.create, update: item.update });
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
}`;
|
|
446
|
+
}).join('\n')}
|
|
447
|
+
|
|
448
|
+
if (Object.keys(postUpdateSets).length > 0 || Object.keys(postUpdatePushes).length > 0 || Object.keys(postUpdatePulls).length > 0) {
|
|
449
|
+
const postUpdateCmd: Record<string, any> = {};
|
|
450
|
+
if (Object.keys(postUpdateSets).length > 0) postUpdateCmd.$set = postUpdateSets;
|
|
451
|
+
if (Object.keys(postUpdatePushes).length > 0) {
|
|
452
|
+
postUpdateCmd.$push = {};
|
|
453
|
+
for (const [field, ids] of Object.entries(postUpdatePushes)) {
|
|
454
|
+
postUpdateCmd.$push[field] = { $each: ids as string[] };
|
|
455
|
+
}
|
|
456
|
+
}
|
|
457
|
+
if (Object.keys(postUpdatePulls).length > 0) {
|
|
458
|
+
const pullCmd: Record<string, any> = {};
|
|
459
|
+
for (const [field, ids] of Object.entries(postUpdatePulls)) {
|
|
460
|
+
pullCmd[field] = { $in: ids as string[] };
|
|
461
|
+
}
|
|
462
|
+
postUpdateCmd.$pull = pullCmd;
|
|
463
|
+
}
|
|
464
|
+
await this.collection.updateOne(
|
|
465
|
+
{ _id: new ObjectId(updatedDocId) },
|
|
466
|
+
postUpdateCmd,
|
|
467
|
+
args.session ? { session: args.session } : {}
|
|
468
|
+
);
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
const finalDoc = await this.collection.findOne(
|
|
472
|
+
{ _id: new ObjectId(updatedDocId) },
|
|
473
|
+
args.session ? { session: args.session } : {}
|
|
474
|
+
)
|
|
475
|
+
|
|
476
|
+
const formatted = RelationResolver.formatDocument(finalDoc || updatedDoc)
|
|
477
|
+
const omitted = this.applyOmit(formatted, args.omit)
|
|
478
|
+
${cascadeUpdateCall}
|
|
479
|
+
if (args.include) {
|
|
480
|
+
return await this.includeRelations(omitted, args.include)
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
return omitted
|
|
484
|
+
})
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
async updateMany(args: { where?: ${model.name}WhereInput; data: ${model.name}UpdateInput; session?: any }): Promise<{ count: number }> {
|
|
488
|
+
return this.execute('updateMany', async () => {
|
|
489
|
+
const whereMany = args.where ? await this.processRelationFilters(args.where) : {}
|
|
490
|
+
const query = QueryBuilder.buildWhere(whereMany)
|
|
491
|
+
const relationFieldNames = ['${model.relations.filter(r => !r.joinCollection).map(r => r.field).join("', '")}'] as const;
|
|
492
|
+
const updateData: Record<string, any> = { updatedAt: new Date() };
|
|
493
|
+
for (const [key, value] of Object.entries(args.data)) {
|
|
494
|
+
if (!relationFieldNames.includes(key as any) || typeof value !== 'object' || value === null || (value as any).equals) {
|
|
495
|
+
updateData[key] = value;
|
|
496
|
+
}
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
${hasBigInt ? 'this.convertBigIntFields(updateData)\n' : ''} const update = QueryBuilder.buildUpdate(updateData)
|
|
500
|
+
const result = await this.collection.updateMany(query, update, args.session ? { session: args.session } : {})
|
|
501
|
+
return { count: result.modifiedCount }
|
|
502
|
+
})
|
|
503
|
+
}
|
|
504
|
+
`;
|
|
505
|
+
}
|
|
506
|
+
export function genUpsert(model, hasBigInt, customIdGenerator) {
|
|
507
|
+
const relationFields = model.relations.filter(r => !r.joinCollection).map(r => r.field);
|
|
508
|
+
const idExpr = genIdExpression(customIdGenerator);
|
|
509
|
+
return `
|
|
510
|
+
async upsert(args: ${model.name}UpsertArgs): Promise<${model.name}> {
|
|
511
|
+
return this.execute('upsert', async () => {
|
|
512
|
+
const whereForUpsert = await this.processRelationFilters(args.where)
|
|
513
|
+
const query = QueryBuilder.buildWhere(whereForUpsert)
|
|
514
|
+
const upsertRelationFields = [${relationFields.map(f => `'${f}'`).join(', ')}] as const;
|
|
515
|
+
const nestedCreate: Record<string, any> = {};
|
|
516
|
+
const scalarCreate: Record<string, any> = {};
|
|
517
|
+
for (const [key, value] of Object.entries(args.create)) {
|
|
518
|
+
if (upsertRelationFields.includes(key as any) && typeof value === 'object' && value !== null && !(value as any).equals) {
|
|
519
|
+
nestedCreate[key] = value;
|
|
520
|
+
} else {
|
|
521
|
+
scalarCreate[key] = value;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
const now = new Date()
|
|
526
|
+
${hasBigInt ? ` this.convertBigIntFields(scalarCreate)\n` : ''} const setData: Record<string, any> = {};
|
|
527
|
+
for (const [key, value] of Object.entries(args.update)) {
|
|
528
|
+
if (!upsertRelationFields.includes(key as any) || typeof value !== 'object' || value === null || (value as any).equals) {
|
|
529
|
+
setData[key] = value;
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
setData.updatedAt = now;
|
|
533
|
+
${hasBigInt ? ` this.convertBigIntFields(setData)\n` : ''}
|
|
534
|
+
const result = await this.collection.findOneAndUpdate(
|
|
535
|
+
query,
|
|
536
|
+
{
|
|
537
|
+
$set: setData,
|
|
538
|
+
$setOnInsert: { ...this.defaultValues, ...scalarCreate, _id: ${idExpr}, createdAt: now, updatedAt: now }
|
|
539
|
+
},
|
|
540
|
+
{ returnDocument: 'after', upsert: true, ...(args.session ? { session: args.session } : {}) }
|
|
541
|
+
)
|
|
542
|
+
|
|
543
|
+
const doc = result && 'value' in result ? result.value : result
|
|
544
|
+
if (!doc) {
|
|
545
|
+
throw new Error('Upsert failed')
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
const formatted = RelationResolver.formatDocument(doc)
|
|
549
|
+
const omitted = this.applyOmit(formatted, args.omit)
|
|
550
|
+
|
|
551
|
+
if (Object.keys(nestedCreate).length > 0) {
|
|
552
|
+
return await this.update({
|
|
553
|
+
where: { id: formatted.id },
|
|
554
|
+
data: nestedCreate as any,
|
|
555
|
+
include: args.include,
|
|
556
|
+
omit: args.omit,
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (args.include) {
|
|
561
|
+
return await this.includeRelations(omitted, args.include)
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
return omitted
|
|
565
|
+
})
|
|
566
|
+
}
|
|
567
|
+
`;
|
|
568
|
+
}
|
|
569
|
+
export function genDeleteMethods(model, cascadeDeleteCall, cascadeDeleteManyBody) {
|
|
570
|
+
return `
|
|
571
|
+
async delete(args: ${model.name}DeleteArgs): Promise<${model.name} | null> {
|
|
572
|
+
return this.execute('delete', async () => {
|
|
573
|
+
const whereForDelete = await this.processRelationFilters(args.where)
|
|
574
|
+
const query = QueryBuilder.buildWhere(whereForDelete)
|
|
575
|
+
const doc = await this.collection.findOne(query, args.session ? { session: args.session } : {})
|
|
576
|
+
|
|
577
|
+
if (!doc) return null
|
|
578
|
+
${cascadeDeleteCall}
|
|
579
|
+
await this.collection.deleteOne(query, args.session ? { session: args.session } : {})
|
|
580
|
+
const formatted = RelationResolver.formatDocument(doc)
|
|
581
|
+
const omitted = this.applyOmit(formatted, args.omit)
|
|
582
|
+
|
|
583
|
+
if (args.include) {
|
|
584
|
+
return await this.includeRelations(omitted, args.include)
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
return omitted
|
|
588
|
+
})
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
async deleteMany(args: { where?: ${model.name}WhereInput; session?: any }): Promise<{ count: number }> {
|
|
592
|
+
return this.execute('deleteMany', async () => {
|
|
593
|
+
${cascadeDeleteManyBody}
|
|
594
|
+
})
|
|
595
|
+
}
|
|
596
|
+
`;
|
|
597
|
+
}
|
|
598
|
+
export function genAggregate(model) {
|
|
599
|
+
return `
|
|
600
|
+
async aggregate(args: ${model.name}AggregateArgs): Promise<${model.name}AggregateResult> {
|
|
601
|
+
return this.execute('aggregate', async () => {
|
|
602
|
+
const pipeline: any[] = [];
|
|
603
|
+
|
|
604
|
+
if (args.where && Object.keys(args.where).length > 0) {
|
|
605
|
+
pipeline.push({ $match: QueryBuilder.buildWhere(args.where) })
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
const groupStage: any = { _id: null };
|
|
609
|
+
|
|
610
|
+
if (args._count) {
|
|
611
|
+
if (args._count === true) {
|
|
612
|
+
groupStage._count_all = { $sum: 1 }
|
|
613
|
+
} else if (Array.isArray(args._count)) {
|
|
614
|
+
for (const field of args._count) {
|
|
615
|
+
groupStage[\`_count_\${field}\`] = { $sum: 1 }
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
for (const op of ['_sum', '_avg', '_min', '_max'] as const) {
|
|
621
|
+
const fields = (args as any)[op];
|
|
622
|
+
if (fields && Array.isArray(fields)) {
|
|
623
|
+
const mongoOp = op === '_sum' ? '$sum' : op === '_avg' ? '$avg' : op === '_min' ? '$min' : '$max';
|
|
624
|
+
for (const field of fields) {
|
|
625
|
+
groupStage[\`\${op}_\${field}\`] = { [mongoOp]: \`$\${field}\` }
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
pipeline.push({ $group: groupStage });
|
|
631
|
+
|
|
632
|
+
const result = await this.collection.aggregate(pipeline, args.session ? { session: args.session } : {}).toArray()
|
|
633
|
+
|
|
634
|
+
if (result.length === 0) {
|
|
635
|
+
const empty: any = { _count: 0 };
|
|
636
|
+
['_sum', '_avg', '_min', '_max'].forEach(op => {
|
|
637
|
+
if ((args as any)[op]) empty[op] = {};
|
|
638
|
+
});
|
|
639
|
+
return empty as ${model.name}AggregateResult
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
const data = result[0];
|
|
643
|
+
const output: any = {};
|
|
644
|
+
|
|
645
|
+
if (args._count === true) {
|
|
646
|
+
output._count = data._count_all || 0
|
|
647
|
+
} else if (Array.isArray(args._count)) {
|
|
648
|
+
const countResult: any = {};
|
|
649
|
+
for (const field of args._count) {
|
|
650
|
+
countResult[field] = data[\`_count_\${field}\`] || 0
|
|
651
|
+
}
|
|
652
|
+
output._count = countResult
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
for (const op of ['_sum', '_avg', '_min', '_max'] as const) {
|
|
656
|
+
const fields = (args as any)[op];
|
|
657
|
+
if (fields && Array.isArray(fields)) {
|
|
658
|
+
const opResult: any = {};
|
|
659
|
+
for (const field of fields) {
|
|
660
|
+
opResult[field] = data[\`\${op}_\${field}\`] ?? null
|
|
661
|
+
}
|
|
662
|
+
output[op] = opResult
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
|
|
666
|
+
return output as ${model.name}AggregateResult
|
|
667
|
+
})
|
|
668
|
+
}
|
|
669
|
+
`;
|
|
670
|
+
}
|
|
671
|
+
export function genGroupBy(model) {
|
|
672
|
+
return `
|
|
673
|
+
async groupBy(args: ${model.name}GroupByArgs): Promise<${model.name}GroupByResult[]> {
|
|
674
|
+
return this.execute('groupBy', async () => {
|
|
675
|
+
const pipeline: any[] = [];
|
|
676
|
+
|
|
677
|
+
if (args.where && Object.keys(args.where).length > 0) {
|
|
678
|
+
pipeline.push({ $match: QueryBuilder.buildWhere(args.where) })
|
|
679
|
+
}
|
|
680
|
+
|
|
681
|
+
const groupId: any = {};
|
|
682
|
+
for (const field of args.by) {
|
|
683
|
+
groupId[field] = \`$\${field}\`;
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
const groupStage: any = { _id: groupId };
|
|
687
|
+
|
|
688
|
+
const addAccumulator = (field: string, op: string, target: string) => {
|
|
689
|
+
if (!groupStage[target]) groupStage[target] = {};
|
|
690
|
+
groupStage[target][field] = { [\`$\${op}\`]: \`$\${field}\` };
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
if (args._count) {
|
|
694
|
+
if (args._count === true) {
|
|
695
|
+
groupStage._count = { _all: { $sum: 1 } };
|
|
696
|
+
} else if (Array.isArray(args._count)) {
|
|
697
|
+
groupStage._count = { _all: { $sum: 1 } };
|
|
698
|
+
for (const field of args._count) {
|
|
699
|
+
if (!groupStage._count) groupStage._count = {};
|
|
700
|
+
groupStage._count[field] = { $sum: { $cond: [{ $ne: [\`$\${field}\`, null] }, 1, 0] } };
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
if (args._sum && Array.isArray(args._sum)) {
|
|
706
|
+
for (const field of args._sum) {
|
|
707
|
+
addAccumulator(field, 'sum', '_sum');
|
|
708
|
+
}
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
if (args._avg && Array.isArray(args._avg)) {
|
|
712
|
+
for (const field of args._avg) {
|
|
713
|
+
addAccumulator(field, 'avg', '_avg');
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
|
|
717
|
+
if (args._min && Array.isArray(args._min)) {
|
|
718
|
+
for (const field of args._min) {
|
|
719
|
+
addAccumulator(field, 'min', '_min');
|
|
720
|
+
}
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
if (args._max && Array.isArray(args._max)) {
|
|
724
|
+
for (const field of args._max) {
|
|
725
|
+
addAccumulator(field, 'max', '_max');
|
|
726
|
+
}
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
pipeline.push({ $group: groupStage });
|
|
730
|
+
|
|
731
|
+
const projectStage: any = { _id: 0 };
|
|
732
|
+
for (const field of args.by) {
|
|
733
|
+
projectStage[field] = \`$\${'_id.' + field}\`;
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
const aggTargets = ['_count', '_sum', '_avg', '_min', '_max'];
|
|
737
|
+
for (const target of aggTargets) {
|
|
738
|
+
if (groupStage[target]) {
|
|
739
|
+
projectStage[target] = 1;
|
|
740
|
+
}
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
if (Object.keys(projectStage).length > 1) {
|
|
744
|
+
pipeline.push({ $project: projectStage });
|
|
745
|
+
}
|
|
746
|
+
|
|
747
|
+
if (args.having && Object.keys(args.having).length > 0) {
|
|
748
|
+
const having = args.having as Record<string, any>;
|
|
749
|
+
const havingQuery = QueryBuilder.buildWhere(having);
|
|
750
|
+
// buildWhere converts id→_id, but after $project: { _id: 0 } the _id field is excluded.
|
|
751
|
+
// The projected field is 'id', so revert the conversion for having filters.
|
|
752
|
+
if ('id' in having && '_id' in havingQuery) {
|
|
753
|
+
havingQuery.id = havingQuery._id;
|
|
754
|
+
delete havingQuery._id;
|
|
755
|
+
}
|
|
756
|
+
pipeline.push({ $match: havingQuery })
|
|
757
|
+
}
|
|
758
|
+
|
|
759
|
+
if (args.orderBy) {
|
|
760
|
+
pipeline.push({ $sort: QueryBuilder.buildSort(args.orderBy) })
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
if (args.skip) {
|
|
764
|
+
pipeline.push({ $skip: args.skip })
|
|
765
|
+
}
|
|
766
|
+
if (args.take) {
|
|
767
|
+
pipeline.push({ $limit: args.take })
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
const result = await this.collection.aggregate(pipeline, args.session ? { session: args.session } : {}).toArray()
|
|
771
|
+
return result as ${model.name}GroupByResult[]
|
|
772
|
+
})
|
|
773
|
+
}
|
|
774
|
+
`;
|
|
775
|
+
}
|
|
776
|
+
//# sourceMappingURL=DelegateTemplateBody.js.map
|