pglue/test.ts

228 lines
5.8 KiB
TypeScript
Raw Normal View History

2025-01-11 00:15:19 +11:00
import pglue, { PostgresError, SqlTypeError } from "./mod.ts";
import { expect } from "jsr:@std/expect";
import { toText } from "jsr:@std/streams";
2025-01-11 00:15:19 +11:00
2025-01-12 06:36:15 +11:00
const pool = pglue(`postgres://test:test@localhost:5432/test`, {
runtime_params: { client_min_messages: "INFO" },
});
2025-01-11 00:15:19 +11:00
2025-01-12 06:36:15 +11:00
pool.on("log", (level, ctx, msg) => console.info(`${level}: ${msg}`, ctx));
2025-01-11 00:15:19 +11:00
Deno.test(`integers`, async () => {
2025-01-12 06:36:15 +11:00
await using pg = await pool.connect();
2025-01-11 00:15:19 +11:00
await using _tx = await pg.begin();
const { a, b, c } = await pg.query`
2025-01-11 00:15:19 +11:00
select
${"0x100"}::int2 as a,
${777}::int4 as b,
${{
[Symbol.toPrimitive](hint: string) {
expect(hint).toBe("number");
return "1234";
},
}}::int8 as c
`.first();
expect(a).toBe(0x100);
expect(b).toBe(777);
expect(c).toBe(1234);
const { large } =
2025-01-11 00:15:19 +11:00
await pg.query`select ${"10000000000000000"}::int8 as large`.first();
expect(large).toBe(10000000000000000n);
await expect(pg.query`select ${100000}::int2`).rejects.toThrow(SqlTypeError);
await expect(pg.query`select ${"100000"}::text::int2`).rejects.toThrow(
PostgresError
);
});
Deno.test(`boolean`, async () => {
2025-01-12 06:36:15 +11:00
await using pg = await pool.connect();
2025-01-11 00:15:19 +11:00
await using _tx = await pg.begin();
const { a, b, c } = await pg.query`
2025-01-11 00:15:19 +11:00
select
${true}::bool as a,
${"n"}::bool as b,
${undefined}::bool as c
`.first();
expect(a).toBe(true);
expect(b).toBe(false);
expect(c).toBe(null);
});
Deno.test(`bytea`, async () => {
2025-01-12 06:36:15 +11:00
await using pg = await pool.connect();
2025-01-11 00:15:19 +11:00
await using _tx = await pg.begin();
const { string, array, buffer } = await pg.query`
2025-01-11 00:15:19 +11:00
select
${"hello, world"}::bytea as string,
${[1, 2, 3, 4, 5]}::bytea as array,
${Uint8Array.of(5, 4, 3, 2, 1)}::bytea as buffer
`.first();
expect(string).toEqual(new TextEncoder().encode("hello, world"));
expect(array).toEqual(Uint8Array.of(1, 2, 3, 4, 5));
expect(buffer).toEqual(Uint8Array.of(5, 4, 3, 2, 1));
});
Deno.test(`row`, async () => {
2025-01-12 06:36:15 +11:00
await using pg = await pool.connect();
2025-01-11 00:15:19 +11:00
await using _tx = await pg.begin();
expect(
(
await pg.query`create table my_table (a text not null, b text not null, c text not null)`
).tag
).toBe(`CREATE TABLE`);
expect(
(
await pg.query`copy my_table from stdin`.stdin(
`field a\tfield b\tfield c`
)
).tag
).toBe(`COPY 1`);
const row = await pg.query`select * from my_table`.first();
2025-01-11 00:15:19 +11:00
{
// columns by name
const { a, b, c } = row;
expect(a).toBe("field a");
expect(b).toBe("field b");
expect(c).toBe("field c");
}
{
// columns by index
const [a, b, c] = row;
expect(a).toBe("field a");
expect(b).toBe("field b");
expect(c).toBe("field c");
}
const { readable, writable } = new TransformStream<Uint8Array>(
{},
new ByteLengthQueuingStrategy({ highWaterMark: 4096 }),
new ByteLengthQueuingStrategy({ highWaterMark: 4096 })
);
await pg.query`copy my_table to stdout`.stdout(writable);
expect(await toText(readable)).toBe(`field a\tfield b\tfield c\n`);
2025-01-11 00:15:19 +11:00
});
Deno.test(`sql injection`, async () => {
2025-01-12 06:36:15 +11:00
await using pg = await pool.connect();
2025-01-11 00:15:19 +11:00
await using _tx = await pg.begin();
const input = `injection'); drop table users; --`;
expect((await pg.query`create table users (name text not null)`).tag).toBe(
`CREATE TABLE`
);
expect((await pg.query`insert into users (name) values (${input})`).tag).toBe(
`INSERT 0 1`
);
const { name } = await pg.query<{ name: string }>`
2025-01-11 00:15:19 +11:00
select name from users
`.first();
expect(name).toBe(input);
});
2025-01-11 02:00:05 +11:00
Deno.test(`listen/notify`, async () => {
2025-01-12 06:36:15 +11:00
await using pg = await pool.connect();
2025-01-11 00:15:19 +11:00
const sent: string[] = [];
await using ch = await pg.listen(`my channel`, (payload) => {
expect(payload).toBe(sent.shift());
});
for (let i = 0; i < 5; i++) {
const payload = `test payload ${i}`;
sent.push(payload);
await ch.notify(payload);
}
2025-01-11 02:00:05 +11:00
expect(sent.length).toBe(0);
2025-01-11 00:15:19 +11:00
});
Deno.test(`transactions`, async () => {
2025-01-12 06:36:15 +11:00
await using pg = await pool.connect();
2025-01-11 00:15:19 +11:00
await pg.begin(async (pg) => {
await pg.begin(async (pg, tx) => {
await pg.query`create table my_table (field text not null)`;
await tx.rollback();
});
await expect(pg.query`select * from my_table`).rejects.toThrow(
PostgresError
);
});
await expect(pg.query`select * from my_table`).rejects.toThrow(PostgresError);
await pg.begin(async (pg) => {
await pg.begin(async (pg, tx) => {
await pg.begin(async (pg, tx) => {
await pg.begin(async (pg) => {
await pg.query`create table my_table (field text not null)`;
});
await tx.commit();
});
expect(await pg.query`select * from my_table`.count()).toBe(0);
await tx.rollback();
});
await expect(pg.query`select * from my_table`).rejects.toThrow(
PostgresError
);
});
});
2025-01-11 00:39:00 +11:00
Deno.test(`streaming`, async () => {
2025-01-12 06:36:15 +11:00
await using pg = await pool.connect();
2025-01-11 00:39:00 +11:00
await using _tx = await pg.begin();
await pg.query`create table my_table (field text not null)`;
2025-01-11 02:00:05 +11:00
for (let i = 0; i < 20; i++) {
2025-01-11 00:39:00 +11:00
await pg.query`insert into my_table (field) values (${i})`;
}
let i = 0;
2025-01-11 02:00:05 +11:00
for await (const chunk of pg.query`select * from my_table`.chunked(5)) {
expect(chunk.length).toBe(5);
2025-01-11 00:39:00 +11:00
for (const row of chunk) expect(row.field).toBe(`${i++}`);
}
2025-01-11 02:00:05 +11:00
expect(i).toBe(20);
});
Deno.test(`simple`, async () => {
2025-01-12 06:36:15 +11:00
await using pg = await pool.connect();
2025-01-11 02:00:05 +11:00
await using _tx = await pg.begin();
const rows = await pg.query`
create table my_table (field text not null);
insert into my_table (field) values ('one'), ('two'), ('three');
select * from my_table;
select * from my_table where field = 'two';
`.simple();
expect(rows.length).toBe(4);
const [{ field: a }, { field: b }, { field: c }, { field: d }] = rows;
expect(a).toBe("one");
expect(b).toBe("two");
expect(c).toBe("three");
expect(d).toBe("two");
2025-01-11 00:39:00 +11:00
});