Skip to content

Commit

Permalink
database building refactor
Browse files Browse the repository at this point in the history
  • Loading branch information
onzag committed Aug 6, 2024
1 parent edd141e commit bf856db
Show file tree
Hide file tree
Showing 8 changed files with 245 additions and 114 deletions.
38 changes: 11 additions & 27 deletions database/AlterTableBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,9 @@ interface IAlterTableColumnData {
name: string;
type: string;
notNull: boolean;
defaultTo?: ValueType;
}

interface IAlterTableColumnDataWithExpressionAsDefault {
name: string;
type: string;
notNull: boolean;
/**
* the default must be a self contained expression
*/
defaultTo?: string;
}

Expand All @@ -28,7 +24,7 @@ export class AlterTableBuilder extends QueryBuilder {
* Table name in question we are updating against
*/
private tableName: string;
private columnRule: IAlterTableColumnDataWithExpressionAsDefault;
private columnRule: IAlterTableColumnData;
private action: string;
/**
* Builds a new alter table query builder
Expand All @@ -50,24 +46,7 @@ export class AlterTableBuilder extends QueryBuilder {
}

this.action = action;

if (info.defaultTo) {
if (Array.isArray(info.defaultTo)) {
this.addBindingSources(info.defaultTo[1]);
this.columnRule = {
...info,
defaultTo: info.defaultTo[0],
};
} else {
this.addBindingSource(info.defaultTo);
this.columnRule = {
...info,
defaultTo: "?",
};
}
} else {
this.columnRule = info as any;
}
this.columnRule = info as any;

return this;
}
Expand Down Expand Up @@ -124,7 +103,12 @@ export class AlterTableBuilder extends QueryBuilder {
return startBit +
this.action + " " + quotedColumn + " TYPE " + this.columnRule.type + ", " +
this.action + " " + quotedColumn + (this.columnRule.notNull ? " SET " : " DROP ") + "NOT NULL, " +
this.action + " " + quotedColumn + (this.columnRule.defaultTo ? " SET DEFAULT " + this.columnRule.defaultTo : " DROP DEFAULT");
this.action + " " + quotedColumn +
(
typeof this.columnRule.defaultTo !== "undefined" && this.columnRule !== null ?
" SET DEFAULT " + this.columnRule.defaultTo :
" DROP DEFAULT"
);
}
}
}
34 changes: 7 additions & 27 deletions database/CreateTableBuilder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,9 @@ interface ICreateTableColumnData {
name: string;
type: string;
notNull: boolean;
defaultTo?: ValueType;
}

interface ICreateTableColumnDataWithExpressionAsDefault {
name: string;
type: string;
notNull: boolean;
/**
* the default must be a self contained expression
*/
defaultTo?: string;
}

Expand All @@ -29,7 +25,7 @@ export class CreateTableBuilder extends QueryBuilder {
*/
private tableName: string;
private createIfNotExists: boolean;
private columns: ICreateTableColumnDataWithExpressionAsDefault[] = [];
private columns: ICreateTableColumnData[] = [];

/**
* Builds a new create table query builder
Expand All @@ -46,24 +42,7 @@ export class CreateTableBuilder extends QueryBuilder {
* @returns itself
*/
public addColumn(info: ICreateTableColumnData) {
if (info.defaultTo) {
if (Array.isArray(info.defaultTo)) {
this.addBindingSources(info.defaultTo[1]);
this.columns.push({
...info,
defaultTo: info.defaultTo[0],
});
} else {
this.addBindingSource(info.defaultTo);
this.columns.push({
...info,
defaultTo: "?",
});
}
} else {
this.columns.push(info as any);
}

this.columns.push(info as any);
return this;
}

Expand Down Expand Up @@ -109,7 +88,8 @@ export class CreateTableBuilder extends QueryBuilder {

return "CREATE TABLE " + (this.createIfNotExists ? "IF NOT EXISTS " : "") + JSON.stringify(this.tableName) +
"(" + this.columns.map((c) => {
return JSON.stringify(c.name) + " " + c.type + (c.notNull ? " NOT NULL" : "") + (c.defaultTo ? " DEFAULT " + c.defaultTo : "");
return JSON.stringify(c.name) + " " + c.type + (c.notNull ? " NOT NULL" : "") +
(typeof c.defaultTo !== "undefined" && c.defaultTo !== null ? " DEFAULT " + c.defaultTo : "");
}).join(", ") + ")";
}
}
19 changes: 18 additions & 1 deletion dbbuilder/build-column.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,23 @@ import { CreateTableBuilder } from "../database/CreateTableBuilder";
import { AlterTableBuilder } from "../database/AlterTableBuilder";
import { ISQLColumnDefinitionType } from "../base/Root/sql";

export function escapeString(str: string) {
return "'" + Array.from(str).map((char: string) => char === "'" ? "\\'" : char).join("") + "'";
}
export function convertValueToExpression(
v: any
) {
if (typeof v === "boolean") {
return v ? "TRUE" : "FALSE";
} else if (typeof v === "string") {
return escapeString(v);
} else if (typeof v === "number") {
return v.toString();
} else {
return escapeString(JSON.stringify(v)) + "::jsonb";
}
}

/**
* Builds a type for the table
* @param columnName the column name we want to create
Expand All @@ -33,7 +50,7 @@ export function buildColumn(
name: columnName,
type: actualType,
notNull: columnData.notNull,
defaultTo: columnData.defaultTo,
defaultTo: convertValueToExpression(columnData.defaultTo),
};

if (tableBuilder instanceof CreateTableBuilder) {
Expand Down
54 changes: 35 additions & 19 deletions dbbuilder/build-foreign-key.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
import colors from "colors/safe";

import { ISQLSchemaDefinitionType } from "../base/Root/sql";
import { showErrorStackAndLogMessage, yesno } from ".";
import { continueOrKill, showErrorStackAndLogMessage, yesno } from ".";
import { DatabaseConnection } from "../database";
import uuidv5 from "uuid/v5";

Expand Down Expand Up @@ -62,14 +62,19 @@ function findActionFor(
k: string,
name: string,
) {
const strEnd = k.split(name)[1].trimStart().toLowerCase();
// FOREIGN KEY ("MODULE_ID", "MODULE_VERSION") REFERENCES "MOD_course"(id, version) ON UPDATE CASCADE ON DELETE CASCADE
const afterSplit = k.split(name)[1];
if (!afterSplit) {
return "no action";
}
const strEnd = afterSplit.trimStart().toLowerCase();

if (!strEnd) {
return "no action";
}

return potentialForeignKeyActions.find((v) => {
return k.startsWith(v);
return strEnd.startsWith(v);
}) || "no action";
}

Expand Down Expand Up @@ -98,10 +103,17 @@ export async function buildForeignKeys(
],
);

const allForeignKeysInPublic = await databaseConnection.queryRows(
let allForeignKeysInPublic = await databaseConnection.queryRows(
"SELECT conrelid::regclass AS table_from, conname, pg_get_constraintdef(oid) FROM pg_constraint WHERE contype='f' AND " +
"connamespace = 'public'::regnamespace ORDER BY conrelid::regclass::text, contype DESC"
);
allForeignKeysInPublic = allForeignKeysInPublic.map((v) => (
{
...v,
// for some weird reason it comes quoted
table_from: JSON.parse(v.table_from),
}
));

// Now we want to check for foreign keys we start over, add foreign keys
// later because we don't know what order were tables added
Expand All @@ -121,7 +133,7 @@ export async function buildForeignKeys(
const newTableForeignKeys: IProcessedForeignKeys = {};
const currentTableForeignKeys: IProcessedForeignKeys = {};

const foreignKeysForTable = allForeignKeysInPublic.filter((v) => v.table_fom === tableName);
const foreignKeysForTable = allForeignKeysInPublic.filter((v) => v.table_from === tableName);

// first we grab all the foreign keys for that given table
foreignKeysForTable.forEach((k) => {
Expand All @@ -130,20 +142,16 @@ export async function buildForeignKeys(

// get the columns that it affects, for example
// FOREIGN KEY ("MODULE_ID", "MODULE_VERSION") REFERENCES "MOD_course"(id, version) ON UPDATE CASCADE ON DELETE CASCADE
// and yes it will always be uppercase, so we want between FOREIGN KEY and REFERENCES
const columnsBase = parseColumns(k.pg_get_constraintdef, "FOREIGN KEY", "REFERENCES");
const columnsReferrenced = parseColumns(k.pg_get_constraintdef, "REFERENCES", "ON");
// and yes it will always be uppercase, so we want between FOREIGN KEY and ) since REFERENCES could be in our id somehow
const columnsBase = parseColumns(k.pg_get_constraintdef, "FOREIGN KEY", ")");
const columnsReferrenced = parseColumns(k.pg_get_constraintdef.split(")")[1], "REFERENCES", ")");

// now we want the target table
let targetTable = k.pg_get_constraintdef.split("REFERENCES")[1].split("ON")[0];
const indexOfPharentesis = targetTable.split("(");

if (indexOfPharentesis === -1) {
return;
let targetTable = (k.pg_get_constraintdef as string).split(")")[1].split("REFERENCES")[1].split("(")[0].trim();
if (targetTable.startsWith("\"")) {
targetTable = JSON.parse(targetTable);
}

targetTable = targetTable.substring(0, indexOfPharentesis);

// now we grab the actions
const deleteAction = findActionFor(k.pg_get_constraintdef, "ON DELETE");
const updateAction = findActionFor(k.pg_get_constraintdef, "ON UPDATE");
Expand Down Expand Up @@ -213,6 +221,8 @@ export async function buildForeignKeys(
`schema has unmatching tables ${newColumnSchema.foreignKey.table} over stored ` +
`${newTableForeignKeys[actualId].targetTable}`,
));

await continueOrKill();
}

// now let's check if the delete action is congrugent
Expand All @@ -225,6 +235,8 @@ export async function buildForeignKeys(
`schema has unmatching delete actions ${newColumnSchema.foreignKey.deleteAction} over stored ` +
`${newTableForeignKeys[actualId].deleteAction}`,
));

await continueOrKill();
}

// now let's check if the update action is congrugent
Expand All @@ -237,6 +249,8 @@ export async function buildForeignKeys(
`schema has unmatching update actions ${newColumnSchema.foreignKey.updateAction} over stored ` +
`${newTableForeignKeys[actualId].updateAction}`,
));

await continueOrKill();
}
}
}
Expand Down Expand Up @@ -287,7 +301,8 @@ export async function buildForeignKeys(
(
// the foreign key signature does not match
newForeignKey.targetTable !== currentForeignKey.targetTable ||
newForeignKey.deleteAction !== currentForeignKey.deleteAction ||
newForeignKey.deleteAction.toLowerCase() !== currentForeignKey.deleteAction ||
newForeignKey.updateAction.toLowerCase() !== currentForeignKey.updateAction ||
newForeignKeySourceColumnsStored.join(",") !== currentForeignKeySourceColumnsStored.join(",") ||
newForeignKeyReferenceColumnsStored.join(",") !== currentForeignKeyReferenceColumnsStored.join(",")
)
Expand All @@ -297,7 +312,8 @@ export async function buildForeignKeys(
if (newForeignKey) {
console.log(colors.yellow(
`Foreign key '${foreignKeyId}' has been changed, ` +
`the current foreign key needs to be dropped`,
`the current foreign key needs to be dropped, current is ` +
`${JSON.stringify(currentForeignKey)} while new is ${JSON.stringify(newForeignKey)}`,
));
} else {
console.log(colors.yellow(
Expand All @@ -319,7 +335,7 @@ export async function buildForeignKeys(
`ALTER TABLE ${JSON.stringify(tableName)} DROP CONSTRAINT ${JSON.stringify(actualId)}`,
);
} catch (err) {
showErrorStackAndLogMessage(err);
await showErrorStackAndLogMessage(err);
wasSupposedToDropCurrentForeignKeyButDidnt = true;
}
} else {
Expand Down Expand Up @@ -372,7 +388,7 @@ export async function buildForeignKeys(
`ON DELETE ${newForeignKey.deleteAction} ON UPDATE ${newForeignKey.updateAction}`
);
} catch (err) {
showErrorStackAndLogMessage(err);
await showErrorStackAndLogMessage(err);
}
}
}
Expand Down
Loading

0 comments on commit bf856db

Please sign in to comment.