cross-schema
Version:
Cross-database schema inspector for Node.js. Retrieve unified metadata for tables, columns, indexes, enums, and more across MySQL, PostgreSQL, SQLite, and SQL Server.
134 lines (132 loc) • 4.99 kB
JavaScript
import {
GENERAL_TYPES,
MYSQL_MAP
} from "./chunk-2NWHUQHD.js";
import "./chunk-YZFATT7X.js";
// src/platforms/mysql.js
function parseEnumValues(columnType) {
if (!/^enum|set/i.test(columnType)) return [];
return columnType.replace(/(enum|set)\((.*)\)/i, "$2").split(",").map((v) => v.trim().replace(/^'(.*)'$/, "$1"));
}
async function listDatabases(knex) {
const rows = await knex("information_schema.schemata").select("schema_name");
return rows.map((row) => row.SCHEMA_NAME || row.schema_name);
}
async function listTables(knex, schema) {
const rows = await knex("information_schema.tables").select("table_name").where("table_type", "BASE TABLE").andWhere("table_schema", schema || knex.raw("DATABASE()"));
return rows.map((row) => row.TABLE_NAME || row.table_name);
}
async function listViews(knex, schema) {
const rows = await knex("information_schema.views").select("table_name").where("table_schema", schema || knex.raw("DATABASE()"));
return rows.map((row) => row.TABLE_NAME || row.table_name);
}
async function listColumns(knex, table, schema) {
const rows = await knex("information_schema.columns").select(
"COLUMN_NAME",
"COLUMN_TYPE",
"DATA_TYPE",
"IS_NULLABLE",
"COLUMN_DEFAULT",
"COLUMN_KEY",
"EXTRA",
"COLUMN_COMMENT",
"CHARACTER_MAXIMUM_LENGTH",
"NUMERIC_PRECISION",
"NUMERIC_SCALE",
"COLUMN_TYPE"
).where("table_schema", schema || knex.raw("DATABASE()")).andWhere("table_name", table);
return rows.map((col) => {
const dbTypeRaw = col.DATA_TYPE.toLowerCase();
const dbType = MYSQL_MAP[dbTypeRaw] || "STRING";
const type = GENERAL_TYPES[dbType] || "string";
return {
name: col.COLUMN_NAME,
allowNull: col.IS_NULLABLE === "YES",
autoIncrement: col.EXTRA.includes("auto_increment"),
comment: col.COLUMN_COMMENT || "",
rawType: col.DATA_TYPE,
dbType,
type,
defaultValue: col.COLUMN_DEFAULT,
enumValues: parseEnumValues(col.COLUMN_TYPE),
isPrimaryKey: col.COLUMN_KEY === "PRI",
precision: col.NUMERIC_PRECISION || null,
scale: col.NUMERIC_SCALE || null,
size: col.CHARACTER_MAXIMUM_LENGTH || null,
unsigned: /unsigned/i.test(col.COLUMN_TYPE)
};
});
}
async function listIndexes(knex, table, schema) {
const rows = await knex("information_schema.statistics").select(
knex.raw("COLUMN_NAME as column_name"),
knex.raw("INDEX_NAME as index_name"),
knex.raw("NOT non_unique AS index_is_unique"),
knex.raw("index_name = 'PRIMARY' AS index_is_primary")
).where("table_schema", schema || knex.raw("DATABASE()")).andWhere("index_schema", schema || knex.raw("DATABASE()")).andWhere("table_name", table);
return rows.map((row) => ({
column_name: row.column_name,
name: row.index_name,
index_is_unique: !!row.index_is_unique,
index_is_primary: !!row.index_is_primary
}));
}
async function listConstraints(knex, table, schema) {
const rows = await knex.select([
"kcu.constraint_name as constraint_name",
"kcu.column_name as column_name",
"kcu.referenced_table_name as referenced_table_name",
"kcu.referenced_column_name as referenced_column_name"
]).from("information_schema.referential_constraints as rc").join("information_schema.key_column_usage as kcu", function() {
this.on("kcu.constraint_schema", "=", "rc.constraint_schema").andOn("kcu.constraint_name", "=", "rc.constraint_name").andOn(function() {
this.on("kcu.constraint_catalog", "=", "rc.constraint_catalog").orOn(
knex.raw(
"kcu.constraint_catalog IS NULL AND rc.constraint_catalog IS NULL"
)
);
});
}).where("rc.constraint_schema", "=", schema || knex.raw("DATABASE()")).andWhere("kcu.table_schema", "=", schema || knex.raw("DATABASE()")).andWhere("rc.table_name", "=", table).andWhere("kcu.table_name", "=", table);
return rows;
}
async function getTableSchema(knex, table, schema) {
const columns = await listColumns(knex, table, schema);
const indexes = await listIndexes(knex, table, schema);
const foreignKeys = await listConstraints(knex, table, schema);
let sequenceName = null;
for (const column of columns) {
if (column.autoIncrement) {
sequenceName = column.name;
break;
}
}
const primaryKeys = indexes.filter((idx) => idx.index_is_primary).map((idx) => idx.column_name);
return {
schemaName: schema || await getDatabaseName(knex),
tableName: table,
primaryKeys,
sequenceName,
foreignKeys,
columns
};
}
async function getDatabaseVersion(knex) {
const rows = await knex.raw("SELECT VERSION() as version");
return rows[0][0].version;
}
async function getDatabaseName(knex) {
const rows = await knex.raw("SELECT DATABASE() as db");
return rows[0][0].db;
}
var mysql_default = {
listDatabases,
listTables,
listViews,
listColumns,
listIndexes,
listConstraints,
getTableSchema,
getDatabaseVersion
};
export {
mysql_default as default
};