Add more postgres utility wrappers
This commit is contained in:
parent
a4c0055c79
commit
c2ff6b4359
87
query.ts
87
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 = {
|
export const int2: SqlType = {
|
||||||
input(s) {
|
input(s) {
|
||||||
const n = Number(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 = {
|
export const int8: SqlType = {
|
||||||
input(s) {
|
input(s) {
|
||||||
const n = BigInt(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 === "number" || typeof x === "bigint") n = x;
|
||||||
else if (typeof x === "string") n = BigInt(x);
|
else if (typeof x === "string") n = BigInt(x);
|
||||||
else n = Number(x);
|
else n = Number(x);
|
||||||
if (Number.isInteger(n)) {
|
if (
|
||||||
if (-9007199254740991 <= n && n <= 9007199254740991) return n.toString();
|
(typeof n === "number" && Number.isSafeInteger(n)) ||
|
||||||
else throw new SqlTypeError(`unsafe int8 output '${x}'`);
|
(typeof n === "bigint" &&
|
||||||
} else if (typeof n === "bigint") {
|
-9223372036854775808n <= n &&
|
||||||
if (-9223372036854775808n <= n && n <= 9223372036854775807n)
|
n <= 9223372036854775807n)
|
||||||
return n.toString();
|
) {
|
||||||
}
|
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 = {
|
export const sql_types: SqlTypeMap = {
|
||||||
|
0: text,
|
||||||
16: bool, // bool
|
16: bool, // bool
|
||||||
25: text, // text
|
17: bytea, // bytea
|
||||||
|
18: char, // char
|
||||||
|
19: text, // name
|
||||||
|
20: int8, // int8
|
||||||
21: int2, // int2
|
21: int2, // int2
|
||||||
23: int4, // int4
|
23: int4, // int4
|
||||||
20: int8, // int8
|
25: text, // text
|
||||||
26: int8, // oid
|
26: uint4, // oid
|
||||||
|
28: uint4, // xid
|
||||||
|
29: uint4, // cid
|
||||||
|
114: json, // json
|
||||||
700: float4, // float4
|
700: float4, // float4
|
||||||
701: float8, // float8
|
701: float8, // float8
|
||||||
1082: timestamptz, // date
|
1082: timestamptz, // date
|
||||||
1114: timestamptz, // timestamp
|
1114: timestamptz, // timestamp
|
||||||
1184: timestamptz, // timestamptz
|
1184: timestamptz, // timestamptz
|
||||||
17: bytea, // bytea
|
|
||||||
114: json, // json
|
|
||||||
3802: json, // jsonb
|
3802: json, // jsonb
|
||||||
|
5069: uint8, // xid8
|
||||||
};
|
};
|
||||||
|
|
||||||
sql.types = sql_types;
|
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);
|
return this.#notify(channel, payload);
|
||||||
}
|
}
|
||||||
|
|
||||||
async get(param: string) {
|
async current_setting(name: string) {
|
||||||
return await this.query`select current_setting(${param}, true)`
|
return await this.query<[string]>`select current_setting(${name}, true)`
|
||||||
.map(([s]) => String(s))
|
.map(([x]) => x)
|
||||||
.first_or(null);
|
.first_or(null);
|
||||||
}
|
}
|
||||||
|
|
||||||
async set(param: string, value: string, local = false) {
|
async set_config(name: string, value: string, local = false) {
|
||||||
return await this.query`select set_config(${param}, ${value}, ${local})`
|
return await this.query<
|
||||||
.map(([s]) => String(s))
|
[string]
|
||||||
|
>`select set_config(${name}, ${value}, ${local})`
|
||||||
|
.map(([x]) => x)
|
||||||
.first();
|
.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) {
|
close(reason?: unknown) {
|
||||||
this.#close(reason);
|
this.#close(reason);
|
||||||
}
|
}
|
||||||
@ -1017,7 +1158,7 @@ function wire_impl(
|
|||||||
return jit.compiled<ParameterSerializer>`function ser_params(xs) {
|
return jit.compiled<ParameterSerializer>`function ser_params(xs) {
|
||||||
return [
|
return [
|
||||||
${jit.map(", ", param_types, (type_oid, i) => {
|
${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}])`;
|
return jit`${type}.output(xs[${i}])`;
|
||||||
})}
|
})}
|
||||||
];
|
];
|
||||||
@ -1034,7 +1175,7 @@ function wire_impl(
|
|||||||
function make_row_ctor({ columns }: RowDescription) {
|
function make_row_ctor({ columns }: RowDescription) {
|
||||||
const Row = jit.compiled<RowConstructor>`function Row(xs) {
|
const Row = jit.compiled<RowConstructor>`function Row(xs) {
|
||||||
${jit.map(" ", columns, ({ name, type_oid }, i) => {
|
${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}]));`;
|
return jit`this[${name}] = xs[${i}] === null ? null : ${type}.input(${from_utf8}(xs[${i}]));`;
|
||||||
})}
|
})}
|
||||||
}`;
|
}`;
|
||||||
|
Loading…
Reference in New Issue
Block a user