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.
Files changed (173) hide show
  1. package/README.md +3 -3
  2. package/dist/cjs/__tests__/01_node_env.spec.js +7 -0
  3. package/dist/cjs/__tests__/01_node_env.spec.js.map +1 -0
  4. package/dist/cjs/__tests__/02_getValueForSqlMs.spec.js +50 -0
  5. package/dist/cjs/__tests__/02_getValueForSqlMs.spec.js.map +1 -0
  6. package/dist/cjs/__tests__/global-setup.js +7 -0
  7. package/dist/cjs/__tests__/global-setup.js.map +1 -0
  8. package/dist/cjs/__tests__/global-teardown.js +7 -0
  9. package/dist/cjs/__tests__/global-teardown.js.map +1 -0
  10. package/dist/cjs/{interfaces.js → src/@types/i-common.js} +1 -1
  11. package/dist/cjs/src/@types/i-common.js.map +1 -0
  12. package/dist/cjs/src/@types/i-config.js +3 -0
  13. package/dist/cjs/src/@types/i-config.js.map +1 -0
  14. package/dist/cjs/src/@types/i-ms.js +3 -0
  15. package/dist/cjs/src/@types/i-ms.js.map +1 -0
  16. package/dist/cjs/src/@types/i-pg.js +24 -0
  17. package/dist/cjs/src/@types/i-pg.js.map +1 -0
  18. package/dist/cjs/src/common.js +30 -0
  19. package/dist/cjs/src/common.js.map +1 -0
  20. package/dist/cjs/src/index.js +59 -0
  21. package/dist/cjs/src/index.js.map +1 -0
  22. package/dist/cjs/src/logger-error.js +10 -0
  23. package/dist/cjs/src/logger-error.js.map +1 -0
  24. package/dist/cjs/{get-value-for-sql.js → src/mssql/get-value-for-sql.js} +12 -8
  25. package/dist/cjs/src/mssql/get-value-for-sql.js.map +1 -0
  26. package/dist/cjs/{db.js → src/mssql/pool-ms.js} +73 -77
  27. package/dist/cjs/src/mssql/pool-ms.js.map +1 -0
  28. package/dist/cjs/src/mssql/query-ms.js +47 -0
  29. package/dist/cjs/src/mssql/query-ms.js.map +1 -0
  30. package/dist/cjs/{sql.js → src/mssql/sql.js} +72 -49
  31. package/dist/cjs/src/mssql/sql.js.map +1 -0
  32. package/dist/cjs/src/mssql/utils.js.map +1 -0
  33. package/dist/cjs/src/pg/get-merge-sql.js +50 -0
  34. package/dist/cjs/src/pg/get-merge-sql.js.map +1 -0
  35. package/dist/cjs/src/pg/get-update-sql.js +29 -0
  36. package/dist/cjs/src/pg/get-update-sql.js.map +1 -0
  37. package/dist/cjs/src/pg/insert.js +93 -0
  38. package/dist/cjs/src/pg/insert.js.map +1 -0
  39. package/dist/cjs/src/pg/is-table-or-view-exists.js +21 -0
  40. package/dist/cjs/src/pg/is-table-or-view-exists.js.map +1 -0
  41. package/dist/cjs/src/pg/pg-pool.js +52 -0
  42. package/dist/cjs/src/pg/pg-pool.js.map +1 -0
  43. package/dist/cjs/src/pg/prepare-value.js +84 -0
  44. package/dist/cjs/src/pg/prepare-value.js.map +1 -0
  45. package/dist/cjs/src/pg/query-pg.js +23 -0
  46. package/dist/cjs/src/pg/query-pg.js.map +1 -0
  47. package/dist/cjs/src/pg/table-schema.js +169 -0
  48. package/dist/cjs/src/pg/table-schema.js.map +1 -0
  49. package/dist/esm/src/@types/i-common.js +2 -0
  50. package/dist/esm/src/@types/i-common.js.map +1 -0
  51. package/dist/esm/src/@types/i-config.js +2 -0
  52. package/dist/esm/src/@types/i-config.js.map +1 -0
  53. package/dist/esm/src/@types/i-ms.js +2 -0
  54. package/dist/esm/src/@types/i-ms.js.map +1 -0
  55. package/dist/esm/src/@types/i-pg.js +21 -0
  56. package/dist/esm/src/@types/i-pg.js.map +1 -0
  57. package/dist/esm/src/common.js +25 -0
  58. package/dist/esm/src/common.js.map +1 -0
  59. package/dist/esm/src/index.js +15 -0
  60. package/dist/esm/src/index.js.map +1 -0
  61. package/dist/esm/src/logger-error.js +6 -0
  62. package/dist/esm/src/logger-error.js.map +1 -0
  63. package/dist/esm/{get-value-for-sql.js → src/mssql/get-value-for-sql.js} +11 -7
  64. package/dist/esm/src/mssql/get-value-for-sql.js.map +1 -0
  65. package/dist/esm/{db.js → src/mssql/pool-ms.js} +35 -62
  66. package/dist/esm/src/mssql/pool-ms.js.map +1 -0
  67. package/dist/esm/src/mssql/query-ms.js +20 -0
  68. package/dist/esm/src/mssql/query-ms.js.map +1 -0
  69. package/dist/esm/{sql.js → src/mssql/sql.js} +36 -36
  70. package/dist/esm/src/mssql/sql.js.map +1 -0
  71. package/dist/esm/src/mssql/utils.js.map +1 -0
  72. package/dist/esm/src/pg/get-merge-sql.js +46 -0
  73. package/dist/esm/src/pg/get-merge-sql.js.map +1 -0
  74. package/dist/esm/src/pg/get-update-sql.js +25 -0
  75. package/dist/esm/src/pg/get-update-sql.js.map +1 -0
  76. package/dist/esm/src/pg/insert.js +89 -0
  77. package/dist/esm/src/pg/insert.js.map +1 -0
  78. package/dist/esm/src/pg/is-table-or-view-exists.js +17 -0
  79. package/dist/esm/src/pg/is-table-or-view-exists.js.map +1 -0
  80. package/dist/esm/src/pg/pg-pool.js +43 -0
  81. package/dist/esm/src/pg/pg-pool.js.map +1 -0
  82. package/dist/esm/src/pg/prepare-value.js +79 -0
  83. package/dist/esm/src/pg/prepare-value.js.map +1 -0
  84. package/dist/esm/src/pg/query-pg.js +19 -0
  85. package/dist/esm/src/pg/query-pg.js.map +1 -0
  86. package/dist/esm/src/pg/table-schema.js +164 -0
  87. package/dist/esm/src/pg/table-schema.js.map +1 -0
  88. package/dist/types/src/@types/i-common.d.ts +35 -0
  89. package/dist/types/src/@types/i-common.d.ts.map +1 -0
  90. package/dist/types/src/@types/i-config.d.ts +60 -0
  91. package/dist/types/src/@types/i-config.d.ts.map +1 -0
  92. package/dist/types/{interfaces.d.ts → src/@types/i-ms.d.ts} +30 -77
  93. package/dist/types/src/@types/i-ms.d.ts.map +1 -0
  94. package/dist/types/src/@types/i-pg.d.ts +62 -0
  95. package/dist/types/src/@types/i-pg.d.ts.map +1 -0
  96. package/dist/types/src/common.d.ts +6 -0
  97. package/dist/types/src/common.d.ts.map +1 -0
  98. package/dist/types/src/index.d.ts +18 -0
  99. package/dist/types/src/index.d.ts.map +1 -0
  100. package/dist/types/src/logger-error.d.ts +7 -0
  101. package/dist/types/src/logger-error.d.ts.map +1 -0
  102. package/dist/types/src/mssql/get-value-for-sql.d.ts +11 -0
  103. package/dist/types/src/mssql/get-value-for-sql.d.ts.map +1 -0
  104. package/dist/types/{db.d.ts → src/mssql/pool-ms.d.ts} +18 -15
  105. package/dist/types/src/mssql/pool-ms.d.ts.map +1 -0
  106. package/dist/types/src/mssql/query-ms.d.ts +3 -0
  107. package/dist/types/src/mssql/query-ms.d.ts.map +1 -0
  108. package/dist/types/{sql.d.ts → src/mssql/sql.d.ts} +17 -16
  109. package/dist/types/src/mssql/sql.d.ts.map +1 -0
  110. package/dist/types/src/mssql/utils.d.ts.map +1 -0
  111. package/dist/types/src/pg/get-merge-sql.d.ts +9 -0
  112. package/dist/types/src/pg/get-merge-sql.d.ts.map +1 -0
  113. package/dist/types/src/pg/get-update-sql.d.ts +3 -0
  114. package/dist/types/src/pg/get-update-sql.d.ts.map +1 -0
  115. package/dist/types/src/pg/insert.d.ts +15 -0
  116. package/dist/types/src/pg/insert.d.ts.map +1 -0
  117. package/dist/types/src/pg/is-table-or-view-exists.d.ts +2 -0
  118. package/dist/types/src/pg/is-table-or-view-exists.d.ts.map +1 -0
  119. package/dist/types/src/pg/pg-pool.d.ts +6 -0
  120. package/dist/types/src/pg/pg-pool.d.ts.map +1 -0
  121. package/dist/types/src/pg/prepare-value.d.ts +7 -0
  122. package/dist/types/src/pg/prepare-value.d.ts.map +1 -0
  123. package/dist/types/src/pg/query-pg.d.ts +3 -0
  124. package/dist/types/src/pg/query-pg.d.ts.map +1 -0
  125. package/dist/types/src/pg/table-schema.d.ts +12 -0
  126. package/dist/types/src/pg/table-schema.d.ts.map +1 -0
  127. package/package.json +21 -24
  128. package/src/@types/i-common.ts +39 -0
  129. package/src/@types/i-config.ts +75 -0
  130. package/src/{interfaces.ts → @types/i-ms.ts} +29 -86
  131. package/src/@types/i-pg.ts +67 -0
  132. package/src/common.ts +26 -0
  133. package/src/index.ts +104 -42
  134. package/src/logger-error.ts +11 -0
  135. package/src/{get-value-for-sql.ts → mssql/get-value-for-sql.ts} +15 -9
  136. package/src/{db.ts → mssql/pool-ms.ts} +40 -71
  137. package/src/mssql/query-ms.ts +25 -0
  138. package/src/{sql.ts → mssql/sql.ts} +56 -59
  139. package/src/pg/get-merge-sql.ts +60 -0
  140. package/src/pg/get-update-sql.ts +31 -0
  141. package/src/pg/insert.ts +118 -0
  142. package/src/pg/is-table-or-view-exists.ts +21 -0
  143. package/src/pg/pg-pool.ts +49 -0
  144. package/src/pg/prepare-value.ts +90 -0
  145. package/src/pg/query-pg.ts +26 -0
  146. package/src/pg/table-schema.ts +178 -0
  147. package/dist/cjs/db.js.map +0 -1
  148. package/dist/cjs/get-value-for-sql.js.map +0 -1
  149. package/dist/cjs/index.js +0 -21
  150. package/dist/cjs/index.js.map +0 -1
  151. package/dist/cjs/interfaces.js.map +0 -1
  152. package/dist/cjs/sql.js.map +0 -1
  153. package/dist/cjs/utils.js.map +0 -1
  154. package/dist/esm/db.js.map +0 -1
  155. package/dist/esm/get-value-for-sql.js.map +0 -1
  156. package/dist/esm/index.js +0 -4
  157. package/dist/esm/index.js.map +0 -1
  158. package/dist/esm/interfaces.js +0 -2
  159. package/dist/esm/interfaces.js.map +0 -1
  160. package/dist/esm/sql.js.map +0 -1
  161. package/dist/esm/utils.js.map +0 -1
  162. package/dist/types/db.d.ts.map +0 -1
  163. package/dist/types/get-value-for-sql.d.ts +0 -7
  164. package/dist/types/get-value-for-sql.d.ts.map +0 -1
  165. package/dist/types/index.d.ts +0 -5
  166. package/dist/types/index.d.ts.map +0 -1
  167. package/dist/types/interfaces.d.ts.map +0 -1
  168. package/dist/types/sql.d.ts.map +0 -1
  169. package/dist/types/utils.d.ts.map +0 -1
  170. /package/dist/cjs/{utils.js → src/mssql/utils.js} +0 -0
  171. /package/dist/esm/{utils.js → src/mssql/utils.js} +0 -0
  172. /package/dist/types/{utils.d.ts → src/mssql/utils.d.ts} +0 -0
  173. /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 { IDateTimeOptionsEx, IGetValueForSQLArgs, IPrepareSqlStringArgs } from './interfaces';
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 getValueForSQL = (args: IGetValueForSQLArgs): string | number | null => {
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: IPrepareSqlStringArgs = {
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 prepareSqlString({ ...prepareSqlStringArgs, value });
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 prepareSqlString(prepareSqlStringArgs);
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 prepareSqlString({ ...prepareSqlStringArgs, value, length: 0 });
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 prepareSqlString(prepareSqlStringArgs);
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 prepareSqlString(prepareSqlStringArgs);
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 * as config from 'config';
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, IResult } from 'mssql';
6
- import * as _ from 'lodash';
4
+ import { ConnectionPool } from 'mssql';
7
5
  import { sleep } from 'af-tools-ts';
8
- import { IConnectionPools, TGetPoolConnectionOptions } from './interfaces';
6
+ import { IDbOptionsMs, IDbsMs } from '../@types/i-config';
7
+ import { logSqlError } from '../common';
8
+ import { IConnectionPoolsMs, TGetPoolConnectionOptionsMs } from '../@types/i-ms';
9
9
 
10
- export const getFirstConfigId = () => Object.keys(config.get<any>('database') || {}).filter((v) => !['dialect', '_common_'].includes(v))[0];
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 pools: IConnectionPools = {};
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 getPoolConnection = async (connectionId: string, options: TGetPoolConnectionOptions = {}): Promise<ConnectionPool | undefined> => {
20
+ export const getPoolConnectionMs = async (connectionId: string, options: TGetPoolConnectionOptionsMs = {}): Promise<ConnectionPool | undefined> => {
20
21
  const { prefix = '', errorCode = 0 } = options;
21
- let pool = pools[connectionId];
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
- pools[connectionId] = pool;
56
+ poolsCacheMs[connectionId] = pool;
56
57
  // @ts-ignore
57
58
  pool._connectionId = connectionId;
58
59
  pool.on('close', () => {
59
- delete pools[connectionId];
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 closeDbConnections = async (poolsToClose: ConnectionPool | ConnectionPool[] | string | string[], prefix?: string, noEcho?: boolean) => {
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 = pools[connectionId];
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 pools[connectionId];
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 closeAllDbConnections = async (prefix?: string, noEcho?: boolean) => {
126
- const poolsToClose = _.map(pools, (p) => p);
127
- await closeDbConnections(poolsToClose, prefix, noEcho);
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 closeDbConnectionsAndExit = async (poolsToClose: ConnectionPool | ConnectionPool[], prefix?: string) => {
137
- await closeDbConnections(poolsToClose, prefix);
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 Request = async (connectionId: string, strSQL: string): Promise<any> => {
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
- res = await request.query(textSQL);
191
- return res;
160
+ return getPoolConnectionMs(connectionId);
192
161
  } catch (err) {
193
- logSqlError(err, noThrow, textSQL, prefix);
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 * as db from './db';
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 { getValueForSQL } from './get-value-for-sql';
10
- import { IDBConfig,
11
- IFieldSchema,
12
- IGetMergeSQLOptions,
13
- IGetValueForSQLArgs, IPrepareArgs,
14
- IPrepareSqlStringArgs,
15
- TDBRecord,
16
- TFieldName,
17
- TFieldTypeCorrection,
18
- TGetRecordSchemaResult,
19
- TGetRecordSchemaOptions,
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 prepareSqlString = (args: IPrepareSqlStringArgs): string | null => {
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 correctRecordSchema = (
62
- recordSchemaAssoc: TRecordSchemaAssoc,
58
+ export const correctRecordSchemaMs = (
59
+ recordSchemaAssoc: TRecordSchemaAssocMs,
63
60
  // объект корректировок
64
- fieldTypeCorrection?: TFieldTypeCorrection,
61
+ fieldTypeCorrection?: TFieldTypeCorrectionMs,
65
62
  ) => {
66
- _.each(recordSchemaAssoc, (fieldSchema: IFieldSchema, fieldName: TFieldName) => {
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
- _.each(fieldTypeCorrection, (correction: IFieldSchema, fieldName: TFieldName) => {
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 IFieldSchema;
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
- * Все поля записи обрабатываются функцией getValueForSQL
98
+ * Все поля записи обрабатываются функцией getValueForSqlMs
102
99
  */
103
- export const prepareRecordForSQL = (record: TDBRecord, args: IPrepareArgs) => {
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: IGetValueForSQLArgs = {
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: IFieldSchema) => {
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] = getValueForSQL({ ...options, value: record[name], fieldSchema });
117
+ record[name] = getValueForSqlMs({ ...options, value: record[name], fieldSchema });
121
118
  } else if ((!fieldSchema.nullable && addValues4NotNullableFields) || addMissingFields) {
122
- record[name] = getValueForSQL({ ...options, value: null, fieldSchema });
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
- * Все поля всех записей обрабатываются функцией getValueForSQL
127
+ * Все поля всех записей обрабатываются функцией getValueForSqlMs
131
128
  */
132
- export const prepareDataForSQL = (recordSet: TRecordSet, args: IPrepareArgs) => {
129
+ export const prepareDataForSqlMs = (recordSet: TRecordSet, args: IPrepareRecordForSqlArgsMs) => {
133
130
  if (recordSet._isPreparedForSQL) {
134
131
  return;
135
132
  }
136
133
  recordSet.forEach((record) => {
137
- prepareRecordForSQL(record, args);
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 getRecordValuesForSQL = (record: TDBRecord, recordSchema: TRecordSchema): TDBRecord => {
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] = getValueForSQL({
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, то вернет TRecordSchema, при этом удалит поля, указанные в omitFields
169
- * Иначе вернет TRecordSchemaAssoc
165
+ * Если asArray = true, то вернет TRecordSchemaMs, при этом удалит поля, указанные в omitFields
166
+ * Иначе вернет TRecordSchemaAssocMs
170
167
  */
171
- export const getRecordSchema = async (
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: TGetRecordSchemaOptions = {} as TGetRecordSchemaOptions,
178
- ): Promise<TGetRecordSchemaResult | undefined> => {
174
+ options: TGetRecordSchemaOptionsMs = {} as TGetRecordSchemaOptionsMs,
175
+ ): Promise<TGetRecordSchemaResultMs | undefined> => {
179
176
  const propertyPath = `schemas.${connectionId}.${schemaAndTable}`;
180
177
 
181
- let result: TGetRecordSchemaResult | undefined = cache.get(propertyPath) as TGetRecordSchemaResult | undefined;
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.getPoolConnection(connectionId, { prefix: 'getRecordSchema' });
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(`getRecordSchema SQL 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> = _.omit<IColumnMetadata>(columns, omitFields2);
215
- schemaAssoc = Array.isArray(pickFields) ? _.pick(schemaAssoc, pickFields) : schemaAssoc;
216
- correctRecordSchema(schemaAssoc as TRecordSchemaAssoc, fieldTypeCorrection);
217
- const schema: ISchemaArray = _.map(schemaAssoc, (fo) => (fo))
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 ISchemaArray;
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: IDBConfig = db.getDbConfig(connectionId) as IDBConfig;
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: IGetMergeSQLOptions = {}): string {
259
+ getMergeSQL (packet: TRecordSet, prepareOptions: IGetMergeSQLOptionsMs = {}): string {
263
260
  if (prepareOptions.isPrepareForSQL) {
264
- prepareDataForSQL(packet, { recordSchema: this.schema, ...prepareOptions });
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 = getRecordValuesForSQL(record, this.schema);
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 wrapTransaction = (strSQL: string): string => `BEGIN TRY
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 serialize = (args: IGetValueForSQLArgs): string | number | null => {
374
- const val = getValueForSQL(args);
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 getSqlSetExpression = (record: TDBRecord, recordSchema: TRecordSchema): string => {
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}] = ${getValueForSQL({
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 getSqlValuesExpression = (record: TDBRecord, recordSchema: TRecordSchema, addOutputInserted: boolean = false): string => {
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 = getValueForSQL({
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 getRowsAffected = (qResult: any) => (qResult.rowsAffected && qResult.rowsAffected.reduce((a: number, v: number) => a + v, 0)) || 0;
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
+ };