@stacksjs/database 0.70.106 → 0.70.107
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/migrations.js +65 -4
- package/package.json +10 -10
package/dist/migrations.js
CHANGED
|
@@ -537,16 +537,76 @@ ${readFileSync(join(migrationsDir, f), "utf8")}`;
|
|
|
537
537
|
}
|
|
538
538
|
return written;
|
|
539
539
|
}
|
|
540
|
+
function normalizeCreateStatements(sqlStatements) {
|
|
541
|
+
const creates = [], constraints = [], passthrough = [];
|
|
542
|
+
for (const raw of sqlStatements) {
|
|
543
|
+
const statement = raw.trim();
|
|
544
|
+
if (!statement)
|
|
545
|
+
continue;
|
|
546
|
+
const create = statement.match(/^CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?["`]?(\w+)["`]?/i);
|
|
547
|
+
if (create?.[1]) {
|
|
548
|
+
creates.push({ statement, table: create[1] });
|
|
549
|
+
continue;
|
|
550
|
+
}
|
|
551
|
+
const constraint = statement.match(/^ALTER\s+TABLE\s+["`]?(\w+)["`]?\s+ADD\s+CONSTRAINT\s+([\s\S]+?);?$/i);
|
|
552
|
+
if (constraint?.[1] && constraint[2]) {
|
|
553
|
+
const references = [...constraint[2].matchAll(/REFERENCES\s+["`]?(\w+)["`]?/gi)].flatMap((match) => match[1] ? [match[1]] : []);
|
|
554
|
+
constraints.push({ body: `CONSTRAINT ${constraint[2].replace(/;\s*$/, "")}`, references, statement, table: constraint[1] });
|
|
555
|
+
continue;
|
|
556
|
+
}
|
|
557
|
+
passthrough.push(statement);
|
|
558
|
+
}
|
|
559
|
+
if (creates.length === 0)
|
|
560
|
+
return sqlStatements.map((statement) => statement.trim()).filter(Boolean);
|
|
561
|
+
const createdTables = new Set(creates.map((create) => create.table)), createOrder = new Map(creates.map((create, index) => [create.table, index])), relevantConstraints = constraints.filter((constraint) => createdTables.has(constraint.table)), unrelatedConstraints = constraints.filter((constraint) => !createdTables.has(constraint.table)), dependencies = new Map(creates.map((create) => [
|
|
562
|
+
create.table,
|
|
563
|
+
new Set(relevantConstraints.filter((constraint) => constraint.table === create.table).flatMap((constraint) => constraint.references).filter((reference) => reference !== create.table && createdTables.has(reference)))
|
|
564
|
+
])), sortTables = (ignoredEdges = new Set) => {
|
|
565
|
+
const remaining = new Set(createdTables), sorted = [];
|
|
566
|
+
while (remaining.size > 0) {
|
|
567
|
+
const ready = [...remaining].filter((table) => [...dependencies.get(table) ?? []].every((dependency) => {
|
|
568
|
+
return !remaining.has(dependency) || ignoredEdges.has(`${table}->${dependency}`);
|
|
569
|
+
})).sort((a, b) => (createOrder.get(a) ?? 0) - (createOrder.get(b) ?? 0));
|
|
570
|
+
if (ready.length === 0)
|
|
571
|
+
break;
|
|
572
|
+
for (const table of ready) {
|
|
573
|
+
remaining.delete(table);
|
|
574
|
+
sorted.push(table);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
return sorted;
|
|
578
|
+
}, initiallySorted = sortTables(), cyclicTables = new Set([...createdTables].filter((table) => !initiallySorted.includes(table))), deferred = relevantConstraints.filter((constraint) => constraint.references.some((reference) => {
|
|
579
|
+
return reference !== constraint.table && cyclicTables.has(constraint.table) && cyclicTables.has(reference);
|
|
580
|
+
})), deferredStatements = new Set(deferred.map((constraint) => constraint.statement)), ignoredEdges = new Set(deferred.flatMap((constraint) => constraint.references.map((reference) => `${constraint.table}->${reference}`))), orderedTables = sortTables(ignoredEdges), byTable = new Map(creates.map((create) => [create.table, create]));
|
|
581
|
+
return [
|
|
582
|
+
...orderedTables.map((table) => {
|
|
583
|
+
const create = byTable.get(table), inline = relevantConstraints.filter((constraint) => constraint.table === table && !deferredStatements.has(constraint.statement));
|
|
584
|
+
if (inline.length === 0)
|
|
585
|
+
return create.statement;
|
|
586
|
+
const closing = create.statement.lastIndexOf(")");
|
|
587
|
+
if (closing < 0)
|
|
588
|
+
return create.statement;
|
|
589
|
+
const before = create.statement.slice(0, closing).trimEnd(), after = create.statement.slice(closing);
|
|
590
|
+
return `${before},
|
|
591
|
+
${inline.map((constraint) => constraint.body).join(`,
|
|
592
|
+
`)}
|
|
593
|
+
${after}`;
|
|
594
|
+
}),
|
|
595
|
+
...passthrough,
|
|
596
|
+
...unrelatedConstraints.map((constraint) => constraint.statement),
|
|
597
|
+
...deferred.map((constraint) => constraint.statement)
|
|
598
|
+
];
|
|
599
|
+
}
|
|
540
600
|
export function groupGeneratedStatements(sqlStatements) {
|
|
541
|
-
const groups = new Map, push = (label, stmt) => {
|
|
601
|
+
const normalizedStatements = normalizeCreateStatements(sqlStatements), groups = new Map, push = (label, stmt) => {
|
|
542
602
|
const list = groups.get(label) ?? [];
|
|
543
603
|
list.push(stmt);
|
|
544
604
|
groups.set(label, list);
|
|
545
|
-
}, createdTables = new Set(
|
|
605
|
+
}, createdTables = new Set(normalizedStatements.flatMap((raw) => {
|
|
546
606
|
const match = raw.trim().match(/^\s*CREATE\s+TABLE\s+(?:IF\s+NOT\s+EXISTS\s+)?["`]?(\w+)["`]?/i);
|
|
547
607
|
return match?.[1] ? [match[1]] : [];
|
|
548
608
|
}));
|
|
549
|
-
for (const raw of
|
|
609
|
+
for (const raw of normalizedStatements) {
|
|
550
610
|
const stmt = raw.trim();
|
|
551
611
|
if (!stmt)
|
|
552
612
|
continue;
|
|
@@ -557,7 +617,8 @@ export function groupGeneratedStatements(sqlStatements) {
|
|
|
557
617
|
}
|
|
558
618
|
const alter = stmt.match(/^\s*ALTER\s+TABLE\s+["`]?(\w+)["`]?\s+(?:ADD\s+COLUMN\s+["`]?(\w+)["`]?|DROP\s+COLUMN\s+["`]?(\w+)["`]?|ADD\s+CONSTRAINT)/i);
|
|
559
619
|
if (alter) {
|
|
560
|
-
|
|
620
|
+
const isCreateTimeConstraint = createdTables.has(alter[1]) && !alter[2] && !alter[3];
|
|
621
|
+
push(isCreateTimeConstraint ? "create-foreign-key-constraints" : `alter-${alter[1]}-${alter[2] || alter[3] || "constraint"}`, stmt);
|
|
561
622
|
continue;
|
|
562
623
|
}
|
|
563
624
|
const idx = stmt.match(/^\s*CREATE\s+(?:UNIQUE\s+)?INDEX\s+(?:IF\s+NOT\s+EXISTS\s+)?["`]?(\w+)["`]?\s+ON\s+["`]?(\w+)["`]?/i), idxName = idx?.[1], idxTable = idx?.[2];
|
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"name": "@stacksjs/database",
|
|
3
3
|
"type": "module",
|
|
4
4
|
"sideEffects": false,
|
|
5
|
-
"version": "0.70.
|
|
5
|
+
"version": "0.70.107",
|
|
6
6
|
"description": "The Stacks database integration.",
|
|
7
7
|
"author": "Chris Breuer",
|
|
8
8
|
"contributors": [
|
|
@@ -58,15 +58,15 @@
|
|
|
58
58
|
"bun-query-builder": "^0.1.54"
|
|
59
59
|
},
|
|
60
60
|
"devDependencies": {
|
|
61
|
-
"@stacksjs/cli": "0.70.
|
|
62
|
-
"@stacksjs/config": "0.70.
|
|
63
|
-
"@stacksjs/logging": "0.70.
|
|
64
|
-
"@stacksjs/router": "0.70.
|
|
61
|
+
"@stacksjs/cli": "0.70.107",
|
|
62
|
+
"@stacksjs/config": "0.70.107",
|
|
63
|
+
"@stacksjs/logging": "0.70.107",
|
|
64
|
+
"@stacksjs/router": "0.70.107",
|
|
65
65
|
"better-dx": "^0.2.16",
|
|
66
|
-
"@stacksjs/path": "0.70.
|
|
67
|
-
"@stacksjs/query-builder": "0.70.
|
|
68
|
-
"@stacksjs/storage": "0.70.
|
|
69
|
-
"@stacksjs/strings": "0.70.
|
|
70
|
-
"@stacksjs/utils": "0.70.
|
|
66
|
+
"@stacksjs/path": "0.70.107",
|
|
67
|
+
"@stacksjs/query-builder": "0.70.107",
|
|
68
|
+
"@stacksjs/storage": "0.70.107",
|
|
69
|
+
"@stacksjs/strings": "0.70.107",
|
|
70
|
+
"@stacksjs/utils": "0.70.107"
|
|
71
71
|
}
|
|
72
72
|
}
|