ddlforge 0.2.1 → 0.5.0
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/src/cli.d.ts +2 -2
- package/dist/src/cli.d.ts.map +1 -1
- package/dist/src/cli.js +32 -4
- package/dist/src/cli.js.map +1 -1
- package/dist/src/index.d.ts +1 -0
- package/dist/src/index.d.ts.map +1 -1
- package/dist/src/index.js +2 -0
- package/dist/src/index.js.map +1 -1
- package/dist/src/reporters/index.d.ts +1 -0
- package/dist/src/reporters/index.d.ts.map +1 -1
- package/dist/src/reporters/index.js +1 -0
- package/dist/src/reporters/index.js.map +1 -1
- package/dist/src/reporters/sarif.d.ts +72 -0
- package/dist/src/reporters/sarif.d.ts.map +1 -0
- package/dist/src/reporters/sarif.js +103 -0
- package/dist/src/reporters/sarif.js.map +1 -0
- package/dist/src/rules/checkConstraintNotValid.d.ts +9 -0
- package/dist/src/rules/checkConstraintNotValid.d.ts.map +1 -0
- package/dist/src/rules/checkConstraintNotValid.js +116 -0
- package/dist/src/rules/checkConstraintNotValid.js.map +1 -0
- package/dist/src/rules/index.d.ts +3 -0
- package/dist/src/rules/index.d.ts.map +1 -1
- package/dist/src/rules/index.js +9 -0
- package/dist/src/rules/index.js.map +1 -1
- package/dist/src/rules/sessionAdvisoryLock.d.ts +9 -0
- package/dist/src/rules/sessionAdvisoryLock.d.ts.map +1 -0
- package/dist/src/rules/sessionAdvisoryLock.js +47 -0
- package/dist/src/rules/sessionAdvisoryLock.js.map +1 -0
- package/dist/src/rules/uniqueConstraintUsingIndex.d.ts +9 -0
- package/dist/src/rules/uniqueConstraintUsingIndex.d.ts.map +1 -0
- package/dist/src/rules/uniqueConstraintUsingIndex.js +145 -0
- package/dist/src/rules/uniqueConstraintUsingIndex.js.map +1 -0
- package/dist/src/wrapper/orchestrator.d.ts +62 -0
- package/dist/src/wrapper/orchestrator.d.ts.map +1 -0
- package/dist/src/wrapper/orchestrator.js +481 -0
- package/dist/src/wrapper/orchestrator.js.map +1 -0
- package/package.json +2 -2
package/dist/src/rules/index.js
CHANGED
|
@@ -9,6 +9,9 @@ export { foreignKeyNotValidRule } from './foreignKeyNotValid.js';
|
|
|
9
9
|
export { prismaRenameDropAddRule } from './prismaRenameDropAdd.js';
|
|
10
10
|
export { setNotNullFullScanRule } from './setNotNullFullScan.js';
|
|
11
11
|
export { unbatchedBackfillRule } from './unbatchedBackfill.js';
|
|
12
|
+
export { checkConstraintNotValidRule } from './checkConstraintNotValid.js';
|
|
13
|
+
export { uniqueConstraintUsingIndexRule } from './uniqueConstraintUsingIndex.js';
|
|
14
|
+
export { sessionAdvisoryLockRule } from './sessionAdvisoryLock.js';
|
|
12
15
|
import { indexConcurrentlyRule } from './indexConcurrently.js';
|
|
13
16
|
import { transactionTrapRule } from './transactionTrap.js';
|
|
14
17
|
import { addColumnNotNullRule } from './addColumnNotNull.js';
|
|
@@ -16,6 +19,9 @@ import { foreignKeyNotValidRule } from './foreignKeyNotValid.js';
|
|
|
16
19
|
import { prismaRenameDropAddRule } from './prismaRenameDropAdd.js';
|
|
17
20
|
import { setNotNullFullScanRule } from './setNotNullFullScan.js';
|
|
18
21
|
import { unbatchedBackfillRule } from './unbatchedBackfill.js';
|
|
22
|
+
import { checkConstraintNotValidRule } from './checkConstraintNotValid.js';
|
|
23
|
+
import { uniqueConstraintUsingIndexRule } from './uniqueConstraintUsingIndex.js';
|
|
24
|
+
import { sessionAdvisoryLockRule } from './sessionAdvisoryLock.js';
|
|
19
25
|
export const ALL_RULES = [
|
|
20
26
|
indexConcurrentlyRule,
|
|
21
27
|
transactionTrapRule,
|
|
@@ -24,5 +30,8 @@ export const ALL_RULES = [
|
|
|
24
30
|
prismaRenameDropAddRule,
|
|
25
31
|
setNotNullFullScanRule,
|
|
26
32
|
unbatchedBackfillRule,
|
|
33
|
+
checkConstraintNotValidRule,
|
|
34
|
+
uniqueConstraintUsingIndexRule,
|
|
35
|
+
sessionAdvisoryLockRule,
|
|
27
36
|
];
|
|
28
37
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/rules/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/rules/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,cAAc,YAAY,CAAC;AAC3B,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAE,8BAA8B,EAAE,MAAM,iCAAiC,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAGnE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,uBAAuB,CAAC;AAC7D,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AACnE,OAAO,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AACjE,OAAO,EAAE,qBAAqB,EAAE,MAAM,wBAAwB,CAAC;AAC/D,OAAO,EAAE,2BAA2B,EAAE,MAAM,8BAA8B,CAAC;AAC3E,OAAO,EAAE,8BAA8B,EAAE,MAAM,iCAAiC,CAAC;AACjF,OAAO,EAAE,uBAAuB,EAAE,MAAM,0BAA0B,CAAC;AAEnE,MAAM,CAAC,MAAM,SAAS,GAAW;IAC/B,qBAAqB;IACrB,mBAAmB;IACnB,oBAAoB;IACpB,sBAAsB;IACtB,uBAAuB;IACvB,sBAAsB;IACtB,qBAAqB;IACrB,2BAA2B;IAC3B,8BAA8B;IAC9B,uBAAuB;CACxB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionAdvisoryLock.d.ts","sourceRoot":"","sources":["../../../src/rules/sessionAdvisoryLock.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAwB,MAAM,YAAY,CAAC;AAGxD,eAAO,MAAM,uBAAuB,EAAE,IA8CrC,CAAC"}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ddlforge Rule: Session-level advisory lock
|
|
3
|
+
*
|
|
4
|
+
* Severity: WARNING
|
|
5
|
+
* Lock: NONE
|
|
6
|
+
*/
|
|
7
|
+
import { PostgresLockLevel } from '../engine/locks.js';
|
|
8
|
+
export const sessionAdvisoryLockRule = {
|
|
9
|
+
id: 'session-advisory-lock',
|
|
10
|
+
name: 'Session-level advisory lock',
|
|
11
|
+
description: 'Session-level advisory locks (pg_advisory_lock / pg_try_advisory_lock) are tied to the database connection, not the transaction. In connection-pooled environments, these locks leak across connections.',
|
|
12
|
+
defaultSeverity: 'WARNING',
|
|
13
|
+
lockLevel: PostgresLockLevel.NONE,
|
|
14
|
+
check(context) {
|
|
15
|
+
const findings = [];
|
|
16
|
+
for (const stmt of context.statements) {
|
|
17
|
+
if (stmt.hasIgnore(this.id))
|
|
18
|
+
continue;
|
|
19
|
+
for (const token of stmt.tokens) {
|
|
20
|
+
const raw = token.raw;
|
|
21
|
+
// Match pg_advisory_lock or pg_try_advisory_lock (case-insensitive)
|
|
22
|
+
// but NOT pg_advisory_xact_lock or pg_try_advisory_xact_lock
|
|
23
|
+
if (/^pg_(try_)?advisory_lock$/i.test(raw) &&
|
|
24
|
+
!/^pg_(try_)?advisory_xact_lock$/i.test(raw)) {
|
|
25
|
+
findings.push({
|
|
26
|
+
ruleId: this.id,
|
|
27
|
+
ruleName: this.name,
|
|
28
|
+
severity: this.defaultSeverity,
|
|
29
|
+
lockLevel: this.lockLevel,
|
|
30
|
+
message: `Session-level advisory lock "${raw}(...)" detected.`,
|
|
31
|
+
detail: `Session-level advisory locks (pg_advisory_lock / pg_try_advisory_lock) are tied to the database connection, not the transaction. ` +
|
|
32
|
+
`In connection-pooled environments (PgBouncer transaction mode), these locks leak across connections, leading to stranded locks and potential migration deadlocks.`,
|
|
33
|
+
suggestion: `Replace with transaction-scoped variants that auto-release on COMMIT or ROLLBACK:\n` +
|
|
34
|
+
` pg_advisory_xact_lock(key) -- blocks until acquired\n` +
|
|
35
|
+
` pg_try_advisory_xact_lock(key) -- returns false if not immediately available`,
|
|
36
|
+
file: context.filePath,
|
|
37
|
+
line: stmt.startLine,
|
|
38
|
+
column: stmt.startColumn,
|
|
39
|
+
codeSnippet: stmt.raw,
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return findings;
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
//# sourceMappingURL=sessionAdvisoryLock.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sessionAdvisoryLock.js","sourceRoot":"","sources":["../../../src/rules/sessionAdvisoryLock.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAEvD,MAAM,CAAC,MAAM,uBAAuB,GAAS;IAC3C,EAAE,EAAE,uBAAuB;IAC3B,IAAI,EAAE,6BAA6B;IACnC,WAAW,EAAE,0MAA0M;IACvN,eAAe,EAAE,SAAS;IAC1B,SAAS,EAAE,iBAAiB,CAAC,IAAI;IAEjC,KAAK,CAAC,OAAoB;QACxB,MAAM,QAAQ,GAAc,EAAE,CAAC;QAE/B,KAAK,MAAM,IAAI,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;YACtC,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAE,CAAC;gBAAE,SAAS;YAEtC,KAAK,MAAM,KAAK,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChC,MAAM,GAAG,GAAG,KAAK,CAAC,GAAG,CAAC;gBAEtB,oEAAoE;gBACpE,6DAA6D;gBAC7D,IACE,4BAA4B,CAAC,IAAI,CAAC,GAAG,CAAC;oBACtC,CAAC,iCAAiC,CAAC,IAAI,CAAC,GAAG,CAAC,EAC5C,CAAC;oBACD,QAAQ,CAAC,IAAI,CAAC;wBACZ,MAAM,EAAE,IAAI,CAAC,EAAE;wBACf,QAAQ,EAAE,IAAI,CAAC,IAAI;wBACnB,QAAQ,EAAE,IAAI,CAAC,eAAe;wBAC9B,SAAS,EAAE,IAAI,CAAC,SAAS;wBACzB,OAAO,EAAE,gCAAgC,GAAG,kBAAkB;wBAC9D,MAAM,EACJ,mIAAmI;4BACnI,mKAAmK;wBACrK,UAAU,EACR,qFAAqF;4BACrF,8DAA8D;4BAC9D,iFAAiF;wBACnF,IAAI,EAAE,OAAO,CAAC,QAAQ;wBACtB,IAAI,EAAE,IAAI,CAAC,SAAS;wBACpB,MAAM,EAAE,IAAI,CAAC,WAAW;wBACxB,WAAW,EAAE,IAAI,CAAC,GAAG;qBACtB,CAAC,CAAC;gBACL,CAAC;YACH,CAAC;QACH,CAAC;QAED,OAAO,QAAQ,CAAC;IAClB,CAAC;CACF,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ddlforge Rule: ADD CONSTRAINT UNIQUE without pre-built index
|
|
3
|
+
*
|
|
4
|
+
* Severity: BLOCKER
|
|
5
|
+
* Lock: SHARE
|
|
6
|
+
*/
|
|
7
|
+
import { Rule } from './types.js';
|
|
8
|
+
export declare const uniqueConstraintUsingIndexRule: Rule;
|
|
9
|
+
//# sourceMappingURL=uniqueConstraintUsingIndex.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uniqueConstraintUsingIndex.d.ts","sourceRoot":"","sources":["../../../src/rules/uniqueConstraintUsingIndex.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,EAAE,IAAI,EAAwB,MAAM,YAAY,CAAC;AA0GxD,eAAO,MAAM,8BAA8B,EAAE,IAyD5C,CAAC"}
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ddlforge Rule: ADD CONSTRAINT UNIQUE without pre-built index
|
|
3
|
+
*
|
|
4
|
+
* Severity: BLOCKER
|
|
5
|
+
* Lock: SHARE
|
|
6
|
+
*/
|
|
7
|
+
import { PostgresLockLevel } from '../engine/locks.js';
|
|
8
|
+
function extractUniqueConstraintClauses(tokens) {
|
|
9
|
+
const clauses = [];
|
|
10
|
+
let parenDepth = 0;
|
|
11
|
+
let i = 0;
|
|
12
|
+
while (i < tokens.length) {
|
|
13
|
+
if (tokens[i].value === '(') {
|
|
14
|
+
parenDepth++;
|
|
15
|
+
i++;
|
|
16
|
+
continue;
|
|
17
|
+
}
|
|
18
|
+
if (tokens[i].value === ')') {
|
|
19
|
+
parenDepth--;
|
|
20
|
+
i++;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
if (parenDepth === 0 && tokens[i].value === 'ADD') {
|
|
24
|
+
let currentIdx = i + 1;
|
|
25
|
+
let constraintName;
|
|
26
|
+
if (tokens[currentIdx]?.value === 'CONSTRAINT') {
|
|
27
|
+
currentIdx++;
|
|
28
|
+
constraintName = tokens[currentIdx]?.raw;
|
|
29
|
+
currentIdx++;
|
|
30
|
+
}
|
|
31
|
+
// Check if this clause is a UNIQUE constraint
|
|
32
|
+
if (tokens[currentIdx]?.value === 'UNIQUE') {
|
|
33
|
+
currentIdx++;
|
|
34
|
+
// If next significant token is USING, it's the safe USING INDEX form
|
|
35
|
+
const isUsingIndex = tokens[currentIdx]?.value === 'USING' &&
|
|
36
|
+
tokens[currentIdx + 1]?.value === 'INDEX';
|
|
37
|
+
// Collect column list from the (...) after UNIQUE, if present
|
|
38
|
+
let columns = '<columns>';
|
|
39
|
+
if (!isUsingIndex && tokens[currentIdx]?.value === '(') {
|
|
40
|
+
// Collect raw tokens inside the parens
|
|
41
|
+
const colTokens = [];
|
|
42
|
+
let subParen = 1;
|
|
43
|
+
currentIdx++; // move past '('
|
|
44
|
+
while (currentIdx < tokens.length && subParen > 0) {
|
|
45
|
+
const t = tokens[currentIdx];
|
|
46
|
+
if (t.value === '(')
|
|
47
|
+
subParen++;
|
|
48
|
+
else if (t.value === ')') {
|
|
49
|
+
subParen--;
|
|
50
|
+
if (subParen === 0)
|
|
51
|
+
break;
|
|
52
|
+
}
|
|
53
|
+
colTokens.push(t.raw);
|
|
54
|
+
currentIdx++;
|
|
55
|
+
}
|
|
56
|
+
columns = colTokens.join(', ');
|
|
57
|
+
}
|
|
58
|
+
// Collect all tokens for this constraint until top-level comma or end
|
|
59
|
+
const clauseTokens = [];
|
|
60
|
+
let subParen = 0;
|
|
61
|
+
// Reset to position right after UNIQUE keyword (already advanced above)
|
|
62
|
+
// Re-scan from after UNIQUE to gather full clause tokens
|
|
63
|
+
let scanIdx = i + 1;
|
|
64
|
+
// Skip past CONSTRAINT <name> and UNIQUE
|
|
65
|
+
if (tokens[scanIdx]?.value === 'CONSTRAINT')
|
|
66
|
+
scanIdx += 2;
|
|
67
|
+
scanIdx++; // skip UNIQUE
|
|
68
|
+
while (scanIdx < tokens.length) {
|
|
69
|
+
const t = tokens[scanIdx];
|
|
70
|
+
if (t.value === '(')
|
|
71
|
+
subParen++;
|
|
72
|
+
if (t.value === ')')
|
|
73
|
+
subParen--;
|
|
74
|
+
if (subParen === 0 && t.value === ',')
|
|
75
|
+
break;
|
|
76
|
+
clauseTokens.push(t);
|
|
77
|
+
scanIdx++;
|
|
78
|
+
}
|
|
79
|
+
clauses.push({
|
|
80
|
+
constraintName,
|
|
81
|
+
columns,
|
|
82
|
+
isUsingIndex,
|
|
83
|
+
tokens: clauseTokens,
|
|
84
|
+
});
|
|
85
|
+
i = scanIdx;
|
|
86
|
+
continue;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
i++;
|
|
90
|
+
}
|
|
91
|
+
return clauses;
|
|
92
|
+
}
|
|
93
|
+
export const uniqueConstraintUsingIndexRule = {
|
|
94
|
+
id: 'unique-constraint-using-index',
|
|
95
|
+
name: 'ADD CONSTRAINT UNIQUE without pre-built index',
|
|
96
|
+
description: 'Adding a UNIQUE constraint directly takes a SHARE lock and performs a full-table scan, blocking all concurrent writes (INSERT, UPDATE, DELETE) for the entire duration.',
|
|
97
|
+
defaultSeverity: 'BLOCKER',
|
|
98
|
+
lockLevel: PostgresLockLevel.SHARE,
|
|
99
|
+
check(context) {
|
|
100
|
+
const findings = [];
|
|
101
|
+
for (const stmt of context.statements) {
|
|
102
|
+
if (stmt.hasIgnore(this.id))
|
|
103
|
+
continue;
|
|
104
|
+
const tokens = stmt.tokens;
|
|
105
|
+
if (tokens.length < 6)
|
|
106
|
+
continue;
|
|
107
|
+
if (tokens[0].value !== 'ALTER' || tokens[1].value !== 'TABLE')
|
|
108
|
+
continue;
|
|
109
|
+
// Extract table name
|
|
110
|
+
let idx = 2;
|
|
111
|
+
if (tokens[idx]?.value === 'ONLY')
|
|
112
|
+
idx++;
|
|
113
|
+
if (tokens[idx]?.value === 'IF' && tokens[idx + 1]?.value === 'EXISTS')
|
|
114
|
+
idx += 2;
|
|
115
|
+
const tableName = tokens[idx]?.raw ?? 'table';
|
|
116
|
+
idx++;
|
|
117
|
+
const clauses = extractUniqueConstraintClauses(tokens.slice(idx));
|
|
118
|
+
for (const clause of clauses) {
|
|
119
|
+
if (!clause.isUsingIndex) {
|
|
120
|
+
const cName = clause.constraintName ?? 'uq_name';
|
|
121
|
+
const cNameDisplay = clause.constraintName ? ` "${clause.constraintName}"` : '';
|
|
122
|
+
const idxName = clause.constraintName ? `${clause.constraintName}_idx` : 'uq_idx_name';
|
|
123
|
+
findings.push({
|
|
124
|
+
ruleId: this.id,
|
|
125
|
+
ruleName: this.name,
|
|
126
|
+
severity: this.defaultSeverity,
|
|
127
|
+
lockLevel: this.lockLevel,
|
|
128
|
+
message: `UNIQUE constraint${cNameDisplay} on table "${tableName}" added without a pre-built index.`,
|
|
129
|
+
detail: `Adding a UNIQUE constraint directly takes a SHARE lock and performs a full-table scan, blocking all concurrent writes (INSERT, UPDATE, DELETE) for the entire duration.`,
|
|
130
|
+
suggestion: `1. Build the unique index concurrently first (no table lock):\n` +
|
|
131
|
+
` CREATE UNIQUE INDEX CONCURRENTLY ${idxName} ON ${tableName} (${clause.columns});\n` +
|
|
132
|
+
`2. Attach it as a constraint without a table scan:\n` +
|
|
133
|
+
` ALTER TABLE ${tableName} ADD CONSTRAINT ${cName} UNIQUE USING INDEX ${idxName};`,
|
|
134
|
+
file: context.filePath,
|
|
135
|
+
line: stmt.startLine,
|
|
136
|
+
column: stmt.startColumn,
|
|
137
|
+
codeSnippet: stmt.raw,
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
return findings;
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
//# sourceMappingURL=uniqueConstraintUsingIndex.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uniqueConstraintUsingIndex.js","sourceRoot":"","sources":["../../../src/rules/uniqueConstraintUsingIndex.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ddlforge - ORM Migration Supervisor (Wrap orchestrator)
|
|
3
|
+
*
|
|
4
|
+
* Intercepts pending migration files (Prisma / Drizzle / custom),
|
|
5
|
+
* runs pre-flight safety analysis, and delegates execution to the
|
|
6
|
+
* underlying migration command.
|
|
7
|
+
*/
|
|
8
|
+
import { AnalysisResult } from '../engine/analyzer.js';
|
|
9
|
+
export interface DiscoveredMigration {
|
|
10
|
+
name: string;
|
|
11
|
+
filePath: string;
|
|
12
|
+
projectType: 'prisma' | 'drizzle' | 'generic';
|
|
13
|
+
}
|
|
14
|
+
export interface WrapOptions {
|
|
15
|
+
dir?: string;
|
|
16
|
+
allowBlockers?: boolean;
|
|
17
|
+
databaseUrl?: string;
|
|
18
|
+
command: string[];
|
|
19
|
+
help?: boolean;
|
|
20
|
+
cwd?: string;
|
|
21
|
+
}
|
|
22
|
+
export interface WrapResult {
|
|
23
|
+
success: boolean;
|
|
24
|
+
exitCode: number;
|
|
25
|
+
blockersCount: number;
|
|
26
|
+
warningsCount: number;
|
|
27
|
+
migrationsCount: number;
|
|
28
|
+
executedCommand: boolean;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Parses arguments for the `wrap` subcommand.
|
|
32
|
+
* argv should be the args after the "wrap" token.
|
|
33
|
+
* E.g. `['--dir=./drizzle', '--', 'npx', 'drizzle-kit', 'migrate']`
|
|
34
|
+
*/
|
|
35
|
+
export declare function parseWrapArgs(argv: string[]): WrapOptions;
|
|
36
|
+
/**
|
|
37
|
+
* Scans directories to detect migration files for Prisma, Drizzle, or generic layouts.
|
|
38
|
+
*/
|
|
39
|
+
export declare function detectMigrations(dir?: string, cwd?: string): DiscoveredMigration[];
|
|
40
|
+
/**
|
|
41
|
+
* Connects to PostgreSQL and queries applied migration tables (_prisma_migrations or __drizzle_migrations).
|
|
42
|
+
* Returns the filtered set of pending (unapplied) migrations.
|
|
43
|
+
*/
|
|
44
|
+
export declare function filterPendingMigrations(migrations: DiscoveredMigration[], databaseUrl?: string): Promise<DiscoveredMigration[]>;
|
|
45
|
+
/**
|
|
46
|
+
* Runs ddlforge rules against candidate migration files.
|
|
47
|
+
*/
|
|
48
|
+
export declare function runPreflightCheck(migrations: DiscoveredMigration[]): AnalysisResult[];
|
|
49
|
+
/**
|
|
50
|
+
* Spawns the user migration command as a child process with inherited stdio.
|
|
51
|
+
*/
|
|
52
|
+
export declare function spawnCommand(command: string[], cwd?: string): Promise<number>;
|
|
53
|
+
/**
|
|
54
|
+
* Main orchestrator workflow for `ddlforge wrap`.
|
|
55
|
+
*/
|
|
56
|
+
export declare function orchestrateWrap(options: WrapOptions): Promise<WrapResult>;
|
|
57
|
+
export declare function printWrapHelp(): void;
|
|
58
|
+
/**
|
|
59
|
+
* CLI entry point for the `wrap` subcommand.
|
|
60
|
+
*/
|
|
61
|
+
export declare function runWrap(argv: string[], cwd?: string): Promise<number>;
|
|
62
|
+
//# sourceMappingURL=orchestrator.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"orchestrator.d.ts","sourceRoot":"","sources":["../../../src/wrapper/orchestrator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,EAAqB,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG1E,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;CAC/C;AAED,MAAM,WAAW,WAAW;IAC1B,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;IACjB,aAAa,EAAE,MAAM,CAAC;IACtB,aAAa,EAAE,MAAM,CAAC;IACtB,eAAe,EAAE,MAAM,CAAC;IACxB,eAAe,EAAE,OAAO,CAAC;CAC1B;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,WAAW,CAwEzD;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,CAAC,EAAE,MAAM,EAAE,GAAG,GAAE,MAAsB,GAAG,mBAAmB,EAAE,CA6IjG;AAqBD;;;GAGG;AACH,wBAAsB,uBAAuB,CAC3C,UAAU,EAAE,mBAAmB,EAAE,EACjC,WAAW,CAAC,EAAE,MAAM,GACnB,OAAO,CAAC,mBAAmB,EAAE,CAAC,CAsEhC;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,UAAU,EAAE,mBAAmB,EAAE,GAAG,cAAc,EAAE,CAqBrF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyC5F;AAED;;GAEG;AACH,wBAAsB,eAAe,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,UAAU,CAAC,CAoE/E;AAED,wBAAgB,aAAa,IAAI,IAAI,CAqBpC;AAED;;GAEG;AACH,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,GAAG,GAAE,MAAsB,GAAG,OAAO,CAAC,MAAM,CAAC,CAiB1F"}
|