Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions cf/src/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -563,7 +563,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose

if (needsTypes) {
initial.reserve && (initial = null)
return fetchArrayTypes()
return fetchTypes()
}

initial && !initial.reserve && execute(initial)
Expand Down Expand Up @@ -659,7 +659,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
name: transform.column.from
? transform.column.from(x.toString('utf8', start, index - 1))
: x.toString('utf8', start, index - 1),
parser: parsers[type],
parser: parsers[type] || parsers[options.shared.typeOidToName[type]],
table,
number,
type
Expand Down Expand Up @@ -767,26 +767,29 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
backend.secret = x.readUInt32BE(9)
}

async function fetchArrayTypes() {
async function fetchTypes() {
needsTypes = false
const types = await new Query([`
select b.oid, b.typarray
from pg_catalog.pg_type a
left join pg_catalog.pg_type b on b.oid = a.typelem
where a.typcategory = 'A'
group by b.oid, b.typarray
order by b.oid
select oid, typname, typarray
from pg_catalog.pg_type
order by oid
`], [], execute)
types.forEach(({ oid, typarray }) => addArrayType(oid, typarray))
types.forEach(({ oid, typname, typarray }) => {
options.shared.typeNameToOid[typname] = oid
options.shared.typeOidToName[oid] = typname

if (typarray) addArrayType(oid, typarray)
})
}

function addArrayType(oid, typarray) {
if (!!options.parsers[typarray] && !!options.serializers[typarray]) return
const parser = options.parsers[oid]
const name = options.shared.typeOidToName[oid]
const parser = options.parsers[oid] || options.parsers[name]
options.shared.typeArrayMap[oid] = typarray
options.parsers[typarray] = (xs) => arrayParser(xs, parser, typarray)
options.parsers[typarray].array = true
options.serializers[typarray] = (xs) => arraySerializer(xs, options.serializers[oid], options, typarray)
options.serializers[typarray] = (xs) => arraySerializer(xs, options.serializers[oid] || options.serializers[name], options, typarray)
}

function tryNext(x, xs) {
Expand Down Expand Up @@ -973,7 +976,10 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose

function Parse(str, parameters, types, name = '') {
b().P().str(name + b.N).str(str + b.N).i16(parameters.length)
parameters.forEach((x, i) => b.i32(types[i] || 0))
parameters.forEach((x, i) => {
const type = types[i]
b.i32(options.shared.typeNameToOid[type] || type || 0)
})
return b.end()
}

Expand Down
2 changes: 1 addition & 1 deletion cf/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ function parseOptions(a, b) {
socket : o.socket,
transform : parseTransform(o.transform || { undefined: undefined }),
parameters : {},
shared : { retries: 0, typeArrayMap: {} },
shared : { retries: 0, typeArrayMap: {}, typeNameToOid: {}, typeOidToName: {} },
...mergeUserTypes(o.types)
}
}
Expand Down
2 changes: 1 addition & 1 deletion cf/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export function handleValue(x, parameters, types, options) {
return '$' + (types.push(
x instanceof Parameter
? (parameters.push(x.value), x.array
? x.array[x.type || inferType(x.value)] || x.type || firstIsString(x.value)
? x.array[options.shared.typeNameToOid[x.type] || x.type || inferType(x.value)] || x.type || firstIsString(x.value)
: x.type
)
: (parameters.push(x), inferType(x))
Expand Down
32 changes: 19 additions & 13 deletions cjs/src/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -561,7 +561,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose

if (needsTypes) {
initial.reserve && (initial = null)
return fetchArrayTypes()
return fetchTypes()
}

initial && !initial.reserve && execute(initial)
Expand Down Expand Up @@ -657,7 +657,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
name: transform.column.from
? transform.column.from(x.toString('utf8', start, index - 1))
: x.toString('utf8', start, index - 1),
parser: parsers[type],
parser: parsers[type] || parsers[options.shared.typeOidToName[type]],
table,
number,
type
Expand Down Expand Up @@ -765,26 +765,29 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
backend.secret = x.readUInt32BE(9)
}

async function fetchArrayTypes() {
async function fetchTypes() {
needsTypes = false
const types = await new Query([`
select b.oid, b.typarray
from pg_catalog.pg_type a
left join pg_catalog.pg_type b on b.oid = a.typelem
where a.typcategory = 'A'
group by b.oid, b.typarray
order by b.oid
select oid, typname, typarray
from pg_catalog.pg_type
order by oid
`], [], execute)
types.forEach(({ oid, typarray }) => addArrayType(oid, typarray))
types.forEach(({ oid, typname, typarray }) => {
options.shared.typeNameToOid[typname] = oid
options.shared.typeOidToName[oid] = typname

if (typarray) addArrayType(oid, typarray)
})
}

function addArrayType(oid, typarray) {
if (!!options.parsers[typarray] && !!options.serializers[typarray]) return
const parser = options.parsers[oid]
const name = options.shared.typeOidToName[oid]
const parser = options.parsers[oid] || options.parsers[name]
options.shared.typeArrayMap[oid] = typarray
options.parsers[typarray] = (xs) => arrayParser(xs, parser, typarray)
options.parsers[typarray].array = true
options.serializers[typarray] = (xs) => arraySerializer(xs, options.serializers[oid], options, typarray)
options.serializers[typarray] = (xs) => arraySerializer(xs, options.serializers[oid] || options.serializers[name], options, typarray)
}

function tryNext(x, xs) {
Expand Down Expand Up @@ -971,7 +974,10 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose

function Parse(str, parameters, types, name = '') {
b().P().str(name + b.N).str(str + b.N).i16(parameters.length)
parameters.forEach((x, i) => b.i32(types[i] || 0))
parameters.forEach((x, i) => {
const type = types[i]
b.i32(options.shared.typeNameToOid[type] || type || 0)
})
return b.end()
}

Expand Down
2 changes: 1 addition & 1 deletion cjs/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ function parseOptions(a, b) {
socket : o.socket,
transform : parseTransform(o.transform || { undefined: undefined }),
parameters : {},
shared : { retries: 0, typeArrayMap: {} },
shared : { retries: 0, typeArrayMap: {}, typeNameToOid: {}, typeOidToName: {} },
...mergeUserTypes(o.types)
}
}
Expand Down
2 changes: 1 addition & 1 deletion cjs/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ module.exports.handleValue = handleValue;function handleValue(x, parameters, typ
return '$' + (types.push(
x instanceof Parameter
? (parameters.push(x.value), x.array
? x.array[x.type || inferType(x.value)] || x.type || firstIsString(x.value)
? x.array[options.shared.typeNameToOid[x.type] || x.type || inferType(x.value)] || x.type || firstIsString(x.value)
: x.type
)
: (parameters.push(x), inferType(x))
Expand Down
18 changes: 18 additions & 0 deletions cjs/tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -539,6 +539,24 @@ t('Point type array', async() => {
return [30, (await sql`select x from test`)[0].x[1][1], await sql`drop table test`]
})

t('Point type with named OIDs', async() => {
const sql = postgres({
...options,
types: {
point: {
to: 'point',
from: ['point'],
serialize: ([x, y]) => '(' + x + ',' + y + ')',
parse: (x) => x.slice(1, -1).split(',').map(x => +x)
}
}
})

await sql`create table test (x point)`
await sql`insert into test (x) values (${ sql.types.point([10, 20]) })`
return [20, (await sql`select x from test`)[0].x[1], await sql`drop table test`]
})

t('sql file', async() =>
[1, (await sql.file(rel('select.sql')))[0].x]
)
Expand Down
32 changes: 19 additions & 13 deletions deno/src/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose

if (needsTypes) {
initial.reserve && (initial = null)
return fetchArrayTypes()
return fetchTypes()
}

initial && !initial.reserve && execute(initial)
Expand Down Expand Up @@ -660,7 +660,7 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
name: transform.column.from
? transform.column.from(x.toString('utf8', start, index - 1))
: x.toString('utf8', start, index - 1),
parser: parsers[type],
parser: parsers[type] || parsers[options.shared.typeOidToName[type]],
table,
number,
type
Expand Down Expand Up @@ -768,26 +768,29 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose
backend.secret = x.readUInt32BE(9)
}

async function fetchArrayTypes() {
async function fetchTypes() {
needsTypes = false
const types = await new Query([`
select b.oid, b.typarray
from pg_catalog.pg_type a
left join pg_catalog.pg_type b on b.oid = a.typelem
where a.typcategory = 'A'
group by b.oid, b.typarray
order by b.oid
select oid, typname, typarray
from pg_catalog.pg_type
order by oid
`], [], execute)
types.forEach(({ oid, typarray }) => addArrayType(oid, typarray))
types.forEach(({ oid, typname, typarray }) => {
options.shared.typeNameToOid[typname] = oid
options.shared.typeOidToName[oid] = typname

if (typarray) addArrayType(oid, typarray)
})
}

function addArrayType(oid, typarray) {
if (!!options.parsers[typarray] && !!options.serializers[typarray]) return
const parser = options.parsers[oid]
const name = options.shared.typeOidToName[oid]
const parser = options.parsers[oid] || options.parsers[name]
options.shared.typeArrayMap[oid] = typarray
options.parsers[typarray] = (xs) => arrayParser(xs, parser, typarray)
options.parsers[typarray].array = true
options.serializers[typarray] = (xs) => arraySerializer(xs, options.serializers[oid], options, typarray)
options.serializers[typarray] = (xs) => arraySerializer(xs, options.serializers[oid] || options.serializers[name], options, typarray)
}

function tryNext(x, xs) {
Expand Down Expand Up @@ -974,7 +977,10 @@ function Connection(options, queues = {}, { onopen = noop, onend = noop, onclose

function Parse(str, parameters, types, name = '') {
b().P().str(name + b.N).str(str + b.N).i16(parameters.length)
parameters.forEach((x, i) => b.i32(types[i] || 0))
parameters.forEach((x, i) => {
const type = types[i]
b.i32(options.shared.typeNameToOid[type] || type || 0)
})
return b.end()
}

Expand Down
2 changes: 1 addition & 1 deletion deno/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ function parseOptions(a, b) {
socket : o.socket,
transform : parseTransform(o.transform || { undefined: undefined }),
parameters : {},
shared : { retries: 0, typeArrayMap: {} },
shared : { retries: 0, typeArrayMap: {}, typeNameToOid: {}, typeOidToName: {} },
...mergeUserTypes(o.types)
}
}
Expand Down
2 changes: 1 addition & 1 deletion deno/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export function handleValue(x, parameters, types, options) {
return '$' + (types.push(
x instanceof Parameter
? (parameters.push(x.value), x.array
? x.array[x.type || inferType(x.value)] || x.type || firstIsString(x.value)
? x.array[options.shared.typeNameToOid[x.type] || x.type || inferType(x.value)] || x.type || firstIsString(x.value)
: x.type
)
: (parameters.push(x), inferType(x))
Expand Down
18 changes: 18 additions & 0 deletions deno/tests/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -541,6 +541,24 @@ t('Point type array', async() => {
return [30, (await sql`select x from test`)[0].x[1][1], await sql`drop table test`]
})

t('Point type with named OIDs', async() => {
const sql = postgres({
...options,
types: {
point: {
to: 'point',
from: ['point'],
serialize: ([x, y]) => '(' + x + ',' + y + ')',
parse: (x) => x.slice(1, -1).split(',').map(x => +x)
}
}
})

await sql`create table test (x point)`
await sql`insert into test (x) values (${ sql.types.point([10, 20]) })`
return [20, (await sql`select x from test`)[0].x[1], await sql`drop table test`]
})

t('sql file', async() =>
[1, (await sql.file(rel('select.sql')))[0].x]
)
Expand Down
16 changes: 8 additions & 8 deletions deno/types/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -319,8 +319,8 @@ declare namespace postgres {
const BigInt: PostgresType<bigint>;

interface PostgresType<T = any> {
to: number;
from: number[];
to: (number | string);
from: (number | string)[];
serialize: (value: T) => unknown;
parse: (raw: any) => T;
}
Expand Down Expand Up @@ -386,8 +386,8 @@ declare namespace postgres {
pass: null;
/** @inheritdoc */
transform: Transform;
serializers: Record<number, (value: any) => unknown>;
parsers: Record<number, (value: any) => unknown>;
serializers: Record<number | string, (value: any) => unknown>;
parsers: Record<number | string, (value: any) => unknown>;
}

interface Transform {
Expand Down Expand Up @@ -419,9 +419,9 @@ declare namespace postgres {

interface Parameter<T = SerializableParameter> extends NotAPromise {
/**
* PostgreSQL OID of the type
* PostgreSQL OID or type name of the type
*/
type: number;
type: number | string;
/**
* Serialized value
*/
Expand Down Expand Up @@ -684,7 +684,7 @@ declare namespace postgres {
options: ParsedOptions<TTypes>;
parameters: ConnectionParameters;
types: this['typed'];
typed: (<T>(value: T, oid: number) => Parameter<T>) & {
typed: (<T>(value: T, type: number | string) => Parameter<T>) & {
[name in keyof TTypes]: (value: TTypes[name]) => postgres.Parameter<TTypes[name]>
};

Expand All @@ -701,7 +701,7 @@ declare namespace postgres {
begin<T>(cb: (sql: TransactionSql<TTypes>) => T | Promise<T>): Promise<UnwrapPromiseArray<T>>;
begin<T>(options: string, cb: (sql: TransactionSql<TTypes>) => T | Promise<T>): Promise<UnwrapPromiseArray<T>>;

array<T extends SerializableParameter<TTypes[keyof TTypes]>[] = SerializableParameter<TTypes[keyof TTypes]>[]>(value: T, type?: number | undefined): ArrayParameter<T>;
array<T extends SerializableParameter<TTypes[keyof TTypes]>[] = SerializableParameter<TTypes[keyof TTypes]>[]>(value: T, type?: number | string | undefined): ArrayParameter<T>;
file<T extends readonly any[] = Row[]>(path: string | Buffer | URL | number, options?: { cache?: boolean | undefined } | undefined): PendingQuery<T>;
file<T extends readonly any[] = Row[]>(path: string | Buffer | URL | number, args: (ParameterOrJSON<TTypes[keyof TTypes]>)[], options?: { cache?: boolean | undefined } | undefined): PendingQuery<T>;
json(value: JSONValue): Parameter;
Expand Down
Loading