UNPKG

tspace-mysql

Version:

Tspace MySQL is a promise-based ORM for Node.js, designed with modern TypeScript and providing type safety for schema databases.

912 lines (896 loc) 31.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.PostgresQueryBuilder = void 0; const pluralize_1 = require("pluralize"); const __1 = require(".."); class PostgresQueryBuilder extends __1.QueryBuilder { _returnStart = 'RETURNING *'; constructor(state) { super(state); } select = (selectColumns) => { const combindSQL = [ this.bindSelect(selectColumns ?? this.$state.get("SELECT")), this.bindFrom({ from: !this.$state.get("FROM").length ? [this.$state.get("TABLE_NAME")].filter(Boolean).map(String) : [this.$state.get("TABLE_NAME"), ...this.$state.get("FROM")].filter(Boolean).map(String), alias: this.$state.get("ALIAS"), rawAlias: this.$state.get("RAW_ALIAS"), }), this.bindJoin(this.$state.get("JOIN")), this.bindWhere(this.$state.get("WHERE")), this.bindGroupBy(this.$state.get("GROUP_BY")), this.bindHaving(this.$state.get("HAVING")), this.bindOrderBy(this.$state.get("ORDER_BY")), this.bindLimit(this.$state.get("LIMIT")), this.bindOffset(this.$state.get("OFFSET")), this.bindRowLevelLock(this.$state.get("ROW_LEVEL_LOCK")), ]; let sql = this.format(combindSQL).trimEnd(); if (this.$state.get("UNION").length) { sql = `(${sql}) ${this.$state .get("UNION") .map((union) => `${this.$constants("UNION")} (${union})`) .join(" ")}`; } if (this.$state.get("UNION_ALL").length) { sql = `(${sql}) ${this.$state .get("UNION_ALL") .map((union) => `${this.$constants("UNION_ALL")} (${union})`) .join(" ")}`; } if (this.$state.get("CTE").length) { sql = `${this.$constants("WITH")} ${this.$state .get("CTE") .join(", ")} ${sql}`; } return sql; }; insert() { const query = this.$state.get("INSERT"); if (!query) return ''; const table = this.$state.get("TABLE_NAME"); const columns = `(${query.columns})`; const values = query.values.map(v => `(${v})`).join(', '); const sql = this.format([ this.$constants("INSERT"), table, columns, this.$constants("VALUES"), values, this._returnStart ]); return sql; } update() { if (this.$state.get("UPDATE") == null) { return ''; } const primaryKey = `${this.$state.get("TABLE_NAME")}.\`${this.$state.get("PRIMARY_KEY")}\``; const sql = this.format([ this.$constants("UPDATE"), this.$state.get("TABLE_NAME"), this.$constants("SET"), this.$state.get("UPDATE"), this.bindWhere([ { column: `${primaryKey}`, operator: `${this.$constants('IN')}`, value: `(${this.select([primaryKey])})` } ]), this._returnStart ]); return sql; } remove() { const query = this.$state.get("DELETE"); if (!query) { throw new Error("Bad query builder: DELETE state not found. Please check your query configuration."); } const primaryKey = `${this.$state.get("TABLE_NAME")}.\`${this.$state.get("PRIMARY_KEY")}\``; let sql = this.format([ this.$constants("DELETE"), this.$constants("FROM"), this.$state.get("TABLE_NAME"), this.bindWhere([ { column: `${primaryKey}`, operator: `${this.$constants('IN')}`, value: `(${this.select([primaryKey])})` } ]), this._returnStart ]); if (this.$state.get("CTE").length) { sql = `${this.$constants("WITH")} ${this.$state .get("CTE") .join(", ")} ${sql}`; } return sql; } any() { if (this.$state.get("INSERT")) return this.insert(); if (this.$state.get("UPDATE")) return this.update(); if (this.$state.get("DELETE")) return this.remove(); return this.select(); } getColumns({ database, table }) { const sql = [ `SELECT COLUMN_NAME as "Field", CASE WHEN CHARACTER_MAXIMUM_LENGTH IS NOT NULL THEN DATA_TYPE || '(' || CHARACTER_MAXIMUM_LENGTH || ')' WHEN NUMERIC_PRECISION IS NOT NULL THEN DATA_TYPE || '(' || NUMERIC_PRECISION || COALESCE(',' || NUMERIC_SCALE, '') || ')' ELSE DATA_TYPE END AS "ColumnType", DATA_TYPE as "Type", IS_NULLABLE as "Nullable", COLUMN_DEFAULT as "Default" `, `FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '${table.replace(/\`/g, "")}' AND TABLE_CATALOG = '${database.replace(/\`/g, "")}' ORDER BY ORDINAL_POSITION `, ]; return this.format(sql); } getSchema({ database, table }) { const sql = [ `SELECT COLUMN_NAME as "Field", CASE WHEN column_default LIKE 'nextval(%' THEN 'PRI' ELSE NULL END AS "Key", CASE WHEN DATA_TYPE = 'USER-DEFINED' THEN 'enum(' || ( SELECT string_agg(quote_literal(e.enumlabel), ',') FROM PG_TYPE t JOIN PG_ENUM e ON t.oid = e.enumtypid WHERE t.typname = udt_name ) || ')' WHEN DATA_TYPE = 'character varying' AND CHARACTER_MAXIMUM_LENGTH IS NOT NULL THEN DATA_TYPE || '(' || CHARACTER_MAXIMUM_LENGTH || ')' ELSE DATA_TYPE END AS "Type", IS_NULLABLE as "Nullable", CASE WHEN COLUMN_DEFAULT LIKE 'nextval(%' THEN NULL WHEN COLUMN_DEFAULT = 'CURRENT_TIMESTAMP' THEN 'IS_CONST:CURRENT_TIMESTAMP' ELSE COLUMN_DEFAULT END AS "Default", CASE WHEN COLUMN_DEFAULT LIKE 'nextval(%' THEN 'AUTO_INCREMENT' ELSE NULL END AS "Extra" FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = '${table.replace(/\`/g, "")}' AND TABLE_CATALOG = '${database.replace(/\`/g, "")}' ORDER BY ORDINAL_POSITION `, ]; return this.format(sql); } getTables(database) { const sql = [ ` SELECT TABLE_NAME AS "Tables" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_CATALOG = '${database.replace(/\`/g, "")}' AND UPPER(TABLE_SCHEMA) NOT IN ( 'PG_CATALOG', 'INFORMATION_SCHEMA', 'PG_TOAST' ) `, ]; return this.format(sql); } getTable({ database, table }) { const sql = [ ` SELECT TABLE_NAME AS "TABLES" FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_CATALOG = '${database.replace(/\`/g, "")}' AND TABLE_NAME LIKE '${table.replace(/\`/g, "")}' AND UPPER(TABLE_SCHEMA) NOT IN ( 'PG_CATALOG', 'INFORMATION_SCHEMA', 'PG_TOAST' ) `, ]; return this.format(sql); } hasTable({ database, table }) { const sql = [ `SELECT EXISTS( SELECT 1 FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_TYPE = 'BASE TABLE' AND TABLE_CATALOG = '${database.replace(/\`/g, "")}' AND TABLE_NAME LIKE '${table.replace(/\`/g, "")}' AND UPPER(TABLE_SCHEMA) NOT IN ( 'PG_CATALOG', 'INFORMATION_SCHEMA', 'PG_TOAST' ) ) AS "IS_EXISTS"`, ]; return this.format(sql); } createDatabase(database) { const sql = `CREATE DATABASE \`${database}\``; return this.format(sql); } createTable({ database, table, schema, }) { let columns = []; if (Array.isArray(schema)) { const sql = [ `${this.$constants("CREATE_TABLE_NOT_EXISTS")}`, `\`${database.replace(/`/g, "")}\`.\`${table.replace(/`/g, "")}\``, `(${schema.join(", ")})`, ]; return this.format(sql); } const detectSchema = (schema) => { try { return { type: schema?.type ?? schema["_type"] ?? null, attributes: schema?.attributes ?? schema["_attributes"] ?? null, }; } catch (e) { return { type: null, attributes: null, }; } }; for (const key in schema) { const data = schema[key]; const { type, attributes } = detectSchema(data); if (type == null || attributes == null) continue; const { formatedAttributes, formatedType } = this._formatedTypeAndAttributes({ type, attributes, key, }); columns = [ ...columns, `\`${key}\` ${formatedType} ${formatedAttributes.join(" ")}`, ]; } const sql = [ `${this.$constants("CREATE_TABLE_NOT_EXISTS")}`, `${table} (${columns.join(", ")})`, ]; return this.format(sql); } addColumn({ table, column, type, attributes, after, }) { const { formatedAttributes, formatedType } = this._formatedTypeAndAttributes({ type, attributes, key: column, }); const sql = [ this.$constants("ALTER_TABLE"), `\`${table}\``, this.$constants("ADD"), this.$constants("COLUMN"), `\`${column}\` ${formatedType} ${formatedAttributes != null && formatedAttributes.length ? `${formatedAttributes.join(" ")}` : ""}`, `${after ? "" : ""}`, ]; return this.format(sql); } changeColumn({ table, column, type, attributes, }) { const { formatedAttributes, formatedType, raws } = this._formatedTypeAndAttributes({ table, type, attributes, key: column, changed: true }); if (raws) { return this.format(raws); } const sql = [ this.$constants("ALTER_TABLE"), `\`${table}\``, this.$constants("ALTER_COLUMN"), `\`${column}\``, `${this.$constants("TYPE")} ${formatedType}`, ]; const sqlAttr = []; for (const formatedAttribute of formatedAttributes) { if (formatedAttribute.startsWith("PRIMARY KEY") || formatedAttribute.startsWith("NULL")) { continue; } sqlAttr.push([ this.$constants("ALTER_TABLE"), `\`${table}\``, this.$constants("ALTER_COLUMN"), `\`${column}\``, `${this.$constants("SET")} ${formatedAttribute}`, ].join(" ")); } if (!sqlAttr.length) { return this.format(sql); } return [this.format(sql), this.format(sqlAttr)].join("; "); } getChildFKs({ database, table }) { const sql = [ ` SELECT con.CONNAME AS "Constraint", conrel.RELNAME AS "ChildTable", STRING_AGG(att2.ATTNAME, ',') AS "ChildColumn", confrel.RELNAME AS "ParentTable", STRING_AGG(att.ATTNAME, ',') AS "ParentColumn" FROM PG_CONSTRAINT con JOIN PG_CLASS conrel ON con.CONRELID = conrel.OID JOIN PG_CLASS confrel ON con.CONFRELID = confrel.OID JOIN UNNEST(con.CONFKEY) WITH ORDINALITY AS cols(CHILD_ATTNUM, ord) ON TRUE JOIN PG_ATTRIBUTE att2 ON att2.ATTNUM = cols.CHILD_ATTNUM AND att2.ATTRELID = conrel.OID JOIN UNNEST(con.CONFKEY) WITH ORDINALITY AS refcols(PARENT_ATTNUM, ORD2) ON cols.ORD = refcols.ORD2 JOIN PG_ATTRIBUTE att ON att.ATTNUM = refcols.PARENT_ATTNUM AND att.ATTRELID = confrel.OID WHERE con.CONTYPE = 'f' AND confrel.RELNAME = '${table.replace(/\`/g, "")}' AND CURRENT_DATABASE() = '${database.replace(/\`/g, "")}' GROUP BY con.CONNAME, conrel.RELNAME, confrel.RELNAME ORDER BY conrel.RELNAME, con.CONNAME `, ]; return this.format(sql); } getFKs({ database, table }) { const sql = [ ` SELECT ccu.TABLE_NAME AS "RefTable", ccu.COLUMN_NAME AS "RefColumn", kcu.COLUMN_NAME AS "Column", tc.CONSTRAINT_NAME AS "Constraint" FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS AS tc JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS kcu ON tc.CONSTRAINT_NAME = kcu.CONSTRAINT_NAME AND tc.TABLE_SCHEMA = kcu.TABLE_SCHEMA JOIN INFORMATION_SCHEMA.CONSTRAINT_COLUMN_USAGE AS ccu ON ccu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME AND ccu.TABLE_SCHEMA = tc.TABLE_SCHEMA WHERE tc.CONSTRAINT_TYPE = 'FOREIGN KEY' AND CURRENT_DATABASE() = '${database.replace(/\`/g, "")}' AND tc.TABLE_NAME = '${table.replace(/\`/g, "")}' `, ]; return this.format(sql); } hasFK({ database, table, constraint, }) { const sql = [ ` SELECT EXISTS( SELECT 1 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE WHERE POSITION_IN_UNIQUE_CONSTRAINT IS NOT NULL AND TABLE_CATALOG = '${database.replace(/\`/g, "")}' AND TABLE_NAME = '${table.replace(/\`/g, "")}' AND CONSTRAINT_NAME = '${constraint}' ) AS "IS_EXISTS" `, ]; return this.format(sql); } addFK({ table, tableRef, key, constraint, foreign, }) { const sql = [ `${this.$constants("ALTER_TABLE")}`, `\`${table}\``, `${this.$constants("ADD_CONSTRAINT")}`, `\`${constraint}\``, `${this.$constants("FOREIGN_KEY")}(\`${key}\`)`, `${this.$constants("REFERENCES")} \`${tableRef}\`(\`${foreign.references}\`)`, `${this.$constants("ON_DELETE")} ${foreign.onDelete}`, `${this.$constants("ON_UPDATE")} ${foreign.onUpdate}`, ].join(" "); return this.format(sql); } dropFK({ table, constraint, }) { const sql = [ `${this.$constants("ALTER_TABLE")}`, `\`${table}\``, `DROP CONSTRAINT`, `\`${constraint}\``, ].join(" "); return this.format(sql); } getIndexes({ database, table }) { const sql = [ ` SELECT DISTINCT ON (a.ATTNAME, i.RELNAME) a.ATTNAME AS "Column", i.RELNAME AS "IndexName", UPPER(am.AMNAME) AS "IndexType", CASE WHEN a.ATTNOTNULL = false THEN 'YES' ELSE 'NO' END AS "Nullable", CASE WHEN ix.INDISUNIQUE = true THEN 'YES' ELSE 'NO' END AS "Unique" FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu JOIN PG_CLASS t ON t.RELNAME = kcu.TABLE_NAME JOIN PG_NAMESPACE n ON t.RELNAMESPACE = n.OID JOIN PG_INDEX ix ON t.OID = ix.INDRELID JOIN PG_CLASS i ON i.OID = ix.INDEXRELID JOIN PG_AM am ON i.RELAM = am.OID JOIN LATERAL ( SELECT UNNEST(ix.INDKEY) AS ATTR_NUM, GENERATE_SERIES(1, ARRAY_LENGTH(ix.INDKEY, 1)) AS NUMBER ) AS seq ON TRUE JOIN PG_ATTRIBUTE a ON a.ATTRELID = t.OID AND a.ATTNUM = seq.ATTR_NUM WHERE t.RELKIND = 'r' AND kcu.TABLE_CATALOG = '${database.replace(/\`/g, "")}' AND t.RELNAME = '${table.replace(/\`/g, "")}' `, ]; return this.format(sql); } hasIndex({ database, table, name, }) { const sql = [ ` SELECT EXISTS( SELECT 1 FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu JOIN PG_CLASS t ON t.RELNAME = kcu.TABLE_NAME JOIN PG_NAMESPACE n ON t.RELNAMESPACE = n.OID JOIN PG_INDEX ix ON t.OID = ix.INDRELID JOIN PG_CLASS i ON i.OID = ix.INDEXRELID WHERE t.RELKIND = 'r' AND kcu.TABLE_CATALOG = '${database.replace(/\`/g, "")}' AND t.RELNAME = '${table.replace(/\`/g, "")}' AND i.RELNAME = '${name}' ) AS "IS_EXISTS" `, ]; return this.format(sql); } addIndex({ table, name, columns, }) { const cols = columns .map(col => `\`${col}\``) .join(", "); const sql = [ this.$constants("CREATE_INDEX"), `\`${name}\``, this.$constants("ON"), `\`${table}\``, `(${cols})` ]; return this.format(sql); } dropIndex({ table, name, }) { const sql = [ this.$constants("DROP"), this.$constants("INDEX"), `\`${name}\`` ]; return this.format(sql); } hasUnique({ database, table, name, }) { const sql = [ ` SELECT EXISTS( SELECT 1 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA = '${database.replace(/['"`]/g, "")}' AND TABLE_NAME = '${table.replace(/['"`]/g, "")}' AND CONSTRAINT_NAME = '${name.replace(/['"`]/g, "")}' AND CONSTRAINT_TYPE = '${this.$constants("UNIQUE")}' ) AS "IS_EXISTS" ` ]; return this.format(sql); } addUnique({ table, name, columns }) { const cols = columns .map(col => `\`${col}\``) .join(", "); const sql = [ this.$constants("ALTER_TABLE"), `\`${table}\``, this.$constants("ADD_CONSTRAINT"), `\`${name}\``, this.$constants("UNIQUE"), `(${cols})` ]; return this.format(sql); } dropUnique({ table, name, }) { const sql = [ this.$constants("ALTER_TABLE"), `\`${table}\``, this.$constants("DROP"), this.$constants("CONSTRAINT"), `\`${name}\`` ]; return this.format(sql); } hasPrimaryKey({ database, table, }) { const sql = ` SELECT EXISTS ( SELECT 1 FROM INFORMATION_SCHEMA.TABLE_CONSTRAINTS WHERE TABLE_SCHEMA = '${database.replace(/['"`]/g, "")}' AND TABLE_NAME = '${table.replace(/['"`]/g, "")}' AND CONSTRAINT_TYPE = '${this.$constants('PRIMARY_KEY')}' ) AS "IS_EXISTS" `; return this.format(sql); } addPrimaryKey({ table, columns, }) { const cols = columns .map(col => `\`${col}\``) .join(", "); const sql = ` ${this.$constants('ALTER_TABLE')} \`${table}\` ${this.$constants('ADD')} ${this.$constants('PRIMARY_KEY')} (${cols}) `; return this.format(sql); } dropPrimaryKey({ table }) { const sql = [ this.$constants("ALTER_TABLE"), `\`${table}\``, this.$constants("DROP"), this.$constants("CONSTRAINT"), `\`${table}_pkey\`` ]; return this.format(sql); } getDatabase(database) { const sql = [ `SELECT DATNAME AS Database FROM PG_DATABASE WHERE DATNAME = '${database.replace(/`/g, "")}'`, ].join(" "); return this.format(sql); } dropDatabase(database) { const sql = [ `${this.$constants("DROP_DATABASE")}`, `\`${database.replace(/`/g, "")}\`` ].join(" "); return this.format(sql); } dropView(view) { const sql = [ `${this.$constants("DROP_VIEW")}`, `\`${view.replace(/`/g, "")}\`` ].join(" "); return this.format(sql); } dropTable(table) { const sql = [ `${this.$constants("DROP_TABLE")}`, `\`${table.replace(/`/g, "")}\`` ].join(" "); return this.format(sql); } truncate(table) { const sql = [ `${this.$constants("TRUNCATE_TABLE")}`, `\`${table.replace(/`/g, "")}\`` ].join(" "); return this.format(sql); } sleep(second) { return `PG_SLEEP(${second})`; } format(sql) { if (typeof sql === "string") sql = [sql]; const formated = sql .filter((s) => s !== "" || s == null) .join(" ") .replace(/\s+/g, " "); const replaceBackticksWithDoubleQuotes = (sqlString) => { const updateRegex = /^UPDATE\b/i; const insertRegex = /^INSERT\b/i; const deleteRegex = /^DELETE\b/i; const truncateRegex = /^TRUNCATE\b/i; if (updateRegex.test(sqlString)) { sqlString = sqlString.replace(/(SET\s+)(.*?)(\s+WHERE)/is, (_, start, setPart, end) => { const cleaned = setPart.replace(/`[\w$_]+`\./g, ''); return start + cleaned + end; }); } if (insertRegex.test(sqlString) || deleteRegex.test(sqlString) || truncateRegex.test(sqlString)) { return sqlString .replace(/`[\w$_]+`\.`([\w$_]+)`/g, "`$1`") .replace(/`([^`]+)`/g, '"$1"'); } return sqlString.replace(/`([^`]+)`/g, '"$1"'); }; return replaceBackticksWithDoubleQuotes(formated); } getActiveConnections() { const sql = ` SELECT COUNT(*) AS "Connections" FROM PG_STAT_ACTIVITY `; return this.format(sql); } getMaxConnections() { const sql = ` SELECT setting::int AS "MaxConnections" FROM PG_SETTINGS WHERE name = 'max_connections' `; return this.format(sql); } bindJoin(values) { if (!Array.isArray(values) || !values.length) return null; return values.join(" "); } bindWhere(values) { if (!Array.isArray(values) || !values.length) return null; const serializeWhere = (wheres) => { const resolveValue = ({ operator, value }) => { let valueStr = ''; if (operator?.toUpperCase() === this.$constants('IN') && Array.isArray(value)) { valueStr = `(${value.map((v) => v).join(',')})`; } else if (operator?.toUpperCase() === this.$constants('IS_NULL') || operator?.toUpperCase() === this.$constants('IS_NOT_NULL')) { valueStr = ''; } else { valueStr = `${value}`; } return valueStr; }; const conditionToSQL = (cond, isFirst = false) => { const { column = '', operator = '', condition, value, nested } = cond; if (nested && nested.length) { const nestedSQL = nested .map((c) => conditionToSQL(c)) .join(' '); const valueStr = resolveValue({ operator, value }); if (!isFirst) { return `${condition ?? this.$constants('AND')} (${column} ${operator} ${valueStr} ${nestedSQL})`; } return `(${column} ${operator} ${valueStr} ${nestedSQL})`; } const valueStr = resolveValue({ operator, value }); if (!isFirst) { return `${condition ?? this.$constants('AND')} ${column} ${operator} ${valueStr}`.trim(); } return `${column} ${operator} ${valueStr}`.trim(); }; return wheres.map((cond, i) => conditionToSQL(cond, !i)).join(' '); }; return `${this.$constants("WHERE")} ${serializeWhere(values)}`; } bindOrderBy(values) { if (!Array.isArray(values) || !values.length) return null; return `${this.$constants("ORDER_BY")} ${values .map((v) => v.replace(/^\s/, "").replace(/\s+/g, " ")) .join(", ")}`; } bindGroupBy(values) { if (!Array.isArray(values) || !values.length) return null; return `${this.$constants("GROUP_BY")} ${values .map((v) => v.replace(/^\s/, "").replace(/\s+/g, " ")) .join(", ")}`; } bindSelect(values, { distinct } = {}) { if (!values.length) { if (!distinct) return `${this.$constants("SELECT")} *`; return `${this.$constants("SELECT")} ${this.$constants("DISTINCT")} *`; } const findIndex = values.indexOf("*"); if (findIndex > -1) { const removed = values.splice(findIndex, 1); values.unshift(removed[0]); } return `${this.$constants("SELECT")} ${values.join(", ")}`; } bindFrom({ from, alias, rawAlias, }) { if (!from.length || from.every((f) => f == null || f === "")) { return ""; } if (alias != null && alias !== "") { if (rawAlias != null && rawAlias !== "") { const raw = String(rawAlias) .replace(/^\(\s*|\s*\)$/g, "") .trim(); const normalizedRawAlias = raw.startsWith("(") && raw.endsWith(")") ? raw.slice(1, -1) : raw; raw.startsWith("(") && raw.endsWith(")") ? raw.slice(1, -1) : raw; return `${this.$constants("FROM")} (${normalizedRawAlias}) ${this.$constants("AS")} \`${alias}\``; } return `${this.$constants("FROM")} ${from.join(", ")} ${this.$constants("AS")} \`${alias}\``; } return `${this.$constants("FROM")} ${from.join(", ")}`; } bindLimit(limit) { if (limit === "" || limit == null) return ""; return `${this.$constants("LIMIT")} ${limit}`; } bindOffset(offset) { if (offset === "" || offset == null) return ""; return `${this.$constants("OFFSET")} ${offset}`; } bindHaving(having) { if (having == null || having === '') return ""; return `${this.$constants("HAVING")} ${having}`; } bindRowLevelLock(rowLevelLock) { if (rowLevelLock.mode == null) return ''; let modeLock = rowLevelLock.mode === "FOR_UPDATE" ? this.$constants("ROW_LEVEL_LOCK").update : this.$constants("ROW_LEVEL_LOCK").share; if (rowLevelLock.skipLocked) { modeLock += ` ${this.$constants("ROW_LEVEL_LOCK").skipLocked}`; } if (rowLevelLock.nowait) { modeLock += ` ${this.$constants("ROW_LEVEL_LOCK").nowait}`; } return modeLock; } _formatedTypeAndAttributes({ table, type, attributes, key, changed }) { let formatedType = type; let formatedAttributes = attributes; let raws = null; if (type.startsWith("INT") && attributes.some((v) => v === "PRIMARY KEY")) { formatedType = "SERIAL"; if (changed) { formatedType = `INT USING "${key}"::INTEGER`; } formatedAttributes = attributes.filter((attr) => { return !attr.startsWith("AUTO_INCREMENT"); }); } if (type.startsWith("TINYINT")) { formatedType = "SMALLINT"; } if (type.startsWith("LONGTEXT") || type.startsWith("MEDIUMTEXT")) { formatedType = "TEXT"; } if (type.startsWith("ENUM")) { const enums = type.replace("ENUM", ""); const totalLength = enums .slice(1, -1) .split(",") .map((s) => s.replace(/'/g, "")) .reduce((sum, item) => sum + item.length, 0); formatedType = `VARCHAR(${totalLength}) CHECK (${key} IN ${enums})`; } if (changed && type.startsWith("ENUM")) { const enums = type.replace("ENUM", ""); const totalLength = enums .slice(1, -1) .split(",") .map((s) => s.replace(/'/g, "")) .reduce((sum, item) => sum + item.length, 0); const enumType = `${[(0, pluralize_1.singular)(String(table ?? '')), key].join('_')}`; raws = ` DO $$ DECLARE tname text; BEGIN SELECT t.TYPNAME INTO tname FROM PG_ATTRIBUTE a JOIN PG_CLASS c ON c.OID = a.ATTRELID JOIN PG_TYPE t ON t.OID = a.ATTTYPID WHERE c.RELNAME = '${table}' AND a.ATTNAME = '${key}' AND a.ATTNUM > 0 AND t.TYPTYPE = 'e' LIMIT 1; IF tname IS NOT NULL THEN ALTER TABLE ${table} ALTER COLUMN ${key} DROP DEFAULT; ALTER TABLE ${table} ALTER COLUMN ${key} TYPE varchar(${totalLength}); EXECUTE 'DROP TYPE IF EXISTS ' || quote_ident(tname); END IF; DROP TYPE IF EXISTS ${enumType}; CREATE TYPE ${enumType} AS ENUM ${enums}; ALTER TABLE ${table} ALTER COLUMN ${key} DROP DEFAULT; ALTER TABLE ${table} ALTER COLUMN ${key} TYPE ${enumType} USING ${key}::${enumType}; END $$ `; } if (type.startsWith("BOOLEAN")) { formatedAttributes = attributes.map((attr) => { if (attr.startsWith("DEFAULT")) { return attr.replace(/\b0\b/, "false").replace(/\b1\b/, "true"); } return attr; }); } return { formatedType, formatedAttributes, raws }; } } exports.PostgresQueryBuilder = PostgresQueryBuilder; //# sourceMappingURL=PostgresQueryBuilder.js.map