af-db-ts 1.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 (44) hide show
  1. package/README.md +3 -0
  2. package/dist/cjs/db.js +199 -0
  3. package/dist/cjs/db.js.map +1 -0
  4. package/dist/cjs/get-value-for-sql.js +256 -0
  5. package/dist/cjs/get-value-for-sql.js.map +1 -0
  6. package/dist/cjs/index.js +20 -0
  7. package/dist/cjs/index.js.map +1 -0
  8. package/dist/cjs/interfaces.js +3 -0
  9. package/dist/cjs/interfaces.js.map +1 -0
  10. package/dist/cjs/sql.js +375 -0
  11. package/dist/cjs/sql.js.map +1 -0
  12. package/dist/cjs/utils.js +36 -0
  13. package/dist/cjs/utils.js.map +1 -0
  14. package/dist/esm/db.js +185 -0
  15. package/dist/esm/db.js.map +1 -0
  16. package/dist/esm/get-value-for-sql.js +251 -0
  17. package/dist/esm/get-value-for-sql.js.map +1 -0
  18. package/dist/esm/index.js +4 -0
  19. package/dist/esm/index.js.map +1 -0
  20. package/dist/esm/interfaces.js +2 -0
  21. package/dist/esm/interfaces.js.map +1 -0
  22. package/dist/esm/sql.js +361 -0
  23. package/dist/esm/sql.js.map +1 -0
  24. package/dist/esm/utils.js +31 -0
  25. package/dist/esm/utils.js.map +1 -0
  26. package/dist/types/db.d.ts +39 -0
  27. package/dist/types/db.d.ts.map +1 -0
  28. package/dist/types/get-value-for-sql.d.ts +7 -0
  29. package/dist/types/get-value-for-sql.d.ts.map +1 -0
  30. package/dist/types/index.d.ts +5 -0
  31. package/dist/types/index.d.ts.map +1 -0
  32. package/dist/types/interfaces.d.ts +181 -0
  33. package/dist/types/interfaces.d.ts.map +1 -0
  34. package/dist/types/sql.d.ts +56 -0
  35. package/dist/types/sql.d.ts.map +1 -0
  36. package/dist/types/utils.d.ts +10 -0
  37. package/dist/types/utils.d.ts.map +1 -0
  38. package/package.json +75 -0
  39. package/src/db.ts +195 -0
  40. package/src/get-value-for-sql.ts +271 -0
  41. package/src/index.ts +47 -0
  42. package/src/interfaces.ts +232 -0
  43. package/src/sql.ts +403 -0
  44. package/src/utils.ts +31 -0
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Оборачивает строку в одинарные кавычки, если второй аргумент не true
3
+ */
4
+ export const q = (val, noQuotes) => (noQuotes ? val : `'${val}'`);
5
+ /**
6
+ * Экранирование одинарной кавычки и символа % для использования строки в SQL запросе
7
+ * onlySingleQuotes - true - не экранировать %
8
+ */
9
+ export const mssqlEscape = (str, onlySingleQuotes = false) => {
10
+ if (str == null) {
11
+ str = '';
12
+ }
13
+ switch (typeof str) {
14
+ case 'number':
15
+ str = String(str);
16
+ break;
17
+ case 'string':
18
+ break;
19
+ case 'boolean':
20
+ str = str ? '1' : '0';
21
+ break;
22
+ default:
23
+ str = String(str || '');
24
+ }
25
+ str = str.replace(/'/g, `''`);
26
+ if (onlySingleQuotes) {
27
+ return str;
28
+ }
29
+ return str.replace(/%/g, '%%');
30
+ };
31
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,CAAC,MAAM,CAAC,GAAG,CAAC,GAAW,EAAE,QAAkB,EAAU,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,GAAG,GAAG,CAAC,CAAC;AAE5F;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,GAAQ,EAAE,mBAA4B,KAAK,EAAU,EAAE;IACjF,IAAI,GAAG,IAAI,IAAI,EAAE;QACf,GAAG,GAAG,EAAE,CAAC;KACV;IACD,QAAQ,OAAO,GAAG,EAAE;QAClB,KAAK,QAAQ;YACX,GAAG,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;YAClB,MAAM;QACR,KAAK,QAAQ;YACX,MAAM;QACR,KAAK,SAAS;YACZ,GAAG,GAAG,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC;YACtB,MAAM;QACR;YACE,GAAG,GAAG,MAAM,CAAC,GAAG,IAAI,EAAE,CAAC,CAAC;KAC3B;IACD,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC9B,IAAI,gBAAgB,EAAE;QACpB,OAAO,GAAG,CAAC;KACZ;IACD,OAAO,GAAG,CAAC,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;AACjC,CAAC,CAAC"}
@@ -0,0 +1,39 @@
1
+ import * as sql from 'mssql';
2
+ import { ConnectionPool, IResult } from 'mssql';
3
+ import { IConnectionPools, TGetPoolConnectionOptions } from './interfaces';
4
+ export declare const getFirstConfigId: () => string;
5
+ export declare const getDbConfig: (connectionId: string) => any;
6
+ export declare const pools: IConnectionPools;
7
+ /**
8
+ * Возвращает пул соединений для БД, соответствующей преданному ID соединения (borf|cep|hr|global)
9
+ * В случае, если не удается создать пул или открыть соединение, прерывает работу скрипта
10
+ */
11
+ export declare const getPoolConnection: (connectionId: string, options?: TGetPoolConnectionOptions) => Promise<ConnectionPool | undefined>;
12
+ /**
13
+ * Закрывает указанные соединения с БД
14
+ *
15
+ * poolsToClose - пул или массив пулов
16
+ * prefix - Префикс в сообщении о закрытии пула (название синхронизации)
17
+ * noEcho - подавление сообщений о закрытии соединения
18
+ */
19
+ export declare const closeDbConnections: (poolsToClose: ConnectionPool | ConnectionPool[] | string | string[], prefix?: string, noEcho?: boolean) => Promise<void>;
20
+ /**
21
+ * Закрывает все соединения с БД
22
+ *
23
+ * prefix - Префикс в сообщении о закрытии пула (название синхронизации)
24
+ * noEcho - подавление сообщений о закрытии соединения
25
+ */
26
+ export declare const closeAllDbConnections: (prefix?: string, noEcho?: boolean) => Promise<void>;
27
+ /**
28
+ * Закрывает указанные соединения с БД и прерывает работу скрипта
29
+ *
30
+ * poolsToClose - пул или массив пулов
31
+ * prefix - Префикс в сообщении о закрытии пула (название синхронизации)
32
+ */
33
+ export declare const closeDbConnectionsAndExit: (poolsToClose: ConnectionPool | ConnectionPool[], prefix?: string) => Promise<never>;
34
+ export declare const Request: (connectionId: string, strSQL: string) => Promise<any>;
35
+ export declare const setLogger: (logger_: any) => void;
36
+ export declare const logSqlError: (err: Error | any, noThrow?: boolean, textSQL?: string, prefix?: string) => void;
37
+ export declare const getPool: (dbId: string, noThrow?: boolean) => Promise<sql.ConnectionPool | undefined>;
38
+ export declare const query: (dbId: string, textSQL: string, noThrow?: boolean, prefix?: string) => Promise<IResult<any> | undefined>;
39
+ //# sourceMappingURL=db.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"db.d.ts","sourceRoot":"","sources":["../../src/db.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,GAAG,MAAM,OAAO,CAAC;AAC7B,OAAO,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAGhD,OAAO,EAAE,gBAAgB,EAAE,yBAAyB,EAAE,MAAM,cAAc,CAAC;AAE3E,eAAO,MAAM,gBAAgB,cAA8G,CAAC;AAC5I,eAAO,MAAM,WAAW,iBAAkB,MAAM,QAAgD,CAAC;AAEjG,eAAO,MAAM,KAAK,EAAE,gBAAqB,CAAC;AAE1C;;;GAGG;AACH,eAAO,MAAM,iBAAiB,iBAAwB,MAAM,YAAW,yBAAyB,KAAQ,QAAQ,cAAc,GAAG,SAAS,CAmDzI,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,iBAAwB,cAAc,GAAG,cAAc,EAAE,GAAG,MAAM,GAAG,MAAM,EAAE,WAAW,MAAM,WAAW,OAAO,kBAsC9I,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,qBAAqB,YAAmB,MAAM,WAAW,OAAO,kBAG5E,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,yBAAyB,iBAAwB,cAAc,GAAG,cAAc,EAAE,WAAW,MAAM,mBAG/G,CAAC;AAEF,eAAO,MAAM,OAAO,iBAAwB,MAAM,UAAU,MAAM,KAAG,QAAQ,GAAG,CAO/E,CAAC;AAQF,eAAO,MAAM,SAAS,YAAa,GAAG,SAErC,CAAC;AAEF,eAAO,MAAM,WAAW,QAAS,KAAK,GAAG,GAAG,YAAY,OAAO,YAAY,MAAM,WAAW,MAAM,SAWjG,CAAC;AAEF,eAAO,MAAM,OAAO,SAAgB,MAAM,YAAW,OAAO,4CAM3D,CAAC;AAEF,eAAO,MAAM,KAAK,SAAgB,MAAM,WAAW,MAAM,YAAY,OAAO,WAAW,MAAM,KAAG,QAAQ,QAAQ,GAAG,CAAC,GAAG,SAAS,CAc/H,CAAC"}
@@ -0,0 +1,7 @@
1
+ import { IGetValueForSQLArgs } from './interfaces';
2
+ export declare const binToHexString: (value: any) => string | null;
3
+ /**
4
+ * Возвращает значение, готовое для использования в строке SQL запроса
5
+ */
6
+ export declare const getValueForSQL: (args: IGetValueForSQLArgs) => string | number | null;
7
+ //# sourceMappingURL=get-value-for-sql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"get-value-for-sql.d.ts","sourceRoot":"","sources":["../../src/get-value-for-sql.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,mBAAmB,EAAyB,MAAM,cAAc,CAAC;AAI1E,eAAO,MAAM,cAAc,UAAW,GAAG,kBAA6D,CAAC;AAwBvG;;GAEG;AACH,eAAO,MAAM,cAAc,SAAU,mBAAmB,KAAG,MAAM,GAAG,MAAM,GAAG,IA6O5E,CAAC"}
@@ -0,0 +1,5 @@
1
+ export * as db from './db';
2
+ export { prepareSqlString, correctRecordSchema, getRecordSchema, wrapTransaction, serialize, getRecordValuesForSQL, getSqlSetExpression, getSqlValuesExpression, prepareRecordForSQL, prepareDataForSQL, getRowsAffected, } from './sql';
3
+ export { binToHexString, getValueForSQL, } from './get-value-for-sql';
4
+ export { IDBConfig, IFieldSchema, IGetMergeSQLOptions, TDBRecord, TFieldName, TFieldTypeCorrection, TGetRecordSchemaOptions, TRecordSchema, TRecordSchemaAssoc, TRecordSet, TRecordSetAssoc, TMergeRules, TMergeResult, TRecordKey, TGetPoolConnectionOptions, TGetRecordSchemaResult, IPrepareSqlStringArgs, IGetValueForSQLArgs, IDialect, DateTimeOptionsEx, IPrepareArgs, IPrepareRecordParams, ISchemaItem, IValueForSQLPartialArgs, } from './interfaces';
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,MAAM,CAAC;AAE3B,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,eAAe,EACf,SAAS,EACT,qBAAqB,EACrB,mBAAmB,EACnB,sBAAsB,EACtB,mBAAmB,EACnB,iBAAiB,EACjB,eAAe,GAChB,MAAM,OAAO,CAAC;AAEf,OAAO,EACL,cAAc,EACd,cAAc,GACf,MAAM,qBAAqB,CAAC;AAE7B,OAAO,EACL,SAAS,EACT,YAAY,EACZ,mBAAmB,EACnB,SAAS,EACT,UAAU,EACV,oBAAoB,EACpB,uBAAuB,EACvB,aAAa,EACb,kBAAkB,EAClB,UAAU,EACV,eAAe,EACf,WAAW,EACX,YAAY,EACZ,UAAU,EACV,yBAAyB,EACzB,sBAAsB,EACtB,qBAAqB,EACrB,mBAAmB,EACnB,QAAQ,EACR,iBAAiB,EACjB,YAAY,EACZ,oBAAoB,EACpB,WAAW,EACX,uBAAuB,GACxB,MAAM,cAAc,CAAC"}
@@ -0,0 +1,181 @@
1
+ import { ConnectionPool, IColumnMetadata, ISqlType } from 'mssql';
2
+ import { DateTimeOptions } from 'luxon';
3
+ /**
4
+ * Имя поля БД
5
+ */
6
+ export type TFieldName = string;
7
+ /**
8
+ * Значение ключевого поля записи БД
9
+ */
10
+ export type TRecordKey = string | number;
11
+ /**
12
+ * Метаинформация о поле БД
13
+ */
14
+ export interface IFieldSchema {
15
+ index?: number;
16
+ name?: string;
17
+ length?: number;
18
+ type?: any;
19
+ arrayType?: any;
20
+ scale?: number;
21
+ precision?: number;
22
+ nullable?: boolean;
23
+ caseSensitive?: boolean;
24
+ identity?: boolean;
25
+ excludeFromInsert?: boolean;
26
+ readOnly?: boolean;
27
+ inputDateFormat?: string;
28
+ defaultValue?: any;
29
+ noQuotes?: boolean;
30
+ escapeOnlySingleQuotes?: boolean;
31
+ }
32
+ /**
33
+ * Массив объектов с метаинформацией о полях
34
+ */
35
+ export type TRecordSchema = IFieldSchema[];
36
+ /**
37
+ * Метаинформацией о полях, проиндексированная именами полей. (sql.recordset.columns)
38
+ */
39
+ export interface TRecordSchemaAssoc {
40
+ [fieldName: TFieldName]: IFieldSchema;
41
+ }
42
+ /**
43
+ * Объект корректировки типов полей. Наименованию поля соответствует новый тип.
44
+ *
45
+ * В частности, используется для полей, хранящих знаяения типа json в поле типа varchar(max)
46
+ * тогда необходимо явно задать тип поля "json". Если имя поля заканчивается на _json, коррекция типа произойдет автоматически.
47
+ * Также используется для указания входного формата для преобразования строки в тип datetime (свойство inputDateFormat в схеме поля)
48
+ */
49
+ export interface TFieldTypeCorrection {
50
+ [fieldName: TFieldName]: IFieldSchema;
51
+ }
52
+ /**
53
+ * Запись БД. Объект, проиндексированный именами полей. Значения - значения полей
54
+ */
55
+ export interface TDBRecord {
56
+ [fieldName: TFieldName]: any;
57
+ }
58
+ /**
59
+ * Массив записей БД
60
+ *
61
+ * _isPreparedForSQL - Признак того, что значения полей подготовлены для использования в строке SQL
62
+ */
63
+ export type TRecordSet = TDBRecord[] & {
64
+ _isPreparedForSQL?: boolean;
65
+ };
66
+ /**
67
+ * Пакет записей БД.
68
+ * Объект, проиндексированный алиасами. Каждый подобъект содержит TDBRecord.
69
+ */
70
+ export interface TRecordSetAssoc {
71
+ [recordKey: TRecordKey]: TDBRecord;
72
+ }
73
+ export interface TMergeResult {
74
+ total: number;
75
+ inserted: number;
76
+ updated: number;
77
+ }
78
+ /**
79
+ * Метаинформация для формирования инструкции SQL MERGE
80
+ */
81
+ export interface TMergeRules {
82
+ mergeIdentity?: TFieldName[];
83
+ excludeFromInsert?: TFieldName[];
84
+ noUpdateIfNull?: boolean;
85
+ correction?: Function;
86
+ withClause?: string;
87
+ }
88
+ export interface TGetRecordSchemaOptions {
89
+ omitFields?: string[];
90
+ pickFields?: string[];
91
+ fieldTypeCorrection?: TFieldTypeCorrection;
92
+ mergeRules?: TMergeRules;
93
+ noReturnMergeResult?: boolean;
94
+ }
95
+ export interface TGetPoolConnectionOptions {
96
+ prefix?: string;
97
+ onError?: 'exit' | 'throw';
98
+ errorCode?: number;
99
+ }
100
+ export type IDialect = 'mssql' | 'pg';
101
+ interface IDBConfigCommon {
102
+ dialect: IDialect;
103
+ port: string | number | null;
104
+ database: string;
105
+ user: string;
106
+ password: string;
107
+ }
108
+ interface IDBConfigMSSQL extends IDBConfigCommon {
109
+ server: string;
110
+ }
111
+ interface IDBConfigPG extends IDBConfigCommon {
112
+ host: string;
113
+ }
114
+ export type IDBConfig = IDBConfigMSSQL | IDBConfigPG;
115
+ export interface ISchemaItem {
116
+ index: number;
117
+ name: string;
118
+ length: number;
119
+ type: (() => ISqlType) | ISqlType;
120
+ udt?: any;
121
+ scale?: number | undefined;
122
+ precision?: number | undefined;
123
+ nullable: boolean;
124
+ caseSensitive: boolean;
125
+ identity: boolean;
126
+ readOnly: boolean;
127
+ }
128
+ export interface IPrepareSqlStringArgs {
129
+ value: string | number | null;
130
+ defaultValue?: string | null | undefined;
131
+ length?: number;
132
+ nullable?: boolean | number;
133
+ noQuotes?: boolean;
134
+ escapeOnlySingleQuotes?: boolean;
135
+ }
136
+ export interface DateTimeOptionsEx extends DateTimeOptions {
137
+ correctionMillis: number;
138
+ }
139
+ export interface IValueForSQLPartialArgs {
140
+ dateTimeOptions?: DateTimeOptionsEx;
141
+ dialect?: IDialect;
142
+ escapeOnlySingleQuotes?: boolean;
143
+ needValidate?: boolean;
144
+ }
145
+ export interface IPrepareRecordParams {
146
+ addMissingFields?: boolean;
147
+ addValues4NotNullableFields?: boolean;
148
+ }
149
+ export interface IGetValueForSQLArgs extends IValueForSQLPartialArgs {
150
+ value: any;
151
+ fieldSchema: IFieldSchema | string;
152
+ }
153
+ export interface IPrepareArgs extends IValueForSQLPartialArgs, IPrepareRecordParams {
154
+ recordSchema: TRecordSchema;
155
+ }
156
+ export interface IGetMergeSQLOptions extends IValueForSQLPartialArgs, IPrepareRecordParams {
157
+ isPrepareForSQL?: boolean;
158
+ }
159
+ export interface TGetRecordSchemaResult {
160
+ connectionId: string;
161
+ dbConfig: IDBConfig;
162
+ schemaAndTable: string;
163
+ dbSchemaAndTable: string;
164
+ columns: IColumnMetadata;
165
+ schemaAssoc: Partial<IColumnMetadata>;
166
+ schema: ISchemaItem[];
167
+ fields: string[];
168
+ insertFields: string[];
169
+ insertFieldsList: string;
170
+ withClause: string | undefined;
171
+ updateFields: string[];
172
+ mergeIdentity: string[];
173
+ getMergeSQL: (_packet: TRecordSet, _prepareOptions?: IGetMergeSQLOptions) => string;
174
+ getInsertSQL: (_packet: TRecordSet, _addOutputInserted?: boolean) => string;
175
+ getUpdateSQL: (_record: TRecordSet) => string;
176
+ }
177
+ export interface IConnectionPools {
178
+ [poolId: string]: ConnectionPool;
179
+ }
180
+ export {};
181
+ //# sourceMappingURL=interfaces.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interfaces.d.ts","sourceRoot":"","sources":["../../src/interfaces.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAExC;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,CAAC;AAEhC;;GAEG;AACH,MAAM,MAAM,UAAU,GAAG,MAAM,GAAG,MAAM,CAAC;AAEzC;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,GAAG,CAAC;IACX,SAAS,CAAC,EAAE,GAAG,CAAC;IAChB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,YAAY,CAAC,EAAE,GAAG,CAAC;IACnB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,MAAM,aAAa,GAAG,YAAY,EAAE,CAAA;AAE1C;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC,CAAC,SAAS,EAAE,UAAU,GAAG,YAAY,CAAA;CACtC;AAED;;;;;;GAMG;AACH,MAAM,WAAW,oBAAoB;IACnC,CAAC,SAAS,EAAE,UAAU,GAAG,YAAY,CAAA;CACtC;AAID;;GAEG;AACH,MAAM,WAAW,SAAS;IACxB,CAAC,SAAS,EAAE,UAAU,GAAG,GAAG,CAAA;CAC7B;AAED;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,SAAS,EAAE,GAAG;IAAE,iBAAiB,CAAC,EAAE,OAAO,CAAA;CAAE,CAAA;AAEtE;;;GAGG;AACH,MAAM,WAAW,eAAe;IAC9B,CAAC,SAAS,EAAE,UAAU,GAAG,SAAS,CAAA;CACnC;AAED,MAAM,WAAW,YAAY;IAE3B,KAAK,EAAE,MAAM,CAAC;IAEd,QAAQ,EAAE,MAAM,CAAC;IAEjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED;;GAEG;AACH,MAAM,WAAW,WAAW;IAE1B,aAAa,CAAC,EAAE,UAAU,EAAE,CAAC;IAE7B,iBAAiB,CAAC,EAAE,UAAU,EAAE,CAAC;IAEjC,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,UAAU,CAAC,EAAE,QAAQ,CAAC;IACtB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,uBAAuB;IAEtC,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB,UAAU,CAAC,EAAE,MAAM,EAAE,CAAC;IAEtB,mBAAmB,CAAC,EAAE,oBAAoB,CAAC;IAC3C,UAAU,CAAC,EAAE,WAAW,CAAC;IACzB,mBAAmB,CAAC,EAAE,OAAO,CAAC;CAC/B;AAED,MAAM,WAAW,yBAAyB;IAExC,MAAM,CAAC,EAAE,MAAM,CAAC;IAKhB,OAAO,CAAC,EAAE,MAAM,GAAG,OAAO,CAAA;IAC1B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED,MAAM,MAAM,QAAQ,GAAG,OAAO,GAAG,IAAI,CAAC;AAEtC,UAAU,eAAe;IACvB,OAAO,EAAE,QAAQ,CAAC;IAClB,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,cAAe,SAAQ,eAAe;IAC9C,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,UAAU,WAAY,SAAQ,eAAe;IAC3C,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,MAAM,SAAS,GAAG,cAAc,GAAG,WAAW,CAAA;AAEpD,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,CAAC,MAAM,QAAQ,CAAC,GAAG,QAAQ,CAAC;IAClC,GAAG,CAAC,EAAE,GAAG,CAAC;IACV,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,OAAO,CAAC;IAClB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,WAAW,qBAAqB;IAEpC,KAAK,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAE9B,YAAY,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;IAEzC,MAAM,CAAC,EAAE,MAAM,CAAC;IAEhB,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;IAC5B,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,sBAAsB,CAAC,EAAE,OAAO,CAAC;CAClC;AAED,MAAM,WAAW,iBAAkB,SAAQ,eAAe;IACxD,gBAAgB,EAAE,MAAM,CAAC;CAC1B;AAED,MAAM,WAAW,uBAAuB;IACtC,eAAe,CAAC,EAAE,iBAAiB,CAAC;IACpC,OAAO,CAAC,EAAE,QAAQ,CAAA;IAClB,sBAAsB,CAAC,EAAE,OAAO,CAAC;IACjC,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,oBAAoB;IAEnC,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAE3B,2BAA2B,CAAC,EAAE,OAAO,CAAC;CACvC;AAED,MAAM,WAAW,mBAAoB,SAAQ,uBAAuB;IAClE,KAAK,EAAE,GAAG,CAAC;IACX,WAAW,EAAE,YAAY,GAAG,MAAM,CAAC;CACpC;AAED,MAAM,WAAW,YAAa,SAAQ,uBAAuB,EAAE,oBAAoB;IAEjF,YAAY,EAAE,aAAa,CAAC;CAC7B;AAED,MAAM,WAAW,mBAAoB,SAAQ,uBAAuB,EAAE,oBAAoB;IACxF,eAAe,CAAC,EAAE,OAAO,CAAC;CAC3B;AAED,MAAM,WAAW,sBAAsB;IAErC,YAAY,EAAE,MAAM,CAAC;IACrB,QAAQ,EAAE,SAAS,CAAC;IACpB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,OAAO,EAAE,eAAe,CAAC;IACzB,WAAW,EAAE,OAAO,CAAC,eAAe,CAAC,CAAC;IACtC,MAAM,EAAE,WAAW,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,EAAE,CAAC;IACjB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,aAAa,EAAE,MAAM,EAAE,CAAC;IAExB,WAAW,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,eAAe,CAAC,EAAE,mBAAmB,KAAK,MAAM,CAAC;IAEpF,YAAY,EAAE,CAAC,OAAO,EAAE,UAAU,EAAE,kBAAkB,CAAC,EAAE,OAAO,KAAK,MAAM,CAAC;IAE5E,YAAY,EAAE,CAAC,OAAO,EAAE,UAAU,KAAK,MAAM,CAAC;CAC/C;AAED,MAAM,WAAW,gBAAgB;IAC/B,CAAC,MAAM,EAAE,MAAM,GAAG,cAAc,CAAA;CACjC"}
@@ -0,0 +1,56 @@
1
+ import * as sql from 'mssql';
2
+ import { IFieldSchema, IPrepareArgs, IPrepareSqlStringArgs, TDBRecord, TFieldTypeCorrection, TGetRecordSchemaResult, TGetRecordSchemaOptions, TRecordSchema, TRecordSchemaAssoc, TRecordSet } from './interfaces';
3
+ export { sql };
4
+ /**
5
+ * Подготовка строки для передачи в SQL
6
+ */
7
+ export declare const prepareSqlString: (args: IPrepareSqlStringArgs) => string | null;
8
+ /**
9
+ * Корректировка схемы таблицы
10
+ * Поля с суффиксом _json получают тип "json". Остальные корректировки берутся из fieldTypeCorrection
11
+ * Например, для полей типа datetime можно передавать свойство inputDateFormat
12
+ */
13
+ export declare const correctRecordSchema: (recordSchemaAssoc: TRecordSchemaAssoc, fieldTypeCorrection?: TFieldTypeCorrection) => void;
14
+ /**
15
+ * Подготовка значений записи для использования в SQL
16
+ *
17
+ * Все поля записи обрабатываются функцией getValueForSQL
18
+ */
19
+ export declare const prepareRecordForSQL: (record: TDBRecord, args: IPrepareArgs) => void;
20
+ /**
21
+ * Подготовка данных для SQL
22
+ *
23
+ * Все поля всех записей обрабатываются функцией getValueForSQL
24
+ */
25
+ export declare const prepareDataForSQL: (recordSet: TRecordSet, args: IPrepareArgs) => void;
26
+ /**
27
+ * Возвращает рекорд, в котором все значения преобразованы в строки и подготовлены для прямой вставки в SQL
28
+ * В частности, если значение типа строка, то оно уже заключено в одинарные кавычки
29
+ */
30
+ export declare const getRecordValuesForSQL: (record: TDBRecord, recordSchema: TRecordSchema) => TDBRecord;
31
+ /**
32
+ * Возвращает схему полей таблицы БД. Либо в виде объекта, либо в виде массива
33
+ * Если asArray = true, то вернет TRecordSchema, при этом удалит поля, указанные в omitFields
34
+ * Иначе вернет TRecordSchemaAssoc
35
+ */
36
+ export declare const getRecordSchema: (connectionId: string, schemaAndTable: string, options?: TGetRecordSchemaOptions) => Promise<TGetRecordSchemaResult | undefined>;
37
+ /**
38
+ * Оборачивает инструкции SQL в транзакцию
39
+ */
40
+ export declare const wrapTransaction: (strSQL: string) => string;
41
+ /**
42
+ * Возвращает проверенное и серилизованное значение
43
+ */
44
+ export declare const serialize: (value: any, fieldSchema: IFieldSchema) => string | number | null;
45
+ /**
46
+ * Возвращает подготовленное выражение SET для использования в UPDATE
47
+ */
48
+ export declare const getSqlSetExpression: (record: TDBRecord, recordSchema: TRecordSchema) => string;
49
+ /**
50
+ * Возвращает подготовленное выражение (...поля...) VALUES (...значения...) для использования в INSERT
51
+ *
52
+ * addOutputInserted - Если true, добавляется выражение OUTPUT inserted.* перед VALUES
53
+ */
54
+ export declare const getSqlValuesExpression: (record: TDBRecord, recordSchema: TRecordSchema, addOutputInserted?: boolean) => string;
55
+ export declare const getRowsAffected: (qResult: any) => any;
56
+ //# sourceMappingURL=sql.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sql.d.ts","sourceRoot":"","sources":["../../src/sql.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,GAAG,MAAM,OAAO,CAAC;AAQ7B,OAAO,EACL,YAAY,EAES,YAAY,EACjC,qBAAqB,EAErB,SAAS,EAET,oBAAoB,EACpB,sBAAsB,EACtB,uBAAuB,EACvB,aAAa,EACb,kBAAkB,EAClB,UAAU,EAAE,MAAM,cAAc,CAAC;AAEnC,OAAO,EAAE,GAAG,EAAE,CAAC;AAEf;;GAEG;AACH,eAAO,MAAM,gBAAgB,SAAU,qBAAqB,KAAG,MAAM,GAAG,IAsBvE,CAAC;AAKF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,sBACX,kBAAkB,wBAEf,oBAAoB,SAgC3C,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,WAAY,SAAS,QAAQ,YAAY,SAiBxE,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,cAAe,UAAU,QAAQ,YAAY,SAQ1E,CAAC;AAEF;;;GAGG;AACH,eAAO,MAAM,qBAAqB,WAAY,SAAS,kCAAgC,SAYtF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,eAAe,iBAEZ,MAAM,kBAEJ,MAAM,YAEb,uBAAuB,KAC/B,QAAQ,sBAAsB,GAAG,SAAS,CA+J5C,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,eAAe,WAAY,MAAM,KAAG,MAuBtC,CAAC;AAEZ;;GAEG;AACH,eAAO,MAAM,SAAS,UAAW,GAAG,eAAe,YAAY,KAAG,MAAM,GAAG,MAAM,GAAG,IASnF,CAAC;AAEF;;GAEG;AACH,eAAO,MAAM,mBAAmB,WAAY,SAAS,kCAAgC,MASpF,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,WAAY,SAAS,mDAAkD,OAAO,KAAW,MAW3H,CAAC;AAEF,eAAO,MAAM,eAAe,YAAa,GAAG,QAAmG,CAAC"}
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Оборачивает строку в одинарные кавычки, если второй аргумент не true
3
+ */
4
+ export declare const q: (val: string, noQuotes?: boolean) => string;
5
+ /**
6
+ * Экранирование одинарной кавычки и символа % для использования строки в SQL запросе
7
+ * onlySingleQuotes - true - не экранировать %
8
+ */
9
+ export declare const mssqlEscape: (str: any, onlySingleQuotes?: boolean) => string;
10
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/utils.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,eAAO,MAAM,CAAC,QAAS,MAAM,aAAa,OAAO,KAAG,MAAuC,CAAC;AAE5F;;;GAGG;AACH,eAAO,MAAM,WAAW,QAAS,GAAG,qBAAoB,OAAO,KAAW,MAqBzE,CAAC"}
package/package.json ADDED
@@ -0,0 +1,75 @@
1
+ {
2
+ "name": "af-db-ts",
3
+ "version": "1.0.2",
4
+ "description": "A highly specialized function library",
5
+ "main": "./dist/cjs/index.js",
6
+ "module": "./dist/esm/index.js",
7
+ "types": "./dist/types/index.d.ts",
8
+ "author": "Viacheslav Makarov <npmjs@bazilio.ru>",
9
+ "license": "ISC",
10
+ "scripts": {
11
+ "test_": "mocha --require @babel/register 'test/**/**spec.js'",
12
+ "clean": "shx rm -rf dist/*",
13
+ "build": "tsc -b tsconfig.json tsconfig.esm.json tsconfig.types.json",
14
+ "lint": "eslint . --ext .ts ",
15
+ "lint:fix": "eslint . --ext .ts --fix",
16
+ "test": "jest --config jest.config.js",
17
+ "release": "npm run lint:fix && npm run clean && npm run build && npm run test",
18
+ "cb": "npm run clean && npm run build"
19
+ },
20
+ "dependencies": {
21
+ "af-color": "^0.0.8",
22
+ "af-echo-ts": "^1.0.9",
23
+ "af-tools-ts": "^1.0.53",
24
+ "config": "^3.3.9",
25
+ "lodash": "^4.17.21",
26
+ "luxon": "^3.4.2",
27
+ "memory-cache": "^0.2.0",
28
+ "moment": "^2.29.4",
29
+ "moment-timezone": "^0.5.43",
30
+ "mssql": "^9.2.0"
31
+ },
32
+ "devDependencies": {
33
+ "@babel/register": "^7.22.15",
34
+ "@jest/test-sequencer": "^29.6.4",
35
+ "@types/config": "^3.3.0",
36
+ "@types/jest": "^29.5.4",
37
+ "@types/lodash": "^4.14.197",
38
+ "@types/luxon": "^3.3.2",
39
+ "@types/memory-cache": "^0.2.3",
40
+ "@types/mssql": "^8.1.2",
41
+ "@types/node": "^20.5.9",
42
+ "@types/supertest": "^2.0.12",
43
+ "chai": "^4.3.8",
44
+ "eslint-config-af-22": "^1.0.13",
45
+ "jest": "^29.6.4",
46
+ "mocha": "^10.2.0",
47
+ "shx": "^0.3.4",
48
+ "supertest": "^6.3.3",
49
+ "ts-jest": "^29.1.1",
50
+ "ts-node": "^10.9.1",
51
+ "typescript": "^5.2.2"
52
+ },
53
+ "np": {
54
+ "yarn": false,
55
+ "contents": "."
56
+ },
57
+ "publishConfig": {
58
+ "access": "public"
59
+ },
60
+ "files": [
61
+ "dist/cjs",
62
+ "dist/esm",
63
+ "dist/types",
64
+ "src"
65
+ ],
66
+ "repository": {
67
+ "type": "git",
68
+ "url": "git+https://github.com/Bazilio-san/af-db-ts.git"
69
+ },
70
+ "engines": {
71
+ "node": ">= 14",
72
+ "npm": ">= 6.13.4",
73
+ "yarn": ">= 1.21.1"
74
+ }
75
+ }
package/src/db.ts ADDED
@@ -0,0 +1,195 @@
1
+ import * as config from 'config';
2
+ import { magenta } from 'af-color';
3
+ import { echo } from 'af-echo-ts';
4
+ import * as sql from 'mssql';
5
+ import { ConnectionPool, IResult } from 'mssql';
6
+ import * as _ from 'lodash';
7
+ import { sleep } from 'af-tools-ts';
8
+ import { IConnectionPools, TGetPoolConnectionOptions } from './interfaces';
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}`);
12
+
13
+ export const pools: IConnectionPools = {};
14
+
15
+ /**
16
+ * Возвращает пул соединений для БД, соответствующей преданному ID соединения (borf|cep|hr|global)
17
+ * В случае, если не удается создать пул или открыть соединение, прерывает работу скрипта
18
+ */
19
+ export const getPoolConnection = async (connectionId: string, options: TGetPoolConnectionOptions = {}): Promise<ConnectionPool | undefined> => {
20
+ const { prefix = '', errorCode = 0 } = options;
21
+ let pool = pools[connectionId];
22
+ if (pool?.connected) {
23
+ return pool;
24
+ }
25
+ const resume = (errMsg: string) => {
26
+ if (options.onError === 'exit') {
27
+ echo.error(prefix, `${errMsg}\nEXIT PROCESS`);
28
+ process.exit(errorCode);
29
+ } else {
30
+ throw new Error(errMsg);
31
+ }
32
+ };
33
+ try {
34
+ const cfg: any = config.get<any>('database');
35
+ const namedDbConfig = cfg[connectionId];
36
+ if (!namedDbConfig) {
37
+ resume(`Missing configuration for DB id "${connectionId}"`);
38
+ }
39
+ const dbConfig = config.util.extendDeep({}, cfg._common_ || {}, cfg[connectionId]);
40
+ if (pool?.connecting) {
41
+ const startTs = Date.now();
42
+ while (pool?.connecting && (Date.now() - startTs < dbConfig.connectionTimeout)) {
43
+ // eslint-disable-next-line no-await-in-loop
44
+ await sleep(100);
45
+ }
46
+ if (pool?.connected) {
47
+ return pool;
48
+ }
49
+ echo.error(prefix, `Can't connect connectionId "${connectionId}"`);
50
+ }
51
+ pool = new sql.ConnectionPool(dbConfig);
52
+ if (typeof pool !== 'object') {
53
+ resume(`Can't create connection pool "${connectionId}"`);
54
+ }
55
+ pools[connectionId] = pool;
56
+ // @ts-ignore
57
+ pool._connectionId = connectionId;
58
+ pool.on('close', () => {
59
+ delete pools[connectionId];
60
+ });
61
+ pool.on('error', (err) => {
62
+ echo.error('POOL-ERROR', err);
63
+ });
64
+ await pool.connect();
65
+ return pool;
66
+ } catch (err) {
67
+ echo.error(err);
68
+ resume(`Cant connect to "${connectionId}" db`);
69
+ }
70
+ };
71
+
72
+ /**
73
+ * Закрывает указанные соединения с БД
74
+ *
75
+ * poolsToClose - пул или массив пулов
76
+ * prefix - Префикс в сообщении о закрытии пула (название синхронизации)
77
+ * noEcho - подавление сообщений о закрытии соединения
78
+ */
79
+ export const closeDbConnections = async (poolsToClose: ConnectionPool | ConnectionPool[] | string | string[], prefix?: string, noEcho?: boolean) => {
80
+ if (!Array.isArray(poolsToClose)) {
81
+ // @ts-ignore
82
+ poolsToClose = [poolsToClose];
83
+ }
84
+ // @ts-ignore
85
+ for (let i = 0; i < poolsToClose.length; i++) {
86
+ let pool = poolsToClose[i];
87
+ let connectionId: string = '';
88
+ if (pool) {
89
+ if (typeof pool === 'string') {
90
+ connectionId = pool;
91
+ pool = pools[connectionId];
92
+ } else if (typeof pool === 'object') {
93
+ // @ts-ignore
94
+ connectionId = pool._connectionId;
95
+ }
96
+ if (connectionId) {
97
+ delete pools[connectionId];
98
+ }
99
+ if (pool && pool.close) {
100
+ try {
101
+ // eslint-disable-next-line no-await-in-loop
102
+ await pool.close();
103
+ if (!noEcho && connectionId) {
104
+ const msg = `pool "${connectionId}" closed`;
105
+ if (prefix) {
106
+ echo.info(prefix, msg);
107
+ } else {
108
+ echo.info(msg);
109
+ }
110
+ }
111
+ } catch (err) {
112
+ //
113
+ }
114
+ }
115
+ }
116
+ }
117
+ };
118
+
119
+ /**
120
+ * Закрывает все соединения с БД
121
+ *
122
+ * prefix - Префикс в сообщении о закрытии пула (название синхронизации)
123
+ * noEcho - подавление сообщений о закрытии соединения
124
+ */
125
+ export const closeAllDbConnections = async (prefix?: string, noEcho?: boolean) => {
126
+ const poolsToClose = _.map(pools, (p) => p);
127
+ await closeDbConnections(poolsToClose, prefix, noEcho);
128
+ };
129
+
130
+ /**
131
+ * Закрывает указанные соединения с БД и прерывает работу скрипта
132
+ *
133
+ * poolsToClose - пул или массив пулов
134
+ * prefix - Префикс в сообщении о закрытии пула (название синхронизации)
135
+ */
136
+ export const closeDbConnectionsAndExit = async (poolsToClose: ConnectionPool | ConnectionPool[], prefix?: string) => {
137
+ await closeDbConnections(poolsToClose, prefix);
138
+ process.exit(0);
139
+ };
140
+
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>;
189
+ try {
190
+ res = await request.query(textSQL);
191
+ return res;
192
+ } catch (err) {
193
+ logSqlError(err, noThrow, textSQL, prefix);
194
+ }
195
+ };