ddl-manager
Version:
store postgres procedures and triggers in files
622 lines (561 loc) • 17.8 kB
text/typescript
import { DatabaseFunction, IDatabaseFunctionArgument } from "../../lib/database/schema/DatabaseFunction";
import assert from "assert";
import { Comment } from "../../lib/database/schema/Comment";
describe("DatabaseFunction", () => {
it("equal two similar functions", () => {
const func1 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body: "begin\nend"
});
const func2 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body: "begin\nend"
});
assert.ok( func1.equal(func2), "func1 == func2" );
assert.ok( func2.equal(func1), "func2 == func1" );
});
it("equal with different body", () => {
const func1 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body: "body 1"
});
const func2 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body: "body 2"
});
assert.ok( !func1.equal(func2), "func1 != func2" );
assert.ok( !func2.equal(func1), "func2 != func1" );
});
it("equal with different parallel", () => {
const func1 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body: "body",
parallel: ["safe"]
});
const func2 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body: "body",
parallel: ["safe"]
});
assert.ok( func1.equal(func2), "func1 == func2" );
assert.ok( func2.equal(func1), "func2 == func1" );
});
it("equal with different args", () => {
const func1 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body: "body"
});
const func2 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [{name: "hello", type: "bigint"}],
returns: {type: "bigint"},
body: "body"
});
assert.ok( !func1.equal(func2), "func1 != func2" );
assert.ok( !func2.equal(func1), "func2 != func1" );
});
it("equal comment: undefined == null", () => {
const func1 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body: "body",
comment: null as any
});
const func2 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body: "body",
comment: undefined as any
});
assert.ok( func1.equal(func2), "func1 == func2" );
assert.ok( func2.equal(func1), "func2 == func1" );
});
it("equal with different returns", () => {
const func1 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "integer"},
body: "body"
});
const func2 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body: "body"
});
assert.ok( !func1.equal(func2), "func1 != func2" );
assert.ok( !func2.equal(func1), "func2 != func1" );
});
it("equal with different returns type", () => {
const func1 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "integer"},
body: "body"
});
const func2 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body: "body"
});
assert.ok( !func1.equal(func2), "func1 != func2" );
assert.ok( !func2.equal(func1), "func2 != func1" );
});
it("equal args with similar default", () => {
interface IArgCompare {
argA: IDatabaseFunctionArgument;
argB: IDatabaseFunctionArgument;
equal: boolean;
}
const argsCompares: IArgCompare[] = [
{
argA: {
name: "_start_date",
type: "timestamp without time zone",
default: " null"
},
argB: {
name: "_start_date",
type: "timestamp without time zone",
default: "null::timestamp without time zone"
},
equal: true
},
{
argA: {
name: "_start_date",
type: "timestamp without time zone",
default: " null"
},
argB: {
name: "_start_date",
type: "timestamp without time zone",
default: "null "
},
equal: true
},
{
argA: {
name: "_start_date",
type: "timestamp without time zone",
default: "null::timestamp without time zone"
},
argB: {
name: "_start_date",
type: "timestamp WITHOUT time zone",
default: "null::timestamp without time zone "
},
equal: true
},
{
argA: {
name: "_start_date",
type: "timestamp ",
default: "null::timestamp "
},
argB: {
name: "_start_date",
type: "timestamp without time zone",
default: "null::timestamp without time zone "
},
equal: true
},
{
argA: {
name: "_start_date",
type: "numeric",
default: "null::NUMERIc(14, 2)"
},
argB: {
name: "_start_date",
type: "numeric",
default: "null::numeric"
},
equal: true
},
{
argA: {
name: "name",
type: "text",
default: "''::text"
},
argB: {
name: "name",
type: "text",
default: " '' "
},
equal: true
},
{
argA: {
name: "name",
type: "jsonb",
default: "{}::jsonb"
},
argB: {
name: "name",
type: "jsonb",
default: " {} "
},
equal: true
},
{
argA: {
name: "name",
type: "jsonb",
default: "'{}'::jsonb"
},
argB: {
name: "name",
type: "jsonb",
default: " '{}' "
},
equal: true
},
{
argA: {
name: "name",
type: "jsonb",
default: "{}::jsonb"
},
argB: {
name: "name",
type: "jsonb",
default: " '{}' "
},
equal: true
},
{
argA: {
name: "name",
type: "jsonb",
default: "'{}'"
},
argB: {
name: "name",
type: "jsonb",
default: " {} "
},
equal: true
},
{
argA: {
name: "name",
type: "boolean",
default: "false::boolean"
},
argB: {
name: "name",
type: "boolean",
default: " false "
},
equal: true
},
{
argA: {
name: "name",
type: "boolean",
default: "false::boolean"
},
argB: {
name: "name",
type: "boolean",
default: " false "
},
equal: true
},
{
argA: {
name: "name",
type: "boolean",
default: "false ::boolean"
},
argB: {
name: "name",
type: "boolean",
default: " false "
},
equal: true
},
{
argA: {
name: "name",
type: "smallint",
default: "0::smallint"
},
argB: {
name: "name",
type: "smallint",
default: " 0 "
},
equal: true
},
{
argA: {
name: "name",
type: "text",
default: "'both'::text"
},
argB: {
name: "name",
type: "text",
default: " 'both' "
},
equal: true
},
{
argA: {
name: "name",
type: "text[]",
default: "'both'::text[]"
},
argB: {
name: "name",
type: "text[]",
default: " 'both' "
},
equal: true
}
];
for (const {argA, argB, equal} of argsCompares) {
const func1 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [argA],
returns: {type: "bigint"},
body: "body"
});
const func2 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [argB],
returns: {type: "bigint"},
body: "body"
});
assert.strictEqual(
func1.equal(func2),
equal,
`equal("${argA.default}", "${argB.default}") => ${equal}`
);
}
});
// soo, maybe need another way?
it("equal cost: 100 == null", () => {
const func1 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body: "body",
cost: 100 as any
});
const func2 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body: "body",
cost: null as any
});
assert.ok( func1.equal(func2), "func1 == func2" );
assert.ok( func2.equal(func1), "func2 == func1" );
});
it("returns company == returns public.company", () => {
const func1 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {setof: true, type: "company"},
body: "body"
});
const func2 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {setof: true, type: "public.company"},
body: "body"
});
assert.ok( func1.equal(func2), "func1 == func2" );
assert.ok( func2.equal(func1), "func2 == func1" );
});
it("equal arg type: numeric(14, 2) == numeric", () => {
const func1 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [{
name: "test",
type: "numeric(14,2)"
}],
returns: {type: "numeric(14,2)"},
body: "body"
});
const func2 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [{
name: "test",
type: "numeric"
}],
returns: {type: "numeric"},
body: "body"
});
assert.ok( func1.equal(func2), "func1 == func2" );
assert.ok( func2.equal(func1), "func2 == func1" );
});
it("equal two functions similar comments", () => {
const func1 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body: "begin\nend",
comment: Comment.fromFs({
objectType: "function",
})
});
const func2 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body: "begin\nend",
comment: Comment.fromTotalString("function", "hello\nddl-manager-sync")
});
assert.ok( func1.equal(func2), "func1 == func2" );
assert.ok( func2.equal(func1), "func2 == func1" );
});
it("equal arg type: \"order\" == public.order", () => {
const func1 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [{
name: "test",
type: "public.order"
}],
returns: {type: "public.order"},
body: "body"
});
const func2 = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [{
name: "test",
type: "\"order\""
}],
returns: {type: "\"order\""},
body: "body"
});
assert.ok( func1.equal(func2), "func1 == func2" );
assert.ok( func2.equal(func1), "func2 == func1" );
});
describe("findAssignColumns", () => {
it("empty function", () => {
shouldBeAssignedColumns(
"begin\nend",
[]
);
});
it("assign one column", () => {
shouldBeAssignedColumns(`
begin
new.my_column = 123;
end`, ["my_column"]);
});
it("ignore case", () => {
shouldBeAssignedColumns(`
begin
new.MY_COLUMN = 123;
end`, ["my_column"]);
});
it("assign two columns", () => {
shouldBeAssignedColumns(`
begin
new.column_a = 123;
new.column_b = 123;
end`, ["column_a", "column_b"]);
});
it("dont repeat columns", () => {
shouldBeAssignedColumns(`
begin
new.column_x = 123;
new.column_x = 123;
end`, ["column_x"]);
});
it("ignore if condition", () => {
shouldBeAssignedColumns(`
begin
if new.column_x = 1 or new.column_y = 1 then
new.column_z = 123;
end if;
end`, ["column_z"]);
});
it("assign inside loop", () => {
shouldBeAssignedColumns(`
begin
for ... loop
new.column_x = 19;
end loop;
end`, ["column_x"]);
});
it("ignore inline comments before assign", () => {
shouldBeAssignedColumns(`
begin
-- comment
new.column_x = 19;
end`, ["column_x"]);
});
it("ignore multiline comments before assign", () => {
shouldBeAssignedColumns(`
begin
/* comment */
new.column_x = 19;
end`, ["column_x"]);
});
function shouldBeAssignedColumns(
body: string, columns: string[]
) {
const func = new DatabaseFunction({
schema: "public",
name: "my_func",
args: [],
returns: {type: "bigint"},
body
});
assert.deepStrictEqual(
func.findAssignColumns(),
columns
);
}
});
})