UNPKG

knex-types

Version:

Generates TypeScript definitions (types) from a (PostgreSQL) database schema.

180 lines (169 loc) 7.33 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.getType = getType; exports.updateTypes = updateTypes; var _camelCase2 = _interopRequireDefault(require("lodash/camelCase")); var _upperFirst2 = _interopRequireDefault(require("lodash/upperFirst")); var _fs = _interopRequireDefault(require("fs")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } /* SPDX-FileCopyrightText: 2016-present Kriasoft <hello@kriasoft.com> */ /* SPDX-License-Identifier: MIT */ /** * Generates TypeScript definitions (types) from a PostgreSQL database schema. */ async function updateTypes(db, options) { var _options$overrides, _ref, _ref2; const overrides = (_options$overrides = options.overrides) !== null && _options$overrides !== void 0 ? _options$overrides : {}; const output = typeof options.output === "string" ? _fs.default.createWriteStream(options.output, { encoding: "utf-8" }) : options.output; ["// The TypeScript definitions below are automatically generated.\n", "// Do not touch them, or risk, your modifications being lost.\n\n"].forEach(line => output.write(line)); const schema = (_ref = typeof options.schema === "string" ? options.schema.split(",").map(x => x.trim()) : options.schema) !== null && _ref !== void 0 ? _ref : ["public"]; // Schemas to include or exclude const [includeSchemas, excludeSchemas] = schema.reduce((acc, s) => acc[+s.startsWith("!")].push(s) && acc, [[], []]); // Tables to exclude const exclude = (_ref2 = typeof options.exclude === "string" ? options.exclude.split(",").map(x => x.trim()) : options.exclude) !== null && _ref2 !== void 0 ? _ref2 : []; if (options.prefix) { output.write(options.prefix); output.write("\n\n"); } try { // Fetch the list of custom enum types const enums = await db.table("pg_type").join("pg_enum", "pg_enum.enumtypid", "pg_type.oid").orderBy("pg_type.typname").orderBy("pg_enum.enumsortorder").select("pg_type.typname as key", "pg_enum.enumlabel as value"); // Construct TypeScript enum types enums.forEach((x, i) => { var _overrides; // The first line of enum declaration if (!(enums[i - 1] && enums[i - 1].key === x.key)) { var _overrides$x$key; const enumName = (_overrides$x$key = overrides[x.key]) !== null && _overrides$x$key !== void 0 ? _overrides$x$key : (0, _upperFirst2.default)((0, _camelCase2.default)(x.key)); output.write(`export enum ${enumName} {\n`); } // Enum body const key = (_overrides = overrides[`${x.key}.${x.value}`]) !== null && _overrides !== void 0 ? _overrides : (0, _upperFirst2.default)((0, _camelCase2.default)(x.value.replace(/[.-]/g, "_"))); output.write(` ${key} = "${x.value}",\n`); // The closing line if (!(enums[i + 1] && enums[i + 1].key === x.key)) { output.write("}\n\n"); } }); const enumsMap = new Map(enums.map(x => { var _overrides$x$key2; return [x.key, (_overrides$x$key2 = overrides[x.key]) !== null && _overrides$x$key2 !== void 0 ? _overrides$x$key2 : (0, _upperFirst2.default)((0, _camelCase2.default)(x.key))]; })); // Fetch the list of tables/columns const columns = await db.withSchema("information_schema").table("columns").whereIn("table_schema", includeSchemas).whereNotIn("table_schema", excludeSchemas).whereNotIn("table_name", exclude).orderBy("table_schema").orderBy("table_name").orderBy("ordinal_position").select("table_schema as schema", "table_name as table", "column_name as column", db.raw("(is_nullable = 'YES') as nullable"), "column_default as default", "data_type as type", "udt_name as udt"); // The list of database tables as enum output.write("export enum Table {\n"); const tableSet = new Set(columns.map(x => { const schema = x.schema !== "public" ? `${x.schema}.` : ""; return `${schema}${x.table}`; })); Array.from(tableSet).forEach(value => { var _overrides$value; const key = (_overrides$value = overrides[value]) !== null && _overrides$value !== void 0 ? _overrides$value : (0, _upperFirst2.default)((0, _camelCase2.default)(value)); output.write(` ${key} = "${value}",\n`); }); output.write("}\n\n"); // The list of tables as type output.write("export type Tables = {\n"); Array.from(tableSet).forEach(key => { var _overrides$key; const value = (_overrides$key = overrides[key]) !== null && _overrides$key !== void 0 ? _overrides$key : (0, _upperFirst2.default)((0, _camelCase2.default)(key)); output.write(` "${key}": ${value},\n`); }); output.write("};\n\n"); // Construct TypeScript db record types columns.forEach((x, i) => { if (!(columns[i - 1] && columns[i - 1].table === x.table)) { var _overrides$x$table; const tableName = (_overrides$x$table = overrides[x.table]) !== null && _overrides$x$table !== void 0 ? _overrides$x$table : (0, _upperFirst2.default)((0, _camelCase2.default)(x.table)); const schemaName = x.schema !== "public" ? (0, _upperFirst2.default)((0, _camelCase2.default)(x.schema)) : ""; output.write(`export type ${schemaName}${tableName} = {\n`); } let type = x.type === "ARRAY" ? `${getType(x.udt.substring(1), enumsMap, x.default)}[]` : getType(x.udt, enumsMap, x.default); if (x.nullable) { type += " | null"; } output.write(` ${sanitize(x.column)}: ${type};\n`); if (!(columns[i + 1] && columns[i + 1].table === x.table)) { output.write("};\n\n"); } }); if (options.suffix) { output.write(options.suffix); output.write("\n"); } } finally { output.end(); db.destroy(); } } function getType(udt, customTypes, defaultValue) { var _customTypes$get; switch (udt) { case "bool": return "boolean"; case "text": case "citext": case "money": case "numeric": case "int8": case "char": case "character": case "bpchar": case "varchar": case "time": case "tsquery": case "tsvector": case "uuid": case "xml": case "cidr": case "inet": case "macaddr": return "string"; case "smallint": case "integer": case "int": case "int2": case "int4": case "real": case "float": case "float4": case "float8": return "number"; case "date": case "timestamp": case "timestamptz": return "Date"; case "json": case "jsonb": if (defaultValue) { if (defaultValue.startsWith("'{")) { return "Record<string, unknown>"; } if (defaultValue.startsWith("'[")) { return "unknown[]"; } } return "unknown"; case "bytea": return "Buffer"; case "interval": return "PostgresInterval"; default: return (_customTypes$get = customTypes.get(udt)) !== null && _customTypes$get !== void 0 ? _customTypes$get : "unknown"; } } /** * Wraps the target property identifier into quotes in case it contains any * invalid characters. * * @see https://developer.mozilla.org/docs/Glossary/Identifier */ function sanitize(name) { return /^[a-zA-Z$_][a-zA-Z$_0-9]*$/.test(name) ? name : JSON.stringify(name); } //# sourceMappingURL=main.js.map