pg-to-ts
Version:
Generate TypeScript-friendly interfaces and constants from (postgres) SQL database schema
126 lines • 6.09 kB
JavaScript
;
/**
* Generate typescript interface from table schema
* Created by xiamx on 2016-08-10.
*/
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.generateEnumType = exports.generateTableInterface = exports.attachJoinTypes = void 0;
//tslint:disable
var lodash_1 = __importDefault(require("lodash"));
function nameIsReservedKeyword(name) {
var reservedKeywords = ['string', 'number', 'package', 'public'];
return reservedKeywords.indexOf(name) !== -1;
}
/**
* Returns a version of the name that can be used as a symbol name, e.g.
* 'number' --> 'number_'.
*/
function getSafeSymbolName(name) {
if (nameIsReservedKeyword(name)) {
return name + '_';
}
else {
return name;
}
}
/** Converts snake_case --> CamelCase */
function toCamelCase(name) {
return name
.split('_')
.map(function (word) { return (word ? word[0].toUpperCase() + word.slice(1) : ''); })
.join('');
}
function quotedArray(xs) {
return '[' + xs.map(function (x) { return "'".concat(x, "'"); }).join(', ') + ']';
}
function quoteNullable(x) {
return x === null || x === undefined ? 'null' : "'".concat(x, "'");
}
function quoteForeignKeyMap(x) {
var colsTs = lodash_1.default.map(x, function (v, k) {
return "".concat(k, ": { table: '").concat(v.table, "', column: '").concat(v.column, "', $type: null as unknown /* ").concat(v.table, " */ },");
});
return '{' + colsTs.join('\n ') + '}';
}
var JSDOC_TYPE_RE = /@type \{([^}]+)\}/;
function isNonNullish(x) {
return x !== null && x !== undefined;
}
/**
* generateTableInterface() leaves some references to be filled in later, when a more complete
* picture of the schema is available. This fills those references in:
* 'null as unknown /* users *\/' --> 'null as unknown as Users'.
*/
function attachJoinTypes(tableTs, tableToNames) {
return tableTs.replace(/(\$type: null as unknown) \/\* ([^*]+) \*\//g, function (match, g1, tableName) {
var names = tableToNames[tableName];
return names ? g1 + ' as ' + names.type : match;
});
}
exports.attachJoinTypes = attachJoinTypes;
/** Returns [Table TypeScript, output variable name, set of TS types to import] */
function generateTableInterface(tableName, tableDefinition, schemaName, options) {
var selectableMembers = '';
var insertableMembers = '';
var columns = [];
var requiredForInsert = [];
var typesToImport = new Set();
for (var _i = 0, _a = Object.keys(tableDefinition.columns); _i < _a.length; _i++) {
var columnNameRaw = _a[_i];
var columnName = options.transformColumnName(columnNameRaw), columnDef = tableDefinition.columns[columnNameRaw], comment_1 = columnDef.comment, possiblyOrNull = columnDef.nullable ? ' | null' : '', insertablyOptional = columnDef.nullable || columnDef.hasDefault ? '?' : '', jsdoc_1 = comment_1 ? "/** ".concat(comment_1, " */\n") : '';
var tsType = columnDef.tsType;
if (tsType === 'Json' && options.options.jsonTypesFile && comment_1) {
var m = JSDOC_TYPE_RE.exec(comment_1);
if (m) {
tsType = m[1].trim();
typesToImport.add(tsType);
}
}
selectableMembers += "".concat(jsdoc_1).concat(columnName, ": ").concat(tsType).concat(possiblyOrNull, ";\n");
insertableMembers += "".concat(jsdoc_1).concat(columnName).concat(insertablyOptional, ": ").concat(tsType).concat(possiblyOrNull, ";\n");
columns.push(columnName);
if (!columnDef.nullable && !columnDef.hasDefault) {
requiredForInsert.push(columnName);
}
}
var prefixWithSchemaNames = options.options.prefixWithSchemaNames;
var qualifiedTableName = tableName;
var sqlTableName = tableName;
if (prefixWithSchemaNames) {
qualifiedTableName = schemaName + '_' + qualifiedTableName;
sqlTableName = schemaName + '.' + sqlTableName;
}
var tableVarName = getSafeSymbolName(qualifiedTableName); // e.g. schema_table_name
var camelTableName = toCamelCase(tableVarName); // e.g. SchemaTableName
var primaryKey = tableDefinition.primaryKey, comment = tableDefinition.comment;
var foreignKeys = lodash_1.default.pickBy(lodash_1.default.mapValues(tableDefinition.columns, function (c) { return c.foreignKey; }), isNonNullish);
var jsdoc = comment ? "/** ".concat(comment, " */\n") : '';
var names = {
var: tableVarName,
type: camelTableName,
input: camelTableName + 'Input',
};
return [
"\n // Table ".concat(sqlTableName, "\n ").concat(jsdoc, " export interface ").concat(names.type, " {\n ").concat(selectableMembers, "}\n ").concat(jsdoc, " export interface ").concat(names.input, " {\n ").concat(insertableMembers, "}\n const ").concat(names.var, " = {\n tableName: '").concat(sqlTableName, "',\n columns: ").concat(quotedArray(columns), ",\n requiredForInsert: ").concat(quotedArray(requiredForInsert), ",\n primaryKey: ").concat(quoteNullable(primaryKey), ",\n foreignKeys: ").concat(quoteForeignKeyMap(foreignKeys), ",\n $type: null as unknown as ").concat(names.type, ",\n $input: null as unknown as ").concat(names.input, "\n } as const;\n "),
names,
typesToImport,
];
}
exports.generateTableInterface = generateTableInterface;
function generateEnumType(enumObject, options) {
var enumString = '';
for (var enumNameRaw in enumObject) {
var enumName = options.transformTypeName(enumNameRaw);
enumString += "export type ".concat(enumName, " = ");
enumString += enumObject[enumNameRaw]
.map(function (v) { return "'".concat(v, "'"); })
.join(' | ');
enumString += ';\n';
}
return enumString;
}
exports.generateEnumType = generateEnumType;
//# sourceMappingURL=typescript.js.map