pogi 2.10.2 → 3.0.0-beta2
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/.vscode/launch.json +47 -15
- package/CHANGELOG.md +11 -0
- package/docs/API/PgDb.md +25 -0
- package/docs/notification.md +19 -0
- package/jest.config.js +23 -0
- package/lib/bin/generateInterface.js +3 -3
- package/lib/bin/generateInterface.js.map +1 -1
- package/lib/connectionOptions.d.ts +10 -0
- package/lib/index.d.ts +1 -1
- package/lib/pgConverters.d.ts +9 -8
- package/lib/pgConverters.js +46 -32
- package/lib/pgConverters.js.map +1 -1
- package/lib/pgConverters.test.d.ts +1 -0
- package/lib/pgConverters.test.js +13 -0
- package/lib/pgConverters.test.js.map +1 -0
- package/lib/pgDb.d.ts +27 -27
- package/lib/pgDb.js +293 -100
- package/lib/pgDb.js.map +1 -1
- package/lib/pgDb.test.d.ts +1 -0
- package/lib/pgDb.test.js +1126 -0
- package/lib/pgDb.test.js.map +1 -0
- package/lib/pgDbInterface.d.ts +53 -0
- package/lib/pgDbInterface.js +11 -0
- package/lib/pgDbInterface.js.map +1 -0
- package/lib/pgDbOperators.d.ts +3 -3
- package/lib/pgDbOperators.js +4 -7
- package/lib/pgDbOperators.js.map +1 -1
- package/lib/pgDbOperators.test.d.ts +1 -0
- package/lib/pgDbOperators.test.js +313 -0
- package/lib/pgDbOperators.test.js.map +1 -0
- package/lib/pgSchema.d.ts +10 -9
- package/lib/pgSchema.js.map +1 -1
- package/lib/pgSchemaInterface.d.ts +12 -0
- package/lib/pgSchemaInterface.js +3 -0
- package/lib/pgSchemaInterface.js.map +1 -0
- package/lib/pgTable.d.ts +15 -40
- package/lib/pgTable.js +54 -54
- package/lib/pgTable.js.map +1 -1
- package/lib/pgTableInterface.d.ts +102 -0
- package/lib/pgTableInterface.js +4 -0
- package/lib/pgTableInterface.js.map +1 -0
- package/lib/pgUtils.d.ts +16 -6
- package/lib/pgUtils.js +162 -31
- package/lib/pgUtils.js.map +1 -1
- package/lib/queryAble.d.ts +20 -53
- package/lib/queryAble.js +149 -80
- package/lib/queryAble.js.map +1 -1
- package/lib/queryAbleInterface.d.ts +55 -0
- package/lib/queryAbleInterface.js +7 -0
- package/lib/queryAbleInterface.js.map +1 -0
- package/lib/queryWhere.d.ts +2 -2
- package/lib/queryWhere.js +19 -23
- package/lib/queryWhere.js.map +1 -1
- package/mkdocs.yml +1 -0
- package/package.json +21 -11
- package/src/bin/generateInterface.ts +2 -2
- package/src/connectionOptions.ts +48 -13
- package/src/index.d.ts +7 -0
- package/src/index.ts +1 -1
- package/src/pgConverters.test.ts +10 -0
- package/src/pgConverters.ts +34 -22
- package/src/pgDb.test.ts +1324 -0
- package/src/pgDb.ts +318 -122
- package/src/pgDbInterface.ts +57 -0
- package/src/pgDbOperators.test.ts +478 -0
- package/src/pgDbOperators.ts +45 -22
- package/src/pgSchema.ts +10 -9
- package/src/pgSchemaInterface.ts +12 -0
- package/src/pgTable.ts +66 -98
- package/src/pgTableInterface.ts +131 -0
- package/src/pgUtils.ts +166 -42
- package/src/queryAble.ts +167 -125
- package/src/queryAbleInterface.ts +104 -0
- package/src/queryWhere.ts +42 -43
- package/{spec/resources → src/test}/init.sql +23 -0
- package/src/test/pgServiceRestartTest.ts +1500 -0
- package/{spec/resources → src/test}/throw_exception.sql +0 -0
- package/{spec/resources → src/test}/tricky.sql +0 -0
- package/{src/tsconfig.json → tsconfig.json} +12 -11
- package/spec/run.js +0 -5
- package/spec/support/jasmine.json +0 -9
- package/src/test/pgDbOperatorSpec.ts +0 -492
- package/src/test/pgDbSpec.ts +0 -994
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { IPgDb } from "./pgDbInterface";
|
|
2
|
+
import { IPgTable } from "./pgTableInterface";
|
|
3
|
+
import { IQueryAble } from "./queryAbleInterface";
|
|
4
|
+
|
|
5
|
+
export interface IPgSchema extends IQueryAble {
|
|
6
|
+
schemaName: string;
|
|
7
|
+
|
|
8
|
+
tables: { [name: string]: IPgTable<any> };
|
|
9
|
+
fn: { [name: string]: (...args: any[]) => any };
|
|
10
|
+
[name: string]: any | IPgTable<any>;
|
|
11
|
+
|
|
12
|
+
}
|
package/src/pgTable.ts
CHANGED
|
@@ -1,60 +1,28 @@
|
|
|
1
|
-
import {QueryAble, QueryOptions} from "./queryAble";
|
|
2
|
-
import {PgDb, FieldType} from "./pgDb";
|
|
3
|
-
import {PgDbLogger} from "./pgDbLogger"
|
|
4
|
-
import generateWhere from "./queryWhere";
|
|
5
|
-
import {PgSchema} from "./pgSchema";
|
|
6
|
-
import {pgUtils} from "./pgUtils";
|
|
7
1
|
import * as _ from 'lodash';
|
|
8
2
|
import * as stream from "stream";
|
|
3
|
+
import { FieldType } from "./pgDb";
|
|
4
|
+
import { IPgDb } from "./pgDbInterface";
|
|
5
|
+
import { PgSchema } from "./pgSchema";
|
|
6
|
+
import { CountOption, InsertOption, IPgTable, Return, Stream, TruncateOptions, UpdateDeleteOption, UpsertOption } from "./pgTableInterface";
|
|
7
|
+
import { pgUtils } from "./pgUtils";
|
|
8
|
+
import { QueryAble } from "./queryAble";
|
|
9
|
+
import { QueryOptions } from "./queryAbleInterface";
|
|
10
|
+
import generateWhere from "./queryWhere";
|
|
9
11
|
|
|
10
|
-
const util = require('util');
|
|
11
|
-
|
|
12
|
-
export interface InsertOption {
|
|
13
|
-
logger?: PgDbLogger;
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
export interface Return {
|
|
17
|
-
return?: string[] | '*';
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
export interface UpdateDeleteOption {
|
|
21
|
-
skipUndefined?: boolean;
|
|
22
|
-
logger?: PgDbLogger;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
export interface UpsertOption {
|
|
26
|
-
constraint?: string,
|
|
27
|
-
columns?: string[],
|
|
28
|
-
logger?: PgDbLogger;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface CountOption {
|
|
32
|
-
skipUndefined?: boolean;
|
|
33
|
-
logger?: PgDbLogger;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
export interface Stream {
|
|
37
|
-
stream: true;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
export interface TruncateOptions {
|
|
41
|
-
restartIdentity?: boolean,
|
|
42
|
-
cascade?: boolean,
|
|
43
|
-
logger?: PgDbLogger;
|
|
44
|
-
}
|
|
45
12
|
|
|
46
|
-
export class PgTable<T> extends QueryAble {
|
|
13
|
+
export class PgTable<T> extends QueryAble implements IPgTable<T> {
|
|
47
14
|
qualifiedName: string;
|
|
48
15
|
pkey: string;
|
|
49
|
-
db:
|
|
16
|
+
db: IPgDb;
|
|
50
17
|
fieldTypes: { [index: string]: FieldType }; //written directly
|
|
51
18
|
|
|
52
|
-
constructor(public schema: PgSchema, protected desc: { name: string, pkey?:string, schema: string }, fieldTypes = {}) {
|
|
19
|
+
constructor(public schema: PgSchema, protected desc: { name: string, pkey?: string, schema: string }, fieldTypes: Record<string, FieldType> = {}) {
|
|
53
20
|
super();
|
|
54
21
|
this.db = schema.db;
|
|
55
|
-
this.qualifiedName =
|
|
22
|
+
this.qualifiedName = `${pgUtils.quoteFieldName(desc.schema)}.${pgUtils.quoteFieldName(desc.name)}`;
|
|
56
23
|
this.pkey = desc.pkey || desc.name + "_pkey"; //poor man's pkey (could be queried by why?)
|
|
57
24
|
this.fieldTypes = fieldTypes;
|
|
25
|
+
return this
|
|
58
26
|
}
|
|
59
27
|
|
|
60
28
|
toString() {
|
|
@@ -89,9 +57,9 @@ export class PgTable<T> extends QueryAble {
|
|
|
89
57
|
return 0; // just return empty arrays so bulk inserting variable-length lists is more friendly
|
|
90
58
|
}
|
|
91
59
|
|
|
92
|
-
let {sql, parameters} = this.getInsertQuery(records);
|
|
60
|
+
let { sql, parameters } = this.getInsertQuery(records);
|
|
93
61
|
sql = "WITH __RESULT as ( " + sql + " RETURNING 1) SELECT SUM(1) FROM __RESULT";
|
|
94
|
-
let result = await this.query(sql, parameters, {logger: options.logger});
|
|
62
|
+
let result = await this.query(sql, parameters, { logger: options.logger });
|
|
95
63
|
return result[0].sum;
|
|
96
64
|
}
|
|
97
65
|
|
|
@@ -110,11 +78,11 @@ export class PgTable<T> extends QueryAble {
|
|
|
110
78
|
return []; // just return empty arrays so bulk inserting variable-length lists is more friendly
|
|
111
79
|
}
|
|
112
80
|
|
|
113
|
-
let {sql, parameters} = this.getInsertQuery(records);
|
|
81
|
+
let { sql, parameters } = this.getInsertQuery(records);
|
|
114
82
|
|
|
115
|
-
sql += " RETURNING " + (options && options.return && Array.isArray(options.return) ? options.return.map(pgUtils.
|
|
83
|
+
sql += " RETURNING " + (options && options.return && Array.isArray(options.return) ? options.return.map(pgUtils.quoteFieldName).join(',') : '*');
|
|
116
84
|
|
|
117
|
-
let result = await this.query(sql, parameters, {logger: options.logger});
|
|
85
|
+
let result = await this.query(sql, parameters, { logger: options.logger });
|
|
118
86
|
if (options.return && options.return.length == 0) {
|
|
119
87
|
return new Array(returnSingle ? 1 : records.length).fill({});
|
|
120
88
|
}
|
|
@@ -142,15 +110,15 @@ export class PgTable<T> extends QueryAble {
|
|
|
142
110
|
}
|
|
143
111
|
|
|
144
112
|
async update(conditions: { [k: string]: any }, fields: { [k: string]: any }, options?: UpdateDeleteOption): Promise<number> {
|
|
145
|
-
let {sql, parameters} = this.getUpdateQuery(conditions, fields, options);
|
|
113
|
+
let { sql, parameters } = this.getUpdateQuery(conditions, fields, options);
|
|
146
114
|
sql = "WITH __RESULT as ( " + sql + " RETURNING 1) SELECT SUM(1) FROM __RESULT";
|
|
147
115
|
let res = await this.query(sql, parameters, options);
|
|
148
116
|
return res[0].sum;
|
|
149
117
|
};
|
|
150
118
|
|
|
151
119
|
async updateAndGet(conditions: { [k: string]: any }, fields: { [k: string]: any }, options?: UpdateDeleteOption & Return): Promise<T[]> {
|
|
152
|
-
let {sql, parameters} = this.getUpdateQuery(conditions, fields, options);
|
|
153
|
-
sql += " RETURNING " + (options && options.return && Array.isArray(options.return) ? options.return.map(pgUtils.
|
|
120
|
+
let { sql, parameters } = this.getUpdateQuery(conditions, fields, options);
|
|
121
|
+
sql += " RETURNING " + (options && options.return && Array.isArray(options.return) ? options.return.map(pgUtils.quoteFieldName).join(',') : '*');
|
|
154
122
|
return this.query(sql, parameters, options);
|
|
155
123
|
};
|
|
156
124
|
|
|
@@ -163,9 +131,9 @@ export class PgTable<T> extends QueryAble {
|
|
|
163
131
|
throw new Error("insert should be called with data");
|
|
164
132
|
}
|
|
165
133
|
|
|
166
|
-
let {sql, parameters} = this.getUpsertQuery(record, options);
|
|
134
|
+
let { sql, parameters } = this.getUpsertQuery(record, options);
|
|
167
135
|
sql = "WITH __RESULT as ( " + sql + " RETURNING 1) SELECT SUM(1) FROM __RESULT";
|
|
168
|
-
let result = await this.query(sql, parameters, {logger: options.logger});
|
|
136
|
+
let result = await this.query(sql, parameters, { logger: options.logger });
|
|
169
137
|
return result[0].sum;
|
|
170
138
|
};
|
|
171
139
|
|
|
@@ -178,19 +146,19 @@ export class PgTable<T> extends QueryAble {
|
|
|
178
146
|
throw new Error("insert should be called with data");
|
|
179
147
|
}
|
|
180
148
|
|
|
181
|
-
let {sql, parameters} = this.getUpsertQuery(record, options);
|
|
182
|
-
sql += " RETURNING " + (options && options.return && Array.isArray(options.return) ? options.return.map(pgUtils.
|
|
149
|
+
let { sql, parameters } = this.getUpsertQuery(record, options);
|
|
150
|
+
sql += " RETURNING " + (options && options.return && Array.isArray(options.return) ? options.return.map(pgUtils.quoteFieldName).join(',') : '*');
|
|
183
151
|
|
|
184
|
-
let result = await this.query(sql, parameters, {logger: options.logger});
|
|
152
|
+
let result = await this.query(sql, parameters, { logger: options.logger });
|
|
185
153
|
|
|
186
154
|
if (options.return && options.return.length == 0) {
|
|
187
155
|
return <T>{};
|
|
188
156
|
}
|
|
189
157
|
return result[0];
|
|
190
|
-
};
|
|
158
|
+
};
|
|
191
159
|
|
|
192
160
|
async delete(conditions: { [k: string]: any }, options?: UpdateDeleteOption): Promise<number> {
|
|
193
|
-
let {sql, parameters} = this.getDeleteQuery(conditions, options);
|
|
161
|
+
let { sql, parameters } = this.getDeleteQuery(conditions, options);
|
|
194
162
|
sql = "WITH __RESULT as ( " + sql + " RETURNING 1) SELECT SUM(1) FROM __RESULT";
|
|
195
163
|
let res = await this.query(sql, parameters, options);
|
|
196
164
|
return res[0].sum;
|
|
@@ -206,8 +174,8 @@ export class PgTable<T> extends QueryAble {
|
|
|
206
174
|
|
|
207
175
|
async deleteAndGet(conditions: { [k: string]: any }, options?: UpdateDeleteOption & Return): Promise<any[]> {
|
|
208
176
|
options = options || {};
|
|
209
|
-
let {sql, parameters} = this.getDeleteQuery(conditions, options);
|
|
210
|
-
sql += " RETURNING " + (options && options.return && Array.isArray(options.return) ? options.return.map(pgUtils.
|
|
177
|
+
let { sql, parameters } = this.getDeleteQuery(conditions, options);
|
|
178
|
+
sql += " RETURNING " + (options && options.return && Array.isArray(options.return) ? options.return.map(pgUtils.quoteFieldName).join(',') : '*');
|
|
211
179
|
return this.query(sql, parameters);
|
|
212
180
|
}
|
|
213
181
|
|
|
@@ -234,19 +202,19 @@ export class PgTable<T> extends QueryAble {
|
|
|
234
202
|
if (options && options.cascade) {
|
|
235
203
|
sql += ' CASCADE';
|
|
236
204
|
}
|
|
237
|
-
await this.query(sql,
|
|
205
|
+
await this.query(sql, undefined, options);
|
|
238
206
|
}
|
|
239
207
|
|
|
240
208
|
async find(conditions: { [k: string]: any }, options?: QueryOptions): Promise<T[]>
|
|
241
209
|
async find(conditions: { [k: string]: any }, options?: QueryOptions & Stream): Promise<stream.Readable>
|
|
242
210
|
async find(conditions: { [k: string]: any }, options?: any): Promise<any> {
|
|
243
211
|
options = options || {};
|
|
244
|
-
options.skipUndefined = options.skipUndefined === true || (options.skipUndefined === undefined && ['all', 'select'].
|
|
212
|
+
options.skipUndefined = options.skipUndefined === true || (options.skipUndefined === undefined && this.db.config.skipUndefined && ['all', 'select'].includes(this.db.config.skipUndefined));
|
|
245
213
|
let where = _.isEmpty(conditions) ? {
|
|
246
|
-
where: "
|
|
247
|
-
params:
|
|
214
|
+
where: "",
|
|
215
|
+
params: undefined
|
|
248
216
|
} : generateWhere(conditions, this.fieldTypes, this.qualifiedName, 0, options.skipUndefined);
|
|
249
|
-
let sql = `SELECT ${pgUtils.processQueryFields(options)} FROM ${this.qualifiedName} ${where.where} ${pgUtils.processQueryOptions(options)}`;
|
|
217
|
+
let sql = `SELECT ${pgUtils.processQueryFields(options)} FROM ${this.qualifiedName} ${where.where} ${pgUtils.processQueryOptions<T>(options, this)}`;
|
|
250
218
|
return options.stream ? this.queryAsStream(sql, where.params, options) : this.query(sql, where.params, options);
|
|
251
219
|
}
|
|
252
220
|
|
|
@@ -255,7 +223,7 @@ export class PgTable<T> extends QueryAble {
|
|
|
255
223
|
async findWhere(where: string, params: any[] | {}, options?: QueryOptions & Stream): Promise<stream.Readable>
|
|
256
224
|
async findWhere(where: string, params: any, options?: any): Promise<any> {
|
|
257
225
|
options = options || {};
|
|
258
|
-
let sql = `SELECT ${pgUtils.processQueryFields(options)} FROM ${this.qualifiedName} WHERE ${where} ${pgUtils.processQueryOptions(options)}`;
|
|
226
|
+
let sql = `SELECT ${pgUtils.processQueryFields(options)} FROM ${this.qualifiedName} WHERE ${where} ${pgUtils.processQueryOptions<T>(options, this)}`;
|
|
259
227
|
return options.stream ? this.queryAsStream(sql, params, options) : this.query(sql, params, options);
|
|
260
228
|
}
|
|
261
229
|
|
|
@@ -263,22 +231,22 @@ export class PgTable<T> extends QueryAble {
|
|
|
263
231
|
public async findAll(options?: QueryOptions & Stream): Promise<stream.Readable>
|
|
264
232
|
public async findAll(options?: any): Promise<any> {
|
|
265
233
|
options = options || {};
|
|
266
|
-
let sql = `SELECT ${pgUtils.processQueryFields(options)} FROM ${this.qualifiedName} ${pgUtils.processQueryOptions(options)}`;
|
|
267
|
-
return options.stream ? this.queryAsStream(sql,
|
|
234
|
+
let sql = `SELECT ${pgUtils.processQueryFields(options)} FROM ${this.qualifiedName} ${pgUtils.processQueryOptions<T>(options, this)}`;
|
|
235
|
+
return options.stream ? this.queryAsStream(sql, undefined, options) : this.query(sql, null, options);
|
|
268
236
|
}
|
|
269
237
|
|
|
270
|
-
async findOne(conditions, options?: QueryOptions): Promise<T> {
|
|
238
|
+
async findOne(conditions: Record<string, any>, options?: QueryOptions): Promise<T> {
|
|
271
239
|
let res = await this.find(conditions, options);
|
|
272
240
|
if (res.length > 1) {
|
|
273
241
|
let logger = (options && options.logger || this.getLogger(false));
|
|
274
242
|
let error = new Error('More then one rows exists');
|
|
275
|
-
pgUtils.logError(logger, { error, sql:this.qualifiedName, params: conditions, connection: this.db.connection });
|
|
243
|
+
pgUtils.logError(logger, { error, sql: this.qualifiedName, params: conditions, connection: this.db.connection });
|
|
276
244
|
throw error;
|
|
277
245
|
}
|
|
278
246
|
return res[0];
|
|
279
247
|
}
|
|
280
248
|
|
|
281
|
-
async findFirst(conditions, options?: QueryOptions): Promise<T> {
|
|
249
|
+
async findFirst(conditions: Record<string, any>, options?: QueryOptions): Promise<T> {
|
|
282
250
|
options = options || {};
|
|
283
251
|
options.limit = 1;
|
|
284
252
|
let res = await this.find(conditions, options);
|
|
@@ -286,19 +254,19 @@ export class PgTable<T> extends QueryAble {
|
|
|
286
254
|
}
|
|
287
255
|
|
|
288
256
|
|
|
289
|
-
async count(conditions?:
|
|
257
|
+
async count(conditions?: Record<string, any>, options?: CountOption): Promise<number> {
|
|
290
258
|
options = options || {};
|
|
291
|
-
options.skipUndefined = options.skipUndefined === true || (options.skipUndefined === undefined && ['all', 'select'].
|
|
259
|
+
options.skipUndefined = options.skipUndefined === true || (options.skipUndefined === undefined && this.db.config.skipUndefined && ['all', 'select'].includes(this.db.config.skipUndefined));
|
|
292
260
|
|
|
293
261
|
let where = _.isEmpty(conditions) ? {
|
|
294
262
|
where: " ",
|
|
295
|
-
params:
|
|
296
|
-
} : generateWhere(conditions
|
|
263
|
+
params: undefined
|
|
264
|
+
} : generateWhere(conditions!, this.fieldTypes, this.qualifiedName, 0, options.skipUndefined);
|
|
297
265
|
let sql = `SELECT COUNT(*) c FROM ${this.qualifiedName} ${where.where}`;
|
|
298
266
|
return (await this.queryOneField(sql, where.params));
|
|
299
267
|
}
|
|
300
268
|
|
|
301
|
-
async findOneFieldOnly(conditions, field: string, options?: QueryOptions): Promise<any> {
|
|
269
|
+
async findOneFieldOnly(conditions: Record<string, any>, field: string, options?: QueryOptions): Promise<any> {
|
|
302
270
|
options = options || {};
|
|
303
271
|
options.fields = [field];
|
|
304
272
|
let res = await this.findOne(conditions, options);
|
|
@@ -314,33 +282,33 @@ export class PgTable<T> extends QueryAble {
|
|
|
314
282
|
}
|
|
315
283
|
});
|
|
316
284
|
let columns = Object.keys(columnsMap);
|
|
317
|
-
let sql =
|
|
318
|
-
let parameters = [];
|
|
285
|
+
let sql = `INSERT INTO ${this.qualifiedName} (${columns.map(pgUtils.quoteFieldName).join(", ")}) VALUES\n`;
|
|
286
|
+
let parameters: string[] = [];
|
|
319
287
|
let placeholders = [];
|
|
320
288
|
|
|
321
289
|
for (let i = 0, seed = 0; i < records.length; i++) {
|
|
322
290
|
placeholders.push('(' + columns.map(c => "$" + (++seed)).join(', ') + ')');
|
|
323
|
-
parameters.push
|
|
291
|
+
parameters.push(...columns.map(c => pgUtils.transformInsertUpdateParams(records[i][c], this.fieldTypes[c])));
|
|
324
292
|
}
|
|
325
293
|
sql += placeholders.join(",\n");
|
|
326
294
|
|
|
327
|
-
return {sql, parameters};
|
|
295
|
+
return { sql, parameters };
|
|
328
296
|
|
|
329
297
|
}
|
|
330
298
|
|
|
331
|
-
protected
|
|
299
|
+
protected getUpdateSetSnippet(fields: { [k: string]: any }, parameters?: any[]): { snippet: string, parameters: any[] } {
|
|
332
300
|
let params = parameters || [];
|
|
333
|
-
let f = [];
|
|
301
|
+
let f: string[] = [];
|
|
334
302
|
let seed = params.length;
|
|
335
303
|
|
|
336
304
|
_.each(fields, (value, fieldName) => {
|
|
337
305
|
if (value === undefined) return;
|
|
338
306
|
|
|
339
|
-
f.push(
|
|
307
|
+
f.push(`${pgUtils.quoteFieldName(fieldName)} = $${(++seed)}`);
|
|
340
308
|
params.push(pgUtils.transformInsertUpdateParams(value, this.fieldTypes[fieldName]));
|
|
341
309
|
});
|
|
342
310
|
|
|
343
|
-
return {
|
|
311
|
+
return { snippet: f.join(', '), parameters: params };
|
|
344
312
|
}
|
|
345
313
|
|
|
346
314
|
protected getUpdateQuery(conditions: { [k: string]: any }, fields: { [k: string]: any }, options?: UpdateDeleteOption): { sql: string, parameters: any[] } {
|
|
@@ -353,49 +321,49 @@ export class PgTable<T> extends QueryAble {
|
|
|
353
321
|
throw new Error('Missing fields for update');
|
|
354
322
|
}
|
|
355
323
|
|
|
356
|
-
let {
|
|
357
|
-
let sql =
|
|
324
|
+
let { snippet, parameters } = this.getUpdateSetSnippet(fields);
|
|
325
|
+
let sql = `UPDATE ${this.qualifiedName} SET ${snippet}`;
|
|
358
326
|
|
|
359
327
|
if (!hasConditions || !_.isEmpty(conditions)) {
|
|
360
328
|
let parsedWhere = generateWhere(conditions, this.fieldTypes, this.qualifiedName, parameters.length, options.skipUndefined);
|
|
361
329
|
sql += parsedWhere.where;
|
|
362
330
|
parameters = parameters.concat(parsedWhere.params);
|
|
363
331
|
}
|
|
364
|
-
return {sql, parameters};
|
|
332
|
+
return { sql, parameters };
|
|
365
333
|
}
|
|
366
334
|
|
|
367
335
|
protected getUpsertQuery(record: T, options?: UpsertOption): { sql: string, parameters: any[] } {
|
|
368
336
|
options = options || {};
|
|
369
|
-
|
|
337
|
+
|
|
370
338
|
if (_.isEmpty(record)) {
|
|
371
339
|
throw new Error('Missing fields for upsert');
|
|
372
340
|
}
|
|
373
341
|
|
|
374
342
|
let insert = this.getInsertQuery([record]);
|
|
375
|
-
let {
|
|
343
|
+
let { snippet, parameters } = this.getUpdateSetSnippet(record, insert.parameters);
|
|
376
344
|
let sql = insert.sql;
|
|
377
345
|
|
|
378
346
|
if (options.columns) {
|
|
379
|
-
sql +=
|
|
347
|
+
sql += ` ON CONFLICT (${options.columns.map(c => pgUtils.quoteFieldName(c)).join(', ')}) DO UPDATE SET ${snippet}`;
|
|
380
348
|
} else {
|
|
381
|
-
let constraint = options.constraint || this.pkey;
|
|
382
|
-
sql +=
|
|
349
|
+
let constraint = pgUtils.quoteFieldName(options.constraint || this.pkey);
|
|
350
|
+
sql += ` ON CONFLICT ON CONSTRAINT ${constraint} DO UPDATE SET ${snippet}`;
|
|
383
351
|
}
|
|
384
|
-
|
|
385
|
-
return {sql, parameters};
|
|
352
|
+
|
|
353
|
+
return { sql, parameters };
|
|
386
354
|
}
|
|
387
355
|
|
|
388
356
|
protected getDeleteQuery(conditions: { [k: string]: any }, options?: UpdateDeleteOption): { sql: string, parameters: any[] } {
|
|
389
357
|
options = options || {};
|
|
390
358
|
options.skipUndefined = options.skipUndefined === true || (options.skipUndefined === undefined && this.db.config.skipUndefined === 'all');
|
|
391
359
|
|
|
392
|
-
let sql =
|
|
360
|
+
let sql = `DELETE FROM ${this.qualifiedName} `;
|
|
393
361
|
|
|
394
362
|
let parsedWhere;
|
|
395
363
|
if (!_.isEmpty(conditions)) {
|
|
396
364
|
parsedWhere = generateWhere(conditions, this.fieldTypes, this.qualifiedName, 0, options.skipUndefined);
|
|
397
365
|
sql += parsedWhere.where;
|
|
398
366
|
}
|
|
399
|
-
return {sql, parameters: parsedWhere && parsedWhere.params || []}
|
|
367
|
+
return { sql, parameters: parsedWhere && parsedWhere.params || [] }
|
|
400
368
|
}
|
|
401
369
|
}
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { IQueryAble, QueryOptions } from "./queryAbleInterface";
|
|
2
|
+
import { PgDb, FieldType } from "./pgDb";
|
|
3
|
+
import { IPgDb } from "./pgDbInterface";
|
|
4
|
+
import { IPgSchema } from "./pgSchemaInterface";
|
|
5
|
+
import { PgDbLogger } from "./pgDbLogger"
|
|
6
|
+
import * as _ from 'lodash';
|
|
7
|
+
import * as stream from "stream";
|
|
8
|
+
|
|
9
|
+
const util = require('util');
|
|
10
|
+
|
|
11
|
+
export interface InsertOption {
|
|
12
|
+
logger?: PgDbLogger;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export interface Return {
|
|
16
|
+
return?: string[] | '*';
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export interface UpdateDeleteOption {
|
|
20
|
+
skipUndefined?: boolean;
|
|
21
|
+
logger?: PgDbLogger;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface UpsertOption {
|
|
25
|
+
constraint?: string,
|
|
26
|
+
columns?: string[],
|
|
27
|
+
logger?: PgDbLogger;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
export interface CountOption {
|
|
31
|
+
skipUndefined?: boolean;
|
|
32
|
+
logger?: PgDbLogger;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export interface Stream {
|
|
36
|
+
stream: true;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export interface TruncateOptions {
|
|
40
|
+
restartIdentity?: boolean,
|
|
41
|
+
cascade?: boolean,
|
|
42
|
+
logger?: PgDbLogger;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
export interface IPgTable<T> extends IQueryAble {
|
|
46
|
+
qualifiedName: string;
|
|
47
|
+
pkey: string;
|
|
48
|
+
db: IPgDb;
|
|
49
|
+
fieldTypes: { [index: string]: FieldType }; //written directly
|
|
50
|
+
|
|
51
|
+
toString: () => String
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* If you dont want to use the result set the options.return to false
|
|
55
|
+
* by default it is true. Also can set it to the fields that need to be returned,
|
|
56
|
+
* e.g.:
|
|
57
|
+
*
|
|
58
|
+
* let res = await table.insert([{username:'anonymous'},{username:'anonymous2'}], {return:['id']})
|
|
59
|
+
* res; // [{id:1},{id:2}]
|
|
60
|
+
*
|
|
61
|
+
* let res = await table.insert({username:'anonymous'}, {return:false})
|
|
62
|
+
* res; // void
|
|
63
|
+
*
|
|
64
|
+
* let res = await table.insert({username:'anonymous'})
|
|
65
|
+
* res; // {id:1, name:'anonymous', created:'...'}
|
|
66
|
+
*
|
|
67
|
+
*/
|
|
68
|
+
insert(records: T[], options?: InsertOption): Promise<number>
|
|
69
|
+
insert(records: T, options?: InsertOption): Promise<number>
|
|
70
|
+
insert(records: any, options?: any): Promise<any>
|
|
71
|
+
|
|
72
|
+
insertAndGet(records: T[], options?: InsertOption & Return): Promise<T[]>
|
|
73
|
+
insertAndGet(records: T, options?: InsertOption & Return): Promise<T>
|
|
74
|
+
insertAndGet(records: any, options?: InsertOption & Return): Promise<any>
|
|
75
|
+
|
|
76
|
+
updateOne(conditions: { [k: string]: any }, fields: { [k: string]: any }, options?: UpdateDeleteOption): Promise<number>
|
|
77
|
+
|
|
78
|
+
updateAndGetOne(conditions: { [k: string]: any }, fields: { [k: string]: any }, options?: UpdateDeleteOption & Return): Promise<T>
|
|
79
|
+
|
|
80
|
+
update(conditions: { [k: string]: any }, fields: { [k: string]: any }, options?: UpdateDeleteOption): Promise<number>
|
|
81
|
+
|
|
82
|
+
updateAndGet(conditions: { [k: string]: any }, fields: { [k: string]: any }, options?: UpdateDeleteOption & Return): Promise<T[]>
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* columnsOrConstraintName is by default the primary key
|
|
86
|
+
*/
|
|
87
|
+
upsert(record: T, options?: UpsertOption): Promise<number>
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* columnsOrConstraintName is by default the primary key
|
|
91
|
+
*/
|
|
92
|
+
upsertAndGet(record: T, options?: UpsertOption & Return): Promise<T>
|
|
93
|
+
|
|
94
|
+
delete(conditions: { [k: string]: any }, options?: UpdateDeleteOption): Promise<number>
|
|
95
|
+
|
|
96
|
+
deleteOne(conditions: { [k: string]: any }, options?: UpdateDeleteOption): Promise<number>
|
|
97
|
+
|
|
98
|
+
deleteAndGet(conditions: { [k: string]: any }, options?: UpdateDeleteOption & Return): Promise<any[]>
|
|
99
|
+
|
|
100
|
+
deleteAndGetOne(conditions: { [k: string]: any }, options?: UpdateDeleteOption & Return): Promise<any>
|
|
101
|
+
|
|
102
|
+
// async deleteAll(options?:UpdateDeleteOption):Promise<number> {
|
|
103
|
+
// let sql = util.format("DELETE FROM %s ", this.qualifiedName);
|
|
104
|
+
// sql = "WITH __RESULT as ( " + sql + " RETURNING 1) SELECT SUM(1) FROM __RESULT";
|
|
105
|
+
// let res = await this.query(sql, {logger:options.logger});
|
|
106
|
+
// return res[0].sum;
|
|
107
|
+
// }
|
|
108
|
+
|
|
109
|
+
truncate(options?: TruncateOptions): Promise<void>
|
|
110
|
+
|
|
111
|
+
find(conditions: { [k: string]: any }, options?: QueryOptions): Promise<T[]>
|
|
112
|
+
find(conditions: { [k: string]: any }, options?: QueryOptions & Stream): Promise<stream.Readable>
|
|
113
|
+
find(conditions: { [k: string]: any }, options?: any): Promise<any>
|
|
114
|
+
|
|
115
|
+
findWhere(where: string, params: any[] | {}, options?: QueryOptions): Promise<T[]>
|
|
116
|
+
findWhere(where: string, params: any[] | {}, options?: QueryOptions & Stream): Promise<stream.Readable>
|
|
117
|
+
findWhere(where: string, params: any, options?: any): Promise<any>
|
|
118
|
+
|
|
119
|
+
findAll(options?: QueryOptions): Promise<T[]>
|
|
120
|
+
findAll(options?: QueryOptions & Stream): Promise<stream.Readable>
|
|
121
|
+
findAll(options?: any): Promise<any>
|
|
122
|
+
|
|
123
|
+
findOne(conditions: Record<string, any>, options?: QueryOptions): Promise<T>
|
|
124
|
+
|
|
125
|
+
findFirst(conditions: Record<string, any>, options?: QueryOptions): Promise<T>
|
|
126
|
+
|
|
127
|
+
count(conditions?: {}, options?: CountOption): Promise<number>
|
|
128
|
+
|
|
129
|
+
findOneFieldOnly(conditions: Record<string, any>, field: string, options?: QueryOptions): Promise<any>
|
|
130
|
+
|
|
131
|
+
}
|