ddl-manager
Version:
store postgres procedures and triggers in files
176 lines (173 loc) • 5.48 kB
text/typescript
import {
AssignVariable,
BlankLine,
Body,
Expression,
Declare,
HardCode,
If,
InlineSelectValues,
SetSelectItem,
Update,
With,
WithQuery,
Select
} from "../../../ast";
import { TableReference } from "../../../database/schema/TableReference";
import { TableID } from "../../../database/schema/TableID";
export interface IUniversalAST {
forTable: string;
triggerTable: TableID;
from: string[];
where?: Expression;
select: Select;
updateColumns: string[];
triggerTableColumns: string[];
}
export function buildUniversalBody(ast: IUniversalAST) {
return new Body({
declares: [
new Declare({
name: "new_row",
type: "record"
}),
new Declare({
name: "old_row",
type: "record"
}),
new Declare({
name: "return_row",
type: "record"
})
],
statements: [
new If({
if: Expression.and([
"TG_OP = 'DELETE'"
]),
then: [
new AssignVariable({
variable: "return_row",
value: new HardCode({
sql: "old"
})
})
],
else: [
new AssignVariable({
variable: "return_row",
value: new HardCode({
sql: "new"
})
})
]
}),
new BlankLine(),
new AssignVariable({
variable: "new_row",
value: new HardCode({
sql: "return_row"
})
}),
new AssignVariable({
variable: "old_row",
value: new HardCode({
sql: "return_row"
})
}),
new BlankLine(),
new If({
if: Expression.and([
"TG_OP in ('INSERT', 'UPDATE')"
]),
then: [
new AssignVariable({
variable: "new_row",
value: new HardCode({
sql: "new"
})
})
]
}),
new If({
if: Expression.and([
"TG_OP in ('UPDATE', 'DELETE')"
]),
then: [
new AssignVariable({
variable: "old_row",
value: new HardCode({
sql: "old"
})
})
]
}),
new BlankLine(),
new If({
if: Expression.and([
"TG_OP = 'UPDATE'"
]),
then: [
new If({
if: Expression.and([
ast.triggerTableColumns
.filter(column => column !== "id")
.map(column =>
`new.${column} is NOT distinct from old.${column}`
).join(" and ")
]),
then: [
new HardCode({
sql: "return new;"
})
]
})
]
}),
new BlankLine(),
new Update({
with: new With({
queries: [
new WithQuery({
name: "changed_rows",
select: new InlineSelectValues({
values: ast.triggerTableColumns.map(column =>
`old_row.${column}`
),
union: new InlineSelectValues({
values: ast.triggerTableColumns.map(column =>
`new_row.${column}`
)
})
})
})
]
}),
table: ast.forTable,
set: [new SetSelectItem({
columns: ast.updateColumns,
select: ast.select
})],
from: ast.from.map(fromTable => {
if ( fromTable === ast.triggerTable.toStringWithoutPublic() ) {
return "changed_rows";
}
return fromTable;
}),
where: ast.where ?
ast.where.replaceTable(
ast.triggerTable,
new TableReference(
ast.triggerTable,
"changed_rows"
)
) :
undefined
}),
new BlankLine(),
new HardCode({
sql: "return return_row;"
})
]
})
}