@autobe/compiler 0.30.0-dev.20260315 → 0.30.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 (52) hide show
  1. package/LICENSE +661 -661
  2. package/lib/database/validateDatabaseApplication.js +318 -318
  3. package/lib/raw/AutoBeCompilerCommonTemplate.js +5 -5
  4. package/lib/raw/AutoBeCompilerCommonTemplate.js.map +1 -1
  5. package/lib/raw/AutoBeCompilerInterfaceTemplate.js +4 -4
  6. package/lib/raw/AutoBeCompilerInterfaceTemplate.js.map +1 -1
  7. package/lib/raw/AutoBeCompilerRealizeTemplate.js +27 -27
  8. package/lib/raw/AutoBeCompilerRealizeTemplate.js.map +1 -1
  9. package/lib/raw/AutoBeCompilerRealizeTemplateOfPostgres.js +4 -4
  10. package/lib/raw/AutoBeCompilerRealizeTemplateOfPostgres.js.map +1 -1
  11. package/lib/raw/AutoBeCompilerRealizeTemplateOfSQLite.js +4 -4
  12. package/lib/raw/AutoBeCompilerRealizeTemplateOfSQLite.js.map +1 -1
  13. package/lib/raw/AutoBeCompilerTestTemplate.js +8 -8
  14. package/lib/raw/AutoBeCompilerTestTemplate.js.map +1 -1
  15. package/lib/raw/nestjs.json +1640 -1640
  16. package/lib/raw/test.json +130 -130
  17. package/package.json +4 -4
  18. package/src/AutoBeCompiler.ts +93 -93
  19. package/src/AutoBeTypeScriptCompiler.ts +136 -136
  20. package/src/database/AutoBeDatabaseCompiler.ts +48 -48
  21. package/src/database/validateDatabaseApplication.ts +873 -873
  22. package/src/index.ts +5 -5
  23. package/src/interface/AutoBeInterfaceCompiler.ts +79 -79
  24. package/src/raw/AutoBeCompilerCommonTemplate.ts +5 -5
  25. package/src/raw/AutoBeCompilerInterfaceTemplate.ts +4 -4
  26. package/src/raw/AutoBeCompilerRealizeTemplate.ts +27 -27
  27. package/src/raw/AutoBeCompilerRealizeTemplateOfPostgres.ts +4 -4
  28. package/src/raw/AutoBeCompilerRealizeTemplateOfSQLite.ts +4 -4
  29. package/src/raw/AutoBeCompilerTestTemplate.ts +8 -8
  30. package/src/raw/nestjs.json +1640 -1640
  31. package/src/raw/test.json +130 -130
  32. package/src/realize/AutoBeRealizeCompiler.ts +42 -42
  33. package/src/realize/testRealizeProject.ts +78 -78
  34. package/src/realize/writeRealizeControllers.ts +217 -217
  35. package/src/test/AutoBeTestCompiler.ts +112 -112
  36. package/src/test/programmers/AutoBeTestAccessorProgrammer.ts +42 -42
  37. package/src/test/programmers/AutoBeTestFunctionalProgrammer.ts +87 -87
  38. package/src/test/programmers/AutoBeTestLiteralProgrammer.ts +65 -65
  39. package/src/test/programmers/AutoBeTestOperatorProgrammer.ts +84 -84
  40. package/src/test/programmers/AutoBeTestPredicateProgrammer.ts +131 -131
  41. package/src/test/programmers/AutoBeTestRandomProgrammer.ts +304 -304
  42. package/src/test/programmers/AutoBeTestStatementProgrammer.ts +154 -154
  43. package/src/test/programmers/IAutoBeTestApiFunction.ts +6 -6
  44. package/src/test/programmers/IAutoBeTestProgrammerContext.ts +11 -11
  45. package/src/test/programmers/writeTestExpression.ts +29 -29
  46. package/src/test/programmers/writeTestFunction.ts +103 -103
  47. package/src/test/programmers/writeTestStatement.ts +19 -19
  48. package/src/utils/ArrayUtil.ts +21 -21
  49. package/src/utils/FilePrinter.ts +67 -67
  50. package/src/utils/ProcessUtil.ts +14 -14
  51. package/src/utils/shrinkCompileResult.ts +16 -16
  52. package/README.md +0 -261
@@ -60,15 +60,15 @@ function validateDuplicatedFiles(app) {
60
60
  path: `application.files[${container.index}]`,
61
61
  table: null,
62
62
  field: null,
63
- message: utils_1.StringUtil.trim `
64
- File ${container.file.filename} is duplicated.
65
-
66
- Accessors of the other duplicated files are:
67
-
63
+ message: utils_1.StringUtil.trim `
64
+ File ${container.file.filename} is duplicated.
65
+
66
+ Accessors of the other duplicated files are:
67
+
68
68
  ${array
69
69
  .filter((_oppo, j) => i !== j)
70
70
  .map((oppo) => `- application.files[${oppo.index}]`)
71
- .join("\n")},
71
+ .join("\n")},
72
72
  `,
73
73
  });
74
74
  });
@@ -95,15 +95,15 @@ function validateDuplicatedModels(app) {
95
95
  path: `application.files[${container.fileIndex}].models[${container.modelIndex}]`,
96
96
  table: container.model.name,
97
97
  field: null,
98
- message: utils_1.StringUtil.trim `
99
- Model ${container.model.name} is duplicated.
100
-
101
- Accessors of the other duplicated models are:
102
-
98
+ message: utils_1.StringUtil.trim `
99
+ Model ${container.model.name} is duplicated.
100
+
101
+ Accessors of the other duplicated models are:
102
+
103
103
  ${array
104
104
  .filter((_oppo, j) => i !== j)
105
105
  .map((oppo) => `- application.files[${oppo.fileIndex}].models[${oppo.modelIndex}]`)
106
- .join("\n")},
106
+ .join("\n")},
107
107
  `,
108
108
  });
109
109
  });
@@ -126,15 +126,15 @@ function validateDuplicatedFields(dict, model, accessor) {
126
126
  path,
127
127
  table: model.name,
128
128
  field,
129
- message: utils_1.StringUtil.trim `
130
- Field ${field} is duplicated.
131
-
132
- Accessors of the other duplicated fields are:
133
-
129
+ message: utils_1.StringUtil.trim `
130
+ Field ${field} is duplicated.
131
+
132
+ Accessors of the other duplicated fields are:
133
+
134
134
  ${array
135
135
  .filter((_oppo, j) => i !== j)
136
136
  .map((a) => `- ${a}`)
137
- .join("\n")},
137
+ .join("\n")},
138
138
  `,
139
139
  });
140
140
  });
@@ -145,38 +145,38 @@ function validateDuplicatedFields(dict, model, accessor) {
145
145
  path: `${accessor}.plainFields[${i}].name`,
146
146
  table: model.name,
147
147
  field: field.name,
148
- message: utils_1.StringUtil.trim `
149
- Field name conflicts with an existing table name.
150
-
151
- **What happened?**
152
- The field "${field.name}" in model "${model.name}" has the same name as another table "${field.name}".
153
- This can cause confusion and potential issues in the generated code.
154
-
155
- **Why is this a problem?**
156
- - Naming conflicts can lead to ambiguous references in your code
157
- - It may cause issues with Prisma's relation inference
158
- - It makes the schema harder to understand and maintain
159
-
160
- **How to fix this:**
161
-
162
- 1. **If this is a denormalization field (pre-calculated value):**
163
- - Consider if this field is really necessary
164
- - If it's storing aggregated data from the related table, it might be better to calculate it dynamically
165
- - Remove the field if it's redundant
166
-
167
- 2. **If this is a legitimate field:**
168
- - Rename the field to be more descriptive
169
- - Good naming examples:
170
- - Instead of "user", use "user_name" or "user_id"
171
- - Instead of "order", use "order_status" or "order_count"
172
- - Instead of "product", use "product_name" or "product_code"
173
-
174
- 3. **Naming best practices:**
175
- - Use specific, descriptive names that indicate the field's purpose
176
- - Avoid using table names as field names
177
- - Consider adding a suffix or prefix to clarify the field's role
178
-
179
- Please rename the field or remove it if unnecessary.
148
+ message: utils_1.StringUtil.trim `
149
+ Field name conflicts with an existing table name.
150
+
151
+ **What happened?**
152
+ The field "${field.name}" in model "${model.name}" has the same name as another table "${field.name}".
153
+ This can cause confusion and potential issues in the generated code.
154
+
155
+ **Why is this a problem?**
156
+ - Naming conflicts can lead to ambiguous references in your code
157
+ - It may cause issues with Prisma's relation inference
158
+ - It makes the schema harder to understand and maintain
159
+
160
+ **How to fix this:**
161
+
162
+ 1. **If this is a denormalization field (pre-calculated value):**
163
+ - Consider if this field is really necessary
164
+ - If it's storing aggregated data from the related table, it might be better to calculate it dynamically
165
+ - Remove the field if it's redundant
166
+
167
+ 2. **If this is a legitimate field:**
168
+ - Rename the field to be more descriptive
169
+ - Good naming examples:
170
+ - Instead of "user", use "user_name" or "user_id"
171
+ - Instead of "order", use "order_status" or "order_count"
172
+ - Instead of "product", use "product_name" or "product_code"
173
+
174
+ 3. **Naming best practices:**
175
+ - Use specific, descriptive names that indicate the field's purpose
176
+ - Avoid using table names as field names
177
+ - Consider adding a suffix or prefix to clarify the field's role
178
+
179
+ Please rename the field or remove it if unnecessary.
180
180
  `,
181
181
  });
182
182
  });
@@ -202,15 +202,15 @@ function validateDuplicatedIndexes(model, accessor) {
202
202
  path,
203
203
  table: model.name,
204
204
  field: null,
205
- message: utils_1.StringUtil.trim `
206
- Duplicated index found (${fieldNames.join(", ")}).
207
-
208
- Accessors of the other duplicated indexes are:
209
-
205
+ message: utils_1.StringUtil.trim `
206
+ Duplicated index found (${fieldNames.join(", ")}).
207
+
208
+ Accessors of the other duplicated indexes are:
209
+
210
210
  ${array
211
211
  .filter((_oppo, j) => i !== j)
212
212
  .map((a) => `- ${a}`)
213
- .join("\n")},
213
+ .join("\n")},
214
214
  `,
215
215
  });
216
216
  });
@@ -228,13 +228,13 @@ function validateDuplicatedIndexes(model, accessor) {
228
228
  path: `${accessor}.uniqueIndexes[${i}].fieldNames[0]`,
229
229
  table: model.name,
230
230
  field: null,
231
- message: utils_1.StringUtil.trim `
232
- Duplicated unique index found (${subset[0]}).
233
-
234
- You have defined an unique index that is already included,
235
- in the foreign field with unique constraint.
236
-
237
- Remove this unique index to avoid the duplication.
231
+ message: utils_1.StringUtil.trim `
232
+ Duplicated unique index found (${subset[0]}).
233
+
234
+ You have defined an unique index that is already included,
235
+ in the foreign field with unique constraint.
236
+
237
+ Remove this unique index to avoid the duplication.
238
238
  `,
239
239
  });
240
240
  const cIndex = model.uniqueIndexes.findIndex((u) => u.fieldNames.length === subset.length &&
@@ -244,45 +244,45 @@ function validateDuplicatedIndexes(model, accessor) {
244
244
  path: `${accessor}.uniqueIndexes[${i}].fieldNames`,
245
245
  table: model.name,
246
246
  field: null,
247
- message: utils_1.StringUtil.trim `
248
- Redundant subset unique index detected.
249
-
250
- **What is a subset unique index problem?**
251
- When you have a unique index on multiple fields, any subset of those fields is automatically unique too.
252
- This is a fundamental property of unique constraints in databases.
253
-
254
- **Current situation:**
255
- - You have a unique index on: (${unique.fieldNames.join(", ")})
256
- - But there's already a unique index on its subset: (${subset.join(", ")})
257
- - This makes the larger unique index redundant for uniqueness purposes
258
-
259
- **Why is this a problem?**
260
- 1. **Logical redundancy**: If (A) is unique, then (A, B) is automatically unique
261
- 2. **Performance overhead**: Maintaining unnecessary indexes slows down write operations
262
- 3. **Storage waste**: Each index consumes disk space
263
- 4. **Confusion**: It's unclear which uniqueness constraint is the intended one
264
-
265
- **Example to illustrate:**
266
- If email is unique, then (email, name) is automatically unique because:
267
- - No two records can have the same email
268
- - Therefore, no two records can have the same (email, name) combination
269
-
270
- **How to fix:**
271
- Choose one of these solutions based on your needs:
272
-
273
- 1. **If you need uniqueness only:**
274
- - Keep just the subset unique index: (${subset.join(", ")})
275
- - Remove the larger unique index
276
-
277
- 2. **If you need the multi-field index for query performance:**
278
- - Keep the subset as unique index: (${subset.join(", ")})
279
- - Change the larger index to a plain (non-unique) index for performance
280
-
281
- 3. **If the subset unique was added by mistake:**
282
- - Remove the subset unique index
283
- - Keep the multi-field unique index
284
-
285
- Please review your uniqueness requirements and adjust accordingly.
247
+ message: utils_1.StringUtil.trim `
248
+ Redundant subset unique index detected.
249
+
250
+ **What is a subset unique index problem?**
251
+ When you have a unique index on multiple fields, any subset of those fields is automatically unique too.
252
+ This is a fundamental property of unique constraints in databases.
253
+
254
+ **Current situation:**
255
+ - You have a unique index on: (${unique.fieldNames.join(", ")})
256
+ - But there's already a unique index on its subset: (${subset.join(", ")})
257
+ - This makes the larger unique index redundant for uniqueness purposes
258
+
259
+ **Why is this a problem?**
260
+ 1. **Logical redundancy**: If (A) is unique, then (A, B) is automatically unique
261
+ 2. **Performance overhead**: Maintaining unnecessary indexes slows down write operations
262
+ 3. **Storage waste**: Each index consumes disk space
263
+ 4. **Confusion**: It's unclear which uniqueness constraint is the intended one
264
+
265
+ **Example to illustrate:**
266
+ If email is unique, then (email, name) is automatically unique because:
267
+ - No two records can have the same email
268
+ - Therefore, no two records can have the same (email, name) combination
269
+
270
+ **How to fix:**
271
+ Choose one of these solutions based on your needs:
272
+
273
+ 1. **If you need uniqueness only:**
274
+ - Keep just the subset unique index: (${subset.join(", ")})
275
+ - Remove the larger unique index
276
+
277
+ 2. **If you need the multi-field index for query performance:**
278
+ - Keep the subset as unique index: (${subset.join(", ")})
279
+ - Change the larger index to a plain (non-unique) index for performance
280
+
281
+ 3. **If the subset unique was added by mistake:**
282
+ - Remove the subset unique index
283
+ - Keep the multi-field unique index
284
+
285
+ Please review your uniqueness requirements and adjust accordingly.
286
286
  `,
287
287
  });
288
288
  });
@@ -298,43 +298,43 @@ function validateDuplicatedIndexes(model, accessor) {
298
298
  path: `${accessor}.plainIndexes[${i}].fieldNames`,
299
299
  table: model.name,
300
300
  field: null,
301
- message: utils_1.StringUtil.trim `
302
- Inefficient subset index detected - superset index exists.
303
-
304
- **What is a subset/superset index problem?**
305
- In database indexing, when you have an index on (A, B, C), it can efficiently serve queries
306
- that filter by A, or by (A, B), or by (A, B, C). This is called index prefix matching.
307
-
308
- **Current situation:**
309
- - You have a plain index on: (${x.fieldNames.join(", ")})
310
- - But there's already a plain index on its superset: (${y.fieldNames.join(", ")})
311
- - The subset index is redundant because the superset can handle the same queries
312
-
313
- **Why is this a problem?**
314
- 1. **Query efficiency**: The superset index can handle all queries the subset can
315
- 2. **Storage waste**: You're maintaining two indexes where one would suffice
316
- 3. **Write performance**: Each index slows down INSERT, UPDATE, and DELETE operations
317
- 4. **Maintenance overhead**: More indexes mean more work for the database
318
-
319
- **How indexes work (example):**
320
- If you have an index on (country, city, street):
321
- - ✅ Can efficiently find by country
322
- - ✅ Can efficiently find by country + city
323
- - ✅ Can efficiently find by country + city + street
324
- - ❌ Cannot efficiently find by city alone
325
- - ❌ Cannot efficiently find by street alone
326
-
327
- **How to fix:**
328
- Remove the subset index (${x.fieldNames.join(", ")}) because:
329
- - The superset index (${y.fieldNames.join(", ")}) already covers these queries
330
- - You'll save storage space and improve write performance
331
- - Query performance will remain the same
332
-
333
- **When to keep both indexes:**
334
- Only if the subset index is UNIQUE (which it isn't in this case), as unique
335
- constraints serve a different purpose than performance optimization.
336
-
337
- Please remove the redundant subset index.
301
+ message: utils_1.StringUtil.trim `
302
+ Inefficient subset index detected - superset index exists.
303
+
304
+ **What is a subset/superset index problem?**
305
+ In database indexing, when you have an index on (A, B, C), it can efficiently serve queries
306
+ that filter by A, or by (A, B), or by (A, B, C). This is called index prefix matching.
307
+
308
+ **Current situation:**
309
+ - You have a plain index on: (${x.fieldNames.join(", ")})
310
+ - But there's already a plain index on its superset: (${y.fieldNames.join(", ")})
311
+ - The subset index is redundant because the superset can handle the same queries
312
+
313
+ **Why is this a problem?**
314
+ 1. **Query efficiency**: The superset index can handle all queries the subset can
315
+ 2. **Storage waste**: You're maintaining two indexes where one would suffice
316
+ 3. **Write performance**: Each index slows down INSERT, UPDATE, and DELETE operations
317
+ 4. **Maintenance overhead**: More indexes mean more work for the database
318
+
319
+ **How indexes work (example):**
320
+ If you have an index on (country, city, street):
321
+ - ✅ Can efficiently find by country
322
+ - ✅ Can efficiently find by country + city
323
+ - ✅ Can efficiently find by country + city + street
324
+ - ❌ Cannot efficiently find by city alone
325
+ - ❌ Cannot efficiently find by street alone
326
+
327
+ **How to fix:**
328
+ Remove the subset index (${x.fieldNames.join(", ")}) because:
329
+ - The superset index (${y.fieldNames.join(", ")}) already covers these queries
330
+ - You'll save storage space and improve write performance
331
+ - Query performance will remain the same
332
+
333
+ **When to keep both indexes:**
334
+ Only if the subset index is UNIQUE (which it isn't in this case), as unique
335
+ constraints serve a different purpose than performance optimization.
336
+
337
+ Please remove the redundant subset index.
338
338
  `,
339
339
  });
340
340
  });
@@ -346,12 +346,12 @@ function validateDuplicatedIndexes(model, accessor) {
346
346
  path: `${accessor}.ginIndexes`,
347
347
  table: model.name,
348
348
  field: null,
349
- message: utils_1.StringUtil.trim `
350
- Duplicated GIN index found.
351
-
352
- GIN index can only be used once per field.
353
-
354
- Please remove the duplicated GIN indexes.
349
+ message: utils_1.StringUtil.trim `
350
+ Duplicated GIN index found.
351
+
352
+ GIN index can only be used once per field.
353
+
354
+ Please remove the duplicated GIN indexes.
355
355
  `,
356
356
  });
357
357
  return errors;
@@ -387,24 +387,24 @@ function validateDuplicatedRelationOppositeNames(dict, model) {
387
387
  path: `application.files[${c.fileIndex}].models[${c.modelIndex}].foreignFields[${item.foreignFieldIndex}].relation.oppositeName`,
388
388
  table: c.model.name,
389
389
  field: ff.name,
390
- message: utils_1.StringUtil.trim `
391
- oppositeName "${oppositeName}" conflicts with existing field in target model "${model.name}".
392
-
393
- **What happened?**
394
- The oppositeName "${oppositeName}" would create a reverse relation property in "${model.name}",
395
- but "${model.name}" already has a field or relation with that name.
396
-
397
- **Why is this a problem?**
398
- - Prisma cannot have two properties with the same name in a model
399
- - This will cause Prisma schema compilation errors
400
- - The reverse relation would overwrite or conflict with the existing field
401
-
402
- **How to fix:**
403
- Choose a different oppositeName that doesn't conflict with existing fields in "${model.name}".
404
-
405
- **Naming suggestions:**
406
- - Add a descriptive prefix/suffix: "${oppositeName}List", "${oppositeName}Items", "related${oppositeName.charAt(0).toUpperCase() + oppositeName.slice(1)}"
407
- - Use the source model name: "${c.model.name.replace(/_/g, "").toLowerCase()}s"
390
+ message: utils_1.StringUtil.trim `
391
+ oppositeName "${oppositeName}" conflicts with existing field in target model "${model.name}".
392
+
393
+ **What happened?**
394
+ The oppositeName "${oppositeName}" would create a reverse relation property in "${model.name}",
395
+ but "${model.name}" already has a field or relation with that name.
396
+
397
+ **Why is this a problem?**
398
+ - Prisma cannot have two properties with the same name in a model
399
+ - This will cause Prisma schema compilation errors
400
+ - The reverse relation would overwrite or conflict with the existing field
401
+
402
+ **How to fix:**
403
+ Choose a different oppositeName that doesn't conflict with existing fields in "${model.name}".
404
+
405
+ **Naming suggestions:**
406
+ - Add a descriptive prefix/suffix: "${oppositeName}List", "${oppositeName}Items", "related${oppositeName.charAt(0).toUpperCase() + oppositeName.slice(1)}"
407
+ - Use the source model name: "${c.model.name.replace(/_/g, "").toLowerCase()}s"
408
408
  `,
409
409
  });
410
410
  });
@@ -421,41 +421,41 @@ function validateDuplicatedRelationOppositeNames(dict, model) {
421
421
  path: `application.files[${c.fileIndex}].models[${c.modelIndex}].foreignFields[${item.foreignFieldIndex}].relation.oppositeName`,
422
422
  table: c.model.name,
423
423
  field: ff.name,
424
- message: utils_1.StringUtil.trim `
425
- Duplicated relation oppositeName "${oppositeName}" detected on target model "${model.name}".
426
-
427
- **What is oppositeName?**
428
- In Prisma relations, oppositeName defines the name of the reverse relation field
429
- on the target model. It allows the target model to access related records through
430
- this named property.
431
-
432
- **Current situation:**
433
- Multiple foreign key fields from different models are trying to create reverse
434
- relations on "${model.name}" with the same oppositeName "${oppositeName}".
435
-
436
- **Conflicting relations:**
424
+ message: utils_1.StringUtil.trim `
425
+ Duplicated relation oppositeName "${oppositeName}" detected on target model "${model.name}".
426
+
427
+ **What is oppositeName?**
428
+ In Prisma relations, oppositeName defines the name of the reverse relation field
429
+ on the target model. It allows the target model to access related records through
430
+ this named property.
431
+
432
+ **Current situation:**
433
+ Multiple foreign key fields from different models are trying to create reverse
434
+ relations on "${model.name}" with the same oppositeName "${oppositeName}".
435
+
436
+ **Conflicting relations:**
437
437
  ${array
438
438
  .filter((_, j) => i !== j)
439
439
  .map((oppo) => `- Model "${oppo.container.model.name}", field "${oppo.foreignField.name}" (accessor: application.files[${oppo.container.fileIndex}].models[${oppo.container.modelIndex}].foreignFields[${oppo.foreignFieldIndex}].relation.oppositeName)`)
440
- .join("\n")}
441
-
442
- **Why is this a problem?**
443
- - Prisma requires unique relation names within a model
444
- - When "${model.name}" tries to access related records, it won't know which relation to use
445
- - This will cause Prisma schema compilation errors
446
-
447
- **How to fix:**
448
- Each relation pointing to "${model.name}" must have a unique oppositeName.
449
-
450
- **Naming suggestions:**
451
- - Use descriptive names that indicate the relationship's purpose
452
- - Include the source model name for clarity
453
- - Examples:
454
- - Instead of both using "orders", use "customerOrders" and "sellerOrders"
455
- - Instead of both using "users", use "createdByUser" and "assignedToUser"
456
- - For "${c.model.name}" → "${model.name}": consider "${c.model.name.charAt(0).toLowerCase() + c.model.name.slice(1)}s" or a more descriptive name
457
-
458
- Please rename the oppositeName to be unique across all relations targeting "${model.name}".
440
+ .join("\n")}
441
+
442
+ **Why is this a problem?**
443
+ - Prisma requires unique relation names within a model
444
+ - When "${model.name}" tries to access related records, it won't know which relation to use
445
+ - This will cause Prisma schema compilation errors
446
+
447
+ **How to fix:**
448
+ Each relation pointing to "${model.name}" must have a unique oppositeName.
449
+
450
+ **Naming suggestions:**
451
+ - Use descriptive names that indicate the relationship's purpose
452
+ - Include the source model name for clarity
453
+ - Examples:
454
+ - Instead of both using "orders", use "customerOrders" and "sellerOrders"
455
+ - Instead of both using "users", use "createdByUser" and "assignedToUser"
456
+ - For "${c.model.name}" → "${model.name}": consider "${c.model.name.charAt(0).toLowerCase() + c.model.name.slice(1)}s" or a more descriptive name
457
+
458
+ Please rename the oppositeName to be unique across all relations targeting "${model.name}".
459
459
  `,
460
460
  });
461
461
  });
@@ -473,8 +473,8 @@ function validateValidNames(model, accessor) {
473
473
  path: props.accessor,
474
474
  table: model.name,
475
475
  field: props.field,
476
- message: utils_1.StringUtil.trim `
477
- The name "${props.value}" is a system reserved keyword and cannot be used.
476
+ message: utils_1.StringUtil.trim `
477
+ The name "${props.value}" is a system reserved keyword and cannot be used.
478
478
  `,
479
479
  });
480
480
  else if (utils_1.AutoBeEscaper.variable(props.value) === false)
@@ -482,10 +482,10 @@ function validateValidNames(model, accessor) {
482
482
  path: props.accessor,
483
483
  table: model.name,
484
484
  field: props.field,
485
- message: utils_1.StringUtil.trim `
486
- The name "${props.value}" is not a valid identifier.
487
-
488
- Change to a valid identifier which can be a variable name in programming languages.
485
+ message: utils_1.StringUtil.trim `
486
+ The name "${props.value}" is not a valid identifier.
487
+
488
+ Change to a valid identifier which can be a variable name in programming languages.
489
489
  `,
490
490
  });
491
491
  };
@@ -584,38 +584,38 @@ function validateIndexes(model, accessor) {
584
584
  path: `${accessor}.ginIndexes[${i}].fieldName`,
585
585
  table: model.name,
586
586
  field: null,
587
- message: utils_1.StringUtil.trim `
588
- GIN index cannot be applied to this field.
589
-
590
- **What is a GIN index?**
591
- GIN (Generalized Inverted Index) is a special index type in PostgreSQL designed for
592
- full-text search and operations on complex data types. In AutoBE, GIN indexes are
593
- used exclusively for string fields to enable efficient text searching.
594
-
595
- **Current problem:**
596
- The field "${gin.fieldName}" specified for GIN index does not exist in the plain fields
597
- of model "${model.name}".
598
-
599
- **Possible causes:**
600
- 1. The field name is misspelled
601
- 2. The field is a foreign key field (not a plain field)
602
- 3. The field was removed but the index definition remained
603
-
604
- **How to fix:**
605
- 1. Check if the field name is correct
606
- 2. Ensure the field exists in the plainFields array
607
- 3. Make sure the field is of type "string" (GIN indexes only work with strings)
608
- 4. If the field doesn't exist, either:
609
- - Add the missing string field to plainFields
610
- - Remove this GIN index definition
611
-
612
- **Example of correct GIN index usage:**
613
- plainFields: [
614
- { name: "content", type: "string" } // ✓ Can use GIN index
615
- ]
616
- ginIndexes: [
617
- { fieldName: "content" } // ✓ Correct
618
- ]
587
+ message: utils_1.StringUtil.trim `
588
+ GIN index cannot be applied to this field.
589
+
590
+ **What is a GIN index?**
591
+ GIN (Generalized Inverted Index) is a special index type in PostgreSQL designed for
592
+ full-text search and operations on complex data types. In AutoBE, GIN indexes are
593
+ used exclusively for string fields to enable efficient text searching.
594
+
595
+ **Current problem:**
596
+ The field "${gin.fieldName}" specified for GIN index does not exist in the plain fields
597
+ of model "${model.name}".
598
+
599
+ **Possible causes:**
600
+ 1. The field name is misspelled
601
+ 2. The field is a foreign key field (not a plain field)
602
+ 3. The field was removed but the index definition remained
603
+
604
+ **How to fix:**
605
+ 1. Check if the field name is correct
606
+ 2. Ensure the field exists in the plainFields array
607
+ 3. Make sure the field is of type "string" (GIN indexes only work with strings)
608
+ 4. If the field doesn't exist, either:
609
+ - Add the missing string field to plainFields
610
+ - Remove this GIN index definition
611
+
612
+ **Example of correct GIN index usage:**
613
+ plainFields: [
614
+ { name: "content", type: "string" } // ✓ Can use GIN index
615
+ ]
616
+ ginIndexes: [
617
+ { fieldName: "content" } // ✓ Correct
618
+ ]
619
619
  `,
620
620
  });
621
621
  else if (model.plainFields[pIndex].type !== "string")
@@ -623,44 +623,44 @@ function validateIndexes(model, accessor) {
623
623
  path: `${accessor}.ginIndexes[${i}].fieldName`,
624
624
  table: model.name,
625
625
  field: model.plainFields[pIndex].name,
626
- message: utils_1.StringUtil.trim `
627
- GIN index type mismatch - requires string field.
628
-
629
- **What is a GIN index?**
630
- GIN (Generalized Inverted Index) is PostgreSQL's specialized index for full-text search.
631
- It's designed to efficiently search within text content, making it perfect for features like:
632
- - Search functionality in articles or posts
633
- - Finding keywords in product descriptions
634
- - Filtering by text content
635
-
636
- **Current problem:**
637
- You're trying to apply a GIN index to field "${gin.fieldName}" which is of type "${model.plainFields[pIndex].type}".
638
- GIN indexes can ONLY be applied to "string" type fields.
639
-
640
- **Why string fields only?**
641
- GIN indexes work by breaking down text into searchable tokens (words, phrases).
642
- Other data types like numbers, booleans, or dates don't have this text structure.
643
-
644
- **How to fix:**
645
-
646
- 1. **If you need text search on this field:**
647
- - Change the field type to "string"
648
- - Example: If storing a product code as number, consider storing as string instead
649
-
650
- 2. **If the field should remain as ${model.plainFields[pIndex].type}:**
651
- - Remove the GIN index for this field
652
- - Use a regular index instead (plainIndexes)
653
- - Consider if you really need an index on this field
654
-
655
- 3. **Alternative indexing strategies:**
656
- - For ${model.plainFields[pIndex].type} fields, use plainIndexes for general performance
657
- - For unique ${model.plainFields[pIndex].type} values, use uniqueIndexes
658
- - GIN indexes should be reserved for text search scenarios only
659
-
660
- **Location of the field:**
661
- - Field definition: ${`${accessor}.plainFields[${pIndex}]`}
662
-
663
- Please either change the field type to "string" or remove the GIN index.
626
+ message: utils_1.StringUtil.trim `
627
+ GIN index type mismatch - requires string field.
628
+
629
+ **What is a GIN index?**
630
+ GIN (Generalized Inverted Index) is PostgreSQL's specialized index for full-text search.
631
+ It's designed to efficiently search within text content, making it perfect for features like:
632
+ - Search functionality in articles or posts
633
+ - Finding keywords in product descriptions
634
+ - Filtering by text content
635
+
636
+ **Current problem:**
637
+ You're trying to apply a GIN index to field "${gin.fieldName}" which is of type "${model.plainFields[pIndex].type}".
638
+ GIN indexes can ONLY be applied to "string" type fields.
639
+
640
+ **Why string fields only?**
641
+ GIN indexes work by breaking down text into searchable tokens (words, phrases).
642
+ Other data types like numbers, booleans, or dates don't have this text structure.
643
+
644
+ **How to fix:**
645
+
646
+ 1. **If you need text search on this field:**
647
+ - Change the field type to "string"
648
+ - Example: If storing a product code as number, consider storing as string instead
649
+
650
+ 2. **If the field should remain as ${model.plainFields[pIndex].type}:**
651
+ - Remove the GIN index for this field
652
+ - Use a regular index instead (plainIndexes)
653
+ - Consider if you really need an index on this field
654
+
655
+ 3. **Alternative indexing strategies:**
656
+ - For ${model.plainFields[pIndex].type} fields, use plainIndexes for general performance
657
+ - For unique ${model.plainFields[pIndex].type} values, use uniqueIndexes
658
+ - GIN indexes should be reserved for text search scenarios only
659
+
660
+ **Location of the field:**
661
+ - Field definition: ${`${accessor}.plainFields[${pIndex}]`}
662
+
663
+ Please either change the field type to "string" or remove the GIN index.
664
664
  `,
665
665
  });
666
666
  },
@@ -689,53 +689,53 @@ function validateReferences(model, accessor, dict) {
689
689
  path: `${accessor}.foreignFields[${i}].relation.targetModel`,
690
690
  table: model.name,
691
691
  field: field.name,
692
- message: utils_1.StringUtil.trim `
693
- Cross-reference dependency detected between models.
694
-
695
- **What is Cross-reference dependency?**
696
- A cross-reference dependency (also known as circular dependency) occurs when two models
697
- reference each other through foreign key fields. This creates a circular relationship
698
- where Model A references Model B, and Model B also references Model A.
699
-
700
- **Current situation:**
701
- - ${model.name} model has a foreign key field "${field.name}" that references ${field.relation.targetModel}
702
- - ${field.relation.targetModel} model also has a foreign key field that references ${model.name}
703
- - Location of opposite reference: application.files[${target.fileIndex}].models[${target.modelIndex}].foreignFields[${j}].relation.targetModel
704
-
705
- **Why is this a problem?**
706
- Circular dependencies can cause issues with:
707
- - Database initialization (which table to create first?)
708
- - Data insertion (which record to insert first?)
709
- - Cascading updates and deletes
710
- - Query performance and complexity
711
-
712
- **How to fix this:**
713
- You need to remove one of the foreign key relationships. Here's how to decide:
714
-
715
- 1. **Identify the primary relationship direction**
716
- - Which model is the "parent" and which is the "child"?
717
- - Which relationship is essential for your business logic?
718
- - Example: In User ↔ Profile, User is typically the parent
719
-
720
- 2. **Remove the redundant foreign key**
721
- - Keep the foreign key in the child model pointing to the parent
722
- - Remove the foreign key in the parent model pointing to the child
723
- - You can still access the reverse relationship through Prisma's implicit relations
724
-
725
- 3. **Update any affected indexes**
726
- - Remove indexes that include the deleted foreign key field
727
- - Update composite indexes if necessary
728
-
729
- **Example solution:**
730
- If you have:
731
- - User model with profileId foreign key
732
- - Profile model with userId foreign key
733
-
734
- You should:
735
- - Keep userId in Profile (child references parent)
736
- - Remove profileId from User
737
- - Access user's profile through: user.profile (Prisma will handle this)
738
-
692
+ message: utils_1.StringUtil.trim `
693
+ Cross-reference dependency detected between models.
694
+
695
+ **What is Cross-reference dependency?**
696
+ A cross-reference dependency (also known as circular dependency) occurs when two models
697
+ reference each other through foreign key fields. This creates a circular relationship
698
+ where Model A references Model B, and Model B also references Model A.
699
+
700
+ **Current situation:**
701
+ - ${model.name} model has a foreign key field "${field.name}" that references ${field.relation.targetModel}
702
+ - ${field.relation.targetModel} model also has a foreign key field that references ${model.name}
703
+ - Location of opposite reference: application.files[${target.fileIndex}].models[${target.modelIndex}].foreignFields[${j}].relation.targetModel
704
+
705
+ **Why is this a problem?**
706
+ Circular dependencies can cause issues with:
707
+ - Database initialization (which table to create first?)
708
+ - Data insertion (which record to insert first?)
709
+ - Cascading updates and deletes
710
+ - Query performance and complexity
711
+
712
+ **How to fix this:**
713
+ You need to remove one of the foreign key relationships. Here's how to decide:
714
+
715
+ 1. **Identify the primary relationship direction**
716
+ - Which model is the "parent" and which is the "child"?
717
+ - Which relationship is essential for your business logic?
718
+ - Example: In User ↔ Profile, User is typically the parent
719
+
720
+ 2. **Remove the redundant foreign key**
721
+ - Keep the foreign key in the child model pointing to the parent
722
+ - Remove the foreign key in the parent model pointing to the child
723
+ - You can still access the reverse relationship through Prisma's implicit relations
724
+
725
+ 3. **Update any affected indexes**
726
+ - Remove indexes that include the deleted foreign key field
727
+ - Update composite indexes if necessary
728
+
729
+ **Example solution:**
730
+ If you have:
731
+ - User model with profileId foreign key
732
+ - Profile model with userId foreign key
733
+
734
+ You should:
735
+ - Keep userId in Profile (child references parent)
736
+ - Remove profileId from User
737
+ - Access user's profile through: user.profile (Prisma will handle this)
738
+
739
739
  Please eliminate the circular dependency and regenerate the schema.`,
740
740
  });
741
741
  }