Skip to content

Commit c55304e

Browse files
authored
Typescript support (porsager#8)
* Add Typescript declarations * Start adding JSdoc
1 parent 5e3fff8 commit c55304e

File tree

4 files changed

+361
-1
lines changed

4 files changed

+361
-1
lines changed

package.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,14 +3,17 @@
33
"version": "1.0.2",
44
"description": "Fastest full featured PostgreSQL client for Node.js",
55
"main": "lib/index.js",
6+
"types": "types/index.d.ts",
7+
"typings": "types/index.d.ts",
68
"type": "commonjs",
79
"scripts": {
810
"test": "node tests/index.js",
911
"lint": "eslint lib && eslint tests",
1012
"prepublishOnly": "npm run lint && npm test"
1113
},
1214
"files": [
13-
"/lib"
15+
"/lib",
16+
"/types"
1417
],
1518
"author": "Rasmus Porsager <rasmus@porsager.com>",
1619
"license": "WTFPL",

tests/index.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ const { t, not, ot } = require('./test.js') // eslint-disable-line
44
const cp = require('child_process')
55
const path = require('path')
66

7+
/** @type {import('../types')} */
78
const postgres = require('../lib')
89
const delay = ms => new Promise(r => setTimeout(r, ms))
910

types/index.d.ts

Lines changed: 343 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,343 @@
1+
/**
2+
* Establish a connection to a PostgreSQL server.
3+
* @param options Connection options - default to the same as psql
4+
* @returns An utility function to make queries to the server
5+
*/
6+
declare function postgres<T extends JSToPostgresTypeMap>(options?: postgres.Options<T>): postgres.Sql<JSToPostgresTypeMap extends T ? {} : T>
7+
/**
8+
* Establish a connection to a PostgreSQL server.
9+
* @param url Connection string used for authentication
10+
* @param options Connection options - default to the same as psql
11+
* @returns An utility function to make queries to the server
12+
*/
13+
declare function postgres<T extends JSToPostgresTypeMap>(url: string, options?: postgres.Options<T>): postgres.Sql<JSToPostgresTypeMap extends T ? {} : T>
14+
15+
/**
16+
* Connection options of Postgres.
17+
*/
18+
interface BaseOptions<T extends JSToPostgresTypeMap> {
19+
/** Postgres ip address or domain name */
20+
host: string;
21+
/** Postgres server port */
22+
port: number;
23+
/** Name of database to connect to */
24+
database: string;
25+
/** Username of database user */
26+
username: string;
27+
/** True; or options for tls.connect */
28+
ssl: boolean | object;
29+
/** Max number of connections */
30+
max: number;
31+
/** Idle connection timeout in seconds */
32+
idle_timeout: number | undefined;
33+
/** Connect timeout in seconds */
34+
connect_timeout: number;
35+
/** Array of custom types; see more below */
36+
types: PostgresTypeList<T>;
37+
/** Defaults to console.log */
38+
onnotice: (notice: postgres.Notice) => void;
39+
/** (key; value) when server param change */
40+
onparameter: (key: string, value: any) => void;
41+
/** Is called with (connection; query; parameters) */
42+
debug: boolean | ((connection: number, query: string, parameters: any[]) => void);
43+
/** Transform hooks */
44+
transform: {
45+
/** Transforms incoming column names */
46+
column?: (column: string) => string;
47+
/** Transforms incoming row values */
48+
value?: (value: any) => any;
49+
/** Transforms entire rows */
50+
row?: (row: postgres.Row) => any;
51+
};
52+
/** Connection parameters */
53+
connection: Partial<postgres.ConnectionParameters>;
54+
}
55+
56+
type PostgresTypeList<T> = {
57+
[name in keyof T]: T[name] extends (...args: any) => unknown
58+
? postgres.PostgresType<T[name]>
59+
: postgres.PostgresType;
60+
};
61+
62+
interface JSToPostgresTypeMap {
63+
[name: string]: unknown;
64+
}
65+
66+
declare class PostgresError extends Error {
67+
name: 'PostgresError';
68+
severity_local: string;
69+
severity: string;
70+
code: string;
71+
position: string;
72+
file: string;
73+
line: string;
74+
routine: string;
75+
76+
detail?: string;
77+
hint?: string;
78+
internal_position?: string;
79+
internal_query?: string;
80+
where?: string;
81+
schema_name?: string;
82+
table_name?: string;
83+
column_name?: string;
84+
data?: string;
85+
type_name?: string;
86+
constraint_name?: string;
87+
88+
// Disable user-side creation of PostgresError
89+
private constructor();
90+
}
91+
92+
type UnwrapPromiseArray<T> = T extends any[] ? {
93+
[k in keyof T]: T[k] extends Promise<infer R> ? R : T[k]
94+
} : T;
95+
96+
declare namespace postgres {
97+
98+
/**
99+
* Convert a string to Pascal case.
100+
* @param str THe string to convert
101+
* @returns The new string in Pascal case
102+
*/
103+
function toPascal(str: string): string;
104+
/**
105+
* Convert a string to Camel case.
106+
* @param str THe string to convert
107+
* @returns The new string in Camel case
108+
*/
109+
function toCamel(str: string): string;
110+
/**
111+
* Convert a string to Kebab case.
112+
* @param str THe string to convert
113+
* @returns The new string in Kebab case
114+
*/
115+
function toKebab(str: string): string;
116+
117+
const BigInt: PostgresType<(number: BigInt) => string>;
118+
119+
interface ConnectionParameters {
120+
/** Default application_name */
121+
application_name: string;
122+
/** Other connection parameters */
123+
[name: string]: any;
124+
}
125+
126+
interface Options<T extends JSToPostgresTypeMap> extends Partial<BaseOptions<T>> {
127+
/** unix socket path (usually '/tmp') */
128+
path?: string | (() => string);
129+
/** Password of database user (an alias for `password`) */
130+
pass?: Options<T>['password'];
131+
/** Password of database user */
132+
password?: string | (() => string | Promise<string>);
133+
/** Name of database to connect to (an alias for `database`) */
134+
db?: Options<T>['database'];
135+
/** Username of database user (an alias for `username`) */
136+
user?: Options<T>['username'];
137+
/** Postgres ip address or domain name (an alias for `host`) */
138+
hostname?: Options<T>['host'];
139+
}
140+
141+
interface ParsedOptions<T extends JSToPostgresTypeMap> extends BaseOptions<T> {
142+
/** @inheritdoc */
143+
pass: null;
144+
serializers: { [oid: number]: T[keyof T] };
145+
parsers: { [oid: number]: T[keyof T] };
146+
}
147+
148+
interface Notice {
149+
[field: string]: string;
150+
}
151+
152+
interface PostgresType<T extends (...args: any) => any = (...args: any) => any> {
153+
to: number;
154+
from: number[];
155+
serialize: T;
156+
parse: (raw: ReturnType<T>) => unknown;
157+
}
158+
159+
interface Parameter<T = SerializableParameter> {
160+
/**
161+
* PostgreSQL OID of the type
162+
*/
163+
type: number;
164+
/**
165+
* Value to serialize
166+
*/
167+
value: T;
168+
}
169+
170+
interface ArrayParameter<T extends SerializableParameter[] = SerializableParameter[]> extends Parameter<T | T[]> {
171+
array: true;
172+
}
173+
174+
interface ConnectionError extends globalThis.Error {
175+
code: never
176+
| 'CONNECTION_DESTROYED'
177+
| 'CONNECT_TIMEOUT'
178+
| 'CONNECTION_CLOSED'
179+
| 'CONNECTION_ENDED';
180+
errno: this['code'];
181+
address: string;
182+
port?: number;
183+
}
184+
185+
interface NotSupportedError extends globalThis.Error {
186+
code: 'MESSAGE_NOT_SUPPORTED';
187+
name: never
188+
| 'CopyInResponse'
189+
| 'CopyOutResponse'
190+
| 'ParameterDescription'
191+
| 'FunctionCallResponse'
192+
| 'NegotiateProtocolVersion'
193+
| 'CopyBothResponse';
194+
}
195+
196+
interface GenericError extends globalThis.Error {
197+
code: never
198+
| 'NOT_TAGGED_CALL'
199+
| 'UNDEFINED_VALUE'
200+
| 'MAX_PARAMETERS_EXCEEDED'
201+
| 'SASL_SIGNATURE_MISMATCH';
202+
message: string;
203+
}
204+
205+
interface AuthNotImplementedError extends globalThis.Error {
206+
code: 'AUTH_TYPE_NOT_IMPLEMENTED';
207+
type: number
208+
| 'KerberosV5'
209+
| 'CleartextPassword'
210+
| 'MD5Password'
211+
| 'SCMCredential'
212+
| 'GSS'
213+
| 'GSSContinue'
214+
| 'SSPI'
215+
| 'SASL'
216+
| 'SASLContinue'
217+
| 'SASLFinal';
218+
message: string;
219+
}
220+
221+
type Error = never
222+
| PostgresError
223+
| ConnectionError
224+
| NotSupportedError
225+
| GenericError
226+
| AuthNotImplementedError;
227+
228+
type Serializable = null
229+
| boolean
230+
| number
231+
| string
232+
| Date
233+
| Buffer;
234+
235+
type SerializableParameter = Serializable
236+
| Helper<any>
237+
| Parameter<any>
238+
| ArrayParameter
239+
| SerializableParameter[];
240+
241+
type HelperSerializable = { [index: string]: SerializableParameter } | { [index: string]: SerializableParameter }[];
242+
243+
interface Row {
244+
[column: string]: any;
245+
}
246+
247+
interface Column<T extends string> {
248+
name: T;
249+
type: number;
250+
parser(raw: string): string;
251+
}
252+
253+
type ColumnList<T> = (T extends string ? Column<T> : never)[];
254+
255+
interface State {
256+
state: 'I';
257+
pid: number;
258+
secret: number;
259+
}
260+
261+
interface ResultMeta<T extends number | null> {
262+
count: T; // For tuples
263+
command: string;
264+
state: State;
265+
}
266+
267+
interface ResultQueryMeta<T extends number | null, U> extends ResultMeta<T> {
268+
columns: ColumnList<U>;
269+
}
270+
271+
type ExecutionResult<T> = [] & ResultQueryMeta<number, T>;
272+
type RowList<T extends readonly Row[]> = T & ResultQueryMeta<T['length'], keyof T[number]>;
273+
274+
interface PendingQuery<TRow extends readonly Row[]> extends Promise<RowList<TRow>> {
275+
stream(cb: (row: TRow[number], result: ExecutionResult<TRow[number]>) => void): Promise<ExecutionResult<keyof TRow[number]>>;
276+
cursor(cb: (row: TRow[number]) => void): Promise<ExecutionResult<keyof TRow[number]>>;
277+
cursor(size: 1, cb: (row: TRow[number]) => void): Promise<ExecutionResult<keyof TRow[number]>>;
278+
cursor(size: number, cb: (rows: TRow) => void): Promise<ExecutionResult<keyof TRow[number]>>;
279+
}
280+
281+
interface PendingRequest extends Promise<[] & ResultMeta<null>> { }
282+
283+
interface Helper<T, U extends any[] = T[]> {
284+
first: T;
285+
rest: U;
286+
}
287+
288+
interface Sql<TTypes extends JSToPostgresTypeMap> {
289+
290+
/**
291+
* Execute the SQL query passed as a template string. Can only be used as template string tag.
292+
* @param template The template generated from the template string
293+
* @param args Interpoled values of the template string
294+
* @returns A promise resolving to the result of your query
295+
*/
296+
<T extends Row | Row[] = Row>(template: TemplateStringsArray, ...args: SerializableParameter[]): PendingQuery<T extends Row[] ? T : T[]>;
297+
298+
/**
299+
* Escape column names
300+
* @param columns Columns to escape
301+
* @returns A formated representation of the column names
302+
*/
303+
(columns: string[]): Helper<string>;
304+
(...columns: string[]): Helper<string>;
305+
306+
/**
307+
* Extract properties from an object or from an array of objects
308+
* @param objOrArray An object or an array of objects to extract properties from
309+
* @param keys Keys to extract from the object or from objets inside the array
310+
* @returns A formated representation of the parameter
311+
*/
312+
<T extends HelperSerializable, U extends (keyof (T extends any[] ? T[number] : T))[]>(objOrArray: T, ...keys: U): Helper<T, U>;
313+
314+
END: {}; // FIXME unique symbol ?
315+
PostgresError: typeof PostgresError;
316+
317+
array<T extends SerializableParameter[] = SerializableParameter[]>(value: T): ArrayParameter<T>;
318+
begin<T>(cb: (sql: TransactionSql<TTypes>) => T | Promise<T>): Promise<UnwrapPromiseArray<T>>;
319+
begin<T>(options: string, cb: (sql: TransactionSql<TTypes>) => T | Promise<T>): Promise<UnwrapPromiseArray<T>>;
320+
end(options?: { timeout?: number }): Promise<void>;
321+
file<T extends Row | Row[] = Row>(path: string, options?: { cache?: boolean }): PendingQuery<T extends Row[] ? T : T[]>;
322+
file<T extends Row | Row[] = Row>(path: string, args: SerializableParameter[], options?: { cache?: boolean }): PendingQuery<T extends Row[] ? T : T[]>;
323+
json(value: any): Parameter;
324+
listen(channel: string, cb: (value?: string) => void): PendingRequest;
325+
notify(channel: string, payload: string): PendingRequest;
326+
options: ParsedOptions<TTypes>;
327+
parameters: ConnectionParameters;
328+
types: {
329+
[name in keyof TTypes]: TTypes[name] extends (...args: any) => any
330+
? (...args: Parameters<TTypes[name]>) => postgres.Parameter<ReturnType<TTypes[name]>>
331+
: (...args: any) => postgres.Parameter<any>;
332+
};
333+
unsafe<T extends Row | Row[] = any[]>(query: string, parameters?: SerializableParameter[]): PendingQuery<T extends Row[] ? T : T[]>;
334+
}
335+
336+
interface TransactionSql<TTypes extends JSToPostgresTypeMap> extends Sql<TTypes> {
337+
savepoint<T>(cb: (sql: TransactionSql<TTypes>) => T | Promise<T>): Promise<UnwrapPromiseArray<T>>;
338+
savepoint<T>(name: string, cb: (sql: TransactionSql<TTypes>) => T | Promise<T>): Promise<UnwrapPromiseArray<T>>;
339+
}
340+
341+
}
342+
343+
export = postgres;

types/tsconfig.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"compilerOptions": {
3+
"lib": [
4+
"ES2015"
5+
],
6+
"types": [
7+
"node"
8+
],
9+
"esModuleInterop": true,
10+
"strict": true,
11+
"noImplicitAny": true
12+
}
13+
}

0 commit comments

Comments
 (0)