@rapidd/build 2.0.3 → 2.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (60) hide show
  1. package/README.md +26 -165
  2. package/dist/bin/cli.js +0 -2
  3. package/dist/bin/cli.js.map +1 -1
  4. package/dist/index.d.ts +2 -11
  5. package/dist/index.d.ts.map +1 -1
  6. package/dist/index.js +1 -12
  7. package/dist/index.js.map +1 -1
  8. package/dist/src/commands/build.d.ts +1 -3
  9. package/dist/src/commands/build.d.ts.map +1 -1
  10. package/dist/src/commands/build.js +2 -107
  11. package/dist/src/commands/build.js.map +1 -1
  12. package/dist/src/generators/aclGenerator.d.ts +2 -2
  13. package/dist/src/generators/aclGenerator.d.ts.map +1 -1
  14. package/dist/src/generators/aclGenerator.js +11 -304
  15. package/dist/src/generators/aclGenerator.js.map +1 -1
  16. package/dist/src/generators/index.d.ts +1 -1
  17. package/dist/src/generators/index.d.ts.map +1 -1
  18. package/dist/src/generators/index.js +3 -1
  19. package/dist/src/generators/index.js.map +1 -1
  20. package/dist/src/generators/modelGenerator.d.ts +1 -1
  21. package/dist/src/generators/modelGenerator.d.ts.map +1 -1
  22. package/dist/src/generators/modelGenerator.js +46 -16
  23. package/dist/src/generators/modelGenerator.js.map +1 -1
  24. package/dist/src/generators/routeGenerator.d.ts +25 -5
  25. package/dist/src/generators/routeGenerator.d.ts.map +1 -1
  26. package/dist/src/generators/routeGenerator.js +397 -15
  27. package/dist/src/generators/routeGenerator.js.map +1 -1
  28. package/dist/src/parsers/index.d.ts +1 -10
  29. package/dist/src/parsers/index.d.ts.map +1 -1
  30. package/dist/src/parsers/index.js +1 -14
  31. package/dist/src/parsers/index.js.map +1 -1
  32. package/dist/src/parsers/prismaParser.d.ts +1 -1
  33. package/dist/src/parsers/prismaParser.d.ts.map +1 -1
  34. package/dist/src/parsers/prismaParser.js +20 -5
  35. package/dist/src/parsers/prismaParser.js.map +1 -1
  36. package/dist/src/parsers/types.d.ts +34 -0
  37. package/dist/src/parsers/types.d.ts.map +1 -0
  38. package/dist/src/parsers/types.js +3 -0
  39. package/dist/src/parsers/types.js.map +1 -0
  40. package/package.json +14 -19
  41. package/dist/src/parsers/datasourceParser.d.ts +0 -11
  42. package/dist/src/parsers/datasourceParser.d.ts.map +0 -1
  43. package/dist/src/parsers/datasourceParser.js +0 -131
  44. package/dist/src/parsers/datasourceParser.js.map +0 -1
  45. package/dist/src/parsers/deepSQLAnalyzer.d.ts +0 -85
  46. package/dist/src/parsers/deepSQLAnalyzer.d.ts.map +0 -1
  47. package/dist/src/parsers/deepSQLAnalyzer.js +0 -482
  48. package/dist/src/parsers/deepSQLAnalyzer.js.map +0 -1
  49. package/dist/src/parsers/enhancedRLSConverter.d.ts +0 -14
  50. package/dist/src/parsers/enhancedRLSConverter.d.ts.map +0 -1
  51. package/dist/src/parsers/enhancedRLSConverter.js +0 -168
  52. package/dist/src/parsers/enhancedRLSConverter.js.map +0 -1
  53. package/dist/src/parsers/functionAnalyzer.d.ts +0 -55
  54. package/dist/src/parsers/functionAnalyzer.d.ts.map +0 -1
  55. package/dist/src/parsers/functionAnalyzer.js +0 -274
  56. package/dist/src/parsers/functionAnalyzer.js.map +0 -1
  57. package/dist/src/parsers/prismaFilterBuilder.d.ts +0 -79
  58. package/dist/src/parsers/prismaFilterBuilder.d.ts.map +0 -1
  59. package/dist/src/parsers/prismaFilterBuilder.js +0 -322
  60. package/dist/src/parsers/prismaFilterBuilder.js.map +0 -1
@@ -34,6 +34,8 @@ var __importStar = (this && this.__importStar) || (function () {
34
34
  })();
35
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
36
  exports.generateRouteFile = generateRouteFile;
37
+ exports.generateParentRouteFile = generateParentRouteFile;
38
+ exports.generateSubRouteFile = generateSubRouteFile;
37
39
  exports.generateAllRoutes = generateAllRoutes;
38
40
  const fs = __importStar(require("fs"));
39
41
  const path = __importStar(require("path"));
@@ -47,13 +49,226 @@ function toClassName(modelName) {
47
49
  .map(word => word.charAt(0).toUpperCase() + word.slice(1))
48
50
  .join('');
49
51
  }
52
+ const numericTypes = ['Int', 'Float', 'Decimal', 'BigInt'];
50
53
  /**
51
- * Generate Fastify route for a single model (TypeScript)
54
+ * Detect if the primary key field is numeric
52
55
  */
53
- function generateRouteFile(modelName) {
56
+ function isNumericId(modelInfo) {
57
+ for (const field of Object.values(modelInfo.fields)) {
58
+ if (field.isId && numericTypes.includes(field.type)) {
59
+ return true;
60
+ }
61
+ }
62
+ return false;
63
+ }
64
+ // ─── Junction table detection ────────────────────────────────────────
65
+ const AUDIT_FK_FIELDS = ['createdBy', 'updatedBy'];
66
+ /**
67
+ * Detect if a model is a junction (n:m) table.
68
+ * A junction table has exactly 2 non-audit, non-self FK relations
69
+ * AND a composite primary key or compound unique constraint covering both FK fields.
70
+ */
71
+ function detectJunctionTable(modelName, modelInfo) {
72
+ const parentRelations = [];
73
+ for (const rel of modelInfo.relations) {
74
+ if (!rel.relationFromFields || rel.relationFromFields.length === 0)
75
+ continue;
76
+ if (rel.type === modelName)
77
+ continue;
78
+ const isAudit = rel.relationFromFields.every(f => AUDIT_FK_FIELDS.includes(f));
79
+ if (isAudit)
80
+ continue;
81
+ parentRelations.push({
82
+ fkField: rel.relationFromFields[0],
83
+ parentModel: rel.type,
84
+ });
85
+ }
86
+ if (parentRelations.length !== 2) {
87
+ return { isJunction: false, parentRelations };
88
+ }
89
+ // Require a composite key or compound unique constraint that includes both FK fields
90
+ const fkFields = parentRelations.map(r => r.fkField);
91
+ const hasCompositePK = modelInfo.compositeKey !== null &&
92
+ fkFields.every(f => modelInfo.compositeKey.includes(f));
93
+ const hasCompoundUnique = modelInfo.uniqueFields.some(uf => fkFields.every(f => uf.includes(f)));
94
+ return {
95
+ isJunction: hasCompositePK || hasCompoundUnique,
96
+ parentRelations,
97
+ };
98
+ }
99
+ /**
100
+ * Normalise a word for prefix comparison (strip trailing plural 's'/'es').
101
+ */
102
+ function singularize(word) {
103
+ if (word.endsWith('ies'))
104
+ return word.slice(0, -3) + 'y';
105
+ if (word.endsWith('ses') || word.endsWith('xes') || word.endsWith('zes') || word.endsWith('ches') || word.endsWith('shes'))
106
+ return word.slice(0, -2);
107
+ if (word.endsWith('s') && !word.endsWith('ss'))
108
+ return word.slice(0, -1);
109
+ return word;
110
+ }
111
+ /**
112
+ * Derive sub-route name by stripping the common leading word(s)
113
+ * between parent model name and junction table name.
114
+ * Handles plural/singular differences (e.g. "messages" vs "message_attachments").
115
+ */
116
+ function computeSubRouteName(parentName, junctionName) {
117
+ const parentWords = parentName.split('_');
118
+ const junctionWords = junctionName.split('_');
119
+ let commonCount = 0;
120
+ for (let i = 0; i < Math.min(parentWords.length, junctionWords.length); i++) {
121
+ if (singularize(parentWords[i]) === singularize(junctionWords[i])) {
122
+ commonCount++;
123
+ }
124
+ else {
125
+ break;
126
+ }
127
+ }
128
+ if (commonCount > 0 && commonCount < junctionWords.length) {
129
+ return junctionWords.slice(commonCount).join('_');
130
+ }
131
+ return junctionName;
132
+ }
133
+ /**
134
+ * Analyse all models and build the junction / parent-sub-route map.
135
+ */
136
+ function buildJunctionMap(models) {
137
+ const junctionModels = new Set();
138
+ const parentSubRoutes = new Map();
139
+ for (const [modelName, modelInfo] of Object.entries(models)) {
140
+ const junction = detectJunctionTable(modelName, modelInfo);
141
+ if (!junction.isJunction)
142
+ continue;
143
+ junctionModels.add(modelName);
144
+ for (let i = 0; i < junction.parentRelations.length; i++) {
145
+ const parentRel = junction.parentRelations[i];
146
+ const otherRel = junction.parentRelations[1 - i];
147
+ if (!models[parentRel.parentModel])
148
+ continue;
149
+ if (!parentSubRoutes.has(parentRel.parentModel)) {
150
+ parentSubRoutes.set(parentRel.parentModel, []);
151
+ }
152
+ parentSubRoutes.get(parentRel.parentModel).push({
153
+ junctionModelName: modelName,
154
+ junctionModelInfo: modelInfo,
155
+ subRouteName: computeSubRouteName(parentRel.parentModel, modelName),
156
+ fkFieldToParent: parentRel.fkField,
157
+ otherFkField: otherRel.fkField,
158
+ });
159
+ }
160
+ }
161
+ // Remove sub-route entries where the parent is itself a junction table
162
+ for (const parentModel of parentSubRoutes.keys()) {
163
+ if (junctionModels.has(parentModel)) {
164
+ parentSubRoutes.delete(parentModel);
165
+ }
166
+ }
167
+ return { junctionModels, parentSubRoutes };
168
+ }
169
+ // ─── Route file generators ──────────────────────────────────────────
170
+ /**
171
+ * Generate Fastify route for a standalone model (TypeScript)
172
+ */
173
+ function generateRouteFile(modelName, modelInfo, importPathPrefix = '../../../src/models') {
174
+ const className = toClassName(modelName);
175
+ const numeric = isNumericId(modelInfo);
176
+ const idType = numeric ? 'number' : 'string';
177
+ const idCast = numeric ? 'Number(rawId)' : 'rawId';
178
+ return `import { FastifyPluginAsync, FastifyRequest, FastifyReply } from 'fastify';
179
+ import { ${className}, QueryBuilder } from '${importPathPrefix}/${className}';
180
+
181
+ const ${modelName}Routes: FastifyPluginAsync = async (fastify) => {
182
+ fastify.addHook('preHandler', async (request, reply) => {
183
+ if (!request.user) {
184
+ return reply.sendError(401, 'no_valid_session');
185
+ }
186
+ (request as any).${className} = new ${className}({ user: request.user });
187
+ });
188
+
189
+ fastify.get('/', async (request: FastifyRequest, reply: FastifyReply) => {
190
+ try {
191
+ const { q = {}, include = '', limit = '25', offset = '0', sortBy = 'id', sortOrder = 'asc' } = request.query as Record<string, string>;
192
+ const model = (request as any).${className} as ${className};
193
+ const results = await model.getMany(q, include, Number(limit), Number(offset), sortBy, sortOrder as 'asc' | 'desc');
194
+ return reply.sendList(results.data, results.meta);
195
+ } catch (error: any) {
196
+ const response = QueryBuilder.errorHandler(error);
197
+ return reply.code(response.status_code).send(response);
198
+ }
199
+ });
200
+
201
+ fastify.get('/:id', async (request: FastifyRequest, reply: FastifyReply) => {
202
+ try {
203
+ const { id: rawId } = request.params as { id: string };
204
+ const id: ${idType} = ${idCast};
205
+ const { include = '' } = request.query as { include?: string };
206
+ const model = (request as any).${className} as ${className};
207
+ const response = await model.get(id, include);
208
+ return reply.send(response);
209
+ } catch (error: any) {
210
+ const response = QueryBuilder.errorHandler(error);
211
+ return reply.code(response.status_code).send(response);
212
+ }
213
+ });
214
+
215
+ fastify.post('/', async (request: FastifyRequest, reply: FastifyReply) => {
216
+ const payload = request.body as Record<string, unknown>;
217
+ try {
218
+ const model = (request as any).${className} as ${className};
219
+ const response = await model.create(payload);
220
+ return reply.code(201).send(response);
221
+ } catch (error: any) {
222
+ const response = QueryBuilder.errorHandler(error, payload);
223
+ return reply.code(response.status_code).send(response);
224
+ }
225
+ });
226
+
227
+ fastify.patch('/:id', async (request: FastifyRequest, reply: FastifyReply) => {
228
+ const { id: rawId } = request.params as { id: string };
229
+ const id: ${idType} = ${idCast};
230
+ const payload = request.body as Record<string, unknown>;
231
+ try {
232
+ const model = (request as any).${className} as ${className};
233
+ const response = await model.update(id, payload);
234
+ return reply.send(response);
235
+ } catch (error: any) {
236
+ const response = QueryBuilder.errorHandler(error, payload);
237
+ return reply.code(response.status_code).send(response);
238
+ }
239
+ });
240
+
241
+ fastify.delete('/:id', async (request: FastifyRequest, reply: FastifyReply) => {
242
+ try {
243
+ const { id: rawId } = request.params as { id: string };
244
+ const id: ${idType} = ${idCast};
245
+ const model = (request as any).${className} as ${className};
246
+ await model.delete(id);
247
+ return reply.sendResponse(200, 'object_deleted_successfully', { modelName: '${className}' });
248
+ } catch (error: any) {
249
+ const response = QueryBuilder.errorHandler(error);
250
+ return reply.code(response.status_code).send(response);
251
+ }
252
+ });
253
+ };
254
+
255
+ export default ${modelName}Routes;
256
+ `;
257
+ }
258
+ /**
259
+ * Generate Fastify route for a parent model that has sub-routes (TypeScript)
260
+ */
261
+ function generateParentRouteFile(modelName, modelInfo, subRoutes) {
54
262
  const className = toClassName(modelName);
263
+ const numeric = isNumericId(modelInfo);
264
+ const idType = numeric ? 'number' : 'string';
265
+ const idCast = numeric ? 'Number(rawId)' : 'rawId';
266
+ const importPath = '../../../../src/models';
267
+ const subRouteImports = subRoutes.map(sr => `import ${sr.subRouteName}Routes from './_${sr.subRouteName}';`).join('\n');
268
+ const subRouteRegistrations = subRoutes.map(sr => ` fastify.register(${sr.subRouteName}Routes, { prefix: '/:id/${sr.subRouteName}' });`).join('\n');
55
269
  return `import { FastifyPluginAsync, FastifyRequest, FastifyReply } from 'fastify';
56
- import { ${className}, QueryBuilder } from '../../../src/models/${className}';
270
+ import { ${className}, QueryBuilder } from '${importPath}/${className}';
271
+ ${subRouteImports}
57
272
 
58
273
  const ${modelName}Routes: FastifyPluginAsync = async (fastify) => {
59
274
  fastify.addHook('preHandler', async (request, reply) => {
@@ -63,6 +278,8 @@ const ${modelName}Routes: FastifyPluginAsync = async (fastify) => {
63
278
  (request as any).${className} = new ${className}({ user: request.user });
64
279
  });
65
280
 
281
+ ${subRouteRegistrations}
282
+
66
283
  fastify.get('/', async (request: FastifyRequest, reply: FastifyReply) => {
67
284
  try {
68
285
  const { q = {}, include = '', limit = '25', offset = '0', sortBy = 'id', sortOrder = 'asc' } = request.query as Record<string, string>;
@@ -77,7 +294,8 @@ const ${modelName}Routes: FastifyPluginAsync = async (fastify) => {
77
294
 
78
295
  fastify.get('/:id', async (request: FastifyRequest, reply: FastifyReply) => {
79
296
  try {
80
- const { id } = request.params as { id: string };
297
+ const { id: rawId } = request.params as { id: string };
298
+ const id: ${idType} = ${idCast};
81
299
  const { include = '' } = request.query as { include?: string };
82
300
  const model = (request as any).${className} as ${className};
83
301
  const response = await model.get(id, include);
@@ -101,7 +319,8 @@ const ${modelName}Routes: FastifyPluginAsync = async (fastify) => {
101
319
  });
102
320
 
103
321
  fastify.patch('/:id', async (request: FastifyRequest, reply: FastifyReply) => {
104
- const { id } = request.params as { id: string };
322
+ const { id: rawId } = request.params as { id: string };
323
+ const id: ${idType} = ${idCast};
105
324
  const payload = request.body as Record<string, unknown>;
106
325
  try {
107
326
  const model = (request as any).${className} as ${className};
@@ -115,7 +334,8 @@ const ${modelName}Routes: FastifyPluginAsync = async (fastify) => {
115
334
 
116
335
  fastify.delete('/:id', async (request: FastifyRequest, reply: FastifyReply) => {
117
336
  try {
118
- const { id } = request.params as { id: string };
337
+ const { id: rawId } = request.params as { id: string };
338
+ const id: ${idType} = ${idCast};
119
339
  const model = (request as any).${className} as ${className};
120
340
  await model.delete(id);
121
341
  return reply.sendResponse(200, 'object_deleted_successfully', { modelName: '${className}' });
@@ -130,19 +350,181 @@ export default ${modelName}Routes;
130
350
  `;
131
351
  }
132
352
  /**
133
- * Generate all route files
353
+ * Check if a specific field in a model is numeric
354
+ */
355
+ function isFieldNumeric(modelInfo, fieldName) {
356
+ const field = modelInfo.fields[fieldName];
357
+ return !!field && numericTypes.includes(field.type);
358
+ }
359
+ /**
360
+ * Generate Fastify sub-route for a junction table (TypeScript).
361
+ * Uses composite key { fkFieldToParent: parentId, otherFkField: subId }
362
+ * for get, update, and delete operations.
363
+ */
364
+ function generateSubRouteFile(junctionModelName, junctionModelInfo, parentModelInfo, fkFieldToParent, otherFkField) {
365
+ const className = toClassName(junctionModelName);
366
+ const numericParentId = isNumericId(parentModelInfo);
367
+ const numericOtherFk = isFieldNumeric(junctionModelInfo, otherFkField);
368
+ const parentIdType = numericParentId ? 'number' : 'string';
369
+ const otherFkType = numericOtherFk ? 'number' : 'string';
370
+ const parentIdCast = numericParentId ? 'Number(rawParentId)' : 'rawParentId';
371
+ const otherFkCast = numericOtherFk ? 'Number(rawSubId)' : 'rawSubId';
372
+ const importPath = '../../../../src/models';
373
+ return `import { FastifyPluginAsync, FastifyRequest, FastifyReply } from 'fastify';
374
+ import { ${className}, QueryBuilder } from '${importPath}/${className}';
375
+
376
+ const ${junctionModelName}Routes: FastifyPluginAsync = async (fastify) => {
377
+ fastify.addHook('preHandler', async (request, reply) => {
378
+ if (!request.user) {
379
+ return reply.sendError(401, 'no_valid_session');
380
+ }
381
+ (request as any).${className} = new ${className}({ user: request.user });
382
+ });
383
+
384
+ fastify.get('/', async (request: FastifyRequest, reply: FastifyReply) => {
385
+ try {
386
+ const { id: rawParentId } = request.params as { id: string };
387
+ const parentId: ${parentIdType} = ${parentIdCast};
388
+ const { q = {}, include = '', limit = '25', offset = '0', sortBy = 'id', sortOrder = 'asc' } = request.query as Record<string, string>;
389
+ const filter = typeof q === 'object' ? { ...q, ${fkFieldToParent}: parentId } : { ${fkFieldToParent}: parentId };
390
+ const model = (request as any).${className} as ${className};
391
+ const results = await model.getMany(filter, include, Number(limit), Number(offset), sortBy, sortOrder as 'asc' | 'desc');
392
+ return reply.sendList(results.data, results.meta);
393
+ } catch (error: any) {
394
+ const response = QueryBuilder.errorHandler(error);
395
+ return reply.code(response.status_code).send(response);
396
+ }
397
+ });
398
+
399
+ fastify.get('/:subId', async (request: FastifyRequest, reply: FastifyReply) => {
400
+ try {
401
+ const { id: rawParentId, subId: rawSubId } = request.params as { id: string; subId: string };
402
+ const parentId: ${parentIdType} = ${parentIdCast};
403
+ const ${otherFkField}: ${otherFkType} = ${otherFkCast};
404
+ const compositeId = { ${fkFieldToParent}: parentId, ${otherFkField} };
405
+ const { include = '' } = request.query as { include?: string };
406
+ const model = (request as any).${className} as ${className};
407
+ const response = await model.get(compositeId, include);
408
+ return reply.send(response);
409
+ } catch (error: any) {
410
+ const response = QueryBuilder.errorHandler(error);
411
+ return reply.code(response.status_code).send(response);
412
+ }
413
+ });
414
+
415
+ fastify.post('/', async (request: FastifyRequest, reply: FastifyReply) => {
416
+ const { id: rawParentId } = request.params as { id: string };
417
+ const parentId: ${parentIdType} = ${parentIdCast};
418
+ const payload = { ...(request.body as Record<string, unknown>), ${fkFieldToParent}: parentId };
419
+ try {
420
+ const model = (request as any).${className} as ${className};
421
+ const response = await model.create(payload);
422
+ return reply.code(201).send(response);
423
+ } catch (error: any) {
424
+ const response = QueryBuilder.errorHandler(error, payload);
425
+ return reply.code(response.status_code).send(response);
426
+ }
427
+ });
428
+
429
+ fastify.patch('/:subId', async (request: FastifyRequest, reply: FastifyReply) => {
430
+ const { id: rawParentId, subId: rawSubId } = request.params as { id: string; subId: string };
431
+ const parentId: ${parentIdType} = ${parentIdCast};
432
+ const ${otherFkField}: ${otherFkType} = ${otherFkCast};
433
+ const compositeId = { ${fkFieldToParent}: parentId, ${otherFkField} };
434
+ const payload = request.body as Record<string, unknown>;
435
+ try {
436
+ const model = (request as any).${className} as ${className};
437
+ const response = await model.update(compositeId, payload);
438
+ return reply.send(response);
439
+ } catch (error: any) {
440
+ const response = QueryBuilder.errorHandler(error, payload);
441
+ return reply.code(response.status_code).send(response);
442
+ }
443
+ });
444
+
445
+ fastify.delete('/:subId', async (request: FastifyRequest, reply: FastifyReply) => {
446
+ try {
447
+ const { id: rawParentId, subId: rawSubId } = request.params as { id: string; subId: string };
448
+ const parentId: ${parentIdType} = ${parentIdCast};
449
+ const ${otherFkField}: ${otherFkType} = ${otherFkCast};
450
+ const compositeId = { ${fkFieldToParent}: parentId, ${otherFkField} };
451
+ const model = (request as any).${className} as ${className};
452
+ await model.delete(compositeId);
453
+ return reply.sendResponse(200, 'object_deleted_successfully', { modelName: '${className}' });
454
+ } catch (error: any) {
455
+ const response = QueryBuilder.errorHandler(error);
456
+ return reply.code(response.status_code).send(response);
457
+ }
458
+ });
459
+ };
460
+
461
+ export default ${junctionModelName}Routes;
462
+ `;
463
+ }
464
+ // ─── Main generation orchestrator ───────────────────────────────────
465
+ /**
466
+ * Generate all route files with junction-table-aware nested structure.
467
+ * @param models Models to generate routes for (may be filtered by --model)
468
+ * @param routesDir Output directory (e.g. routes/api/v1)
469
+ * @param allModels Full models map for junction detection (defaults to models)
134
470
  */
135
- function generateAllRoutes(models, routesDir) {
136
- // Create routes directory if it doesn't exist
471
+ function generateAllRoutes(models, routesDir, allModels) {
137
472
  if (!fs.existsSync(routesDir)) {
138
473
  fs.mkdirSync(routesDir, { recursive: true });
139
474
  }
140
- // Generate individual route files
141
- for (const modelName of Object.keys(models)) {
142
- const routeCode = generateRouteFile(modelName);
143
- const routePath = path.join(routesDir, `${modelName}.ts`);
144
- fs.writeFileSync(routePath, routeCode);
145
- console.log(`Generated route: ${modelName}.ts`);
475
+ const { junctionModels, parentSubRoutes } = buildJunctionMap(allModels ?? models);
476
+ for (const [modelName, modelInfo] of Object.entries(models)) {
477
+ // Skip junction tables – they become sub-routes, not standalone files
478
+ if (junctionModels.has(modelName)) {
479
+ console.log(`Skipped route (junction table): ${modelName}`);
480
+ continue;
481
+ }
482
+ const subRoutes = parentSubRoutes.get(modelName);
483
+ if (subRoutes && subRoutes.length > 0) {
484
+ // ── Parent model with sub-routes → directory structure ──
485
+ const parentDir = path.join(routesDir, modelName);
486
+ const indexPath = path.join(parentDir, 'index.ts');
487
+ // If a legacy flat file exists, skip entirely (never overwrite)
488
+ const legacyFlatPath = path.join(routesDir, `${modelName}.ts`);
489
+ if (fs.existsSync(legacyFlatPath)) {
490
+ console.log(`Skipped route (legacy flat file exists): ${modelName}.ts`);
491
+ continue;
492
+ }
493
+ if (!fs.existsSync(parentDir)) {
494
+ fs.mkdirSync(parentDir, { recursive: true });
495
+ }
496
+ // Generate parent index.ts
497
+ if (fs.existsSync(indexPath)) {
498
+ console.log(`Skipped route (exists): ${modelName}/index.ts`);
499
+ }
500
+ else {
501
+ const parentCode = generateParentRouteFile(modelName, modelInfo, subRoutes);
502
+ fs.writeFileSync(indexPath, parentCode);
503
+ console.log(`Generated route: ${modelName}/index.ts`);
504
+ }
505
+ // Generate each sub-route file
506
+ for (const sr of subRoutes) {
507
+ const subRoutePath = path.join(parentDir, `_${sr.subRouteName}.ts`);
508
+ if (fs.existsSync(subRoutePath)) {
509
+ console.log(`Skipped sub-route (exists): ${modelName}/_${sr.subRouteName}.ts`);
510
+ continue;
511
+ }
512
+ const subRouteCode = generateSubRouteFile(sr.junctionModelName, sr.junctionModelInfo, modelInfo, sr.fkFieldToParent, sr.otherFkField);
513
+ fs.writeFileSync(subRoutePath, subRouteCode);
514
+ console.log(`Generated sub-route: ${modelName}/_${sr.subRouteName}.ts`);
515
+ }
516
+ }
517
+ else {
518
+ // ── Standalone model → flat file (unchanged behaviour) ──
519
+ const routePath = path.join(routesDir, `${modelName}.ts`);
520
+ if (fs.existsSync(routePath)) {
521
+ console.log(`Skipped route (exists): ${modelName}.ts`);
522
+ continue;
523
+ }
524
+ const routeCode = generateRouteFile(modelName, modelInfo);
525
+ fs.writeFileSync(routePath, routeCode);
526
+ console.log(`Generated route: ${modelName}.ts`);
527
+ }
146
528
  }
147
529
  }
148
530
  //# sourceMappingURL=routeGenerator.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"routeGenerator.js","sourceRoot":"","sources":["../../../src/generators/routeGenerator.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAkBA,8CA+EC;AAKD,8CAaC;AAnHD,uCAAyB;AACzB,2CAA6B;AAG7B;;GAEG;AACH,SAAS,WAAW,CAAC,SAAiB;IACpC,OAAO,SAAS;SACb,KAAK,CAAC,eAAe,CAAC;SACtB,MAAM,CAAC,OAAO,CAAC;SACf,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,WAAW,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;SACzD,IAAI,CAAC,EAAE,CAAC,CAAC;AACd,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB,CAAC,SAAiB;IACjD,MAAM,SAAS,GAAG,WAAW,CAAC,SAAS,CAAC,CAAC;IAEzC,OAAO;WACE,SAAS,8CAA8C,SAAS;;QAEnE,SAAS;;;;;2BAKU,SAAS,UAAU,SAAS;;;;;;6CAMV,SAAS,OAAO,SAAS;;;;;;;;;;;;;6CAazB,SAAS,OAAO,SAAS;;;;;;;;;;;;6CAYzB,SAAS,OAAO,SAAS;;;;;;;;;;;;;6CAazB,SAAS,OAAO,SAAS;;;;;;;;;;;;6CAYzB,SAAS,OAAO,SAAS;;0FAEoB,SAAS;;;;;;;;iBAQlF,SAAS;CACzB,CAAC;AACF,CAAC;AAED;;GAEG;AACH,SAAgB,iBAAiB,CAAC,MAAiC,EAAE,SAAiB;IACpF,8CAA8C;IAC9C,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC9B,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,kCAAkC;IAClC,KAAK,MAAM,SAAS,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,EAAE,CAAC;QAC5C,MAAM,SAAS,GAAG,iBAAiB,CAAC,SAAS,CAAC,CAAC;QAC/C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,GAAG,SAAS,KAAK,CAAC,CAAC;QAC1D,EAAE,CAAC,aAAa,CAAC,SAAS,EAAE,SAAS,CAAC,CAAC;QACvC,OAAO,CAAC,GAAG,CAAC,oBAAoB,SAAS,KAAK,CAAC,CAAC;IAClD,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"routeGenerator.js","sourceRoot":"","sources":["../../../src/generators/routeGenerator.ts"],"names":[],"mappings":"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"}
@@ -1,13 +1,4 @@
1
1
  export { parsePrismaSchema, parsePrismaDMMF } from './prismaParser';
2
2
  export type { ParsedSchema } from './prismaParser';
3
- export { parseDatasource } from './datasourceParser';
4
- export type { DatasourceConfig } from './datasourceParser';
5
- export { DeepSQLAnalyzer } from './deepSQLAnalyzer';
6
- export type { SQLFilter, SQLCondition, SQLAnalysis } from './deepSQLAnalyzer';
7
- export { PrismaFilterBuilder } from './prismaFilterBuilder';
8
- export type { ModelField, ModelRelation, ModelInfo, RelationshipInfo } from './prismaFilterBuilder';
9
- export { createEnhancedConverter } from './enhancedRLSConverter';
10
- export type { EnhancedConverter } from './enhancedRLSConverter';
11
- export { analyzeFunctions, analyzeFunctionBody, generateMappingConfig } from './functionAnalyzer';
12
- export type { FunctionMapping, FunctionAnalysisResult, MappingConfig } from './functionAnalyzer';
3
+ export type { ModelField, ModelRelation, ModelInfo } from './types';
13
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/parsers/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACpE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,YAAY,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AAE3D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,YAAY,EAAE,SAAS,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAE9E,OAAO,EAAE,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAC5D,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,gBAAgB,EAAE,MAAM,uBAAuB,CAAC;AAEpG,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,YAAY,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AAEhE,OAAO,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC;AAClG,YAAY,EAAE,eAAe,EAAE,sBAAsB,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/parsers/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,iBAAiB,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAC;AACpE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,YAAY,EAAE,UAAU,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC"}
@@ -1,20 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateMappingConfig = exports.analyzeFunctionBody = exports.analyzeFunctions = exports.createEnhancedConverter = exports.PrismaFilterBuilder = exports.DeepSQLAnalyzer = exports.parseDatasource = exports.parsePrismaDMMF = exports.parsePrismaSchema = void 0;
4
- // Re-export all parsers
3
+ exports.parsePrismaDMMF = exports.parsePrismaSchema = void 0;
5
4
  var prismaParser_1 = require("./prismaParser");
6
5
  Object.defineProperty(exports, "parsePrismaSchema", { enumerable: true, get: function () { return prismaParser_1.parsePrismaSchema; } });
7
6
  Object.defineProperty(exports, "parsePrismaDMMF", { enumerable: true, get: function () { return prismaParser_1.parsePrismaDMMF; } });
8
- var datasourceParser_1 = require("./datasourceParser");
9
- Object.defineProperty(exports, "parseDatasource", { enumerable: true, get: function () { return datasourceParser_1.parseDatasource; } });
10
- var deepSQLAnalyzer_1 = require("./deepSQLAnalyzer");
11
- Object.defineProperty(exports, "DeepSQLAnalyzer", { enumerable: true, get: function () { return deepSQLAnalyzer_1.DeepSQLAnalyzer; } });
12
- var prismaFilterBuilder_1 = require("./prismaFilterBuilder");
13
- Object.defineProperty(exports, "PrismaFilterBuilder", { enumerable: true, get: function () { return prismaFilterBuilder_1.PrismaFilterBuilder; } });
14
- var enhancedRLSConverter_1 = require("./enhancedRLSConverter");
15
- Object.defineProperty(exports, "createEnhancedConverter", { enumerable: true, get: function () { return enhancedRLSConverter_1.createEnhancedConverter; } });
16
- var functionAnalyzer_1 = require("./functionAnalyzer");
17
- Object.defineProperty(exports, "analyzeFunctions", { enumerable: true, get: function () { return functionAnalyzer_1.analyzeFunctions; } });
18
- Object.defineProperty(exports, "analyzeFunctionBody", { enumerable: true, get: function () { return functionAnalyzer_1.analyzeFunctionBody; } });
19
- Object.defineProperty(exports, "generateMappingConfig", { enumerable: true, get: function () { return functionAnalyzer_1.generateMappingConfig; } });
20
7
  //# sourceMappingURL=index.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/parsers/index.ts"],"names":[],"mappings":";;;AAAA,wBAAwB;AACxB,+CAAoE;AAA3D,iHAAA,iBAAiB,OAAA;AAAE,+GAAA,eAAe,OAAA;AAG3C,uDAAqD;AAA5C,mHAAA,eAAe,OAAA;AAGxB,qDAAoD;AAA3C,kHAAA,eAAe,OAAA;AAGxB,6DAA4D;AAAnD,0HAAA,mBAAmB,OAAA;AAG5B,+DAAiE;AAAxD,+HAAA,uBAAuB,OAAA;AAGhC,uDAAkG;AAAzF,oHAAA,gBAAgB,OAAA;AAAE,uHAAA,mBAAmB,OAAA;AAAE,yHAAA,qBAAqB,OAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/parsers/index.ts"],"names":[],"mappings":";;;AAAA,+CAAoE;AAA3D,iHAAA,iBAAiB,OAAA;AAAE,+GAAA,eAAe,OAAA"}
@@ -1,4 +1,4 @@
1
- import type { ModelInfo } from './prismaFilterBuilder';
1
+ import type { ModelInfo } from './types';
2
2
  export interface ParsedSchema {
3
3
  models: Record<string, ModelInfo>;
4
4
  enums: Record<string, string[]>;
@@ -1 +1 @@
1
- {"version":3,"file":"prismaParser.d.ts","sourceRoot":"","sources":["../../../src/parsers/prismaParser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAA6B,MAAM,uBAAuB,CAAC;AAElF,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACjC;AA8BD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CAqClE;AAuHD;;GAEG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAqEtF"}
1
+ {"version":3,"file":"prismaParser.d.ts","sourceRoot":"","sources":["../../../src/parsers/prismaParser.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,SAAS,EAA6B,MAAM,SAAS,CAAC;AAEpE,MAAM,WAAW,YAAY;IAC3B,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;IAClC,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;CACjC;AA8BD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,YAAY,CAsClE;AAwID;;GAEG;AACH,wBAAsB,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC,CAsEtF"}
@@ -86,6 +86,7 @@ function parsePrismaSchema(schemaPath) {
86
86
  fields,
87
87
  relations: parseModelRelations(body),
88
88
  compositeKey: compositeKeyFields,
89
+ uniqueFields: parseUniqueFields(body),
89
90
  dbName: dbName || name.toLowerCase() // Default to lowercase model name
90
91
  };
91
92
  }
@@ -112,6 +113,20 @@ function parseCompositeKey(modelBody) {
112
113
  }
113
114
  return null;
114
115
  }
116
+ /**
117
+ * Parse @@unique directives to get compound unique constraints
118
+ */
119
+ function parseUniqueFields(modelBody) {
120
+ const result = [];
121
+ const lines = modelBody.split('\n').map(line => line.trim());
122
+ for (const line of lines) {
123
+ const match = line.match(/^@@unique\(\[([^\]]+)\]\)/);
124
+ if (match) {
125
+ result.push(match[1].split(',').map(f => f.trim()));
126
+ }
127
+ }
128
+ return result;
129
+ }
115
130
  /**
116
131
  * Parse @@map directive to get database table name
117
132
  */
@@ -200,14 +215,11 @@ function parseEnumValues(enumBody) {
200
215
  */
201
216
  async function parsePrismaDMMF(schemaPath) {
202
217
  try {
203
- // In Prisma 7, DMMF is no longer exposed on the client
204
- // We need to use getDMMF from @prisma/internals instead
205
218
  const { getDMMF } = require('@prisma/internals');
206
- // Read the schema file
219
+ // Read schema directly to avoid getSchemaWithPath merging with prisma.config.ts
207
220
  const schemaContent = fs.readFileSync(schemaPath, 'utf-8');
208
- // Get DMMF from the schema
209
221
  const dmmf = await getDMMF({
210
- datamodel: schemaContent
222
+ datamodel: [[schemaPath, schemaContent]]
211
223
  });
212
224
  const models = {};
213
225
  for (const model of dmmf.datamodel.models) {
@@ -215,11 +227,14 @@ async function parsePrismaDMMF(schemaPath) {
215
227
  const compositeKey = model.primaryKey && model.primaryKey.fields && model.primaryKey.fields.length > 1
216
228
  ? model.primaryKey.fields
217
229
  : null;
230
+ // Extract compound unique constraints
231
+ const uniqueFields = Array.isArray(model.uniqueFields) ? model.uniqueFields : [];
218
232
  models[model.name] = {
219
233
  name: model.name,
220
234
  fields: {},
221
235
  relations: [],
222
236
  compositeKey,
237
+ uniqueFields,
223
238
  dbName: model.dbName || model.name.toLowerCase() // Use dbName from DMMF or default to lowercase
224
239
  };
225
240
  for (const field of model.fields) {