mirror of
https://github.com/whyour/qinglong.git
synced 2026-09-22 02:27:44 +08:00
feat(ql3): establish 3.0 incubation baseline
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
const assert = require('node:assert/strict');
|
||||
const fs = require('node:fs');
|
||||
const os = require('node:os');
|
||||
const path = require('node:path');
|
||||
const { DatabaseSync } = require('node:sqlite');
|
||||
const { test } = require('node:test');
|
||||
const { getTableName } = require('drizzle-orm');
|
||||
const { getTableConfig } = require('drizzle-orm/sqlite-core');
|
||||
const { migrateLocalSqlitePath } = require('../dist/migration/migration');
|
||||
const { localSqliteSchema } = require('../dist/storage/schema');
|
||||
|
||||
function sorted(values) {
|
||||
return [...values].sort((left, right) =>
|
||||
JSON.stringify(left).localeCompare(JSON.stringify(right)),
|
||||
);
|
||||
}
|
||||
|
||||
function tableSql(client, tableName) {
|
||||
const row = client
|
||||
.prepare(
|
||||
`SELECT sql FROM sqlite_schema WHERE type = 'table' AND name = ?`,
|
||||
)
|
||||
.get(tableName);
|
||||
assert.equal(typeof row?.sql, 'string');
|
||||
return row.sql;
|
||||
}
|
||||
|
||||
function catalogChecks(sql) {
|
||||
return [...sql.matchAll(/CONSTRAINT\s+([A-Za-z0-9_]+)\s+CHECK\b/gi)].map(
|
||||
(match) => match[1],
|
||||
);
|
||||
}
|
||||
|
||||
function catalogForeignKeys(client, tableName) {
|
||||
const grouped = new Map();
|
||||
for (const entry of client
|
||||
.prepare(`PRAGMA foreign_key_list("${tableName}")`)
|
||||
.all()) {
|
||||
const current = grouped.get(entry.id) ?? {
|
||||
columns: [],
|
||||
foreignTable: entry.table,
|
||||
foreignColumns: [],
|
||||
onDelete: entry.on_delete,
|
||||
onUpdate: entry.on_update,
|
||||
};
|
||||
current.columns[entry.seq] = entry.from;
|
||||
current.foreignColumns[entry.seq] = entry.to;
|
||||
grouped.set(entry.id, current);
|
||||
}
|
||||
return [...grouped.values()];
|
||||
}
|
||||
|
||||
function drizzleForeignKeys(config) {
|
||||
return config.foreignKeys.map((foreignKey) => {
|
||||
const reference = foreignKey.reference();
|
||||
return {
|
||||
columns: reference.columns.map(({ name }) => name),
|
||||
foreignTable: getTableName(reference.foreignTable),
|
||||
foreignColumns: reference.foreignColumns.map(({ name }) => name),
|
||||
onDelete: (foreignKey.onDelete ?? 'no action').toUpperCase(),
|
||||
onUpdate: (foreignKey.onUpdate ?? 'no action').toUpperCase(),
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
test('typed SQLite schema matches every reviewed table, column, index, check and foreign key', async (t) => {
|
||||
const directory = fs.mkdtempSync(path.join(os.tmpdir(), 'ql3-schema-lockstep-'));
|
||||
const databasePath = path.join(directory, 'qinglong3.sqlite');
|
||||
t.after(() => fs.rmSync(directory, { recursive: true, force: true }));
|
||||
await migrateLocalSqlitePath({ databasePath, profile: 'edge' });
|
||||
|
||||
const client = new DatabaseSync(databasePath, { readOnly: true });
|
||||
try {
|
||||
const actualTables = client
|
||||
.prepare(
|
||||
`SELECT name FROM sqlite_schema
|
||||
WHERE type = 'table' AND name NOT LIKE 'sqlite_%' ORDER BY name`,
|
||||
)
|
||||
.all()
|
||||
.map(({ name }) => name);
|
||||
const drizzleTables = Object.values(localSqliteSchema).map(getTableConfig);
|
||||
assert.deepEqual(
|
||||
actualTables,
|
||||
drizzleTables.map(({ name }) => name).sort(),
|
||||
);
|
||||
|
||||
for (const config of drizzleTables) {
|
||||
const columns = client
|
||||
.prepare(`PRAGMA table_info("${config.name}")`)
|
||||
.all()
|
||||
.map(({ name }) => name);
|
||||
assert.deepEqual(
|
||||
columns,
|
||||
config.columns.map(({ name }) => name),
|
||||
`${config.name} columns`,
|
||||
);
|
||||
|
||||
const indexes = client
|
||||
.prepare(`PRAGMA index_list("${config.name}")`)
|
||||
.all()
|
||||
.map(({ name }) => name)
|
||||
.filter((name) => !name.startsWith('sqlite_autoindex_'));
|
||||
assert.deepEqual(
|
||||
indexes.sort(),
|
||||
config.indexes.map(({ config: value }) => value.name).sort(),
|
||||
`${config.name} indexes`,
|
||||
);
|
||||
assert.deepEqual(
|
||||
catalogChecks(tableSql(client, config.name)).sort(),
|
||||
config.checks.map(({ name }) => name).sort(),
|
||||
`${config.name} checks`,
|
||||
);
|
||||
assert.deepEqual(
|
||||
sorted(catalogForeignKeys(client, config.name)),
|
||||
sorted(drizzleForeignKeys(config)),
|
||||
`${config.name} foreign keys`,
|
||||
);
|
||||
}
|
||||
} finally {
|
||||
client.close();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user