Files
baiyue-firstleg/scripts/sql-baseline-contract-helpers.mjs
T

67 lines
2.6 KiB
JavaScript
Raw Normal View History

2026-09-16 17:15:18 +08:00
// Offline SQL-test helpers. No database access or command-line entry point.
import { readFileSync } from 'node:fs'
export function readInitialization(region = 'CN') {
const name = region === 'CN' ? '头程数据库统一增量-MySQL8.sql' : '海外区域统一增量-MySQL8.sql'
return readFileSync(new URL(`../deploy/sql/${name}`, import.meta.url), 'utf8')
}
export function tableDefinitions(sql) {
const result = new Map()
let schema
for (const match of sql.matchAll(/^USE (\w+);|^CREATE TABLE (\w+) \([\s\S]*?^\) ENGINE=[^\n]+;/gm)) {
if (match[1]) schema = match[1]
else {
const key = `${schema}.${match[2]}`
if (result.has(key)) throw new Error(`Duplicate table definition: ${key}`)
result.set(key, match[0])
}
}
return result
}
export function table(sql, schema, name) {
const value = tableDefinitions(sql).get(`${schema}.${name}`)
if (!value) throw new Error(`Missing table: ${schema}.${name}`)
return value
}
function splitValues(value) {
const items = []
let start = 0, depth = 0, quoted = false
for (let i = 0; i < value.length; i++) {
const c = value[i]
if (quoted && c === '\\') { i++; continue }
if (c === "'") {
if (quoted && value[i + 1] === "'") { i++; continue }
quoted = !quoted
}
if (quoted) continue
if (c === '(') depth++
if (c === ')') depth--
if (c === ',' && depth === 0) { items.push(value.slice(start, i).trim()); start = i + 1 }
}
if (quoted || depth) throw new Error('Unbalanced SQL seed value')
items.push(value.slice(start).trim())
return items.map(item => item === 'NULL' ? null : item.startsWith("'")
? item.slice(1, -1).replace(/''/g, "'").replace(/\\([\\'"nrt0])/g, (_, c) => ({ n: '\n', r: '\r', t: '\t', 0: '\0' }[c] ?? c))
: item)
}
export function seedRows(sql, name) {
const pattern = new RegExp(`^INSERT INTO ${name} \\(([^\\n]+?)\\) VALUES \\(([^\\n]+)\\);$`, 'gm')
return [...sql.matchAll(pattern)].map(match => {
const keys = match[1].split(',').map(key => key.trim())
const values = splitValues(match[2])
if (keys.length !== values.length) throw new Error(`Invalid seed columns: ${name}`)
return Object.fromEntries(keys.map((key, i) => [key, values[i]]))
})
}
export function roleAuthorities(sql, roleCode) {
const role = seedRows(sql, 'iam_role').find(row => row.role_code === roleCode)
if (!role) throw new Error(`Missing role: ${roleCode}`)
const granted = new Set(seedRows(sql, 'iam_role_permission').filter(row => row.role_id === role.id).map(row => row.permission_id))
return new Set(seedRows(sql, 'iam_permission').filter(row => granted.has(row.id)).map(row => row.permission_code))
}