nucleus-core-ts 0.10.14 → 0.10.15
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/dist/.build-ok +1 -1
- package/package.json +1 -1
- package/scripts/generate-schema.test.ts +60 -1
- package/scripts/generate-schema.ts +30 -2
package/dist/.build-ok
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
0.10.
|
|
1
|
+
0.10.15
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "nucleus-core-ts",
|
|
3
|
-
"version": "0.10.
|
|
3
|
+
"version": "0.10.15",
|
|
4
4
|
"description": "Production-ready, enterprise-grade TypeScript framework for building multi-tenant APIs",
|
|
5
5
|
"author": "Hidayet Can Özcan <hidayetcan@gmail.com>",
|
|
6
6
|
"license": "SEE LICENSE IN LICENSE",
|
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { describe, expect, it } from 'bun:test'
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
generateColumnCode,
|
|
4
|
+
generateRelationsFile,
|
|
5
|
+
generateTableCode,
|
|
6
|
+
selectEmittedTables,
|
|
7
|
+
} from './generate-schema'
|
|
3
8
|
|
|
4
9
|
const table = (table_name: string) => ({ table_name })
|
|
5
10
|
|
|
@@ -214,3 +219,57 @@ describe('table-level constraints', () => {
|
|
|
214
219
|
expect(code).not.toContain('check(')
|
|
215
220
|
})
|
|
216
221
|
})
|
|
222
|
+
|
|
223
|
+
describe('generateRelationsFile', () => {
|
|
224
|
+
const branchTable = {
|
|
225
|
+
table_name: 'survey_branches',
|
|
226
|
+
columns: [
|
|
227
|
+
{
|
|
228
|
+
name: 'trigger_question_id',
|
|
229
|
+
type: 'uuid',
|
|
230
|
+
references: { table: 'survey_questions', column: 'id' },
|
|
231
|
+
},
|
|
232
|
+
{
|
|
233
|
+
name: 'target_question_id',
|
|
234
|
+
type: 'uuid',
|
|
235
|
+
references: { table: 'survey_questions', column: 'id' },
|
|
236
|
+
},
|
|
237
|
+
{
|
|
238
|
+
name: 'survey_id',
|
|
239
|
+
type: 'uuid',
|
|
240
|
+
references: { table: 'surveys', column: 'id' },
|
|
241
|
+
},
|
|
242
|
+
],
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
it('names two references to the SAME table after their columns', () => {
|
|
246
|
+
/*
|
|
247
|
+
* Both used to be emitted as `surveyQuestions:`, so the object literal had
|
|
248
|
+
* the same key twice and the generated file did not compile — a config
|
|
249
|
+
* change that produces broken output rather than a wrong result. A branch
|
|
250
|
+
* whose trigger and target are both questions is what found it; `created_by`
|
|
251
|
+
* with `updated_by` would have found it just as well.
|
|
252
|
+
*/
|
|
253
|
+
const code = generateRelationsFile([
|
|
254
|
+
branchTable,
|
|
255
|
+
{ table_name: 'survey_questions' },
|
|
256
|
+
{ table_name: 'surveys' },
|
|
257
|
+
] as never)
|
|
258
|
+
|
|
259
|
+
expect(code).toContain('triggerQuestion: one(surveyQuestions')
|
|
260
|
+
expect(code).toContain('targetQuestion: one(surveyQuestions')
|
|
261
|
+
expect(code.match(/surveyQuestions: one\(/g)).toBeNull()
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
it('and leaves a lone reference named after its table, as before', () => {
|
|
265
|
+
// The control: renaming everything would churn every existing generated
|
|
266
|
+
// file and rename relations consumers already query by.
|
|
267
|
+
const code = generateRelationsFile([
|
|
268
|
+
branchTable,
|
|
269
|
+
{ table_name: 'survey_questions' },
|
|
270
|
+
{ table_name: 'surveys' },
|
|
271
|
+
] as never)
|
|
272
|
+
|
|
273
|
+
expect(code).toContain('surveys: one(surveys')
|
|
274
|
+
})
|
|
275
|
+
})
|
|
@@ -607,7 +607,7 @@ function topologicalSort(tables: TableDef[], allTableNames: string[]): TableDef[
|
|
|
607
607
|
return result
|
|
608
608
|
}
|
|
609
609
|
|
|
610
|
-
function generateRelationsFile(tables: TableDef[]): string {
|
|
610
|
+
export function generateRelationsFile(tables: TableDef[]): string {
|
|
611
611
|
const allTableNames = new Set(tables.map((t) => t.table_name))
|
|
612
612
|
const relationsByTable: Map<
|
|
613
613
|
string,
|
|
@@ -640,9 +640,37 @@ function generateRelationsFile(tables: TableDef[]): string {
|
|
|
640
640
|
const fromTable = toCamelCase(tableName)
|
|
641
641
|
code += `export const ${fromTable}Relations = relations(${fromTable}, ({ one, many }) => ({\n`
|
|
642
642
|
|
|
643
|
+
/*
|
|
644
|
+
* How many of this table's foreign keys point at the same table.
|
|
645
|
+
*
|
|
646
|
+
* The relation used to be named after the TARGET TABLE, which is fine until
|
|
647
|
+
* a table references the same one twice — and then the generator emits two
|
|
648
|
+
* properties with the same key and the output does not compile:
|
|
649
|
+
*
|
|
650
|
+
* surveyQuestions: one(surveyQuestions, { fields: [...triggerQuestionId] }),
|
|
651
|
+
* surveyQuestions: one(surveyQuestions, { fields: [...targetQuestionId] }),
|
|
652
|
+
*
|
|
653
|
+
* That is not an exotic shape. `created_by`/`updated_by`, `from_user`/
|
|
654
|
+
* `to_user`, and here a branch's trigger question and its target question
|
|
655
|
+
* all land on it. Found when survey branching grew a second kind of target.
|
|
656
|
+
*/
|
|
657
|
+
const referencesToTable = new Map<string, number>()
|
|
658
|
+
for (const rel of rels) {
|
|
659
|
+
referencesToTable.set(rel.to, (referencesToTable.get(rel.to) ?? 0) + 1)
|
|
660
|
+
}
|
|
661
|
+
|
|
643
662
|
for (const rel of rels) {
|
|
644
663
|
const toTable = toCamelCase(rel.to)
|
|
645
|
-
|
|
664
|
+
// Only the ambiguous ones are renamed, so a config with one reference per
|
|
665
|
+
// table generates exactly what it generated before.
|
|
666
|
+
const ambiguous = (referencesToTable.get(rel.to) ?? 0) > 1
|
|
667
|
+
const relationName = ambiguous
|
|
668
|
+
? // `trigger_question_id` -> `triggerQuestion`: the column says which of
|
|
669
|
+
// the two this is, which is the only thing that tells them apart.
|
|
670
|
+
toCamelCase(rel.fromCol.replace(/_id$/, ''))
|
|
671
|
+
: rel.isSelf
|
|
672
|
+
? 'parent'
|
|
673
|
+
: toTable
|
|
646
674
|
const fields = `${fromTable}.${toCamelCase(rel.fromCol)}`
|
|
647
675
|
const references = `${toTable}.${toCamelCase(rel.toCol)}`
|
|
648
676
|
|