turbine-orm 0.27.0 → 0.27.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.
@@ -75,6 +75,45 @@ function stripCommentsAndStrings(sql) {
75
75
  /** Unquote a "quoted" identifier for display. */
76
76
  const ident = (raw) => (raw ?? '?').replace(/^"|"$/g, '');
77
77
  const IDENT = String.raw `("[^"]+"|[a-zA-Z_][\w$]*)(\.("[^"]+"|[a-zA-Z_][\w$]*))?`;
78
+ /** Ordered rules — first match per statement wins. */
79
+ const RULES = [
80
+ {
81
+ kind: 'drop-table',
82
+ regex: new RegExp(String.raw `^DROP\s+TABLE\s+(IF\s+EXISTS\s+)?${IDENT}`, 'i'),
83
+ target: (m) => (m[4] ? `${ident(m[2])}.${ident(m[4])}` : ident(m[2])),
84
+ },
85
+ {
86
+ kind: 'drop-schema',
87
+ regex: new RegExp(String.raw `^DROP\s+SCHEMA\s+(IF\s+EXISTS\s+)?${IDENT}`, 'i'),
88
+ target: (m) => ident(m[2]),
89
+ },
90
+ {
91
+ kind: 'truncate',
92
+ regex: new RegExp(String.raw `^TRUNCATE\s+(TABLE\s+)?(ONLY\s+)?${IDENT}`, 'i'),
93
+ target: (m) => (m[5] ? `${ident(m[3])}.${ident(m[5])}` : ident(m[3])),
94
+ },
95
+ {
96
+ kind: 'drop-column',
97
+ regex: new RegExp(String.raw `^ALTER\s+TABLE\s+(IF\s+EXISTS\s+)?(ONLY\s+)?${IDENT}[\s\S]*?\bDROP\s+COLUMN\s+(IF\s+EXISTS\s+)?${IDENT}`, 'i'),
98
+ target: (m) => `${ident(m[3])}.${ident(m[7])}`,
99
+ },
100
+ {
101
+ kind: 'alter-column-type',
102
+ regex: new RegExp(String.raw `^ALTER\s+TABLE\s+(IF\s+EXISTS\s+)?(ONLY\s+)?${IDENT}[\s\S]*?\bALTER\s+(COLUMN\s+)?${IDENT}\s+(SET\s+DATA\s+)?TYPE\b`, 'i'),
103
+ target: (m) => `${ident(m[3])}.${ident(m[7])}`,
104
+ },
105
+ {
106
+ kind: 'delete',
107
+ regex: new RegExp(String.raw `^DELETE\s+FROM\s+(ONLY\s+)?${IDENT}`, 'i'),
108
+ target: (m) => ident(m[2]),
109
+ },
110
+ {
111
+ kind: 'update-without-where',
112
+ regex: new RegExp(String.raw `^UPDATE\s+(ONLY\s+)?${IDENT}\b`, 'i'),
113
+ target: (m) => ident(m[2]),
114
+ also: (stmt) => !/\bWHERE\b/i.test(stmt),
115
+ },
116
+ ];
78
117
  /**
79
118
  * Scan SQL (one file's worth; may contain many `;`-separated statements) and
80
119
  * return every statement that can destroy data.
@@ -86,37 +125,14 @@ function scanDestructiveSql(sql) {
86
125
  const stmt = rawStmt.trim();
87
126
  if (!stmt)
88
127
  continue;
89
- const display = stmt.replace(/\s+/g, ' ');
90
- let m;
91
- if ((m = stmt.match(new RegExp(String.raw `^DROP\s+TABLE\s+(IF\s+EXISTS\s+)?${IDENT}`, 'i')))) {
92
- found.push({
93
- statement: display,
94
- kind: 'drop-table',
95
- target: ident(m[4] ? `${ident(m[2])}.${ident(m[4])}` : m[2]),
96
- });
97
- }
98
- else if ((m = stmt.match(new RegExp(String.raw `^DROP\s+SCHEMA\s+(IF\s+EXISTS\s+)?${IDENT}`, 'i')))) {
99
- found.push({ statement: display, kind: 'drop-schema', target: ident(m[2]) });
100
- }
101
- else if ((m = stmt.match(new RegExp(String.raw `^TRUNCATE\s+(TABLE\s+)?(ONLY\s+)?${IDENT}`, 'i')))) {
102
- found.push({
103
- statement: display,
104
- kind: 'truncate',
105
- target: ident(m[5] ? `${ident(m[3])}.${ident(m[5])}` : m[3]),
106
- });
107
- }
108
- else if ((m = stmt.match(new RegExp(String.raw `^ALTER\s+TABLE\s+(IF\s+EXISTS\s+)?(ONLY\s+)?${IDENT}[\s\S]*?\bDROP\s+COLUMN\s+(IF\s+EXISTS\s+)?${IDENT}`, 'i')))) {
109
- found.push({ statement: display, kind: 'drop-column', target: `${ident(m[3])}.${ident(m[7])}` });
110
- }
111
- else if ((m = stmt.match(new RegExp(String.raw `^ALTER\s+TABLE\s+(IF\s+EXISTS\s+)?(ONLY\s+)?${IDENT}[\s\S]*?\bALTER\s+(COLUMN\s+)?${IDENT}\s+(SET\s+DATA\s+)?TYPE\b`, 'i')))) {
112
- found.push({ statement: display, kind: 'alter-column-type', target: `${ident(m[3])}.${ident(m[7])}` });
113
- }
114
- else if ((m = stmt.match(new RegExp(String.raw `^DELETE\s+FROM\s+(ONLY\s+)?${IDENT}`, 'i')))) {
115
- found.push({ statement: display, kind: 'delete', target: ident(m[2]) });
116
- }
117
- else if ((m = stmt.match(new RegExp(String.raw `^UPDATE\s+(ONLY\s+)?${IDENT}\b`, 'i'))) &&
118
- !/\bWHERE\b/i.test(stmt)) {
119
- found.push({ statement: display, kind: 'update-without-where', target: ident(m[2]) });
128
+ for (const rule of RULES) {
129
+ const m = stmt.match(rule.regex);
130
+ if (!m)
131
+ continue;
132
+ if (rule.also && !rule.also(stmt))
133
+ continue;
134
+ found.push({ statement: stmt.replace(/\s+/g, ' '), kind: rule.kind, target: rule.target(m) });
135
+ break;
120
136
  }
121
137
  }
122
138
  return found;
@@ -71,6 +71,45 @@ function stripCommentsAndStrings(sql) {
71
71
  /** Unquote a "quoted" identifier for display. */
72
72
  const ident = (raw) => (raw ?? '?').replace(/^"|"$/g, '');
73
73
  const IDENT = String.raw `("[^"]+"|[a-zA-Z_][\w$]*)(\.("[^"]+"|[a-zA-Z_][\w$]*))?`;
74
+ /** Ordered rules — first match per statement wins. */
75
+ const RULES = [
76
+ {
77
+ kind: 'drop-table',
78
+ regex: new RegExp(String.raw `^DROP\s+TABLE\s+(IF\s+EXISTS\s+)?${IDENT}`, 'i'),
79
+ target: (m) => (m[4] ? `${ident(m[2])}.${ident(m[4])}` : ident(m[2])),
80
+ },
81
+ {
82
+ kind: 'drop-schema',
83
+ regex: new RegExp(String.raw `^DROP\s+SCHEMA\s+(IF\s+EXISTS\s+)?${IDENT}`, 'i'),
84
+ target: (m) => ident(m[2]),
85
+ },
86
+ {
87
+ kind: 'truncate',
88
+ regex: new RegExp(String.raw `^TRUNCATE\s+(TABLE\s+)?(ONLY\s+)?${IDENT}`, 'i'),
89
+ target: (m) => (m[5] ? `${ident(m[3])}.${ident(m[5])}` : ident(m[3])),
90
+ },
91
+ {
92
+ kind: 'drop-column',
93
+ regex: new RegExp(String.raw `^ALTER\s+TABLE\s+(IF\s+EXISTS\s+)?(ONLY\s+)?${IDENT}[\s\S]*?\bDROP\s+COLUMN\s+(IF\s+EXISTS\s+)?${IDENT}`, 'i'),
94
+ target: (m) => `${ident(m[3])}.${ident(m[7])}`,
95
+ },
96
+ {
97
+ kind: 'alter-column-type',
98
+ regex: new RegExp(String.raw `^ALTER\s+TABLE\s+(IF\s+EXISTS\s+)?(ONLY\s+)?${IDENT}[\s\S]*?\bALTER\s+(COLUMN\s+)?${IDENT}\s+(SET\s+DATA\s+)?TYPE\b`, 'i'),
99
+ target: (m) => `${ident(m[3])}.${ident(m[7])}`,
100
+ },
101
+ {
102
+ kind: 'delete',
103
+ regex: new RegExp(String.raw `^DELETE\s+FROM\s+(ONLY\s+)?${IDENT}`, 'i'),
104
+ target: (m) => ident(m[2]),
105
+ },
106
+ {
107
+ kind: 'update-without-where',
108
+ regex: new RegExp(String.raw `^UPDATE\s+(ONLY\s+)?${IDENT}\b`, 'i'),
109
+ target: (m) => ident(m[2]),
110
+ also: (stmt) => !/\bWHERE\b/i.test(stmt),
111
+ },
112
+ ];
74
113
  /**
75
114
  * Scan SQL (one file's worth; may contain many `;`-separated statements) and
76
115
  * return every statement that can destroy data.
@@ -82,37 +121,14 @@ export function scanDestructiveSql(sql) {
82
121
  const stmt = rawStmt.trim();
83
122
  if (!stmt)
84
123
  continue;
85
- const display = stmt.replace(/\s+/g, ' ');
86
- let m;
87
- if ((m = stmt.match(new RegExp(String.raw `^DROP\s+TABLE\s+(IF\s+EXISTS\s+)?${IDENT}`, 'i')))) {
88
- found.push({
89
- statement: display,
90
- kind: 'drop-table',
91
- target: ident(m[4] ? `${ident(m[2])}.${ident(m[4])}` : m[2]),
92
- });
93
- }
94
- else if ((m = stmt.match(new RegExp(String.raw `^DROP\s+SCHEMA\s+(IF\s+EXISTS\s+)?${IDENT}`, 'i')))) {
95
- found.push({ statement: display, kind: 'drop-schema', target: ident(m[2]) });
96
- }
97
- else if ((m = stmt.match(new RegExp(String.raw `^TRUNCATE\s+(TABLE\s+)?(ONLY\s+)?${IDENT}`, 'i')))) {
98
- found.push({
99
- statement: display,
100
- kind: 'truncate',
101
- target: ident(m[5] ? `${ident(m[3])}.${ident(m[5])}` : m[3]),
102
- });
103
- }
104
- else if ((m = stmt.match(new RegExp(String.raw `^ALTER\s+TABLE\s+(IF\s+EXISTS\s+)?(ONLY\s+)?${IDENT}[\s\S]*?\bDROP\s+COLUMN\s+(IF\s+EXISTS\s+)?${IDENT}`, 'i')))) {
105
- found.push({ statement: display, kind: 'drop-column', target: `${ident(m[3])}.${ident(m[7])}` });
106
- }
107
- else if ((m = stmt.match(new RegExp(String.raw `^ALTER\s+TABLE\s+(IF\s+EXISTS\s+)?(ONLY\s+)?${IDENT}[\s\S]*?\bALTER\s+(COLUMN\s+)?${IDENT}\s+(SET\s+DATA\s+)?TYPE\b`, 'i')))) {
108
- found.push({ statement: display, kind: 'alter-column-type', target: `${ident(m[3])}.${ident(m[7])}` });
109
- }
110
- else if ((m = stmt.match(new RegExp(String.raw `^DELETE\s+FROM\s+(ONLY\s+)?${IDENT}`, 'i')))) {
111
- found.push({ statement: display, kind: 'delete', target: ident(m[2]) });
112
- }
113
- else if ((m = stmt.match(new RegExp(String.raw `^UPDATE\s+(ONLY\s+)?${IDENT}\b`, 'i'))) &&
114
- !/\bWHERE\b/i.test(stmt)) {
115
- found.push({ statement: display, kind: 'update-without-where', target: ident(m[2]) });
124
+ for (const rule of RULES) {
125
+ const m = stmt.match(rule.regex);
126
+ if (!m)
127
+ continue;
128
+ if (rule.also && !rule.also(stmt))
129
+ continue;
130
+ found.push({ statement: stmt.replace(/\s+/g, ' '), kind: rule.kind, target: rule.target(m) });
131
+ break;
116
132
  }
117
133
  }
118
134
  return found;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "turbine-orm",
3
- "version": "0.27.0",
3
+ "version": "0.27.1",
4
4
  "description": "Postgres-native TypeScript ORM — runs on Neon, Vercel Postgres, Cloudflare, Supabase. Streaming cursors, typed errors, single-query nested relations. One dependency, no WASM engine",
5
5
  "type": "module",
6
6
  "exports": {