@devmoods/express-extras 0.40.1 → 0.41.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/postgres.d.ts +24 -19
- package/dist/postgres.js +28 -11
- package/package.json +11 -10
package/dist/postgres.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import pg, { type PoolClient, type PoolConfig, type QueryResult, type QueryResultRow } from 'pg';
|
|
2
2
|
export declare const escapePostgresIdentifier: typeof pg.escapeIdentifier;
|
|
3
3
|
export declare const escapePostgresLiteral: typeof pg.escapeLiteral;
|
|
4
|
-
export
|
|
4
|
+
export declare const formatSql: (statement: SqlStatement | string) => string;
|
|
5
|
+
export interface PostgresOptions extends PoolConfig, ConnectionOptions {
|
|
5
6
|
onError?: (error: Error, client: any) => void;
|
|
6
7
|
url?: PoolConfig['connectionString'];
|
|
7
8
|
}
|
|
@@ -15,14 +16,18 @@ export declare class IntegrityError extends Error {
|
|
|
15
16
|
constructor(message: string);
|
|
16
17
|
}
|
|
17
18
|
type Value = null | string | number | Date;
|
|
19
|
+
export interface ConnectionOptions {
|
|
20
|
+
onLogStatement?: (statement: SqlStatement | string, values?: unknown[]) => void;
|
|
21
|
+
}
|
|
18
22
|
export declare class Connection {
|
|
23
|
+
private options;
|
|
19
24
|
client: PoolClient;
|
|
20
|
-
constructor(client: PoolClient);
|
|
21
|
-
query<T extends QueryResultRow>(text: string |
|
|
22
|
-
all<T>(text: string |
|
|
23
|
-
insert<T extends QueryResultRow>(text: string |
|
|
24
|
-
first<T>(text: string |
|
|
25
|
-
get<T>(text: string |
|
|
25
|
+
constructor(client: PoolClient, options: ConnectionOptions);
|
|
26
|
+
query<T extends QueryResultRow>(text: string | SqlStatement, values?: Value[]): Promise<QueryResult<T>>;
|
|
27
|
+
all<T extends QueryResultRow>(text: string | SqlStatement, values?: Value[]): Promise<T[]>;
|
|
28
|
+
insert<T extends QueryResultRow>(text: string | SqlStatement, values?: Value[]): Promise<QueryResult<T>>;
|
|
29
|
+
first<T extends QueryResultRow>(text: string | SqlStatement, values?: Value[]): Promise<T | null>;
|
|
30
|
+
get<T extends QueryResultRow>(text: string | SqlStatement, values?: Value[]): Promise<T>;
|
|
26
31
|
}
|
|
27
32
|
export declare class Transaction extends Connection {
|
|
28
33
|
}
|
|
@@ -34,27 +39,27 @@ export declare class Transaction extends Connection {
|
|
|
34
39
|
* @param config
|
|
35
40
|
*/
|
|
36
41
|
export declare function createPostgres({ onError, url, ...config }?: PostgresOptions): {
|
|
37
|
-
insert: <T extends QueryResultRow>(text: string |
|
|
38
|
-
query: <T extends QueryResultRow>(text: string |
|
|
39
|
-
first: <T>(text: string |
|
|
40
|
-
all: <T>(text: string |
|
|
41
|
-
get: <T>(text: string |
|
|
42
|
+
insert: <T extends QueryResultRow>(text: string | SqlStatement, values?: Value[]) => Promise<QueryResult<T>>;
|
|
43
|
+
query: <T extends QueryResultRow>(text: string | SqlStatement, values?: Value[]) => Promise<QueryResult<T>>;
|
|
44
|
+
first: <T extends QueryResultRow>(text: string | SqlStatement, values?: Value[]) => Promise<T | null>;
|
|
45
|
+
all: <T extends QueryResultRow>(text: string | SqlStatement, values?: Value[]) => Promise<T[]>;
|
|
46
|
+
get: <T extends QueryResultRow>(text: string | SqlStatement, values?: Value[]) => Promise<T>;
|
|
42
47
|
withConnection: <T>(callback: (connection: Connection) => Promise<T>) => Promise<T>;
|
|
43
48
|
transaction: <T>(callback: (connection: Transaction) => Promise<T> | T) => Promise<T>;
|
|
44
49
|
instance: pg.Pool;
|
|
45
50
|
clear: (force?: boolean) => Promise<void>;
|
|
46
51
|
end(): Promise<void>;
|
|
47
52
|
};
|
|
48
|
-
declare class
|
|
53
|
+
export declare class SqlStatement {
|
|
49
54
|
stringsAndValues: [string, unknown | undefined][];
|
|
50
55
|
constructor(strings: string[], values: unknown[]);
|
|
51
56
|
_extract(strings: string[], values: unknown[]): void;
|
|
52
|
-
append(statement:
|
|
57
|
+
append(statement: SqlStatement | string): this;
|
|
53
58
|
get values(): ({} | null)[];
|
|
54
59
|
get text(): string;
|
|
55
60
|
}
|
|
56
61
|
export declare const sql: {
|
|
57
|
-
(strings: TemplateStringsArray, ...values: unknown[]):
|
|
62
|
+
(strings: TemplateStringsArray, ...values: unknown[]): SqlStatement;
|
|
58
63
|
identifier(name: string): {
|
|
59
64
|
name: string;
|
|
60
65
|
raw: boolean;
|
|
@@ -63,14 +68,14 @@ export declare const sql: {
|
|
|
63
68
|
name: string;
|
|
64
69
|
raw: boolean;
|
|
65
70
|
};
|
|
66
|
-
literal(name: string): {
|
|
71
|
+
literal(name: string | null): {
|
|
67
72
|
name: string;
|
|
68
73
|
raw: boolean;
|
|
69
74
|
};
|
|
70
75
|
spreadUpdate: typeof spreadUpdate;
|
|
71
76
|
spreadInsert: typeof spreadInsert;
|
|
72
77
|
};
|
|
73
|
-
declare function spreadUpdate(data: Record<string, any>):
|
|
74
|
-
declare function spreadInsert<TData extends Record<string, any>>(data: TData | TData[]):
|
|
75
|
-
export declare function joinStatements(statements:
|
|
78
|
+
declare function spreadUpdate(data: Record<string, any>): SqlStatement;
|
|
79
|
+
declare function spreadInsert<TData extends Record<string, any>>(data: TData | TData[]): SqlStatement;
|
|
80
|
+
export declare function joinStatements(statements: SqlStatement[], separator: string): SqlStatement;
|
|
76
81
|
export {};
|
package/dist/postgres.js
CHANGED
|
@@ -1,7 +1,17 @@
|
|
|
1
1
|
import pg, {} from 'pg';
|
|
2
|
+
import { format } from 'sql-formatter';
|
|
2
3
|
import { readEnv } from './utils.js';
|
|
3
4
|
export const escapePostgresIdentifier = pg.escapeIdentifier;
|
|
4
5
|
export const escapePostgresLiteral = pg.escapeLiteral;
|
|
6
|
+
export const formatSql = (statement) => {
|
|
7
|
+
const value = statement instanceof SqlStatement ? statement.text : statement;
|
|
8
|
+
return format(value, {
|
|
9
|
+
language: 'postgresql',
|
|
10
|
+
keywordCase: 'upper',
|
|
11
|
+
tabWidth: 2,
|
|
12
|
+
useTabs: false,
|
|
13
|
+
});
|
|
14
|
+
};
|
|
5
15
|
export class DoesNotExistError extends Error {
|
|
6
16
|
constructor(message) {
|
|
7
17
|
super(message);
|
|
@@ -21,11 +31,13 @@ export class IntegrityError extends Error {
|
|
|
21
31
|
}
|
|
22
32
|
}
|
|
23
33
|
export class Connection {
|
|
24
|
-
constructor(client) {
|
|
34
|
+
constructor(client, options) {
|
|
35
|
+
this.options = options;
|
|
25
36
|
this.client = client;
|
|
26
37
|
}
|
|
27
38
|
async query(text, values) {
|
|
28
39
|
try {
|
|
40
|
+
this.options.onLogStatement?.(text, values);
|
|
29
41
|
return await this.client.query(text, values);
|
|
30
42
|
}
|
|
31
43
|
catch (error) {
|
|
@@ -36,7 +48,7 @@ export class Connection {
|
|
|
36
48
|
}
|
|
37
49
|
}
|
|
38
50
|
async all(text, values) {
|
|
39
|
-
const result = await this.
|
|
51
|
+
const result = await this.query(text, values);
|
|
40
52
|
if (result.rows) {
|
|
41
53
|
return result.rows;
|
|
42
54
|
/* c8 ignore next 2*/
|
|
@@ -47,11 +59,11 @@ export class Connection {
|
|
|
47
59
|
return await this.query(text, values);
|
|
48
60
|
}
|
|
49
61
|
async first(text, values) {
|
|
50
|
-
const result = await this.
|
|
62
|
+
const result = await this.query(text, values);
|
|
51
63
|
return result.rows && result.rows.length ? result.rows[0] : null;
|
|
52
64
|
}
|
|
53
65
|
async get(text, values) {
|
|
54
|
-
const result = await this.
|
|
66
|
+
const result = await this.query(text, values);
|
|
55
67
|
if (result.rowCount === 0) {
|
|
56
68
|
throw new DoesNotExistError('Row matching query not found');
|
|
57
69
|
}
|
|
@@ -78,7 +90,7 @@ export function createPostgres({ onError, url = readEnv('POSTGRES_URL'), ...conf
|
|
|
78
90
|
async function withConnection(callback) {
|
|
79
91
|
const client = await pool.connect();
|
|
80
92
|
try {
|
|
81
|
-
const result = await callback(new Connection(client));
|
|
93
|
+
const result = await callback(new Connection(client, { onLogStatement: config.onLogStatement }));
|
|
82
94
|
return result;
|
|
83
95
|
}
|
|
84
96
|
finally {
|
|
@@ -104,7 +116,7 @@ export function createPostgres({ onError, url = readEnv('POSTGRES_URL'), ...conf
|
|
|
104
116
|
const client = await pool.connect();
|
|
105
117
|
try {
|
|
106
118
|
await client.query('BEGIN');
|
|
107
|
-
const result = await callback(new Transaction(client));
|
|
119
|
+
const result = await callback(new Transaction(client, { onLogStatement: config.onLogStatement }));
|
|
108
120
|
await client.query('COMMIT');
|
|
109
121
|
return result;
|
|
110
122
|
}
|
|
@@ -160,7 +172,7 @@ export function createPostgres({ onError, url = readEnv('POSTGRES_URL'), ...conf
|
|
|
160
172
|
const isRaw = (value) => {
|
|
161
173
|
return (typeof value === 'object' && value !== null && 'raw' in value && !!value.raw);
|
|
162
174
|
};
|
|
163
|
-
class
|
|
175
|
+
export class SqlStatement {
|
|
164
176
|
constructor(strings, values) {
|
|
165
177
|
this.stringsAndValues = [];
|
|
166
178
|
this._extract(strings, values);
|
|
@@ -172,7 +184,7 @@ class SQLStatement {
|
|
|
172
184
|
if (isRaw(value)) {
|
|
173
185
|
this.stringsAndValues.push([string + value.name, undefined]);
|
|
174
186
|
}
|
|
175
|
-
else if (value instanceof
|
|
187
|
+
else if (value instanceof SqlStatement) {
|
|
176
188
|
this.stringsAndValues.push([string, undefined]);
|
|
177
189
|
this.stringsAndValues.push(...value.stringsAndValues);
|
|
178
190
|
}
|
|
@@ -182,7 +194,7 @@ class SQLStatement {
|
|
|
182
194
|
}
|
|
183
195
|
}
|
|
184
196
|
append(statement) {
|
|
185
|
-
if (statement instanceof
|
|
197
|
+
if (statement instanceof SqlStatement) {
|
|
186
198
|
this.stringsAndValues.push(...statement.stringsAndValues);
|
|
187
199
|
}
|
|
188
200
|
else {
|
|
@@ -211,14 +223,16 @@ class SQLStatement {
|
|
|
211
223
|
}
|
|
212
224
|
}
|
|
213
225
|
export const sql = (strings, ...values) => {
|
|
214
|
-
return new
|
|
226
|
+
return new SqlStatement(Array.from(strings), values);
|
|
215
227
|
};
|
|
216
228
|
function spreadUpdate(data) {
|
|
217
229
|
const entries = Object.entries(data);
|
|
218
230
|
if (entries.length === 0) {
|
|
219
231
|
return sql ``;
|
|
220
232
|
}
|
|
221
|
-
return joinStatements(entries
|
|
233
|
+
return joinStatements(entries
|
|
234
|
+
.filter(([, value]) => typeof value !== 'undefined')
|
|
235
|
+
.map(([key, value]) => sql `${sql.identifier(key)} = ${value == null ? sql.raw('NULL') : value}`), ', ');
|
|
222
236
|
}
|
|
223
237
|
function spreadInsert(data) {
|
|
224
238
|
const rows = Array.isArray(data) ? data : [data];
|
|
@@ -257,6 +271,9 @@ sql.raw = (name) => {
|
|
|
257
271
|
* Inject a literal value into the template string
|
|
258
272
|
*/
|
|
259
273
|
sql.literal = (name) => {
|
|
274
|
+
if (name === null) {
|
|
275
|
+
return { name: 'NULL', raw: true };
|
|
276
|
+
}
|
|
260
277
|
return { name: escapePostgresLiteral(name), raw: true };
|
|
261
278
|
};
|
|
262
279
|
sql.spreadUpdate = spreadUpdate;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devmoods/express-extras",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.41.0",
|
|
4
4
|
"description": "Kubernetes-ready utilities for rapid Node.js application development",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -20,31 +20,31 @@
|
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@devmoods/eslint-config": "^1.15.0",
|
|
22
22
|
"@types/koa-compose": "^3.2.8",
|
|
23
|
-
"@types/node": "22.
|
|
23
|
+
"@types/node": "22.10.1",
|
|
24
24
|
"@types/supertest": "^6.0.2",
|
|
25
|
-
"@typescript-eslint/eslint-plugin": "^8.
|
|
26
|
-
"@typescript-eslint/parser": "^8.
|
|
27
|
-
"@vitest/coverage-v8": "^2.1.
|
|
25
|
+
"@typescript-eslint/eslint-plugin": "^8.16.0",
|
|
26
|
+
"@typescript-eslint/parser": "^8.16.0",
|
|
27
|
+
"@vitest/coverage-v8": "^2.1.6",
|
|
28
28
|
"cookiejar": "^2.1.4",
|
|
29
29
|
"eslint": "^8.57.0",
|
|
30
30
|
"eslint-plugin-import": "^2.31.0",
|
|
31
31
|
"eslint-plugin-prettier": "^5.2.1",
|
|
32
32
|
"faktory-worker": "^4.6.0",
|
|
33
|
-
"prettier": "3.
|
|
33
|
+
"prettier": "3.4.1",
|
|
34
34
|
"supertest": "7.0.0",
|
|
35
35
|
"ts-node": "10.9.2",
|
|
36
36
|
"tsx": "^4.19.2",
|
|
37
37
|
"typescript": "5.7.2",
|
|
38
|
-
"vitest": "^2.1.
|
|
38
|
+
"vitest": "^2.1.6",
|
|
39
39
|
"vitest-fail-on-console": "^0.7.1"
|
|
40
40
|
},
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"@devmoods/fetch": "^4.0.1",
|
|
43
|
-
"@sentry/node": "^8.
|
|
44
|
-
"@sentry/profiling-node": "^8.
|
|
43
|
+
"@sentry/node": "^8.41.0",
|
|
44
|
+
"@sentry/profiling-node": "^8.41.0",
|
|
45
45
|
"@types/bcrypt": "^5.0.2",
|
|
46
46
|
"@types/body-parser": "^1.19.5",
|
|
47
|
-
"@types/cookie-parser": "^1.4.
|
|
47
|
+
"@types/cookie-parser": "^1.4.8",
|
|
48
48
|
"@types/express": "^5.0.0",
|
|
49
49
|
"@types/jsonwebtoken": "^9.0.7",
|
|
50
50
|
"@types/nodemailer": "^6.4.17",
|
|
@@ -65,6 +65,7 @@
|
|
|
65
65
|
"nodemailer": "^6.9.16",
|
|
66
66
|
"pg": "^8.13.1",
|
|
67
67
|
"redis": "^4.7.0",
|
|
68
|
+
"sql-formatter": "^15.4.6",
|
|
68
69
|
"uuid": "^11.0.3"
|
|
69
70
|
},
|
|
70
71
|
"prettier": {
|