MCPcopy Index your code
hub / github.com/simstudioai/sim / classify

Function classify

scripts/check-migrations-safety.ts:194–326  ·  view source on GitHub ↗

* Classify one statement. `createdTables` holds tables created in the same * migration — ops against a brand-new table have no old rows and no live * traffic, so they are always safe and skipped. `sawCommit` tracks whether a * `COMMIT;` breakpoint preceded a CONCURRENTLY index (see migrate.ts).

(sql: string, createdTables: Set<string>, sawCommit: boolean)

Source from the content-addressed store, hash-verified

192 * `COMMIT;` breakpoint preceded a CONCURRENTLY index (see migrate.ts).
193 */
194function classify(sql: string, createdTables: Set<string>, sawCommit: boolean): RawMatch[] {
195 const s = sql.replace(/\s+/g, ' ').trim()
196 const matches: RawMatch[] = []
197
198 const alterTable = s.match(/\bALTER TABLE (?:IF EXISTS )?(?:ONLY )?("?[.\w]+"?)/i)
199 const targetTable = alterTable ? bareName(alterTable[1]) : null
200 const onNewTable = targetTable !== null && createdTables.has(targetTable)
201
202 if (/^CREATE (?:UNIQUE )?INDEX\b/i.test(s)) {
203 const on = s.match(/\bON ("?[.\w]+"?)/i)
204 const indexTable = on ? bareName(on[1]) : null
205 const concurrent = /\bCONCURRENTLY\b/i.test(s)
206 if (!(indexTable && createdTables.has(indexTable))) {
207 if (!concurrent) {
208 matches.push({
209 kind: 'error',
210 rule: 'index-not-concurrent',
211 message:
212 'CREATE INDEX on an existing table write-locks it for the whole build. Use CREATE INDEX CONCURRENTLY IF NOT EXISTS after a COMMIT; breakpoint (see packages/db/scripts/migrate.ts).',
213 })
214 } else if (!/\bIF NOT EXISTS\b/i.test(s)) {
215 matches.push({
216 kind: 'error',
217 rule: 'concurrent-index-not-idempotent',
218 message:
219 'CREATE INDEX CONCURRENTLY must be IF NOT EXISTS — a failed build replays from the top and a partial INVALID index would be skipped forever.',
220 })
221 } else if (!sawCommit) {
222 matches.push({
223 kind: 'error',
224 rule: 'concurrent-index-no-commit',
225 message:
226 'CREATE INDEX CONCURRENTLY cannot run inside the migration transaction. Precede it with a COMMIT; breakpoint and SET lock_timeout = 0 (see packages/db/scripts/migrate.ts).',
227 })
228 }
229 }
230 }
231
232 if (
233 !onNewTable &&
234 /\bADD COLUMN\b/i.test(s) &&
235 /\bNOT NULL\b/i.test(s) &&
236 !/\bDEFAULT\b/i.test(s)
237 ) {
238 matches.push({
239 kind: 'error',
240 rule: 'add-not-null-no-default',
241 message:
242 'ADD COLUMN NOT NULL with no DEFAULT breaks old inserts (and fails on existing rows). Add it nullable or with a DEFAULT, backfill, then SET NOT NULL in a later migration once code populates it.',
243 })
244 }
245
246 if (/\bRENAME COLUMN\b/i.test(s) || /^ALTER TABLE\b[^;]*\bRENAME TO\b/i.test(s)) {
247 matches.push({
248 kind: 'error',
249 rule: 'rename',
250 message:
251 'RENAME of a column/table breaks old code reading the old name. Add the new column/table, dual-write in code, then drop the old one in a later deploy.',

Callers 1

lintSqlFunction · 0.85

Calls 4

bareNameFunction · 0.85
testMethod · 0.80
replaceMethod · 0.65
pushMethod · 0.45

Tested by

no test coverage detected