@art-ws/db-context 1.0.3-rc.4 → 2.0.1
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/{db-client → es/db-client}/db-client.d.ts +5 -4
- package/dist/es/db-client/db-client.js +1 -0
- package/dist/{db-client → es/db-client}/db-query-base.d.ts +3 -2
- package/dist/{db-client → es/db-client}/db-query-base.js +4 -9
- package/dist/{db-client → es/db-client}/index.d.ts +0 -1
- package/dist/es/db-client/index.js +3 -0
- package/dist/{db-context → es/db-context}/db-context.d.ts +6 -5
- package/dist/{db-context → es/db-context}/db-context.js +20 -11
- package/dist/es/db-context/db-model.d.ts +28 -0
- package/dist/es/db-context/db-model.js +235 -0
- package/dist/{db-context → es/db-context}/index.d.ts +0 -1
- package/dist/es/db-context/index.js +4 -0
- package/dist/{db-context → es/db-context}/types.d.ts +11 -4
- package/dist/es/db-context/types.js +1 -0
- package/dist/{index.d.ts → es/index.d.ts} +0 -1
- package/dist/es/index.js +5 -0
- package/dist/es/pg/index.d.ts +1 -0
- package/dist/es/pg/index.js +2 -0
- package/dist/{pg → es/pg}/pg-pool-base.d.ts +2 -2
- package/dist/{pg → es/pg}/pg-pool-base.js +27 -18
- package/dist/{pg-db-client → es/pg-db-client}/index.d.ts +0 -1
- package/dist/es/pg-db-client/index.js +3 -0
- package/dist/es/pg-db-client/pg-db-client.d.ts +13 -0
- package/dist/{pg-db-client → es/pg-db-client}/pg-db-client.js +15 -14
- package/dist/{pg-db-client → es/pg-db-client}/pg-db-query.d.ts +4 -3
- package/dist/{pg-db-client → es/pg-db-client}/pg-db-query.js +14 -8
- package/dist/es/pg-db-client/pg-type-parser.d.ts +10 -0
- package/dist/es/pg-db-client/pg-type-parser.js +57 -0
- package/package.json +25 -55
- package/dist/db-client/db-client.d.ts.map +0 -1
- package/dist/db-client/db-client.js +0 -3
- package/dist/db-client/db-client.js.map +0 -1
- package/dist/db-client/db-query-base.d.ts.map +0 -1
- package/dist/db-client/db-query-base.js.map +0 -1
- package/dist/db-client/index.d.ts.map +0 -1
- package/dist/db-client/index.js +0 -7
- package/dist/db-client/index.js.map +0 -1
- package/dist/db-context/db-context.d.ts.map +0 -1
- package/dist/db-context/db-context.js.map +0 -1
- package/dist/db-context/db-model.d.ts +0 -12
- package/dist/db-context/db-model.d.ts.map +0 -1
- package/dist/db-context/db-model.js +0 -56
- package/dist/db-context/db-model.js.map +0 -1
- package/dist/db-context/index.d.ts.map +0 -1
- package/dist/db-context/index.js +0 -8
- package/dist/db-context/index.js.map +0 -1
- package/dist/db-context/types.d.ts.map +0 -1
- package/dist/db-context/types.js +0 -3
- package/dist/db-context/types.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js +0 -9
- package/dist/index.js.map +0 -1
- package/dist/pg/index.d.ts +0 -2
- package/dist/pg/index.d.ts.map +0 -1
- package/dist/pg/index.js +0 -6
- package/dist/pg/index.js.map +0 -1
- package/dist/pg/pg-pool-base.d.ts.map +0 -1
- package/dist/pg/pg-pool-base.js.map +0 -1
- package/dist/pg/pg-pool.d.ts +0 -24
- package/dist/pg/pg-pool.d.ts.map +0 -1
- package/dist/pg/pg-pool.js +0 -53
- package/dist/pg/pg-pool.js.map +0 -1
- package/dist/pg/pg-result.d.ts +0 -11
- package/dist/pg/pg-result.d.ts.map +0 -1
- package/dist/pg/pg-result.js +0 -22
- package/dist/pg/pg-result.js.map +0 -1
- package/dist/pg-db-client/index.d.ts.map +0 -1
- package/dist/pg-db-client/index.js +0 -7
- package/dist/pg-db-client/index.js.map +0 -1
- package/dist/pg-db-client/pg-db-client-base.d.ts +0 -14
- package/dist/pg-db-client/pg-db-client-base.d.ts.map +0 -1
- package/dist/pg-db-client/pg-db-client-base.js +0 -43
- package/dist/pg-db-client/pg-db-client-base.js.map +0 -1
- package/dist/pg-db-client/pg-db-client.d.ts +0 -14
- package/dist/pg-db-client/pg-db-client.d.ts.map +0 -1
- package/dist/pg-db-client/pg-db-client.js.map +0 -1
- package/dist/pg-db-client/pg-db-query.d.ts.map +0 -1
- package/dist/pg-db-client/pg-db-query.js.map +0 -1
@@ -1,6 +1,7 @@
|
|
1
|
-
import { IDisposable } from "@art-ws/common";
|
2
|
-
export
|
1
|
+
import type { IDisposable } from "@art-ws/common";
|
2
|
+
export type DbClientFactory<C> = () => Promise<DbClient<C>>;
|
3
3
|
export interface DbQueryArgs<P = unknown> {
|
4
|
+
name?: string;
|
4
5
|
sql: string;
|
5
6
|
params?: P;
|
6
7
|
}
|
@@ -8,6 +9,7 @@ export interface DbQuery<T> extends PromiseLike<T[]> {
|
|
8
9
|
single(): Promise<T>;
|
9
10
|
first(): Promise<T>;
|
10
11
|
last(): Promise<T>;
|
12
|
+
exec(): Promise<number>;
|
11
13
|
asArray(): Promise<T[]>;
|
12
14
|
asIterable(): Promise<Iterable<T>>;
|
13
15
|
asAsyncIterable(): Promise<AsyncIterable<T>>;
|
@@ -19,5 +21,4 @@ export interface DbClient<C> extends IDisposable<void> {
|
|
19
21
|
export interface DbQueryConstructorArgs<C, P = unknown> extends DbQueryArgs<P> {
|
20
22
|
dbClientFactory: DbClientFactory<C>;
|
21
23
|
}
|
22
|
-
export
|
23
|
-
//# sourceMappingURL=db-client.d.ts.map
|
24
|
+
export type DbQueryFactory<C = unknown, T = DbQuery<unknown>> = (args: DbQueryConstructorArgs<C>) => T;
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
@@ -1,12 +1,13 @@
|
|
1
|
-
import { DbQuery } from "./db-client";
|
1
|
+
import type { DbQuery } from "./db-client";
|
2
2
|
export declare abstract class DbQueryBase<T> implements DbQuery<T> {
|
3
3
|
then<TResult1 = T[], TResult2 = never>(onfulfilled?: (value: T[]) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2>): PromiseLike<TResult1 | TResult2>;
|
4
|
+
abstract getName(): string;
|
4
5
|
single(): Promise<T>;
|
5
6
|
first(): Promise<T>;
|
6
7
|
last(): Promise<T>;
|
7
8
|
asIterable(): Promise<Iterable<T>>;
|
8
9
|
asAsyncIterable(): Promise<AsyncIterable<T>>;
|
9
10
|
abstract asArray(): Promise<T[]>;
|
11
|
+
abstract exec(): Promise<number>;
|
10
12
|
abstract cancel(reason?: string | Error): Promise<void>;
|
11
13
|
}
|
12
|
-
//# sourceMappingURL=db-query-base.d.ts.map
|
@@ -1,18 +1,15 @@
|
|
1
|
-
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
-
exports.DbQueryBase = void 0;
|
4
|
-
class DbQueryBase {
|
1
|
+
export class DbQueryBase {
|
5
2
|
then(onfulfilled, onrejected) {
|
6
3
|
return this.asArray().then((rows) => {
|
7
|
-
onfulfilled ? onfulfilled(rows) : undefined;
|
4
|
+
return onfulfilled ? onfulfilled(rows) : undefined;
|
8
5
|
}, (err) => {
|
9
|
-
onrejected ? onrejected(err) : undefined;
|
6
|
+
return onrejected ? onrejected(err) : undefined;
|
10
7
|
});
|
11
8
|
}
|
12
9
|
async single() {
|
13
10
|
const rows = await this.asArray();
|
14
11
|
if (rows.length !== 1)
|
15
|
-
throw new Error(`Expected a single query result`);
|
12
|
+
throw new Error(`Expected a single query result (${this.getName()})`);
|
16
13
|
return rows[0];
|
17
14
|
}
|
18
15
|
async first() {
|
@@ -30,5 +27,3 @@ class DbQueryBase {
|
|
30
27
|
throw new Error("Method not implemented.");
|
31
28
|
}
|
32
29
|
}
|
33
|
-
exports.DbQueryBase = DbQueryBase;
|
34
|
-
//# sourceMappingURL=db-query-base.js.map
|
@@ -1,9 +1,9 @@
|
|
1
|
-
import {
|
2
|
-
import {
|
3
|
-
import {
|
1
|
+
import type { IDisposable } from "@art-ws/common";
|
2
|
+
import type { DbClientFactory, DbQuery, DbQueryArgs, DbQueryFactory } from "../db-client";
|
3
|
+
import type { DbContext } from "./types";
|
4
4
|
export declare class DbContextBase<S> implements DbContext.Context, IDisposable<void> {
|
5
5
|
private dbQueryFactory;
|
6
|
-
private dbClient
|
6
|
+
private dbClient?;
|
7
7
|
readonly getDbClient: DbClientFactory<unknown>;
|
8
8
|
private factories;
|
9
9
|
private refs;
|
@@ -11,7 +11,8 @@ export declare class DbContextBase<S> implements DbContext.Context, IDisposable<
|
|
11
11
|
getDbModel<T>(name: string): T;
|
12
12
|
protected add(name: keyof S, fn: Function): void;
|
13
13
|
protected get<T>(name: keyof S): T;
|
14
|
+
query<T>(sql: string, params?: unknown[]): DbQuery<T>;
|
15
|
+
select<T>(sql: string, params?: unknown[]): DbQuery<T>;
|
14
16
|
getDbQuery<T>(args: DbQueryArgs<unknown>): DbQuery<T>;
|
15
17
|
dispose(): void;
|
16
18
|
}
|
17
|
-
//# sourceMappingURL=db-context.d.ts.map
|
@@ -1,13 +1,13 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
1
|
+
import { synchronized } from "@art-ws/common";
|
2
|
+
export class DbContextBase {
|
3
|
+
dbQueryFactory;
|
4
|
+
dbClient;
|
5
|
+
getDbClient;
|
6
|
+
factories = new Map();
|
7
|
+
refs = new Map();
|
6
8
|
constructor(dbClientFactory, dbQueryFactory) {
|
7
9
|
this.dbQueryFactory = dbQueryFactory;
|
8
|
-
this.
|
9
|
-
this.refs = new Map();
|
10
|
-
this.getDbClient = () => common_1.racePromise("getDbClient", async () => {
|
10
|
+
this.getDbClient = () => synchronized("getDbClient", async () => {
|
11
11
|
if (!this.dbClient) {
|
12
12
|
this.dbClient = await dbClientFactory();
|
13
13
|
}
|
@@ -23,10 +23,21 @@ class DbContextBase {
|
|
23
23
|
get(name) {
|
24
24
|
let ref = this.refs.get(name);
|
25
25
|
if (!ref) {
|
26
|
-
|
26
|
+
const factory = this.factories.get(name);
|
27
|
+
if (factory) {
|
28
|
+
ref = factory();
|
29
|
+
}
|
27
30
|
}
|
28
31
|
return ref;
|
29
32
|
}
|
33
|
+
query(sql, params) {
|
34
|
+
const name = sql.substring(0, 10);
|
35
|
+
return this.getDbQuery({ name, sql, params: params ?? [] });
|
36
|
+
}
|
37
|
+
select(sql, params) {
|
38
|
+
const name = sql.substring(0, 10);
|
39
|
+
return this.getDbQuery({ name, sql, params: params ?? [] });
|
40
|
+
}
|
30
41
|
getDbQuery(args) {
|
31
42
|
return this.dbQueryFactory({
|
32
43
|
dbClientFactory: () => this.getDbClient(),
|
@@ -39,5 +50,3 @@ class DbContextBase {
|
|
39
50
|
}
|
40
51
|
}
|
41
52
|
}
|
42
|
-
exports.DbContextBase = DbContextBase;
|
43
|
-
//# sourceMappingURL=db-context.js.map
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import type { DbContext } from "./types";
|
2
|
+
export type GenericOfDbModel<T> = T extends DbModel<infer X> ? X : never;
|
3
|
+
export declare class DbModel<T> implements DbContext.Model, DbContext.ModelApi<T> {
|
4
|
+
dbContext: DbContext.Context;
|
5
|
+
meta: DbContext.ModelInfo;
|
6
|
+
logger: import("@art-ws/slf").Logger;
|
7
|
+
primaryKeys: DbContext.Column[];
|
8
|
+
constructor(dbContext: DbContext.Context, meta: DbContext.ModelInfo);
|
9
|
+
getSeqDefaultName(): string;
|
10
|
+
nextDefaultSeqVal(): Promise<number>;
|
11
|
+
nextval(seq: string): Promise<number>;
|
12
|
+
findAll(options?: DbContext.SelectOptions<T>): DbContext.Query<T>;
|
13
|
+
findById(id: unknown): DbContext.Query<T>;
|
14
|
+
toSqlParams(sqlText: string, p?: object | unknown[]): {
|
15
|
+
sql: string;
|
16
|
+
params: unknown[];
|
17
|
+
};
|
18
|
+
where(sqlWhere: string, p?: object | unknown[]): DbContext.Query<T>;
|
19
|
+
select<D = T>(sqlText: string, p?: object | unknown[]): DbContext.Query<D>;
|
20
|
+
private withTableWhere;
|
21
|
+
findBy(values: Partial<T>, opts?: DbContext.SelectOptions<T>): DbContext.Query<T>;
|
22
|
+
insert(values: Partial<T>): DbContext.Query<T>;
|
23
|
+
upsert(values: Partial<T>, o: {
|
24
|
+
unique: (keyof T)[];
|
25
|
+
}): DbContext.Query<T>;
|
26
|
+
update(values: Partial<T>, where?: (keyof T)[] | Partial<T>): DbContext.Query<T>;
|
27
|
+
del(values: Partial<T>): DbContext.Query<T>;
|
28
|
+
}
|
@@ -0,0 +1,235 @@
|
|
1
|
+
import { getLogger } from "@art-ws/slf";
|
2
|
+
function toOrderBySQL(o) {
|
3
|
+
let s = "";
|
4
|
+
if (o?.orderBy) {
|
5
|
+
s = ` order by ${o?.orderBy}`;
|
6
|
+
}
|
7
|
+
return s;
|
8
|
+
}
|
9
|
+
function toPagingSQL(o, withDefaults) {
|
10
|
+
let s = "";
|
11
|
+
if (o === null)
|
12
|
+
return s;
|
13
|
+
if (!o) {
|
14
|
+
if (withDefaults) {
|
15
|
+
o = {
|
16
|
+
limit: -1,
|
17
|
+
offset: 0,
|
18
|
+
};
|
19
|
+
}
|
20
|
+
else {
|
21
|
+
return s;
|
22
|
+
}
|
23
|
+
}
|
24
|
+
if (o.limit && o.limit > -1)
|
25
|
+
s += ` limit ${o.limit}`;
|
26
|
+
if (o.offset && o.offset > 0)
|
27
|
+
s += ` offset ${o.offset}`;
|
28
|
+
return s;
|
29
|
+
}
|
30
|
+
export class DbModel {
|
31
|
+
dbContext;
|
32
|
+
meta;
|
33
|
+
logger = getLogger(DbModel);
|
34
|
+
primaryKeys = [];
|
35
|
+
constructor(dbContext, meta) {
|
36
|
+
this.dbContext = dbContext;
|
37
|
+
this.meta = meta;
|
38
|
+
this.primaryKeys = meta.columns.filter((col) => col.isPrimaryKey);
|
39
|
+
}
|
40
|
+
getSeqDefaultName() {
|
41
|
+
return `${this.meta.table}_seq`;
|
42
|
+
}
|
43
|
+
async nextDefaultSeqVal() {
|
44
|
+
return this.nextval(this.getSeqDefaultName());
|
45
|
+
}
|
46
|
+
async nextval(seq) {
|
47
|
+
const result = await this.dbContext
|
48
|
+
.getDbQuery({
|
49
|
+
name: `nextval(${seq}) on ${this.meta.table}`,
|
50
|
+
sql: `select nextval('${seq}') as id`,
|
51
|
+
params: [],
|
52
|
+
})
|
53
|
+
.single();
|
54
|
+
return result.id;
|
55
|
+
}
|
56
|
+
// https://stackoverflow.com/questions/3984643/equivalent-of-found-rows-function-in-postgresql/22353886#22353886
|
57
|
+
findAll(options) {
|
58
|
+
const sql = `SELECT * FROM ${this.meta.table} ${toOrderBySQL(options)} ${toPagingSQL(options, true)}`;
|
59
|
+
return this.dbContext.getDbQuery({
|
60
|
+
name: `findAll on ${this.meta.table}`,
|
61
|
+
sql,
|
62
|
+
params: [],
|
63
|
+
});
|
64
|
+
}
|
65
|
+
findById(id) {
|
66
|
+
if (this.primaryKeys?.length !== 1)
|
67
|
+
throw Error(`Table '${this.meta.table}' must have just a single primary key, instead of ${this.primaryKeys.length}`);
|
68
|
+
const pk = this.primaryKeys[0];
|
69
|
+
const sql = `SELECT * FROM ${this.meta.table} WHERE ${pk.name} = $1`;
|
70
|
+
return this.dbContext.getDbQuery({
|
71
|
+
name: `findById(${id}) on ${this.meta.table}`,
|
72
|
+
sql,
|
73
|
+
params: [id],
|
74
|
+
});
|
75
|
+
}
|
76
|
+
toSqlParams(sqlText, p) {
|
77
|
+
let params = [];
|
78
|
+
let sql = sqlText;
|
79
|
+
if (p) {
|
80
|
+
if (Array.isArray(p)) {
|
81
|
+
params = p;
|
82
|
+
}
|
83
|
+
else if (typeof p === "object") {
|
84
|
+
Object.keys(p).forEach((key, i) => {
|
85
|
+
sql = sql.replace(`{${key}}`, `$${i + 1}`);
|
86
|
+
params.push(p[key] ?? null);
|
87
|
+
});
|
88
|
+
}
|
89
|
+
else {
|
90
|
+
params = [p];
|
91
|
+
}
|
92
|
+
}
|
93
|
+
return {
|
94
|
+
sql,
|
95
|
+
params,
|
96
|
+
};
|
97
|
+
}
|
98
|
+
where(sqlWhere, p) {
|
99
|
+
const sql = `SELECT * FROM ${this.meta.table} WHERE ${sqlWhere}`;
|
100
|
+
return this.select(sql, p);
|
101
|
+
}
|
102
|
+
select(sqlText, p) {
|
103
|
+
const par = this.toSqlParams(sqlText, p);
|
104
|
+
return this.dbContext.getDbQuery({
|
105
|
+
name: `select(${sqlText.substring(10)}) on ${this.meta.table}`,
|
106
|
+
sql: par.sql,
|
107
|
+
params: par.params,
|
108
|
+
});
|
109
|
+
}
|
110
|
+
withTableWhere(expr, values, opts) {
|
111
|
+
const params = [];
|
112
|
+
const s = [];
|
113
|
+
let i = 0;
|
114
|
+
Object.keys(values).forEach((key) => {
|
115
|
+
const v = values[key] ?? null;
|
116
|
+
if (v === null) {
|
117
|
+
s.push(`( ${key} IS NULL )`);
|
118
|
+
}
|
119
|
+
else {
|
120
|
+
i++;
|
121
|
+
s.push(`( ${key} = $${i} )`);
|
122
|
+
params.push(v);
|
123
|
+
}
|
124
|
+
});
|
125
|
+
let where = `${s.join(" AND ")}`;
|
126
|
+
if (where) {
|
127
|
+
where = `WHERE ${where}`;
|
128
|
+
}
|
129
|
+
const sql = `${expr} FROM ${this.meta.table} ${where} ${toPagingSQL(opts, true)} ${toOrderBySQL(opts)}`;
|
130
|
+
return this.dbContext.getDbQuery({
|
131
|
+
name: `withTableWhere of ${this.meta.table}`,
|
132
|
+
sql,
|
133
|
+
params: params,
|
134
|
+
});
|
135
|
+
}
|
136
|
+
findBy(values, opts) {
|
137
|
+
return this.withTableWhere("SELECT *", values, opts);
|
138
|
+
}
|
139
|
+
insert(values) {
|
140
|
+
const params = [];
|
141
|
+
const cols = [];
|
142
|
+
const pValues = [];
|
143
|
+
Object.keys(values).forEach((key, i) => {
|
144
|
+
cols.push(key);
|
145
|
+
pValues.push(`$${i + 1}`);
|
146
|
+
params.push(values[key] ?? null);
|
147
|
+
});
|
148
|
+
const sql = `INSERT INTO ${this.meta.table} (${cols.join(",")}) VALUES (${pValues.join(",")}) RETURNING *`;
|
149
|
+
return this.dbContext.getDbQuery({
|
150
|
+
name: `insert into ${this.meta.table}`,
|
151
|
+
sql,
|
152
|
+
params: params,
|
153
|
+
});
|
154
|
+
}
|
155
|
+
// https://www.postgresqltutorial.com/postgresql-upsert/
|
156
|
+
// https://postgrespro.ru/docs/postgrespro/9.6/sql-insert
|
157
|
+
upsert(values, o) {
|
158
|
+
const { unique } = o;
|
159
|
+
const params = [];
|
160
|
+
const cols = [];
|
161
|
+
const pValues = [];
|
162
|
+
const indexes = {};
|
163
|
+
Object.keys(values).forEach((key, i) => {
|
164
|
+
cols.push(key);
|
165
|
+
const idx = i + 1;
|
166
|
+
indexes[key] = idx;
|
167
|
+
pValues.push("$" + idx);
|
168
|
+
params.push(values[key] ?? null);
|
169
|
+
});
|
170
|
+
const updated = cols.filter((x) => !unique.includes(x));
|
171
|
+
let doStatement = "NOTHING";
|
172
|
+
if (updated.length) {
|
173
|
+
const excluded = updated.map((x) => `${x} = EXCLUDED.${x}`);
|
174
|
+
doStatement = `UPDATE SET ${excluded.join(",")}`;
|
175
|
+
}
|
176
|
+
const sql = `INSERT INTO ${this.meta.table} (${cols.join(",")}) VALUES (${pValues.join(",")}) ON CONFLICT(${unique.join(",")}) DO ${doStatement} RETURNING *`;
|
177
|
+
return this.dbContext.getDbQuery({
|
178
|
+
name: `upsert into ${this.meta.table}`,
|
179
|
+
sql,
|
180
|
+
params: params,
|
181
|
+
});
|
182
|
+
}
|
183
|
+
update(values, where) {
|
184
|
+
let whereData = {};
|
185
|
+
const fillWhere = (whereColumns) => {
|
186
|
+
for (const col of whereColumns) {
|
187
|
+
;
|
188
|
+
whereData[col] = values[col] ?? null;
|
189
|
+
delete values[col];
|
190
|
+
}
|
191
|
+
};
|
192
|
+
if (where) {
|
193
|
+
if (Array.isArray(where)) {
|
194
|
+
fillWhere(where);
|
195
|
+
}
|
196
|
+
else {
|
197
|
+
whereData = { ...where };
|
198
|
+
}
|
199
|
+
}
|
200
|
+
else {
|
201
|
+
const whereColumns = this.primaryKeys.map((x) => x.name);
|
202
|
+
fillWhere(whereColumns);
|
203
|
+
}
|
204
|
+
const params = [];
|
205
|
+
let i = 0;
|
206
|
+
const setData = { ...values };
|
207
|
+
const setExpr = [];
|
208
|
+
Object.keys(setData).forEach((key) => {
|
209
|
+
i++;
|
210
|
+
setExpr.push(`${key} = $${i}`);
|
211
|
+
params.push(setData[key] ?? null);
|
212
|
+
});
|
213
|
+
const whereExpr = [];
|
214
|
+
Object.keys(whereData).forEach((key) => {
|
215
|
+
const v = whereData[key] ?? null;
|
216
|
+
if (v === null) {
|
217
|
+
whereExpr.push(`(${key} IS NULL)`);
|
218
|
+
}
|
219
|
+
else {
|
220
|
+
i++;
|
221
|
+
whereExpr.push(`(${key} = $${i})`);
|
222
|
+
params.push(v);
|
223
|
+
}
|
224
|
+
});
|
225
|
+
const sql = `UPDATE ${this.meta.table} SET ${setExpr.join(",")} WHERE ${whereExpr.join(" AND ")}`;
|
226
|
+
return this.dbContext.getDbQuery({
|
227
|
+
name: `update of ${this.meta.table}`,
|
228
|
+
sql,
|
229
|
+
params: params,
|
230
|
+
});
|
231
|
+
}
|
232
|
+
del(values) {
|
233
|
+
return this.withTableWhere("DELETE", values, undefined);
|
234
|
+
}
|
235
|
+
}
|
@@ -1,4 +1,4 @@
|
|
1
|
-
import { DbClientFactory, DbQuery, DbQueryArgs } from "../db-client/db-client";
|
1
|
+
import type { DbClientFactory, DbQuery, DbQueryArgs } from "../db-client/db-client";
|
2
2
|
export declare namespace DbContext {
|
3
3
|
interface Column {
|
4
4
|
name: string;
|
@@ -25,14 +25,22 @@ export declare namespace DbContext {
|
|
25
25
|
limit?: number;
|
26
26
|
offset?: number;
|
27
27
|
}
|
28
|
+
interface OrderByOptions<T = any> {
|
29
|
+
orderBy?: keyof T | `${string & keyof T} desc` | `${string & keyof T} asc`;
|
30
|
+
}
|
31
|
+
interface SelectOptions<T = any> extends Paging, OrderByOptions<T> {
|
32
|
+
}
|
28
33
|
interface Model {
|
29
34
|
dbContext: Context;
|
30
35
|
}
|
31
36
|
type Query<T> = DbQuery<T>;
|
32
37
|
interface ModelApi<T> {
|
33
|
-
findAll(
|
38
|
+
findAll(opts?: SelectOptions): Query<T>;
|
34
39
|
findById(id: unknown): Query<T>;
|
35
|
-
findBy(values: Partial<T
|
40
|
+
findBy(values: Partial<T>, opts?: SelectOptions): Query<T>;
|
41
|
+
insert(values: Partial<T>): Query<T>;
|
42
|
+
del(values: Partial<T>): DbContext.Query<T>;
|
43
|
+
update(values: Partial<T>, where?: (keyof T)[] | Partial<T>): DbContext.Query<T>;
|
36
44
|
}
|
37
45
|
interface Context {
|
38
46
|
getDbClient: DbClientFactory<unknown>;
|
@@ -40,4 +48,3 @@ export declare namespace DbContext {
|
|
40
48
|
getDbModel<T>(name: string): T;
|
41
49
|
}
|
42
50
|
}
|
43
|
-
//# sourceMappingURL=types.d.ts.map
|
@@ -0,0 +1 @@
|
|
1
|
+
export {};
|
package/dist/es/index.js
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
export * from "./pg-pool-base";
|
@@ -1,5 +1,6 @@
|
|
1
1
|
import { MemoryCacheBase } from "@art-ws/common";
|
2
|
-
import { Pool
|
2
|
+
import { Pool } from "pg";
|
3
|
+
import type { PoolClient } from "pg";
|
3
4
|
export interface PgConnectionOptions {
|
4
5
|
PGHOST: string;
|
5
6
|
PGDATABASE: string;
|
@@ -23,4 +24,3 @@ export declare class PgPool {
|
|
23
24
|
acquire(): Promise<PoolClient>;
|
24
25
|
end(): void;
|
25
26
|
}
|
26
|
-
//# sourceMappingURL=pg-pool-base.d.ts.map
|
@@ -1,11 +1,8 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
exports.PgPool = exports.PgPoolsBase = void 0;
|
4
|
-
const common_1 = require("@art-ws/common");
|
5
|
-
const slf_1 = require("@art-ws/slf");
|
1
|
+
import { MemoryCacheBase, racePromise } from "@art-ws/common";
|
2
|
+
import { getLogger } from "@art-ws/slf";
|
6
3
|
// https://node-postgres.com/
|
7
4
|
// https://node-postgres.com/api/cursor
|
8
|
-
|
5
|
+
import { Pool } from "pg";
|
9
6
|
const getPoolKey = (o) => `postgres://${o.PGHOST || "-"}:${o.PGPORT || "-"}/${o.PGDATABASE || "-"}`;
|
10
7
|
const toPoolConfig = (o) => {
|
11
8
|
return {
|
@@ -16,20 +13,23 @@ const toPoolConfig = (o) => {
|
|
16
13
|
host: o.PGHOST || "localhost",
|
17
14
|
};
|
18
15
|
};
|
19
|
-
class PgPoolsBase {
|
16
|
+
export class PgPoolsBase {
|
17
|
+
cache;
|
18
|
+
timeToIdle;
|
19
|
+
logger = getLogger(PgPoolsBase);
|
20
20
|
constructor(cache, timeToIdle) {
|
21
21
|
this.cache = cache;
|
22
22
|
this.timeToIdle = timeToIdle;
|
23
|
-
this.logger = slf_1.getLogger(PgPoolsBase);
|
24
23
|
}
|
25
24
|
async acquire(options) {
|
26
25
|
const key = getPoolKey(options);
|
27
26
|
this.logger.trace(() => [{ key }, "acquire"]);
|
28
|
-
const result = await
|
27
|
+
const result = await racePromise(key, async () => {
|
29
28
|
this.logger.trace(() => [{ key }, "acquire(racePromise)"]);
|
30
29
|
const pool = this.cache.getOrUpdate(key, () => new PgPool(key, options), {
|
31
30
|
timeToIdle: this.timeToIdle,
|
32
31
|
onRemove: (pool) => {
|
32
|
+
this.logger.trace(() => [{ key }, "end"]);
|
33
33
|
pool.end();
|
34
34
|
},
|
35
35
|
});
|
@@ -39,19 +39,30 @@ class PgPoolsBase {
|
|
39
39
|
return result;
|
40
40
|
}
|
41
41
|
}
|
42
|
-
exports.PgPoolsBase = PgPoolsBase;
|
43
42
|
// https://node-postgres.com/api/client
|
44
|
-
class PgPool {
|
43
|
+
export class PgPool {
|
44
|
+
key;
|
45
|
+
options;
|
46
|
+
logger = getLogger(PgPool);
|
47
|
+
pool;
|
45
48
|
constructor(key, options) {
|
46
49
|
this.key = key;
|
47
50
|
this.options = options;
|
48
|
-
this.
|
49
|
-
this.
|
51
|
+
this.pool = new Pool(toPoolConfig(options));
|
52
|
+
this.logger.trace(() => [{ key }, "Pool created."]);
|
50
53
|
}
|
51
54
|
async acquire() {
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
+
const { pool, logger } = this;
|
56
|
+
logger.debug(() => [
|
57
|
+
{
|
58
|
+
totalCount: pool.totalCount,
|
59
|
+
waitingCount: pool.waitingCount,
|
60
|
+
idleCount: pool.idleCount,
|
61
|
+
},
|
62
|
+
"Connecting...",
|
63
|
+
]);
|
64
|
+
const client = await pool.connect();
|
65
|
+
logger.debug(() => ["Connected"]);
|
55
66
|
return client;
|
56
67
|
}
|
57
68
|
end() {
|
@@ -61,5 +72,3 @@ class PgPool {
|
|
61
72
|
});
|
62
73
|
}
|
63
74
|
}
|
64
|
-
exports.PgPool = PgPool;
|
65
|
-
//# sourceMappingURL=pg-pool-base.js.map
|
@@ -0,0 +1,13 @@
|
|
1
|
+
import type { PoolClient, QueryArrayConfig, QueryConfig, QueryResult } from "pg";
|
2
|
+
import type { DbClient } from "../db-client";
|
3
|
+
export declare class PgDbClient implements DbClient<PoolClient> {
|
4
|
+
private pgClientFactory;
|
5
|
+
logger: import("@art-ws/slf").Logger;
|
6
|
+
constructor(pgClientFactory: () => Promise<PoolClient>);
|
7
|
+
private pgClient?;
|
8
|
+
dispose(): void;
|
9
|
+
private ensureClient;
|
10
|
+
queryInternal(queryConfig: QueryConfig | QueryArrayConfig): Promise<QueryResult<any>>;
|
11
|
+
getUnderlying(): Promise<PoolClient>;
|
12
|
+
cancel(_reason?: string | Error): Promise<void>;
|
13
|
+
}
|