@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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { GraphQLDirective, DirectiveLocation, GraphQLString, GraphQLNonNull, GraphQLBoolean } from 'graphql';
|
|
1
|
+
import { GraphQLDirective, DirectiveLocation, GraphQLString, GraphQLNonNull, GraphQLBoolean, GraphQLList } from 'graphql';
|
|
2
2
|
// Определение всех директив Lenz ORM
|
|
3
3
|
export const modelDirective = new GraphQLDirective({
|
|
4
4
|
name: 'model',
|
|
@@ -8,11 +8,31 @@ export const modelDirective = new GraphQLDirective({
|
|
|
8
8
|
export const idDirective = new GraphQLDirective({
|
|
9
9
|
name: 'id',
|
|
10
10
|
locations: [DirectiveLocation.FIELD_DEFINITION],
|
|
11
|
+
args: {
|
|
12
|
+
name: {
|
|
13
|
+
type: GraphQLString,
|
|
14
|
+
description: 'Name for the primary key constraint (Prisma @id map parameter)'
|
|
15
|
+
},
|
|
16
|
+
map: {
|
|
17
|
+
type: GraphQLString,
|
|
18
|
+
description: 'Custom name for the underlying index in the database'
|
|
19
|
+
}
|
|
20
|
+
},
|
|
11
21
|
description: 'Marks a field as primary key (auto-generated ObjectId)'
|
|
12
22
|
});
|
|
13
23
|
export const uniqueDirective = new GraphQLDirective({
|
|
14
24
|
name: 'unique',
|
|
15
25
|
locations: [DirectiveLocation.FIELD_DEFINITION],
|
|
26
|
+
args: {
|
|
27
|
+
name: {
|
|
28
|
+
type: GraphQLString,
|
|
29
|
+
description: 'Name for the unique constraint (Prisma @unique map parameter)'
|
|
30
|
+
},
|
|
31
|
+
map: {
|
|
32
|
+
type: GraphQLString,
|
|
33
|
+
description: 'Custom name for the underlying index in the database'
|
|
34
|
+
}
|
|
35
|
+
},
|
|
16
36
|
description: 'Creates a unique index on the field'
|
|
17
37
|
});
|
|
18
38
|
export const indexDirective = new GraphQLDirective({
|
|
@@ -25,16 +45,24 @@ export const defaultDirective = new GraphQLDirective({
|
|
|
25
45
|
locations: [DirectiveLocation.FIELD_DEFINITION],
|
|
26
46
|
args: {
|
|
27
47
|
value: {
|
|
28
|
-
type:
|
|
29
|
-
description: 'Default value for the field'
|
|
48
|
+
type: GraphQLString,
|
|
49
|
+
description: 'Default value for the field (static value)'
|
|
50
|
+
},
|
|
51
|
+
generator: {
|
|
52
|
+
type: GraphQLString,
|
|
53
|
+
description: 'Default value generator: "uuid", "now", "cuid"'
|
|
30
54
|
}
|
|
31
55
|
},
|
|
32
|
-
description: 'Sets a default value for a field'
|
|
56
|
+
description: 'Sets a default value or generator for a field'
|
|
33
57
|
});
|
|
34
58
|
export const relationDirective = new GraphQLDirective({
|
|
35
59
|
name: 'relation',
|
|
36
60
|
locations: [DirectiveLocation.FIELD_DEFINITION],
|
|
37
61
|
args: {
|
|
62
|
+
name: {
|
|
63
|
+
type: GraphQLString,
|
|
64
|
+
description: 'Name for the relation (required when a model has multiple relations to the same target model)'
|
|
65
|
+
},
|
|
38
66
|
field: {
|
|
39
67
|
type: new GraphQLNonNull(GraphQLString),
|
|
40
68
|
description: 'The field that stores the foreign key'
|
|
@@ -49,7 +77,11 @@ export const relationDirective = new GraphQLDirective({
|
|
|
49
77
|
},
|
|
50
78
|
onDelete: {
|
|
51
79
|
type: GraphQLString,
|
|
52
|
-
description: 'Cascade delete behavior: "Cascade" (delete related), "SetNull" (nullify FK), or "NoAction" (default, no cascade)'
|
|
80
|
+
description: 'Cascade delete behavior: "Cascade" (delete related), "SetNull" (nullify FK), "Restrict" (prevent delete), or "NoAction" (default, no cascade)'
|
|
81
|
+
},
|
|
82
|
+
onUpdate: {
|
|
83
|
+
type: GraphQLString,
|
|
84
|
+
description: 'Cascade update behavior: "SetNull" (nullify FK), "Cascade" (update related), "Restrict" (prevent update), or "NoAction" (default, no cascade)'
|
|
53
85
|
}
|
|
54
86
|
},
|
|
55
87
|
description: 'Defines a relationship between models'
|
|
@@ -74,6 +106,110 @@ export const hideDirective = new GraphQLDirective({
|
|
|
74
106
|
locations: [DirectiveLocation.FIELD_DEFINITION],
|
|
75
107
|
description: 'Excludes field from query results by default. Can be explicitly selected via select option.'
|
|
76
108
|
});
|
|
109
|
+
export const mapDirective = new GraphQLDirective({
|
|
110
|
+
name: 'map',
|
|
111
|
+
locations: [DirectiveLocation.FIELD_DEFINITION],
|
|
112
|
+
args: {
|
|
113
|
+
name: {
|
|
114
|
+
type: new GraphQLNonNull(GraphQLString),
|
|
115
|
+
description: 'The database field name to map to'
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
description: 'Maps a field to a different database column name (Prisma @map)'
|
|
119
|
+
});
|
|
120
|
+
export const modelMapDirective = new GraphQLDirective({
|
|
121
|
+
name: 'modelMap',
|
|
122
|
+
locations: [DirectiveLocation.OBJECT],
|
|
123
|
+
args: {
|
|
124
|
+
name: {
|
|
125
|
+
type: new GraphQLNonNull(GraphQLString),
|
|
126
|
+
description: 'The database collection name to map to (Prisma @@map)'
|
|
127
|
+
}
|
|
128
|
+
},
|
|
129
|
+
description: 'Maps a model to a different database collection name (Prisma @@map)'
|
|
130
|
+
});
|
|
131
|
+
export const ignoreDirective = new GraphQLDirective({
|
|
132
|
+
name: 'ignore',
|
|
133
|
+
locations: [DirectiveLocation.FIELD_DEFINITION],
|
|
134
|
+
description: 'Excludes a field from database operations entirely (Prisma @ignore)'
|
|
135
|
+
});
|
|
136
|
+
export const compoundUniqueDirective = new GraphQLDirective({
|
|
137
|
+
name: 'compoundUnique',
|
|
138
|
+
locations: [DirectiveLocation.OBJECT],
|
|
139
|
+
args: {
|
|
140
|
+
fields: {
|
|
141
|
+
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(GraphQLString))),
|
|
142
|
+
description: 'Field names to include in the compound unique index'
|
|
143
|
+
},
|
|
144
|
+
name: {
|
|
145
|
+
type: GraphQLString,
|
|
146
|
+
description: 'Optional name for the unique constraint (maps to Prisma @@unique map parameter)'
|
|
147
|
+
}
|
|
148
|
+
},
|
|
149
|
+
description: 'Creates a compound unique index on multiple fields (Prisma @@unique)'
|
|
150
|
+
});
|
|
151
|
+
export const compoundIndexDirective = new GraphQLDirective({
|
|
152
|
+
name: 'compoundIndex',
|
|
153
|
+
locations: [DirectiveLocation.OBJECT],
|
|
154
|
+
args: {
|
|
155
|
+
fields: {
|
|
156
|
+
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(GraphQLString))),
|
|
157
|
+
description: 'Field names to include in the compound index'
|
|
158
|
+
},
|
|
159
|
+
name: {
|
|
160
|
+
type: GraphQLString,
|
|
161
|
+
description: 'Optional name for the index (maps to Prisma @@index map parameter)'
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
description: 'Creates a compound index on multiple fields (Prisma @@index)'
|
|
165
|
+
});
|
|
166
|
+
export const compoundIdDirective = new GraphQLDirective({
|
|
167
|
+
name: 'compoundId',
|
|
168
|
+
locations: [DirectiveLocation.OBJECT],
|
|
169
|
+
args: {
|
|
170
|
+
fields: {
|
|
171
|
+
type: new GraphQLNonNull(new GraphQLList(new GraphQLNonNull(GraphQLString))),
|
|
172
|
+
description: 'Field names to include in the compound primary key'
|
|
173
|
+
},
|
|
174
|
+
name: {
|
|
175
|
+
type: GraphQLString,
|
|
176
|
+
description: 'Optional name for the primary key constraint'
|
|
177
|
+
}
|
|
178
|
+
},
|
|
179
|
+
description: 'Defines a compound primary key on multiple fields (Prisma @@id)'
|
|
180
|
+
});
|
|
181
|
+
export const fulltextDirective = new GraphQLDirective({
|
|
182
|
+
name: 'fulltext',
|
|
183
|
+
locations: [DirectiveLocation.OBJECT, DirectiveLocation.FIELD_DEFINITION],
|
|
184
|
+
args: {
|
|
185
|
+
fields: {
|
|
186
|
+
type: new GraphQLList(new GraphQLNonNull(GraphQLString)),
|
|
187
|
+
description: 'Field names to include in the full-text index (for object-level usage: @@fulltext(fields: ["title", "description"]))'
|
|
188
|
+
}
|
|
189
|
+
},
|
|
190
|
+
description: 'Creates a MongoDB text index on specified field(s) for full-text search'
|
|
191
|
+
});
|
|
192
|
+
export const emailDirective = new GraphQLDirective({
|
|
193
|
+
name: 'email',
|
|
194
|
+
locations: [DirectiveLocation.FIELD_DEFINITION],
|
|
195
|
+
description: 'Validates that the field value is a valid email address'
|
|
196
|
+
});
|
|
197
|
+
export const urlDirective = new GraphQLDirective({
|
|
198
|
+
name: 'url',
|
|
199
|
+
locations: [DirectiveLocation.FIELD_DEFINITION],
|
|
200
|
+
description: 'Validates that the field value is a valid URL'
|
|
201
|
+
});
|
|
202
|
+
export const regexDirective = new GraphQLDirective({
|
|
203
|
+
name: 'regex',
|
|
204
|
+
locations: [DirectiveLocation.FIELD_DEFINITION],
|
|
205
|
+
args: {
|
|
206
|
+
pattern: {
|
|
207
|
+
type: new GraphQLNonNull(GraphQLString),
|
|
208
|
+
description: 'Regular expression pattern to validate the field value against'
|
|
209
|
+
}
|
|
210
|
+
},
|
|
211
|
+
description: 'Validates that the field value matches a regular expression pattern'
|
|
212
|
+
});
|
|
77
213
|
// Экспорт всех директив
|
|
78
214
|
export const lenzDirectives = [
|
|
79
215
|
modelDirective,
|
|
@@ -85,7 +221,17 @@ export const lenzDirectives = [
|
|
|
85
221
|
createdAtDirective,
|
|
86
222
|
updatedAtDirective,
|
|
87
223
|
embeddedDirective,
|
|
88
|
-
hideDirective
|
|
224
|
+
hideDirective,
|
|
225
|
+
mapDirective,
|
|
226
|
+
modelMapDirective,
|
|
227
|
+
ignoreDirective,
|
|
228
|
+
compoundUniqueDirective,
|
|
229
|
+
compoundIndexDirective,
|
|
230
|
+
compoundIdDirective,
|
|
231
|
+
fulltextDirective,
|
|
232
|
+
emailDirective,
|
|
233
|
+
urlDirective,
|
|
234
|
+
regexDirective
|
|
89
235
|
];
|
|
90
236
|
// Утилита для проверки, является ли директива директивой Lenz
|
|
91
237
|
export function isLenzDirective(directiveName) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"directives.js","sourceRoot":"","sources":["../../src/engine/directives.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,iBAAiB,EAAE,aAAa,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"directives.js","sourceRoot":"","sources":["../../src/engine/directives.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { GraphQLModel } from '../GraphQLParser.js';
|
|
2
|
+
export declare class ClientGenerator {
|
|
3
|
+
generateIndex(clientName: string): string;
|
|
4
|
+
generateClient(clientName: string, models: GraphQLModel[]): string;
|
|
5
|
+
getModelsForRuntime(models: GraphQLModel[]): any[];
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=ClientGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClientGenerator.d.ts","sourceRoot":"","sources":["../../../src/engine/generators/ClientGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAGnD,qBAAa,eAAe;IAC1B,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM;IAkBzC,cAAc,CAAC,UAAU,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM;IA4VlE,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,GAAG,EAAE;CAmBnD"}
|
|
@@ -0,0 +1,386 @@
|
|
|
1
|
+
import { toCamelCase } from './helpers.js';
|
|
2
|
+
export class ClientGenerator {
|
|
3
|
+
generateIndex(clientName) {
|
|
4
|
+
return `// This file was auto-generated by Lenz. Do not edit manually.
|
|
5
|
+
// @generated
|
|
6
|
+
|
|
7
|
+
export { ${clientName} } from './client'
|
|
8
|
+
export * from './types'
|
|
9
|
+
export * from './enums'
|
|
10
|
+
|
|
11
|
+
import { ${clientName} } from './client'
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Default export for the Lenz client
|
|
15
|
+
*/
|
|
16
|
+
const lenz = new ${clientName}()
|
|
17
|
+
export default lenz
|
|
18
|
+
`;
|
|
19
|
+
}
|
|
20
|
+
generateClient(clientName, models) {
|
|
21
|
+
return `// This file was auto-generated by Lenz. Do not edit manually.
|
|
22
|
+
// @generated
|
|
23
|
+
|
|
24
|
+
import { MongoClient, Db, ObjectId, Collection, Document } from 'mongodb'
|
|
25
|
+
import type { LenzConfig } from './types'
|
|
26
|
+
import { QueryBuilder } from './runtime/query'
|
|
27
|
+
import { RelationResolver } from './runtime/relations'
|
|
28
|
+
import { Logger } from './runtime/logger'
|
|
29
|
+
|
|
30
|
+
${models.map(model => `
|
|
31
|
+
import { ${model.name}Delegate } from './models/${model.name}'`).join('\n')}
|
|
32
|
+
|
|
33
|
+
export class ${clientName} {
|
|
34
|
+
private mongoClient: MongoClient | null = null
|
|
35
|
+
private db: Db | null = null
|
|
36
|
+
private config: LenzConfig
|
|
37
|
+
private database: string
|
|
38
|
+
private supportsTransactions: boolean = false
|
|
39
|
+
private logger: Logger
|
|
40
|
+
|
|
41
|
+
// Model delegates
|
|
42
|
+
${models.map(model => ` public ${toCamelCase(model.name)}: ${model.name}Delegate`).join('\n')}
|
|
43
|
+
|
|
44
|
+
private extractDatabaseFromUrl(url: string): string {
|
|
45
|
+
try {
|
|
46
|
+
const parsed = new URL(url);
|
|
47
|
+
const db = parsed.pathname.replace(/^\//, '').split('/')[0];
|
|
48
|
+
return db || 'myapp';
|
|
49
|
+
} catch {
|
|
50
|
+
return 'myapp';
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
constructor(config: LenzConfig = {}) {
|
|
55
|
+
this.config = {
|
|
56
|
+
...config,
|
|
57
|
+
url: config.url || process.env.MONGODB_URI || 'mongodb://localhost:27017/myapp',
|
|
58
|
+
log: config.log || []
|
|
59
|
+
};
|
|
60
|
+
this.database = config.database || this.extractDatabaseFromUrl(this.config.url);
|
|
61
|
+
this.logger = new Logger(this.config.log);
|
|
62
|
+
|
|
63
|
+
// Initialize model delegates
|
|
64
|
+
${models.map(model => ` this.${toCamelCase(model.name)} = new ${model.name}Delegate(this)`).join('\n')}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Extensions storage ($extends support)
|
|
68
|
+
private extensions: Array<{
|
|
69
|
+
query?: Record<string, Record<string, (params: { args: any; query: (args: any) => Promise<any> }) => Promise<any>>>
|
|
70
|
+
result?: Record<string, Record<string, { needs?: Record<string, boolean>; compute: (parent: any) => any }>>
|
|
71
|
+
client?: Record<string, (...args: any[]) => any>
|
|
72
|
+
}> = []
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Prisma-compatible $extends — add query interception, computed fields, and client methods
|
|
76
|
+
* @example
|
|
77
|
+
* const xprisma = lenz.$extends({
|
|
78
|
+
* query: {
|
|
79
|
+
* user: {
|
|
80
|
+
* findMany: async ({ args, query }) => {
|
|
81
|
+
* args.where = { ...args.where, deleted: false }
|
|
82
|
+
* return query(args)
|
|
83
|
+
* }
|
|
84
|
+
* }
|
|
85
|
+
* },
|
|
86
|
+
* result: {
|
|
87
|
+
* user: {
|
|
88
|
+
* fullName: {
|
|
89
|
+
* needs: { firstName: true, lastName: true },
|
|
90
|
+
* compute: (user) => \`\${user.firstName} \${user.lastName}\`
|
|
91
|
+
* }
|
|
92
|
+
* }
|
|
93
|
+
* },
|
|
94
|
+
* client: {
|
|
95
|
+
* ping: async () => lenz.$mongo.client.db().admin().ping()
|
|
96
|
+
* }
|
|
97
|
+
* })
|
|
98
|
+
*/
|
|
99
|
+
$extends(extension: any): this {
|
|
100
|
+
this.extensions.push(extension)
|
|
101
|
+
|
|
102
|
+
if (extension.client) {
|
|
103
|
+
for (const [key, fn] of Object.entries(extension.client)) {
|
|
104
|
+
;(this as any)[key] = fn
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
return this
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
getQueryExtension(modelName: string, method: string): ((params: { args: any; query: (args: any) => Promise<any> }) => Promise<any>) | null {
|
|
112
|
+
for (const ext of this.extensions) {
|
|
113
|
+
if (ext.query?.[modelName]?.[method]) {
|
|
114
|
+
return ext.query[modelName][method]
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
return null
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
getResultExtensions(modelName: string): Array<{ name: string; compute: (parent: any) => any }> | null {
|
|
121
|
+
const exts: Array<{ name: string; compute: (parent: any) => any }> = []
|
|
122
|
+
for (const ext of this.extensions) {
|
|
123
|
+
if (ext.result?.[modelName]) {
|
|
124
|
+
for (const [name, config] of Object.entries(ext.result[modelName])) {
|
|
125
|
+
exts.push({ name, compute: (config as any).compute })
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
return exts.length > 0 ? exts : null
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
$on(event: string, callback: any): void {
|
|
133
|
+
this.logger.on(event, callback)
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
get $logger(): Logger {
|
|
137
|
+
return this.logger
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
async $connect(): Promise<void> {
|
|
141
|
+
if (this.mongoClient) return
|
|
142
|
+
|
|
143
|
+
this.mongoClient = new MongoClient(this.config.url, {
|
|
144
|
+
maxPoolSize: this.config.maxPoolSize || 10,
|
|
145
|
+
connectTimeoutMS: this.config.connectTimeoutMS || 10000,
|
|
146
|
+
socketTimeoutMS: this.config.socketTimeoutMS || 45000
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
await this.mongoClient.connect()
|
|
150
|
+
this.db = this.mongoClient.db(this.database)
|
|
151
|
+
|
|
152
|
+
await this.db.command({ ping: 1 })
|
|
153
|
+
|
|
154
|
+
try {
|
|
155
|
+
const serverInfo = await this.db.admin().serverInfo()
|
|
156
|
+
this.supportsTransactions = serverInfo.repl?.replSetName !== undefined
|
|
157
|
+
|
|
158
|
+
if (!this.supportsTransactions) {
|
|
159
|
+
console.warn('⚠️ MongoDB is running in standalone mode. Transactions will not work.')
|
|
160
|
+
console.warn(' Consider setting up a replica set for transaction support.')
|
|
161
|
+
console.warn(' Example: mongod --replSet rs0 --port 27017')
|
|
162
|
+
}
|
|
163
|
+
} catch (error) {
|
|
164
|
+
console.warn('⚠️ Could not determine MongoDB deployment type:', error.message)
|
|
165
|
+
this.supportsTransactions = false
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
await this.initializeCollections()
|
|
169
|
+
|
|
170
|
+
if (this.config.log?.includes('info')) {
|
|
171
|
+
console.log('✅ Connected to MongoDB')
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
async $disconnect(): Promise<void> {
|
|
176
|
+
if (this.mongoClient) {
|
|
177
|
+
await this.mongoClient.close()
|
|
178
|
+
this.mongoClient = null
|
|
179
|
+
this.db = null
|
|
180
|
+
|
|
181
|
+
if (this.config.log?.includes('info')) {
|
|
182
|
+
console.log('👋 Disconnected from MongoDB')
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
async $transaction<T>(
|
|
188
|
+
args: Array<(tx: any) => Promise<any>> | ((tx: any) => Promise<T>),
|
|
189
|
+
options?: { maxRetry?: number; timeout?: number }
|
|
190
|
+
): Promise<any> {
|
|
191
|
+
if (!this.mongoClient) {
|
|
192
|
+
throw new Error('Not connected to database')
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
if (!this.supportsTransactions) {
|
|
196
|
+
throw new Error(
|
|
197
|
+
'Transactions are not supported in standalone MongoDB. ' +
|
|
198
|
+
'Set up a replica set or use alternative consistency patterns. ' +
|
|
199
|
+
'During development: mongod --replSet rs0 --port 27017'
|
|
200
|
+
)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const maxRetry = options?.maxRetry ?? 3;
|
|
204
|
+
|
|
205
|
+
const isTransientError = (error: any): boolean => {
|
|
206
|
+
return error?.code === 112 ||
|
|
207
|
+
error?.code === 245 ||
|
|
208
|
+
error?.code === 246 ||
|
|
209
|
+
error?.errorLabels?.includes('TransientTransactionError') ||
|
|
210
|
+
error?.errorLabels?.includes('UnknownTransactionCommitResult')
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
if (Array.isArray(args)) {
|
|
214
|
+
const session = this.mongoClient.startSession()
|
|
215
|
+
try {
|
|
216
|
+
session.startTransaction()
|
|
217
|
+
const fns = args as Array<(tx: any) => Promise<any>>;
|
|
218
|
+
const results: any[] = [];
|
|
219
|
+
for (const fn of fns) {
|
|
220
|
+
results.push(await fn(session));
|
|
221
|
+
}
|
|
222
|
+
await session.commitTransaction()
|
|
223
|
+
return results
|
|
224
|
+
} catch (error) {
|
|
225
|
+
await session.abortTransaction().catch(() => {})
|
|
226
|
+
throw error
|
|
227
|
+
} finally {
|
|
228
|
+
session.endSession()
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
let lastError: any;
|
|
233
|
+
for (let attempt = 0; attempt <= maxRetry; attempt++) {
|
|
234
|
+
const session = this.mongoClient.startSession()
|
|
235
|
+
try {
|
|
236
|
+
session.startTransaction()
|
|
237
|
+
|
|
238
|
+
const result = await (args as (tx: any) => Promise<T>)(session)
|
|
239
|
+
|
|
240
|
+
let committed = false;
|
|
241
|
+
for (let commitAttempt = 0; commitAttempt < 3; commitAttempt++) {
|
|
242
|
+
try {
|
|
243
|
+
await session.commitTransaction()
|
|
244
|
+
committed = true;
|
|
245
|
+
break;
|
|
246
|
+
} catch (commitError: any) {
|
|
247
|
+
if (commitAttempt < 2 && isTransientError(commitError)) {
|
|
248
|
+
await new Promise(r => setTimeout(r, Math.min(100 * Math.pow(2, commitAttempt), 1000)))
|
|
249
|
+
continue
|
|
250
|
+
}
|
|
251
|
+
throw commitError
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
if (!committed) {
|
|
256
|
+
throw new Error('Failed to commit transaction after retries')
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
return result
|
|
260
|
+
} catch (error: any) {
|
|
261
|
+
await session.abortTransaction().catch(() => {})
|
|
262
|
+
|
|
263
|
+
if (attempt < maxRetry && isTransientError(error)) {
|
|
264
|
+
const delay = Math.min(100 * Math.pow(2, attempt), 2000)
|
|
265
|
+
await new Promise(r => setTimeout(r, delay))
|
|
266
|
+
lastError = error
|
|
267
|
+
continue
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
throw error
|
|
271
|
+
} finally {
|
|
272
|
+
session.endSession()
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
throw lastError || new Error('Transaction failed')
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
$supportsTransactions(): boolean {
|
|
280
|
+
return this.supportsTransactions
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
private async initializeCollections(): Promise<void> {
|
|
284
|
+
if (!this.db) return
|
|
285
|
+
|
|
286
|
+
const models = ${JSON.stringify(this.getModelsForRuntime(models), null, 2)}
|
|
287
|
+
|
|
288
|
+
for (const model of models) {
|
|
289
|
+
if (!model.collectionName) continue
|
|
290
|
+
|
|
291
|
+
const collections = await this.db.listCollections({ name: model.collectionName }).toArray()
|
|
292
|
+
|
|
293
|
+
if (collections.length === 0) {
|
|
294
|
+
await this.db.createCollection(model.collectionName)
|
|
295
|
+
|
|
296
|
+
if (model.indexes.length > 0) {
|
|
297
|
+
const indexes = model.indexes.map(index => {
|
|
298
|
+
const spec: any = {
|
|
299
|
+
key: index.fields.reduce((acc, field) => {
|
|
300
|
+
const dbField = model.fieldDbNames?.[field] || field
|
|
301
|
+
acc[dbField] = 1
|
|
302
|
+
return acc
|
|
303
|
+
}, {}),
|
|
304
|
+
unique: index.unique,
|
|
305
|
+
sparse: index.sparse || false
|
|
306
|
+
};
|
|
307
|
+
if (index.name) spec.name = index.name;
|
|
308
|
+
return spec;
|
|
309
|
+
})
|
|
310
|
+
|
|
311
|
+
try {
|
|
312
|
+
await this.db.collection(model.collectionName).createIndexes(indexes)
|
|
313
|
+
} catch (error) {
|
|
314
|
+
console.warn(\`Failed to create indexes for \${model.name}:\`, error)
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// Create full-text search index (if configured)
|
|
319
|
+
if (model.fulltextFields && model.fulltextFields.length > 0) {
|
|
320
|
+
try {
|
|
321
|
+
const textIndex: any = {};
|
|
322
|
+
for (const field of model.fulltextFields) {
|
|
323
|
+
const dbField = model.fieldDbNames?.[field] || field
|
|
324
|
+
textIndex[dbField] = 'text'
|
|
325
|
+
}
|
|
326
|
+
await this.db.collection(model.collectionName).createIndex(textIndex, { name: \`\${model.collectionName}_text\` })
|
|
327
|
+
} catch (error) {
|
|
328
|
+
console.warn(\`Failed to create text index for \${model.name}:\`, error)
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
$isConnected(): boolean {
|
|
336
|
+
return this.mongoClient !== null
|
|
337
|
+
}
|
|
338
|
+
|
|
339
|
+
get $db(): Db {
|
|
340
|
+
if (!this.db) {
|
|
341
|
+
throw new Error('Database not connected. Call $connect() first.')
|
|
342
|
+
}
|
|
343
|
+
return this.db
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
get $mongo(): { client: MongoClient; ObjectId: any } {
|
|
347
|
+
if (!this.mongoClient) {
|
|
348
|
+
throw new Error('Database not connected. Call $connect() first.')
|
|
349
|
+
}
|
|
350
|
+
return {
|
|
351
|
+
client: this.mongoClient,
|
|
352
|
+
ObjectId: ObjectId
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
get $raw(): { collection: (name: string) => Collection<Document> } {
|
|
357
|
+
if (!this.db) {
|
|
358
|
+
throw new Error('Database not connected. Call $connect() first.')
|
|
359
|
+
}
|
|
360
|
+
return {
|
|
361
|
+
collection: (name: string) => this.db!.collection(name)
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
`;
|
|
366
|
+
}
|
|
367
|
+
getModelsForRuntime(models) {
|
|
368
|
+
return models.map(model => ({
|
|
369
|
+
name: model.name,
|
|
370
|
+
collectionName: model.collectionName,
|
|
371
|
+
fieldDbNames: Object.fromEntries(model.fields.filter(f => f.dbName).map(f => [f.name, f.dbName])),
|
|
372
|
+
indexes: model.indexes.map(index => {
|
|
373
|
+
const idx = {
|
|
374
|
+
fields: index.fields,
|
|
375
|
+
unique: index.unique,
|
|
376
|
+
sparse: index.sparse ?? false
|
|
377
|
+
};
|
|
378
|
+
if (index.name)
|
|
379
|
+
idx.name = index.name;
|
|
380
|
+
return idx;
|
|
381
|
+
}),
|
|
382
|
+
fulltextFields: model.fulltextFields
|
|
383
|
+
}));
|
|
384
|
+
}
|
|
385
|
+
}
|
|
386
|
+
//# sourceMappingURL=ClientGenerator.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ClientGenerator.js","sourceRoot":"","sources":["../../../src/engine/generators/ClientGenerator.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAE3C,MAAM,OAAO,eAAe;IAC1B,aAAa,CAAC,UAAkB;QAC9B,OAAO;;;WAGA,UAAU;;;;WAIV,UAAU;;;;;mBAKF,UAAU;;CAE5B,CAAC;IACA,CAAC;IAED,cAAc,CAAC,UAAkB,EAAE,MAAsB;QACvD,OAAO;;;;;;;;;EAST,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;WACX,KAAK,CAAC,IAAI,6BAA6B,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;eAE5D,UAAU;;;;;;;;;EASvB,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,KAAK,CAAC,IAAI,UAAU,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;EAsB5F,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,UAAU,KAAK,CAAC,IAAI,gBAAgB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA8NpF,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CA+E7E,CAAC;IACA,CAAC;IAED,mBAAmB,CAAC,MAAsB;QACxC,OAAO,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YAC1B,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,cAAc,EAAE,KAAK,CAAC,cAAc;YACpC,YAAY,EAAE,MAAM,CAAC,WAAW,CAC9B,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,CAChE;YACD,OAAO,EAAE,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE;gBACjC,MAAM,GAAG,GAAQ;oBACf,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,MAAM,EAAE,KAAK,CAAC,MAAM;oBACpB,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,KAAK;iBAC9B,CAAC;gBACF,IAAI,KAAK,CAAC,IAAI;oBAAE,GAAG,CAAC,IAAI,GAAG,KAAK,CAAC,IAAI,CAAC;gBACtC,OAAO,GAAG,CAAC;YACb,CAAC,CAAC;YACF,cAAc,EAAE,KAAK,CAAC,cAAc;SACrC,CAAC,CAAC,CAAC;IACN,CAAC;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { GraphQLModel } from '../GraphQLParser.js';
|
|
2
|
+
export declare class DelegateGenerator {
|
|
3
|
+
private helpers;
|
|
4
|
+
private relations;
|
|
5
|
+
generateModelsIndex(models: GraphQLModel[]): string;
|
|
6
|
+
generateModelFiles(models: GraphQLModel[]): Record<string, string>;
|
|
7
|
+
generateModelDelegate(model: GraphQLModel, collectionNameMap?: Record<string, string>): string;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=DelegateGenerator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"DelegateGenerator.d.ts","sourceRoot":"","sources":["../../../src/engine/generators/DelegateGenerator.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAKnD,qBAAa,iBAAiB;IAC5B,OAAO,CAAC,OAAO,CAAyB;IACxC,OAAO,CAAC,SAAS,CAA2B;IAE5C,mBAAmB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM;IAInD,kBAAkB,CAAC,MAAM,EAAE,YAAY,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;IAWlE,qBAAqB,CAAC,KAAK,EAAE,YAAY,EAAE,iBAAiB,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,GAAG,MAAM;CAgbnG"}
|