kt-template-online-api/test/helpers/sql-schema.helper.ts

107 lines
2.7 KiB
TypeScript

import * as fs from 'fs';
import * as path from 'path';
const createTableRegex =
/CREATE TABLE IF NOT EXISTS\s+([A-Za-z0-9_]+)\s*\(([\s\S]*?)\)\s*ENGINE=/gi;
const nonColumnTokens = new Set([
'CONSTRAINT',
'FOREIGN',
'KEY',
'PRIMARY',
'UNIQUE',
]);
export type SqlSchemaContract = {
hasTable(tableName: string): boolean;
getTableColumns(tableName: string): SqlSchemaColumn[];
expectTableColumns(tableName: string, columns: readonly string[]): void;
};
export type SqlSchemaColumn = {
definition: string;
name: string;
};
/**
* 解析Columns。
* @param tableBlock - CREATE TABLE 语句片段;影响 parseColumns 的返回值。
* @returns 测试断言转换后的值。
*/
const parseColumns = (tableBlock: string): SqlSchemaColumn[] => {
return tableBlock
.split(/\r?\n/)
.map((line) => line.trim().replace(/,$/, ''))
.flatMap((line) => {
const match = line.match(/^`?([A-Za-z_][A-Za-z0-9_]*)`?\s+/);
if (!match || nonColumnTokens.has(match[1].toUpperCase())) {
return [];
}
return [
{
definition: line,
name: match[1],
},
];
});
};
/**
* 解析Schema。
* @param sql - SQL 文本;提取正则匹配结果。
*/
const parseSchema = (sql: string) => {
const tables = new Map<string, SqlSchemaColumn[]>();
for (const match of sql.matchAll(createTableRegex)) {
const [, tableName, tableBlock] = match;
tables.set(tableName, parseColumns(tableBlock));
}
return tables;
};
/**
* 读取 测试断言资源。
* @returns 测试断言产出的 SqlSchemaContract。
*/
export const readRefactorV3SqlSchema = (): SqlSchemaContract => {
const schemaPath = path.resolve(
__dirname,
'..',
'..',
'sql',
'refactor-v3',
'00-full-schema.sql',
);
const tables = parseSchema(fs.readFileSync(schemaPath, 'utf8'));
return {
/**
* 读取 测试回调数据。
* @param tableName - tableName 输入;驱动 `tables.get()` 的 测试步骤。
*/
getTableColumns: (tableName) => tables.get(tableName) || [],
/**
* 执行 测试回调。
* @param tableName - tableName 输入;驱动 `tables.has()` 的 测试步骤。
*/
hasTable: (tableName) => tables.has(tableName),
/**
* 执行 测试回调。
* @param tableName - tableName 输入;驱动 `tables.get()` 的 测试步骤。
* @param columns - 测试列表;构造测试断言。
*/
expectTableColumns: (tableName, columns) => {
const tableColumns = tables.get(tableName);
expect(tableColumns).toBeDefined();
expect((tableColumns || []).map((column) => column.name)).toEqual(
expect.arrayContaining([...columns]),
);
},
};
};