Add more postgres utility wrappers
This commit is contained in:
parent
a4c0055c79
commit
c2ff6b4359
85
query.ts
85
query.ts
@ -168,6 +168,23 @@ export const text: SqlType = {
|
||||
},
|
||||
};
|
||||
|
||||
export const char: SqlType = {
|
||||
input(c) {
|
||||
const n = c.charCodeAt(0);
|
||||
if (c.length === 1 && 0 <= n && n <= 255) return c;
|
||||
throw new SqlTypeError(`invalid char input '${c}'`);
|
||||
},
|
||||
output(x) {
|
||||
let c: string;
|
||||
if (typeof x === "undefined" || x === null) return null;
|
||||
else if (typeof x === "number") c = String.fromCharCode(x);
|
||||
else c = String(x);
|
||||
const n = c.charCodeAt(0);
|
||||
if (c.length === 1 && 0 <= n && n <= 255) return c;
|
||||
else throw new SqlTypeError(`invalid char output '${x}'`);
|
||||
},
|
||||
};
|
||||
|
||||
export const int2: SqlType = {
|
||||
input(s) {
|
||||
const n = Number(s);
|
||||
@ -201,6 +218,22 @@ export const int4: SqlType = {
|
||||
},
|
||||
};
|
||||
|
||||
export const uint4: SqlType = {
|
||||
input(s) {
|
||||
const n = Number(s);
|
||||
if (Number.isInteger(n) && 0 <= n && n <= 4294967295) return n;
|
||||
else throw new SqlTypeError(`invalid uint4 input '${s}'`);
|
||||
},
|
||||
output(x) {
|
||||
let n: number;
|
||||
if (typeof x === "undefined" || x === null) return null;
|
||||
else if (typeof x === "number") n = x;
|
||||
else n = Number(x);
|
||||
if (Number.isInteger(n) && 0 <= n && n <= 4294967295) return n.toString();
|
||||
else throw new SqlTypeError(`invalid uint4 output '${x}'`);
|
||||
},
|
||||
};
|
||||
|
||||
export const int8: SqlType = {
|
||||
input(s) {
|
||||
const n = BigInt(s);
|
||||
@ -214,14 +247,36 @@ export const int8: SqlType = {
|
||||
else if (typeof x === "number" || typeof x === "bigint") n = x;
|
||||
else if (typeof x === "string") n = BigInt(x);
|
||||
else n = Number(x);
|
||||
if (Number.isInteger(n)) {
|
||||
if (-9007199254740991 <= n && n <= 9007199254740991) return n.toString();
|
||||
else throw new SqlTypeError(`unsafe int8 output '${x}'`);
|
||||
} else if (typeof n === "bigint") {
|
||||
if (-9223372036854775808n <= n && n <= 9223372036854775807n)
|
||||
if (
|
||||
(typeof n === "number" && Number.isSafeInteger(n)) ||
|
||||
(typeof n === "bigint" &&
|
||||
-9223372036854775808n <= n &&
|
||||
n <= 9223372036854775807n)
|
||||
) {
|
||||
return n.toString();
|
||||
}
|
||||
throw new SqlTypeError(`invalid int8 output '${x}'`);
|
||||
} else throw new SqlTypeError(`invalid int8 output '${x}'`);
|
||||
},
|
||||
};
|
||||
|
||||
export const uint8: SqlType = {
|
||||
input(s) {
|
||||
const n = BigInt(s);
|
||||
if (0n <= n && n <= 9007199254740991n) return Number(n);
|
||||
else if (0n <= n && n <= 18446744073709551615n) return n;
|
||||
else throw new SqlTypeError(`invalid uint8 input '${s}'`);
|
||||
},
|
||||
output(x) {
|
||||
let n: number | bigint;
|
||||
if (typeof x === "undefined" || x === null) return null;
|
||||
else if (typeof x === "number" || typeof x === "bigint") n = x;
|
||||
else if (typeof x === "string") n = BigInt(x);
|
||||
else n = Number(x);
|
||||
if (
|
||||
(typeof n === "number" && Number.isSafeInteger(n) && 0 <= n) ||
|
||||
(typeof n === "bigint" && 0n <= n && n <= 18446744073709551615n)
|
||||
) {
|
||||
return n.toString();
|
||||
} else throw new SqlTypeError(`invalid uint8 output '${x}'`);
|
||||
},
|
||||
};
|
||||
|
||||
@ -305,20 +360,26 @@ export const json: SqlType = {
|
||||
};
|
||||
|
||||
export const sql_types: SqlTypeMap = {
|
||||
0: text,
|
||||
16: bool, // bool
|
||||
25: text, // text
|
||||
17: bytea, // bytea
|
||||
18: char, // char
|
||||
19: text, // name
|
||||
20: int8, // int8
|
||||
21: int2, // int2
|
||||
23: int4, // int4
|
||||
20: int8, // int8
|
||||
26: int8, // oid
|
||||
25: text, // text
|
||||
26: uint4, // oid
|
||||
28: uint4, // xid
|
||||
29: uint4, // cid
|
||||
114: json, // json
|
||||
700: float4, // float4
|
||||
701: float8, // float8
|
||||
1082: timestamptz, // date
|
||||
1114: timestamptz, // timestamp
|
||||
1184: timestamptz, // timestamptz
|
||||
17: bytea, // bytea
|
||||
114: json, // json
|
||||
3802: json, // jsonb
|
||||
5069: uint8, // xid8
|
||||
};
|
||||
|
||||
sql.types = sql_types;
|
||||
|
157
wire.ts
157
wire.ts
@ -545,18 +545,159 @@ export class Wire<V extends WireEvents = WireEvents>
|
||||
return this.#notify(channel, payload);
|
||||
}
|
||||
|
||||
async get(param: string) {
|
||||
return await this.query`select current_setting(${param}, true)`
|
||||
.map(([s]) => String(s))
|
||||
async current_setting(name: string) {
|
||||
return await this.query<[string]>`select current_setting(${name}, true)`
|
||||
.map(([x]) => x)
|
||||
.first_or(null);
|
||||
}
|
||||
|
||||
async set(param: string, value: string, local = false) {
|
||||
return await this.query`select set_config(${param}, ${value}, ${local})`
|
||||
.map(([s]) => String(s))
|
||||
async set_config(name: string, value: string, local = false) {
|
||||
return await this.query<
|
||||
[string]
|
||||
>`select set_config(${name}, ${value}, ${local})`
|
||||
.map(([x]) => x)
|
||||
.first();
|
||||
}
|
||||
|
||||
async cancel_backend(pid: number) {
|
||||
return await this.query<[boolean]>`select pg_cancel_backend(${pid})`
|
||||
.map(([x]) => x)
|
||||
.first();
|
||||
}
|
||||
|
||||
async terminate_backend(pid: number, timeout = 0) {
|
||||
return await this.query<
|
||||
[boolean]
|
||||
>`select pg_terminate_backend(${pid}, ${timeout})`
|
||||
.map(([x]) => x)
|
||||
.first();
|
||||
}
|
||||
|
||||
async inet() {
|
||||
return await this.query<{
|
||||
client_addr: string;
|
||||
client_port: number;
|
||||
server_addr: string;
|
||||
server_port: number;
|
||||
}>`
|
||||
select
|
||||
inet_client_addr() as client_addr,
|
||||
inet_client_port() as client_port,
|
||||
inet_server_addr() as server_addr,
|
||||
inet_server_port() as server_por
|
||||
`.first();
|
||||
}
|
||||
|
||||
async listening_channels() {
|
||||
return await this.query<[string]>`select pg_listening_channels()`
|
||||
.map(([x]) => x)
|
||||
.collect();
|
||||
}
|
||||
|
||||
async notification_queue_usage() {
|
||||
return await this.query<[number]>`select pg_notification_queue_usage()`
|
||||
.map(([x]) => x)
|
||||
.first();
|
||||
}
|
||||
|
||||
async postmaster_start_time() {
|
||||
return await this.query<[Date]>`select pg_postmaster_start_time()`
|
||||
.map(([x]) => x)
|
||||
.first();
|
||||
}
|
||||
|
||||
async current_wal() {
|
||||
return await this.query<{
|
||||
lsn: string;
|
||||
insert_lsn: string;
|
||||
flush_lsn: string;
|
||||
}>`
|
||||
select
|
||||
pg_current_wal_lsn() as lsn,
|
||||
pg_current_wal_insert_lsn() as insert_lsn,
|
||||
pg_current_wal_flush_lsn() as flush_lsn
|
||||
`.first();
|
||||
}
|
||||
|
||||
async switch_wal() {
|
||||
return await this.query<[string]>`select pg_switch_wal()`
|
||||
.map(([x]) => x)
|
||||
.first();
|
||||
}
|
||||
|
||||
async nextval(seq: string) {
|
||||
return await this.query<[number | bigint]>`select nextval(${seq})`
|
||||
.map(([x]) => x)
|
||||
.first();
|
||||
}
|
||||
|
||||
async setval(seq: string, value: number | bigint, is_called = true) {
|
||||
return await this.query<
|
||||
[number | bigint]
|
||||
>`select setval(${seq}, ${value}, ${is_called})`
|
||||
.map(([x]) => x)
|
||||
.first();
|
||||
}
|
||||
|
||||
async currval(seq: string) {
|
||||
return await this.query<[number]>`select currval(${seq})`
|
||||
.map(([x]) => x)
|
||||
.first();
|
||||
}
|
||||
|
||||
async lastval() {
|
||||
return await this.query<[number]>`select lastval()`.map(([x]) => x).first();
|
||||
}
|
||||
|
||||
async validate_input(s: string, type: string) {
|
||||
return await this.query<{
|
||||
message: string | null;
|
||||
detail: string | null;
|
||||
hint: string | null;
|
||||
sql_error_code: string | null;
|
||||
}>`select * from pg_input_error_info(${s}, ${type})`.first();
|
||||
}
|
||||
|
||||
async current_xid() {
|
||||
return await this.query<[number | bigint]>`select pg_current_xact_id()`
|
||||
.map(([x]) => x)
|
||||
.first();
|
||||
}
|
||||
|
||||
async current_xid_if_assigned() {
|
||||
return await this.query<
|
||||
[number | bigint | null]
|
||||
>`select pg_current_xact_id_if_assigned()`
|
||||
.map(([x]) => x)
|
||||
.first();
|
||||
}
|
||||
|
||||
async xact_info(xid: number | bigint) {
|
||||
return await this.query<{
|
||||
status: "progress" | "committed" | "aborted";
|
||||
age: number;
|
||||
mxid_age: number;
|
||||
}>`
|
||||
select
|
||||
pg_xact_status(${xid}) as status,
|
||||
age(${xid}) as age,
|
||||
mxid_age(${xid}) as mxid_age
|
||||
`;
|
||||
}
|
||||
|
||||
async version() {
|
||||
return await this.query<{
|
||||
postgres: string;
|
||||
unicode: string;
|
||||
icu_unicode: string | null;
|
||||
}>`
|
||||
select
|
||||
version() as postgres,
|
||||
unicode_version() as unicode,
|
||||
icu_unicode_version() as icu_unicode
|
||||
`.first();
|
||||
}
|
||||
|
||||
close(reason?: unknown) {
|
||||
this.#close(reason);
|
||||
}
|
||||
@ -1017,7 +1158,7 @@ function wire_impl(
|
||||
return jit.compiled<ParameterSerializer>`function ser_params(xs) {
|
||||
return [
|
||||
${jit.map(", ", param_types, (type_oid, i) => {
|
||||
const type = types[type_oid] ?? text;
|
||||
const type = types[type_oid] ?? types[0] ?? text;
|
||||
return jit`${type}.output(xs[${i}])`;
|
||||
})}
|
||||
];
|
||||
@ -1034,7 +1175,7 @@ function wire_impl(
|
||||
function make_row_ctor({ columns }: RowDescription) {
|
||||
const Row = jit.compiled<RowConstructor>`function Row(xs) {
|
||||
${jit.map(" ", columns, ({ name, type_oid }, i) => {
|
||||
const type = types[type_oid] ?? text;
|
||||
const type = types[type_oid] ?? types[0] ?? text;
|
||||
return jit`this[${name}] = xs[${i}] === null ? null : ${type}.input(${from_utf8}(xs[${i}]));`;
|
||||
})}
|
||||
}`;
|
||||
|
Loading…
Reference in New Issue
Block a user