af-db-ts 1.0.5 → 2.0.2
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/README.md +3 -3
- package/dist/cjs/__tests__/01_node_env.spec.js +7 -0
- package/dist/cjs/__tests__/01_node_env.spec.js.map +1 -0
- package/dist/cjs/__tests__/02_getValueForSqlMs.spec.js +50 -0
- package/dist/cjs/__tests__/02_getValueForSqlMs.spec.js.map +1 -0
- package/dist/cjs/__tests__/global-setup.js +7 -0
- package/dist/cjs/__tests__/global-setup.js.map +1 -0
- package/dist/cjs/__tests__/global-teardown.js +7 -0
- package/dist/cjs/__tests__/global-teardown.js.map +1 -0
- package/dist/cjs/{interfaces.js → src/@types/i-common.js} +1 -1
- package/dist/cjs/src/@types/i-common.js.map +1 -0
- package/dist/cjs/src/@types/i-config.js +3 -0
- package/dist/cjs/src/@types/i-config.js.map +1 -0
- package/dist/cjs/src/@types/i-ms.js +3 -0
- package/dist/cjs/src/@types/i-ms.js.map +1 -0
- package/dist/cjs/src/@types/i-pg.js +24 -0
- package/dist/cjs/src/@types/i-pg.js.map +1 -0
- package/dist/cjs/src/common.js +30 -0
- package/dist/cjs/src/common.js.map +1 -0
- package/dist/cjs/src/index.js +59 -0
- package/dist/cjs/src/index.js.map +1 -0
- package/dist/cjs/src/logger-error.js +10 -0
- package/dist/cjs/src/logger-error.js.map +1 -0
- package/dist/cjs/{get-value-for-sql.js → src/mssql/get-value-for-sql.js} +12 -8
- package/dist/cjs/src/mssql/get-value-for-sql.js.map +1 -0
- package/dist/cjs/{db.js → src/mssql/pool-ms.js} +73 -77
- package/dist/cjs/src/mssql/pool-ms.js.map +1 -0
- package/dist/cjs/src/mssql/query-ms.js +47 -0
- package/dist/cjs/src/mssql/query-ms.js.map +1 -0
- package/dist/cjs/{sql.js → src/mssql/sql.js} +72 -49
- package/dist/cjs/src/mssql/sql.js.map +1 -0
- package/dist/cjs/src/mssql/utils.js.map +1 -0
- package/dist/cjs/src/pg/get-merge-sql.js +50 -0
- package/dist/cjs/src/pg/get-merge-sql.js.map +1 -0
- package/dist/cjs/src/pg/get-update-sql.js +29 -0
- package/dist/cjs/src/pg/get-update-sql.js.map +1 -0
- package/dist/cjs/src/pg/insert.js +93 -0
- package/dist/cjs/src/pg/insert.js.map +1 -0
- package/dist/cjs/src/pg/is-table-or-view-exists.js +21 -0
- package/dist/cjs/src/pg/is-table-or-view-exists.js.map +1 -0
- package/dist/cjs/src/pg/pg-pool.js +52 -0
- package/dist/cjs/src/pg/pg-pool.js.map +1 -0
- package/dist/cjs/src/pg/prepare-value.js +84 -0
- package/dist/cjs/src/pg/prepare-value.js.map +1 -0
- package/dist/cjs/src/pg/query-pg.js +23 -0
- package/dist/cjs/src/pg/query-pg.js.map +1 -0
- package/dist/cjs/src/pg/table-schema.js +169 -0
- package/dist/cjs/src/pg/table-schema.js.map +1 -0
- package/dist/esm/src/@types/i-common.js +2 -0
- package/dist/esm/src/@types/i-common.js.map +1 -0
- package/dist/esm/src/@types/i-config.js +2 -0
- package/dist/esm/src/@types/i-config.js.map +1 -0
- package/dist/esm/src/@types/i-ms.js +2 -0
- package/dist/esm/src/@types/i-ms.js.map +1 -0
- package/dist/esm/src/@types/i-pg.js +21 -0
- package/dist/esm/src/@types/i-pg.js.map +1 -0
- package/dist/esm/src/common.js +25 -0
- package/dist/esm/src/common.js.map +1 -0
- package/dist/esm/src/index.js +15 -0
- package/dist/esm/src/index.js.map +1 -0
- package/dist/esm/src/logger-error.js +6 -0
- package/dist/esm/src/logger-error.js.map +1 -0
- package/dist/esm/{get-value-for-sql.js → src/mssql/get-value-for-sql.js} +11 -7
- package/dist/esm/src/mssql/get-value-for-sql.js.map +1 -0
- package/dist/esm/{db.js → src/mssql/pool-ms.js} +35 -62
- package/dist/esm/src/mssql/pool-ms.js.map +1 -0
- package/dist/esm/src/mssql/query-ms.js +20 -0
- package/dist/esm/src/mssql/query-ms.js.map +1 -0
- package/dist/esm/{sql.js → src/mssql/sql.js} +36 -36
- package/dist/esm/src/mssql/sql.js.map +1 -0
- package/dist/esm/src/mssql/utils.js.map +1 -0
- package/dist/esm/src/pg/get-merge-sql.js +46 -0
- package/dist/esm/src/pg/get-merge-sql.js.map +1 -0
- package/dist/esm/src/pg/get-update-sql.js +25 -0
- package/dist/esm/src/pg/get-update-sql.js.map +1 -0
- package/dist/esm/src/pg/insert.js +89 -0
- package/dist/esm/src/pg/insert.js.map +1 -0
- package/dist/esm/src/pg/is-table-or-view-exists.js +17 -0
- package/dist/esm/src/pg/is-table-or-view-exists.js.map +1 -0
- package/dist/esm/src/pg/pg-pool.js +43 -0
- package/dist/esm/src/pg/pg-pool.js.map +1 -0
- package/dist/esm/src/pg/prepare-value.js +79 -0
- package/dist/esm/src/pg/prepare-value.js.map +1 -0
- package/dist/esm/src/pg/query-pg.js +19 -0
- package/dist/esm/src/pg/query-pg.js.map +1 -0
- package/dist/esm/src/pg/table-schema.js +164 -0
- package/dist/esm/src/pg/table-schema.js.map +1 -0
- package/dist/types/src/@types/i-common.d.ts +35 -0
- package/dist/types/src/@types/i-common.d.ts.map +1 -0
- package/dist/types/src/@types/i-config.d.ts +60 -0
- package/dist/types/src/@types/i-config.d.ts.map +1 -0
- package/dist/types/{interfaces.d.ts → src/@types/i-ms.d.ts} +30 -77
- package/dist/types/src/@types/i-ms.d.ts.map +1 -0
- package/dist/types/src/@types/i-pg.d.ts +62 -0
- package/dist/types/src/@types/i-pg.d.ts.map +1 -0
- package/dist/types/src/common.d.ts +6 -0
- package/dist/types/src/common.d.ts.map +1 -0
- package/dist/types/src/index.d.ts +18 -0
- package/dist/types/src/index.d.ts.map +1 -0
- package/dist/types/src/logger-error.d.ts +7 -0
- package/dist/types/src/logger-error.d.ts.map +1 -0
- package/dist/types/src/mssql/get-value-for-sql.d.ts +11 -0
- package/dist/types/src/mssql/get-value-for-sql.d.ts.map +1 -0
- package/dist/types/{db.d.ts → src/mssql/pool-ms.d.ts} +18 -15
- package/dist/types/src/mssql/pool-ms.d.ts.map +1 -0
- package/dist/types/src/mssql/query-ms.d.ts +3 -0
- package/dist/types/src/mssql/query-ms.d.ts.map +1 -0
- package/dist/types/{sql.d.ts → src/mssql/sql.d.ts} +17 -16
- package/dist/types/src/mssql/sql.d.ts.map +1 -0
- package/dist/types/src/mssql/utils.d.ts.map +1 -0
- package/dist/types/src/pg/get-merge-sql.d.ts +9 -0
- package/dist/types/src/pg/get-merge-sql.d.ts.map +1 -0
- package/dist/types/src/pg/get-update-sql.d.ts +3 -0
- package/dist/types/src/pg/get-update-sql.d.ts.map +1 -0
- package/dist/types/src/pg/insert.d.ts +15 -0
- package/dist/types/src/pg/insert.d.ts.map +1 -0
- package/dist/types/src/pg/is-table-or-view-exists.d.ts +2 -0
- package/dist/types/src/pg/is-table-or-view-exists.d.ts.map +1 -0
- package/dist/types/src/pg/pg-pool.d.ts +6 -0
- package/dist/types/src/pg/pg-pool.d.ts.map +1 -0
- package/dist/types/src/pg/prepare-value.d.ts +7 -0
- package/dist/types/src/pg/prepare-value.d.ts.map +1 -0
- package/dist/types/src/pg/query-pg.d.ts +3 -0
- package/dist/types/src/pg/query-pg.d.ts.map +1 -0
- package/dist/types/src/pg/table-schema.d.ts +12 -0
- package/dist/types/src/pg/table-schema.d.ts.map +1 -0
- package/package.json +21 -24
- package/src/@types/i-common.ts +39 -0
- package/src/@types/i-config.ts +75 -0
- package/src/{interfaces.ts → @types/i-ms.ts} +29 -86
- package/src/@types/i-pg.ts +67 -0
- package/src/common.ts +26 -0
- package/src/index.ts +104 -42
- package/src/logger-error.ts +11 -0
- package/src/{get-value-for-sql.ts → mssql/get-value-for-sql.ts} +15 -9
- package/src/{db.ts → mssql/pool-ms.ts} +40 -71
- package/src/mssql/query-ms.ts +25 -0
- package/src/{sql.ts → mssql/sql.ts} +56 -59
- package/src/pg/get-merge-sql.ts +60 -0
- package/src/pg/get-update-sql.ts +31 -0
- package/src/pg/insert.ts +118 -0
- package/src/pg/is-table-or-view-exists.ts +21 -0
- package/src/pg/pg-pool.ts +49 -0
- package/src/pg/prepare-value.ts +90 -0
- package/src/pg/query-pg.ts +26 -0
- package/src/pg/table-schema.ts +178 -0
- package/dist/cjs/db.js.map +0 -1
- package/dist/cjs/get-value-for-sql.js.map +0 -1
- package/dist/cjs/index.js +0 -21
- package/dist/cjs/index.js.map +0 -1
- package/dist/cjs/interfaces.js.map +0 -1
- package/dist/cjs/sql.js.map +0 -1
- package/dist/cjs/utils.js.map +0 -1
- package/dist/esm/db.js.map +0 -1
- package/dist/esm/get-value-for-sql.js.map +0 -1
- package/dist/esm/index.js +0 -4
- package/dist/esm/index.js.map +0 -1
- package/dist/esm/interfaces.js +0 -2
- package/dist/esm/interfaces.js.map +0 -1
- package/dist/esm/sql.js.map +0 -1
- package/dist/esm/utils.js.map +0 -1
- package/dist/types/db.d.ts.map +0 -1
- package/dist/types/get-value-for-sql.d.ts +0 -7
- package/dist/types/get-value-for-sql.d.ts.map +0 -1
- package/dist/types/index.d.ts +0 -5
- package/dist/types/index.d.ts.map +0 -1
- package/dist/types/interfaces.d.ts.map +0 -1
- package/dist/types/sql.d.ts.map +0 -1
- package/dist/types/utils.d.ts.map +0 -1
- /package/dist/cjs/{utils.js → src/mssql/utils.js} +0 -0
- /package/dist/esm/{utils.js → src/mssql/utils.js} +0 -0
- /package/dist/types/{utils.d.ts → src/mssql/utils.d.ts} +0 -0
- /package/src/{utils.ts → mssql/utils.ts} +0 -0
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { DateTime } from 'luxon';
|
|
2
2
|
import { getBool, rn } from 'af-tools-ts';
|
|
3
|
-
import {
|
|
4
|
-
import { prepareSqlString, sql } from './sql';
|
|
3
|
+
import { prepareSqlStringMs, sql } from './sql';
|
|
5
4
|
import { mssqlEscape, q } from './utils';
|
|
5
|
+
import { IGetValueForSqlArgsMs, IPrepareSqlStringArgsMs } from '../@types/i-ms';
|
|
6
|
+
import { IDateTimeOptionsEx } from '../@types/i-common';
|
|
6
7
|
|
|
7
8
|
export const binToHexString = (value: any) => (value ? `0x${value.toString(16).toUpperCase()}` : null);
|
|
8
9
|
|
|
@@ -184,7 +185,7 @@ const array = (
|
|
|
184
185
|
/**
|
|
185
186
|
* Возвращает значение, готовое для использования в строке SQL запроса
|
|
186
187
|
*/
|
|
187
|
-
export const
|
|
188
|
+
export const getValueForSqlMs = (args: IGetValueForSqlArgsMs): string | number | null => {
|
|
188
189
|
let { value, fieldSchema, escapeOnlySingleQuotes } = args;
|
|
189
190
|
const { dateTimeOptions, needValidate } = args;
|
|
190
191
|
if (typeof fieldSchema === 'string') {
|
|
@@ -215,7 +216,7 @@ export const getValueForSQL = (args: IGetValueForSQLArgs): string | number | nul
|
|
|
215
216
|
min, max, value: value_, type, nullable, defaultValue, needValidate, fieldName,
|
|
216
217
|
});
|
|
217
218
|
|
|
218
|
-
const prepareSqlStringArgs:
|
|
219
|
+
const prepareSqlStringArgs: IPrepareSqlStringArgsMs = {
|
|
219
220
|
value, nullable, length, defaultValue, noQuotes, escapeOnlySingleQuotes,
|
|
220
221
|
};
|
|
221
222
|
switch (type) {
|
|
@@ -223,7 +224,7 @@ export const getValueForSQL = (args: IGetValueForSQLArgs): string | number | nul
|
|
|
223
224
|
if (Array.isArray(value) || typeof value === 'object') {
|
|
224
225
|
value = JSON.stringify(value);
|
|
225
226
|
}
|
|
226
|
-
return
|
|
227
|
+
return prepareSqlStringMs({ ...prepareSqlStringArgs, value });
|
|
227
228
|
|
|
228
229
|
case 'string':
|
|
229
230
|
case sql.Char:
|
|
@@ -233,7 +234,7 @@ export const getValueForSQL = (args: IGetValueForSQLArgs): string | number | nul
|
|
|
233
234
|
case sql.VarChar:
|
|
234
235
|
case sql.NVarChar:
|
|
235
236
|
case sql.Xml:
|
|
236
|
-
return
|
|
237
|
+
return prepareSqlStringMs(prepareSqlStringArgs);
|
|
237
238
|
|
|
238
239
|
case 'uid':
|
|
239
240
|
case 'uuid':
|
|
@@ -244,7 +245,7 @@ export const getValueForSQL = (args: IGetValueForSQLArgs): string | number | nul
|
|
|
244
245
|
} else {
|
|
245
246
|
value = value.substring(0, 36).toUpperCase();
|
|
246
247
|
}
|
|
247
|
-
return
|
|
248
|
+
return prepareSqlStringMs({ ...prepareSqlStringArgs, value, length: 0 });
|
|
248
249
|
|
|
249
250
|
case 'datetime':
|
|
250
251
|
case 'date':
|
|
@@ -307,13 +308,18 @@ export const getValueForSQL = (args: IGetValueForSQLArgs): string | number | nul
|
|
|
307
308
|
case sql.Geography:
|
|
308
309
|
case sql.Geometry:
|
|
309
310
|
case sql.Variant:
|
|
310
|
-
return
|
|
311
|
+
return prepareSqlStringMs(prepareSqlStringArgs);
|
|
311
312
|
case 'array': {
|
|
312
313
|
return array({
|
|
313
314
|
value, defaultValue, type, arrayType, fieldName, nullable, needValidate,
|
|
314
315
|
});
|
|
315
316
|
}
|
|
316
317
|
default:
|
|
317
|
-
return
|
|
318
|
+
return prepareSqlStringMs(prepareSqlStringArgs);
|
|
318
319
|
}
|
|
319
320
|
};
|
|
321
|
+
|
|
322
|
+
/**
|
|
323
|
+
* @deprecated since version 2.0.0
|
|
324
|
+
*/
|
|
325
|
+
export const getValueForSQL = getValueForSqlMs;
|
|
@@ -1,24 +1,25 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { magenta } from 'af-color';
|
|
1
|
+
import config from 'config';
|
|
3
2
|
import { echo } from 'af-echo-ts';
|
|
4
3
|
import * as sql from 'mssql';
|
|
5
|
-
import { ConnectionPool
|
|
6
|
-
import * as _ from 'lodash';
|
|
4
|
+
import { ConnectionPool } from 'mssql';
|
|
7
5
|
import { sleep } from 'af-tools-ts';
|
|
8
|
-
import {
|
|
6
|
+
import { IDbOptionsMs, IDbsMs } from '../@types/i-config';
|
|
7
|
+
import { logSqlError } from '../common';
|
|
8
|
+
import { IConnectionPoolsMs, TGetPoolConnectionOptionsMs } from '../@types/i-ms';
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
export const getDbConfig = (connectionId: string) => config.get<any>(`database.${connectionId}`);
|
|
10
|
+
const mssqlConfigs = config.get<{ options: IDbOptionsMs, dbs: IDbsMs }>('db.postgres');
|
|
12
11
|
|
|
13
|
-
export const
|
|
12
|
+
export const getDbConfigMs = (connectionId: string) => mssqlConfigs.dbs[connectionId];
|
|
13
|
+
|
|
14
|
+
export const poolsCacheMs: IConnectionPoolsMs = {};
|
|
14
15
|
|
|
15
16
|
/**
|
|
16
17
|
* Возвращает пул соединений для БД, соответствующей преданному ID соединения (borf|cep|hr|global)
|
|
17
18
|
* В случае, если не удается создать пул или открыть соединение, прерывает работу скрипта
|
|
18
19
|
*/
|
|
19
|
-
export const
|
|
20
|
+
export const getPoolConnectionMs = async (connectionId: string, options: TGetPoolConnectionOptionsMs = {}): Promise<ConnectionPool | undefined> => {
|
|
20
21
|
const { prefix = '', errorCode = 0 } = options;
|
|
21
|
-
let pool =
|
|
22
|
+
let pool = poolsCacheMs[connectionId];
|
|
22
23
|
if (pool?.connected) {
|
|
23
24
|
return pool;
|
|
24
25
|
}
|
|
@@ -52,11 +53,11 @@ export const getPoolConnection = async (connectionId: string, options: TGetPoolC
|
|
|
52
53
|
if (typeof pool !== 'object') {
|
|
53
54
|
resume(`Can't create connection pool "${connectionId}"`);
|
|
54
55
|
}
|
|
55
|
-
|
|
56
|
+
poolsCacheMs[connectionId] = pool;
|
|
56
57
|
// @ts-ignore
|
|
57
58
|
pool._connectionId = connectionId;
|
|
58
59
|
pool.on('close', () => {
|
|
59
|
-
delete
|
|
60
|
+
delete poolsCacheMs[connectionId];
|
|
60
61
|
});
|
|
61
62
|
pool.on('error', (err) => {
|
|
62
63
|
echo.error('POOL-ERROR', err);
|
|
@@ -76,7 +77,7 @@ export const getPoolConnection = async (connectionId: string, options: TGetPoolC
|
|
|
76
77
|
* prefix - Префикс в сообщении о закрытии пула (название синхронизации)
|
|
77
78
|
* noEcho - подавление сообщений о закрытии соединения
|
|
78
79
|
*/
|
|
79
|
-
export const
|
|
80
|
+
export const closeDbConnectionsMs = async (poolsToClose: ConnectionPool | ConnectionPool[] | string | string[], prefix?: string, noEcho?: boolean) => {
|
|
80
81
|
if (!Array.isArray(poolsToClose)) {
|
|
81
82
|
// @ts-ignore
|
|
82
83
|
poolsToClose = [poolsToClose];
|
|
@@ -88,13 +89,13 @@ export const closeDbConnections = async (poolsToClose: ConnectionPool | Connecti
|
|
|
88
89
|
if (pool) {
|
|
89
90
|
if (typeof pool === 'string') {
|
|
90
91
|
connectionId = pool;
|
|
91
|
-
pool =
|
|
92
|
+
pool = poolsCacheMs[connectionId];
|
|
92
93
|
} else if (typeof pool === 'object') {
|
|
93
94
|
// @ts-ignore
|
|
94
95
|
connectionId = pool._connectionId;
|
|
95
96
|
}
|
|
96
97
|
if (connectionId) {
|
|
97
|
-
delete
|
|
98
|
+
delete poolsCacheMs[connectionId];
|
|
98
99
|
}
|
|
99
100
|
if (pool && pool.close) {
|
|
100
101
|
try {
|
|
@@ -116,15 +117,31 @@ export const closeDbConnections = async (poolsToClose: ConnectionPool | Connecti
|
|
|
116
117
|
}
|
|
117
118
|
};
|
|
118
119
|
|
|
120
|
+
/**
|
|
121
|
+
* @deprecated since version 2.0.0
|
|
122
|
+
*/
|
|
123
|
+
export const closeAllDbConnections = async (prefix?: string, noEcho?: boolean) => {
|
|
124
|
+
const poolsToClose = Object.values(poolsCacheMs);
|
|
125
|
+
await closeDbConnectionsMs(poolsToClose, prefix, noEcho);
|
|
126
|
+
};
|
|
127
|
+
|
|
119
128
|
/**
|
|
120
129
|
* Закрывает все соединения с БД
|
|
121
130
|
*
|
|
122
131
|
* prefix - Префикс в сообщении о закрытии пула (название синхронизации)
|
|
123
132
|
* noEcho - подавление сообщений о закрытии соединения
|
|
124
133
|
*/
|
|
125
|
-
export const
|
|
126
|
-
const poolsToClose =
|
|
127
|
-
await
|
|
134
|
+
export const closeAllDbConnectionsMs = async (prefix?: string, noEcho?: boolean) => {
|
|
135
|
+
const poolsToClose = Object.values(poolsCacheMs);
|
|
136
|
+
await closeDbConnectionsMs(poolsToClose, prefix, noEcho);
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
/**
|
|
140
|
+
* @deprecated since version 2.0.0
|
|
141
|
+
*/
|
|
142
|
+
export const closeDbConnectionsAndExit = async (poolsToClose: ConnectionPool | ConnectionPool[], prefix?: string) => {
|
|
143
|
+
await closeDbConnectionsMs(poolsToClose, prefix);
|
|
144
|
+
process.exit(0);
|
|
128
145
|
};
|
|
129
146
|
|
|
130
147
|
/**
|
|
@@ -133,63 +150,15 @@ export const closeAllDbConnections = async (prefix?: string, noEcho?: boolean) =
|
|
|
133
150
|
* poolsToClose - пул или массив пулов
|
|
134
151
|
* prefix - Префикс в сообщении о закрытии пула (название синхронизации)
|
|
135
152
|
*/
|
|
136
|
-
export const
|
|
137
|
-
await
|
|
153
|
+
export const closeDbConnectionsAndExitMs = async (poolsToClose: ConnectionPool | ConnectionPool[], prefix?: string) => {
|
|
154
|
+
await closeDbConnectionsMs(poolsToClose, prefix);
|
|
138
155
|
process.exit(0);
|
|
139
156
|
};
|
|
140
157
|
|
|
141
|
-
export const
|
|
142
|
-
const pool = await getPoolConnection(connectionId, { onError: 'throw' });
|
|
143
|
-
const request = new sql.Request(pool);
|
|
144
|
-
if (strSQL) {
|
|
145
|
-
return request.query(strSQL);
|
|
146
|
-
}
|
|
147
|
-
return request;
|
|
148
|
-
};
|
|
149
|
-
|
|
150
|
-
interface IAsLogger {
|
|
151
|
-
error: Function,
|
|
152
|
-
}
|
|
153
|
-
|
|
154
|
-
let logger: IAsLogger = echo as IAsLogger;
|
|
155
|
-
|
|
156
|
-
export const setLogger = (logger_: any) => {
|
|
157
|
-
logger = logger_ as IAsLogger;
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
export const logSqlError = (err: Error | any, noThrow?: boolean, textSQL?: string, prefix?: string) => {
|
|
161
|
-
if (prefix) {
|
|
162
|
-
logger.error(prefix);
|
|
163
|
-
}
|
|
164
|
-
if (textSQL) {
|
|
165
|
-
logger.error(`SQL Error:\n${magenta}${textSQL}`);
|
|
166
|
-
}
|
|
167
|
-
logger.error(err);
|
|
168
|
-
if (!noThrow) {
|
|
169
|
-
throw err;
|
|
170
|
-
}
|
|
171
|
-
};
|
|
172
|
-
|
|
173
|
-
export const getPool = async (dbId: string, noThrow: boolean = false) => {
|
|
174
|
-
try {
|
|
175
|
-
return getPoolConnection(dbId);
|
|
176
|
-
} catch (err) {
|
|
177
|
-
logSqlError(err, noThrow, `Error while open connection to DB ${dbId}`);
|
|
178
|
-
}
|
|
179
|
-
};
|
|
180
|
-
|
|
181
|
-
export const query = async (dbId: string, textSQL: string, noThrow?: boolean, prefix?: string): Promise<IResult<any> | undefined> => {
|
|
182
|
-
const pool = await getPool(dbId, noThrow);
|
|
183
|
-
if (!pool?.connected && !pool?.connecting) {
|
|
184
|
-
await closeDbConnections(dbId);
|
|
185
|
-
return;
|
|
186
|
-
}
|
|
187
|
-
const request = new sql.Request(pool);
|
|
188
|
-
let res: IResult<any>;
|
|
158
|
+
export const getPoolMs = async (connectionId: string, throwError?: boolean) => {
|
|
189
159
|
try {
|
|
190
|
-
|
|
191
|
-
return res;
|
|
160
|
+
return getPoolConnectionMs(connectionId);
|
|
192
161
|
} catch (err) {
|
|
193
|
-
logSqlError(err,
|
|
162
|
+
logSqlError(err, throwError, `Error while open connection to DB ${connectionId}`);
|
|
194
163
|
}
|
|
195
164
|
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { IResult } from 'mssql';
|
|
2
|
+
import * as sql from 'mssql';
|
|
3
|
+
import { logSqlError } from '../common';
|
|
4
|
+
import { closeDbConnectionsMs, getPoolMs } from './pool-ms';
|
|
5
|
+
|
|
6
|
+
export const queryMs = async (
|
|
7
|
+
connectionId: string,
|
|
8
|
+
sqlText: string,
|
|
9
|
+
throwError?: boolean,
|
|
10
|
+
prefix?: string,
|
|
11
|
+
): Promise<IResult<any> | undefined> => {
|
|
12
|
+
const pool = await getPoolMs(connectionId, throwError);
|
|
13
|
+
if (!pool?.connected && !pool?.connecting) {
|
|
14
|
+
await closeDbConnectionsMs(connectionId);
|
|
15
|
+
return;
|
|
16
|
+
}
|
|
17
|
+
const request = new sql.Request(pool);
|
|
18
|
+
let res: IResult<any>;
|
|
19
|
+
try {
|
|
20
|
+
res = await request.query(sqlText);
|
|
21
|
+
return res;
|
|
22
|
+
} catch (err) {
|
|
23
|
+
logSqlError(err, !throwError, sqlText, prefix);
|
|
24
|
+
}
|
|
25
|
+
};
|
|
@@ -1,32 +1,29 @@
|
|
|
1
1
|
// noinspection SqlResolve
|
|
2
2
|
import * as sql from 'mssql';
|
|
3
3
|
import { IColumnMetadata, IResult } from 'mssql';
|
|
4
|
-
import * as _ from 'lodash';
|
|
5
4
|
import { echo } from 'af-echo-ts';
|
|
6
5
|
import * as cache from 'memory-cache';
|
|
7
|
-
import
|
|
6
|
+
import { each, omit, pick } from 'af-tools-ts';
|
|
7
|
+
import * as db from './pool-ms';
|
|
8
8
|
import { q, mssqlEscape } from './utils';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
TRecordSchema,
|
|
21
|
-
TRecordSchemaAssoc,
|
|
22
|
-
TRecordSet, ISchemaArray } from './interfaces';
|
|
9
|
+
import { getValueForSqlMs } from './get-value-for-sql';
|
|
10
|
+
import { IFieldSchemaMs, IGetMergeSQLOptionsMs,
|
|
11
|
+
IGetValueForSqlArgsMs,
|
|
12
|
+
IPrepareRecordForSqlArgsMs,
|
|
13
|
+
IPrepareSqlStringArgsMs, ISchemaArrayMs,
|
|
14
|
+
TFieldTypeCorrectionMs,
|
|
15
|
+
TGetRecordSchemaOptionsMs, TGetRecordSchemaResultMs,
|
|
16
|
+
TRecordSchemaAssocMs,
|
|
17
|
+
TRecordSchemaMs } from '../@types/i-ms';
|
|
18
|
+
import { TDBRecord, TFieldName, TRecordSet } from '../@types/i-common';
|
|
19
|
+
import { IDBConfigMs } from '../@types/i-config';
|
|
23
20
|
|
|
24
21
|
export { sql };
|
|
25
22
|
|
|
26
23
|
/**
|
|
27
24
|
* Подготовка строки для передачи в SQL
|
|
28
25
|
*/
|
|
29
|
-
export const
|
|
26
|
+
export const prepareSqlStringMs = (args: IPrepareSqlStringArgsMs): string | null => {
|
|
30
27
|
const { value, defaultValue = null, length = 0, nullable = false, noQuotes = false, escapeOnlySingleQuotes = false } = args;
|
|
31
28
|
if (value == null) {
|
|
32
29
|
if (nullable) {
|
|
@@ -58,12 +55,12 @@ const FIELD_SCHEMA_PROPS = ['index', 'name', 'length', 'type', 'scale', 'precisi
|
|
|
58
55
|
* Поля с суффиксом _json получают тип "json". Остальные корректировки берутся из fieldTypeCorrection
|
|
59
56
|
* Например, для полей типа datetime можно передавать свойство inputDateFormat
|
|
60
57
|
*/
|
|
61
|
-
export const
|
|
62
|
-
recordSchemaAssoc:
|
|
58
|
+
export const correctRecordSchemaMs = (
|
|
59
|
+
recordSchemaAssoc: TRecordSchemaAssocMs,
|
|
63
60
|
// объект корректировок
|
|
64
|
-
fieldTypeCorrection?:
|
|
61
|
+
fieldTypeCorrection?: TFieldTypeCorrectionMs,
|
|
65
62
|
) => {
|
|
66
|
-
|
|
63
|
+
each(recordSchemaAssoc, (fieldSchema: IFieldSchemaMs, fieldName: TFieldName) => {
|
|
67
64
|
if (/_json$/i.test(fieldName)) {
|
|
68
65
|
fieldSchema.type = 'json';
|
|
69
66
|
}
|
|
@@ -82,11 +79,11 @@ export const correctRecordSchema = (
|
|
|
82
79
|
}
|
|
83
80
|
});
|
|
84
81
|
if (fieldTypeCorrection && typeof fieldTypeCorrection === 'object') {
|
|
85
|
-
|
|
82
|
+
each(fieldTypeCorrection, (correction: IFieldSchemaMs, fieldName: TFieldName) => {
|
|
86
83
|
FIELD_SCHEMA_PROPS.forEach((prop) => {
|
|
87
84
|
if (correction[prop] !== undefined) {
|
|
88
85
|
if (!recordSchemaAssoc[fieldName]) {
|
|
89
|
-
recordSchemaAssoc[fieldName] = {} as
|
|
86
|
+
recordSchemaAssoc[fieldName] = {} as IFieldSchemaMs;
|
|
90
87
|
}
|
|
91
88
|
recordSchemaAssoc[fieldName][prop] = correction[prop];
|
|
92
89
|
}
|
|
@@ -98,12 +95,12 @@ export const correctRecordSchema = (
|
|
|
98
95
|
/**
|
|
99
96
|
* Подготовка значений записи для использования в SQL
|
|
100
97
|
*
|
|
101
|
-
* Все поля записи обрабатываются функцией
|
|
98
|
+
* Все поля записи обрабатываются функцией getValueForSqlMs
|
|
102
99
|
*/
|
|
103
|
-
export const
|
|
100
|
+
export const prepareRecordForSqlMs = (record: TDBRecord, args: IPrepareRecordForSqlArgsMs) => {
|
|
104
101
|
const { recordSchema, addValues4NotNullableFields, addMissingFields } = args;
|
|
105
102
|
const { dateTimeOptions, needValidate, escapeOnlySingleQuotes, dialect } = args;
|
|
106
|
-
const options:
|
|
103
|
+
const options: IGetValueForSqlArgsMs = {
|
|
107
104
|
value: null,
|
|
108
105
|
fieldSchema: '',
|
|
109
106
|
needValidate,
|
|
@@ -111,15 +108,15 @@ export const prepareRecordForSQL = (record: TDBRecord, args: IPrepareArgs) => {
|
|
|
111
108
|
dialect,
|
|
112
109
|
dateTimeOptions: { ...(recordSchema.dateTimeOptions || {}), ...(dateTimeOptions || {}) },
|
|
113
110
|
};
|
|
114
|
-
recordSchema.forEach((fieldSchema:
|
|
111
|
+
recordSchema.forEach((fieldSchema: IFieldSchemaMs) => {
|
|
115
112
|
const { name = '_#foo#_', readOnly } = fieldSchema;
|
|
116
113
|
if (readOnly) {
|
|
117
114
|
return;
|
|
118
115
|
}
|
|
119
116
|
if (Object.prototype.hasOwnProperty.call(record, name)) {
|
|
120
|
-
record[name] =
|
|
117
|
+
record[name] = getValueForSqlMs({ ...options, value: record[name], fieldSchema });
|
|
121
118
|
} else if ((!fieldSchema.nullable && addValues4NotNullableFields) || addMissingFields) {
|
|
122
|
-
record[name] =
|
|
119
|
+
record[name] = getValueForSqlMs({ ...options, value: null, fieldSchema });
|
|
123
120
|
}
|
|
124
121
|
});
|
|
125
122
|
};
|
|
@@ -127,14 +124,14 @@ export const prepareRecordForSQL = (record: TDBRecord, args: IPrepareArgs) => {
|
|
|
127
124
|
/**
|
|
128
125
|
* Подготовка данных для SQL
|
|
129
126
|
*
|
|
130
|
-
* Все поля всех записей обрабатываются функцией
|
|
127
|
+
* Все поля всех записей обрабатываются функцией getValueForSqlMs
|
|
131
128
|
*/
|
|
132
|
-
export const
|
|
129
|
+
export const prepareDataForSqlMs = (recordSet: TRecordSet, args: IPrepareRecordForSqlArgsMs) => {
|
|
133
130
|
if (recordSet._isPreparedForSQL) {
|
|
134
131
|
return;
|
|
135
132
|
}
|
|
136
133
|
recordSet.forEach((record) => {
|
|
137
|
-
|
|
134
|
+
prepareRecordForSqlMs(record, args);
|
|
138
135
|
});
|
|
139
136
|
recordSet._isPreparedForSQL = true;
|
|
140
137
|
};
|
|
@@ -143,7 +140,7 @@ export const prepareDataForSQL = (recordSet: TRecordSet, args: IPrepareArgs) =>
|
|
|
143
140
|
* Возвращает рекорд, в котором все значения преобразованы в строки и подготовлены для прямой вставки в SQL
|
|
144
141
|
* В частности, если значение типа строка, то оно уже заключено в одинарные кавычки
|
|
145
142
|
*/
|
|
146
|
-
export const
|
|
143
|
+
export const getRecordValuesForSqlMs = (record: TDBRecord, recordSchema: TRecordSchemaMs): TDBRecord => {
|
|
147
144
|
const recordValuesForSQL = {};
|
|
148
145
|
recordSchema.forEach((fieldSchema) => {
|
|
149
146
|
const { name = '_#foo#_', readOnly } = fieldSchema;
|
|
@@ -151,7 +148,7 @@ export const getRecordValuesForSQL = (record: TDBRecord, recordSchema: TRecordSc
|
|
|
151
148
|
return;
|
|
152
149
|
}
|
|
153
150
|
if (Object.prototype.hasOwnProperty.call(record, name)) {
|
|
154
|
-
recordValuesForSQL[name] =
|
|
151
|
+
recordValuesForSQL[name] = getValueForSqlMs({
|
|
155
152
|
value: record[name],
|
|
156
153
|
fieldSchema,
|
|
157
154
|
escapeOnlySingleQuotes: true,
|
|
@@ -165,20 +162,20 @@ export const getRecordValuesForSQL = (record: TDBRecord, recordSchema: TRecordSc
|
|
|
165
162
|
|
|
166
163
|
/**
|
|
167
164
|
* Возвращает схему полей таблицы БД. Либо в виде объекта, либо в виде массива
|
|
168
|
-
* Если asArray = true, то вернет
|
|
169
|
-
* Иначе вернет
|
|
165
|
+
* Если asArray = true, то вернет TRecordSchemaMs, при этом удалит поля, указанные в omitFields
|
|
166
|
+
* Иначе вернет TRecordSchemaAssocMs
|
|
170
167
|
*/
|
|
171
|
-
export const
|
|
168
|
+
export const getRecordSchemaMs = async (
|
|
172
169
|
// ID соединения (borf|cep|hr|global)
|
|
173
170
|
connectionId: string,
|
|
174
171
|
// Субъект в выражении FROM для таблицы, схему которой нужно вернуть
|
|
175
172
|
schemaAndTable: string,
|
|
176
173
|
// Массив имен полей, которые нужно удалить из схемы (не учитывается, если asArray = false)
|
|
177
|
-
options:
|
|
178
|
-
): Promise<
|
|
174
|
+
options: TGetRecordSchemaOptionsMs = {} as TGetRecordSchemaOptionsMs,
|
|
175
|
+
): Promise<TGetRecordSchemaResultMs | undefined> => {
|
|
179
176
|
const propertyPath = `schemas.${connectionId}.${schemaAndTable}`;
|
|
180
177
|
|
|
181
|
-
let result:
|
|
178
|
+
let result: TGetRecordSchemaResultMs | undefined = cache.get(propertyPath) as TGetRecordSchemaResultMs | undefined;
|
|
182
179
|
if (result) {
|
|
183
180
|
return result;
|
|
184
181
|
}
|
|
@@ -196,7 +193,7 @@ export const getRecordSchema = async (
|
|
|
196
193
|
noReturnMergeResult,
|
|
197
194
|
dateTimeOptions,
|
|
198
195
|
} = options;
|
|
199
|
-
const cPool = await db.
|
|
196
|
+
const cPool = await db.getPoolConnectionMs(connectionId, { prefix: 'getRecordSchemaMs' });
|
|
200
197
|
const request = new sql.Request(cPool);
|
|
201
198
|
request.stream = false;
|
|
202
199
|
let res: IResult<any>;
|
|
@@ -204,24 +201,24 @@ export const getRecordSchema = async (
|
|
|
204
201
|
res = await request.query(`SELECT TOP(1) *
|
|
205
202
|
FROM ${schemaAndTable}`);
|
|
206
203
|
} catch (err) {
|
|
207
|
-
echo.error(`
|
|
204
|
+
echo.error(`getRecordSchemaMs SQL ERROR`);
|
|
208
205
|
echo.error(err);
|
|
209
206
|
throw err;
|
|
210
207
|
}
|
|
211
208
|
const { columns } = res.recordset;
|
|
212
209
|
const readOnlyFields = Object.entries(columns).filter(([, { readOnly: ro }]) => ro).map(([f]) => f);
|
|
213
210
|
const omitFields2 = [...readOnlyFields, ...(Array.isArray(omitFields) ? omitFields : [])];
|
|
214
|
-
let schemaAssoc: Partial<IColumnMetadata> =
|
|
215
|
-
schemaAssoc = Array.isArray(pickFields) ?
|
|
216
|
-
|
|
217
|
-
const schema:
|
|
211
|
+
let schemaAssoc: Partial<IColumnMetadata> = omit(columns, omitFields2);
|
|
212
|
+
schemaAssoc = Array.isArray(pickFields) ? pick(schemaAssoc, pickFields) : schemaAssoc;
|
|
213
|
+
correctRecordSchemaMs(schemaAssoc as TRecordSchemaAssocMs, fieldTypeCorrection);
|
|
214
|
+
const schema: ISchemaArrayMs = Object.values(schemaAssoc)
|
|
218
215
|
.sort((a, b) => {
|
|
219
216
|
const ai = (a?.index || 0);
|
|
220
217
|
const bi = (b?.index || 0);
|
|
221
218
|
if (ai > bi) return 1;
|
|
222
219
|
if (ai < bi) return -1;
|
|
223
220
|
return 0;
|
|
224
|
-
}) as
|
|
221
|
+
}) as ISchemaArrayMs;
|
|
225
222
|
schema.dateTimeOptions = dateTimeOptions;
|
|
226
223
|
|
|
227
224
|
const fields = schema.map((o) => o?.name).filter(Boolean) as string[];
|
|
@@ -242,7 +239,7 @@ export const getRecordSchema = async (
|
|
|
242
239
|
} else {
|
|
243
240
|
updateFieldsList = updateFields.map((fName) => (`target.[${fName}] = source.[${fName}]`)).join(', ');
|
|
244
241
|
}
|
|
245
|
-
const dbConfig:
|
|
242
|
+
const dbConfig: IDBConfigMs = db.getDbConfigMs(connectionId);
|
|
246
243
|
const dbSchemaAndTable = `[${dbConfig.database}].${schemaAndTable}`;
|
|
247
244
|
|
|
248
245
|
result = {
|
|
@@ -259,9 +256,9 @@ export const getRecordSchema = async (
|
|
|
259
256
|
withClause,
|
|
260
257
|
updateFields,
|
|
261
258
|
mergeIdentity,
|
|
262
|
-
getMergeSQL (packet: TRecordSet, prepareOptions:
|
|
259
|
+
getMergeSQL (packet: TRecordSet, prepareOptions: IGetMergeSQLOptionsMs = {}): string {
|
|
263
260
|
if (prepareOptions.isPrepareForSQL) {
|
|
264
|
-
|
|
261
|
+
prepareDataForSqlMs(packet, { recordSchema: this.schema, ...prepareOptions });
|
|
265
262
|
}
|
|
266
263
|
const values = `(${packet.map((r) => (fields.map((fName) => (r[fName]))
|
|
267
264
|
.join(',')))
|
|
@@ -320,7 +317,7 @@ SELECT @total as total, @i as inserted, @u as updated;
|
|
|
320
317
|
},
|
|
321
318
|
|
|
322
319
|
getUpdateSQL (record: TRecordSet) {
|
|
323
|
-
const recordForSQL =
|
|
320
|
+
const recordForSQL = getRecordValuesForSqlMs(record, this.schema);
|
|
324
321
|
const setArray: string[] = [];
|
|
325
322
|
updateFields.forEach((fName) => {
|
|
326
323
|
if (recordForSQL[fName] !== undefined) {
|
|
@@ -342,7 +339,7 @@ SELECT @total as total, @i as inserted, @u as updated;
|
|
|
342
339
|
/**
|
|
343
340
|
* Оборачивает инструкции SQL в транзакцию
|
|
344
341
|
*/
|
|
345
|
-
export const
|
|
342
|
+
export const wrapTransactionMs = (strSQL: string): string => `BEGIN TRY
|
|
346
343
|
BEGIN TRANSACTION;
|
|
347
344
|
|
|
348
345
|
${strSQL}
|
|
@@ -370,8 +367,8 @@ END CATCH;`;
|
|
|
370
367
|
/**
|
|
371
368
|
* Возвращает проверенное и серилизованное значение
|
|
372
369
|
*/
|
|
373
|
-
export const
|
|
374
|
-
const val =
|
|
370
|
+
export const serializeMs = (args: IGetValueForSqlArgsMs): string | number | null => {
|
|
371
|
+
const val = getValueForSqlMs(args);
|
|
375
372
|
if (val == null || val === 'NULL') {
|
|
376
373
|
return null;
|
|
377
374
|
}
|
|
@@ -384,13 +381,13 @@ export const serialize = (args: IGetValueForSQLArgs): string | number | null =>
|
|
|
384
381
|
/**
|
|
385
382
|
* Возвращает подготовленное выражение SET для использования в UPDATE
|
|
386
383
|
*/
|
|
387
|
-
export const
|
|
384
|
+
export const getSqlSetExpressionMs = (record: TDBRecord, recordSchema: TRecordSchemaMs): string => {
|
|
388
385
|
const setArray: string[] = [];
|
|
389
386
|
const { dateTimeOptions } = recordSchema;
|
|
390
387
|
recordSchema.forEach((fieldSchema) => {
|
|
391
388
|
const { name = '_#foo#_' } = fieldSchema;
|
|
392
389
|
if (Object.prototype.hasOwnProperty.call(record, name)) {
|
|
393
|
-
setArray.push(`[${name}] = ${
|
|
390
|
+
setArray.push(`[${name}] = ${getValueForSqlMs({
|
|
394
391
|
value: record[name],
|
|
395
392
|
fieldSchema,
|
|
396
393
|
dateTimeOptions,
|
|
@@ -406,7 +403,7 @@ export const getSqlSetExpression = (record: TDBRecord, recordSchema: TRecordSche
|
|
|
406
403
|
*
|
|
407
404
|
* addOutputInserted - Если true, добавляется выражение OUTPUT inserted.* перед VALUES
|
|
408
405
|
*/
|
|
409
|
-
export const
|
|
406
|
+
export const getSqlValuesExpressionMs = (record: TDBRecord, recordSchema: TRecordSchemaMs, addOutputInserted: boolean = false): string => {
|
|
410
407
|
const fieldsArray: string[] = [];
|
|
411
408
|
const valuesArray: string[] = [];
|
|
412
409
|
const { dateTimeOptions } = recordSchema;
|
|
@@ -414,7 +411,7 @@ export const getSqlValuesExpression = (record: TDBRecord, recordSchema: TRecordS
|
|
|
414
411
|
const { name = '_#foo#_' } = fieldSchema;
|
|
415
412
|
if (Object.prototype.hasOwnProperty.call(record, name)) {
|
|
416
413
|
fieldsArray.push(name);
|
|
417
|
-
const val =
|
|
414
|
+
const val = getValueForSqlMs({
|
|
418
415
|
value: record[name],
|
|
419
416
|
fieldSchema,
|
|
420
417
|
dateTimeOptions,
|
|
@@ -426,4 +423,4 @@ export const getSqlValuesExpression = (record: TDBRecord, recordSchema: TRecordS
|
|
|
426
423
|
return `([${fieldsArray.join('], [')}]) ${addOutputInserted ? ' OUTPUT inserted.* ' : ''} VALUES (${valuesArray.join(', ')})`;
|
|
427
424
|
};
|
|
428
425
|
|
|
429
|
-
export const
|
|
426
|
+
export const getRowsAffectedMs = (qResult: any) => (qResult.rowsAffected && qResult.rowsAffected.reduce((a: number, v: number) => a + v, 0)) || 0;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { QueryResultRow } from 'pg';
|
|
2
|
+
import { getTableSchemaPg } from './table-schema';
|
|
3
|
+
import { prepareSqlValuePg } from './prepare-value';
|
|
4
|
+
import { ITableSchemaPg } from '../@types/i-pg';
|
|
5
|
+
|
|
6
|
+
export const getMergeSqlPg = async <U extends QueryResultRow = QueryResultRow> (arg: {
|
|
7
|
+
connectionId: string,
|
|
8
|
+
targetSchemaAndTable: string,
|
|
9
|
+
recordset: U[],
|
|
10
|
+
omitFields?: string[],
|
|
11
|
+
noUpdateIfNull?: boolean,
|
|
12
|
+
}): Promise<string> => {
|
|
13
|
+
const { connectionId, targetSchemaAndTable, recordset, omitFields = [], noUpdateIfNull } = arg;
|
|
14
|
+
if (!recordset?.length) {
|
|
15
|
+
return '';
|
|
16
|
+
}
|
|
17
|
+
const tableSchema: ITableSchemaPg = await getTableSchemaPg(connectionId, targetSchemaAndTable);
|
|
18
|
+
const { recordSchema, pk, fieldsWoSerials, defaults } = tableSchema;
|
|
19
|
+
|
|
20
|
+
let insertFieldsList: string[] = fieldsWoSerials;
|
|
21
|
+
if (omitFields.length) {
|
|
22
|
+
const set = new Set(omitFields);
|
|
23
|
+
insertFieldsList = fieldsWoSerials.filter((fieldName) => !set.has(fieldName));
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const insertValues = recordset.map((record: U) => {
|
|
27
|
+
const preparedValues: (string | number)[] = [];
|
|
28
|
+
|
|
29
|
+
insertFieldsList.forEach((fieldName) => {
|
|
30
|
+
const value = record[fieldName];
|
|
31
|
+
let pgSqlValue = prepareSqlValuePg({ value, fieldDef: recordSchema[fieldName] });
|
|
32
|
+
if (defaults[fieldName] != null && pgSqlValue === 'null') {
|
|
33
|
+
pgSqlValue = defaults[fieldName];
|
|
34
|
+
}
|
|
35
|
+
preparedValues.push(pgSqlValue);
|
|
36
|
+
});
|
|
37
|
+
return `(${preparedValues.join(', ')})`;
|
|
38
|
+
}).join(',\n').trim();
|
|
39
|
+
|
|
40
|
+
const upsertFields = insertFieldsList.map((f) => {
|
|
41
|
+
const vArr = [`EXCLUDED."${f}"`];
|
|
42
|
+
if (noUpdateIfNull) {
|
|
43
|
+
vArr.push(`${targetSchemaAndTable}."${f}"`);
|
|
44
|
+
}
|
|
45
|
+
if (defaults[f]) {
|
|
46
|
+
vArr.push(defaults[f]);
|
|
47
|
+
}
|
|
48
|
+
return `"${f}" = ${vArr.length > 1 ? `COALESCE(${vArr.join(', ')})` : vArr[0]}`;
|
|
49
|
+
}).join(',\n');
|
|
50
|
+
|
|
51
|
+
// noinspection UnnecessaryLocalVariableJS
|
|
52
|
+
const mergeSQL = `${'INSERT'} INTO ${targetSchemaAndTable}
|
|
53
|
+
(${insertFieldsList.join(', ')})
|
|
54
|
+
VALUES ${insertValues}
|
|
55
|
+
ON CONFLICT (${pk.map((f) => `"${f}"`).join(', ')})
|
|
56
|
+
DO UPDATE SET ${upsertFields}
|
|
57
|
+
`;
|
|
58
|
+
|
|
59
|
+
return mergeSQL;
|
|
60
|
+
};
|