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.
- package/README.md +3 -0
- package/dist/cjs/db.js +199 -0
- package/dist/cjs/db.js.map +1 -0
- package/dist/cjs/get-value-for-sql.js +256 -0
- package/dist/cjs/get-value-for-sql.js.map +1 -0
- package/dist/cjs/index.js +20 -0
- package/dist/cjs/index.js.map +1 -0
- package/dist/cjs/interfaces.js +3 -0
- package/dist/cjs/interfaces.js.map +1 -0
- package/dist/cjs/sql.js +375 -0
- package/dist/cjs/sql.js.map +1 -0
- package/dist/cjs/utils.js +36 -0
- package/dist/cjs/utils.js.map +1 -0
- package/dist/esm/db.js +185 -0
- package/dist/esm/db.js.map +1 -0
- package/dist/esm/get-value-for-sql.js +251 -0
- package/dist/esm/get-value-for-sql.js.map +1 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/interfaces.js +2 -0
- package/dist/esm/interfaces.js.map +1 -0
- package/dist/esm/sql.js +361 -0
- package/dist/esm/sql.js.map +1 -0
- package/dist/esm/utils.js +31 -0
- package/dist/esm/utils.js.map +1 -0
- package/dist/types/db.d.ts +39 -0
- package/dist/types/db.d.ts.map +1 -0
- package/dist/types/get-value-for-sql.d.ts +7 -0
- package/dist/types/get-value-for-sql.d.ts.map +1 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/interfaces.d.ts +181 -0
- package/dist/types/interfaces.d.ts.map +1 -0
- package/dist/types/sql.d.ts +56 -0
- package/dist/types/sql.d.ts.map +1 -0
- package/dist/types/utils.d.ts +10 -0
- package/dist/types/utils.d.ts.map +1 -0
- package/package.json +75 -0
- package/src/db.ts +195 -0
- package/src/get-value-for-sql.ts +271 -0
- package/src/index.ts +47 -0
- package/src/interfaces.ts +232 -0
- package/src/sql.ts +403 -0
- package/src/utils.ts +31 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import { DateTime } from 'luxon';
|
|
2
|
+
import { getBool, rn } from 'af-tools-ts';
|
|
3
|
+
import { IGetValueForSQLArgs, IPrepareSqlStringArgs } from './interfaces';
|
|
4
|
+
import { prepareSqlString, sql } from './sql';
|
|
5
|
+
import { mssqlEscape, q } from './utils';
|
|
6
|
+
|
|
7
|
+
export const binToHexString = (value: any) => (value ? `0x${value.toString(16).toUpperCase()}` : null);
|
|
8
|
+
|
|
9
|
+
const getTypeOfDateInput = (v: any): 'string' | 'number' | 'date' | 'luxon' | 'moment' | 'any' | 'null' => {
|
|
10
|
+
const type = typeof v;
|
|
11
|
+
if (type === 'string' || type === 'number') {
|
|
12
|
+
return type;
|
|
13
|
+
}
|
|
14
|
+
if (type === 'boolean' || !v) {
|
|
15
|
+
return 'null';
|
|
16
|
+
}
|
|
17
|
+
if (type === 'object') {
|
|
18
|
+
if (Object.prototype.toString.call(v) === '[object Date]') {
|
|
19
|
+
return 'date';
|
|
20
|
+
}
|
|
21
|
+
if (v.isLuxonDateTime) {
|
|
22
|
+
return 'luxon';
|
|
23
|
+
}
|
|
24
|
+
if (v._isAMomentObject) {
|
|
25
|
+
return 'moment';
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
return 'any';
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Возвращает значение, готовое для использования в строке SQL запроса
|
|
33
|
+
*/
|
|
34
|
+
export const getValueForSQL = (args: IGetValueForSQLArgs): string | number | null => {
|
|
35
|
+
let { value, fieldSchema, escapeOnlySingleQuotes } = args;
|
|
36
|
+
const { dateTimeOptions, needValidate } = args;
|
|
37
|
+
if (typeof fieldSchema === 'string') {
|
|
38
|
+
fieldSchema = { type: fieldSchema };
|
|
39
|
+
}
|
|
40
|
+
const {
|
|
41
|
+
type,
|
|
42
|
+
arrayType,
|
|
43
|
+
length = 0,
|
|
44
|
+
scale,
|
|
45
|
+
nullable = true,
|
|
46
|
+
inputDateFormat,
|
|
47
|
+
defaultValue,
|
|
48
|
+
noQuotes = false,
|
|
49
|
+
name,
|
|
50
|
+
} = fieldSchema;
|
|
51
|
+
let val;
|
|
52
|
+
const IS_POSTGRES = args.dialect === 'pg';
|
|
53
|
+
|
|
54
|
+
if (escapeOnlySingleQuotes == null) {
|
|
55
|
+
({ escapeOnlySingleQuotes } = fieldSchema);
|
|
56
|
+
}
|
|
57
|
+
if (escapeOnlySingleQuotes == null) {
|
|
58
|
+
escapeOnlySingleQuotes = false;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
function prepareNumber (min: number, max: number, value_ = value) {
|
|
62
|
+
if (value_ === 'null' || value_ == null || Number.isNaN(value_)) {
|
|
63
|
+
if (nullable) {
|
|
64
|
+
return 'NULL';
|
|
65
|
+
}
|
|
66
|
+
return (defaultValue || defaultValue === 0) ? `${defaultValue}` : null;
|
|
67
|
+
}
|
|
68
|
+
val = Number(value_);
|
|
69
|
+
if (needValidate && (val < min || val > max)) {
|
|
70
|
+
// throwValidateError()
|
|
71
|
+
throw new Error(`Type [${type}] validate error. Value: ${val} / FName: ${name}`);
|
|
72
|
+
}
|
|
73
|
+
return `${val}`;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const prepareSqlStringArgs: IPrepareSqlStringArgs = {
|
|
77
|
+
value, nullable, length, defaultValue, noQuotes, escapeOnlySingleQuotes,
|
|
78
|
+
};
|
|
79
|
+
switch (type) {
|
|
80
|
+
case 'json':
|
|
81
|
+
if (Array.isArray(value) || typeof value === 'object') {
|
|
82
|
+
value = JSON.stringify(value);
|
|
83
|
+
}
|
|
84
|
+
return prepareSqlString({ ...prepareSqlStringArgs, value });
|
|
85
|
+
|
|
86
|
+
case 'string':
|
|
87
|
+
case sql.Char:
|
|
88
|
+
case sql.NChar:
|
|
89
|
+
case sql.Text:
|
|
90
|
+
case sql.NText:
|
|
91
|
+
case sql.VarChar:
|
|
92
|
+
case sql.NVarChar:
|
|
93
|
+
case sql.Xml:
|
|
94
|
+
return prepareSqlString(prepareSqlStringArgs);
|
|
95
|
+
|
|
96
|
+
case 'uid':
|
|
97
|
+
case 'uuid':
|
|
98
|
+
case 'uniqueIdentifier':
|
|
99
|
+
case sql.UniqueIdentifier:
|
|
100
|
+
if (!value || typeof value !== 'string' || !/^[A-F\d]{8}(-[A-F\d]{4}){4}[A-F\d]{8}/i.test(value)) {
|
|
101
|
+
value = null;
|
|
102
|
+
} else {
|
|
103
|
+
value = value.substring(0, 36).toUpperCase();
|
|
104
|
+
}
|
|
105
|
+
return prepareSqlString({ ...prepareSqlStringArgs, value, length: 0 });
|
|
106
|
+
|
|
107
|
+
case 'datetime':
|
|
108
|
+
case 'date':
|
|
109
|
+
case 'time':
|
|
110
|
+
case sql.DateTime:
|
|
111
|
+
case sql.DateTime2:
|
|
112
|
+
case sql.Time:
|
|
113
|
+
case sql.Date:
|
|
114
|
+
case sql.SmallDateTime:
|
|
115
|
+
case sql.DateTimeOffset: {
|
|
116
|
+
let millis = 0;
|
|
117
|
+
val = value;
|
|
118
|
+
|
|
119
|
+
let inputType = getTypeOfDateInput(value); // 'string' | 'number' | 'date' | 'luxon' | 'moment' | 'any' | 'null'
|
|
120
|
+
|
|
121
|
+
if (inputType === 'null') {
|
|
122
|
+
if (nullable) {
|
|
123
|
+
return 'NULL';
|
|
124
|
+
}
|
|
125
|
+
inputType = 'number';
|
|
126
|
+
val = 0;
|
|
127
|
+
} else if (inputType === 'any') {
|
|
128
|
+
inputType = 'string';
|
|
129
|
+
val = String(value);
|
|
130
|
+
}
|
|
131
|
+
switch (inputType) {
|
|
132
|
+
case 'number':
|
|
133
|
+
millis = val;
|
|
134
|
+
break;
|
|
135
|
+
case 'date':
|
|
136
|
+
millis = +val;
|
|
137
|
+
break;
|
|
138
|
+
case 'luxon':
|
|
139
|
+
millis = val.isValid ? val.toMillis() : 0;
|
|
140
|
+
break;
|
|
141
|
+
case 'moment':
|
|
142
|
+
millis = val.isValid() ? +val : 0;
|
|
143
|
+
break;
|
|
144
|
+
// string and other
|
|
145
|
+
default: {
|
|
146
|
+
val = String(value);
|
|
147
|
+
millis = (inputDateFormat
|
|
148
|
+
? DateTime.fromFormat(val, inputDateFormat, dateTimeOptions)
|
|
149
|
+
: DateTime.fromISO(val, dateTimeOptions)).toMillis();
|
|
150
|
+
break;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
millis = Math.max(millis + (dateTimeOptions?.correctionMillis || 0), 0);
|
|
154
|
+
const luxonDate = DateTime.fromMillis(millis);
|
|
155
|
+
|
|
156
|
+
switch (type) {
|
|
157
|
+
case 'datetime':
|
|
158
|
+
case sql.DateTime:
|
|
159
|
+
case sql.DateTime2:
|
|
160
|
+
return q(luxonDate.toISO({ includeOffset: false }) || '', noQuotes); // 2023-09-05T02:23:54.105
|
|
161
|
+
case 'time':
|
|
162
|
+
case sql.Time:
|
|
163
|
+
return q((luxonDate.toISOTime() || '').substring(0, 12), noQuotes); // 02:22:17.368
|
|
164
|
+
case 'date':
|
|
165
|
+
case sql.Date:
|
|
166
|
+
return q(luxonDate.toSQLDate() || '', noQuotes); // 2023-09-05
|
|
167
|
+
case sql.SmallDateTime:
|
|
168
|
+
return q(`${(luxonDate.toISO() || '').substring(0, 17)}00`, noQuotes); // 2023-09-05T02:20:00
|
|
169
|
+
case sql.DateTimeOffset: { // VVQ TESTS
|
|
170
|
+
const dotScale = scale == null ? 3 : scale;
|
|
171
|
+
const re = /\.(\d+)(?=[^.]*$)/;
|
|
172
|
+
let str = luxonDate.toISO({ includeOffset: false }) || '';
|
|
173
|
+
if (!dotScale) {
|
|
174
|
+
str = str.replace(re, `.000`);
|
|
175
|
+
} else {
|
|
176
|
+
val = inputType === 'string' ? value : str;
|
|
177
|
+
let [, fracSeconds = '0'] = re.exec(val) || [];
|
|
178
|
+
let floatSeconds = parseFloat((`1.${fracSeconds}`));
|
|
179
|
+
floatSeconds = rn(floatSeconds, dotScale);
|
|
180
|
+
fracSeconds = (`${floatSeconds}0000000`).substring(2, 2 + dotScale);
|
|
181
|
+
str = str.replace(re, `.${fracSeconds}`);
|
|
182
|
+
}
|
|
183
|
+
return q(str, noQuotes);
|
|
184
|
+
}
|
|
185
|
+
default:
|
|
186
|
+
return q(luxonDate.toISO({ includeOffset: false }) || '', noQuotes); // 2023-09-05T02:23:54.105
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
case 'boolean':
|
|
191
|
+
case sql.Bit: {
|
|
192
|
+
val = getBool(value);
|
|
193
|
+
if (IS_POSTGRES) {
|
|
194
|
+
return val ? 'true' : 'false';
|
|
195
|
+
}
|
|
196
|
+
return val ? '1' : '0';
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
case sql.TinyInt:
|
|
200
|
+
return prepareNumber(0, 255);
|
|
201
|
+
case 'smallint':
|
|
202
|
+
case sql.SmallInt:
|
|
203
|
+
return prepareNumber(-32768, 32767);
|
|
204
|
+
case 'int':
|
|
205
|
+
case sql.Int:
|
|
206
|
+
case 'integer':
|
|
207
|
+
return prepareNumber(-2147483648, 2147483647);
|
|
208
|
+
case sql.BigInt:
|
|
209
|
+
// eslint-disable-next-line no-loss-of-precision
|
|
210
|
+
return prepareNumber(-9223372036854775808, 9223372036854775807);
|
|
211
|
+
case 'number':
|
|
212
|
+
case sql.Decimal:
|
|
213
|
+
case sql.Float:
|
|
214
|
+
case sql.Money:
|
|
215
|
+
case sql.Numeric:
|
|
216
|
+
case sql.SmallMoney:
|
|
217
|
+
case sql.Real:
|
|
218
|
+
if (value == null) {
|
|
219
|
+
if (nullable) {
|
|
220
|
+
return 'NULL';
|
|
221
|
+
}
|
|
222
|
+
return (defaultValue || defaultValue === 0) ? `${defaultValue}` : null;
|
|
223
|
+
}
|
|
224
|
+
return `${value}`;
|
|
225
|
+
case sql.Binary:
|
|
226
|
+
case sql.VarBinary:
|
|
227
|
+
case sql.Image:
|
|
228
|
+
if (value == null) {
|
|
229
|
+
if (nullable) {
|
|
230
|
+
return 'NULL';
|
|
231
|
+
}
|
|
232
|
+
if (!defaultValue) return null;
|
|
233
|
+
}
|
|
234
|
+
return binToHexString(value);
|
|
235
|
+
case sql.UDT:
|
|
236
|
+
case sql.Geography:
|
|
237
|
+
case sql.Geometry:
|
|
238
|
+
case sql.Variant:
|
|
239
|
+
return prepareSqlString(prepareSqlStringArgs);
|
|
240
|
+
case 'array': {
|
|
241
|
+
let arr: any[] = [];
|
|
242
|
+
if (Array.isArray(value) && value.length) {
|
|
243
|
+
switch (arrayType) {
|
|
244
|
+
case 'int':
|
|
245
|
+
case 'integer':
|
|
246
|
+
arr = value.map((v) => prepareNumber(-2147483648, 2147483647, v));
|
|
247
|
+
break;
|
|
248
|
+
default: // + case 'string'
|
|
249
|
+
arr = value.map((v) => {
|
|
250
|
+
if (v === '') {
|
|
251
|
+
return v;
|
|
252
|
+
}
|
|
253
|
+
if (v == null) {
|
|
254
|
+
return null;
|
|
255
|
+
}
|
|
256
|
+
return mssqlEscape(String(value));
|
|
257
|
+
})
|
|
258
|
+
.filter((v) => v != null)
|
|
259
|
+
.map((v) => `"${v}"`);
|
|
260
|
+
break;
|
|
261
|
+
}
|
|
262
|
+
}
|
|
263
|
+
if (arr.length) {
|
|
264
|
+
return `{${arr.join(',')}`;
|
|
265
|
+
}
|
|
266
|
+
return '{}';
|
|
267
|
+
}
|
|
268
|
+
default:
|
|
269
|
+
return prepareSqlString(prepareSqlStringArgs);
|
|
270
|
+
}
|
|
271
|
+
};
|
package/src/index.ts
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
export * as db from './db';
|
|
2
|
+
|
|
3
|
+
export {
|
|
4
|
+
prepareSqlString,
|
|
5
|
+
correctRecordSchema,
|
|
6
|
+
getRecordSchema,
|
|
7
|
+
wrapTransaction,
|
|
8
|
+
serialize,
|
|
9
|
+
getRecordValuesForSQL,
|
|
10
|
+
getSqlSetExpression,
|
|
11
|
+
getSqlValuesExpression,
|
|
12
|
+
prepareRecordForSQL,
|
|
13
|
+
prepareDataForSQL,
|
|
14
|
+
getRowsAffected,
|
|
15
|
+
} from './sql';
|
|
16
|
+
|
|
17
|
+
export {
|
|
18
|
+
binToHexString,
|
|
19
|
+
getValueForSQL,
|
|
20
|
+
} from './get-value-for-sql';
|
|
21
|
+
|
|
22
|
+
export {
|
|
23
|
+
IDBConfig,
|
|
24
|
+
IFieldSchema,
|
|
25
|
+
IGetMergeSQLOptions,
|
|
26
|
+
TDBRecord,
|
|
27
|
+
TFieldName,
|
|
28
|
+
TFieldTypeCorrection,
|
|
29
|
+
TGetRecordSchemaOptions,
|
|
30
|
+
TRecordSchema,
|
|
31
|
+
TRecordSchemaAssoc,
|
|
32
|
+
TRecordSet,
|
|
33
|
+
TRecordSetAssoc,
|
|
34
|
+
TMergeRules,
|
|
35
|
+
TMergeResult,
|
|
36
|
+
TRecordKey,
|
|
37
|
+
TGetPoolConnectionOptions,
|
|
38
|
+
TGetRecordSchemaResult,
|
|
39
|
+
IPrepareSqlStringArgs,
|
|
40
|
+
IGetValueForSQLArgs,
|
|
41
|
+
IDialect,
|
|
42
|
+
DateTimeOptionsEx,
|
|
43
|
+
IPrepareArgs,
|
|
44
|
+
IPrepareRecordParams,
|
|
45
|
+
ISchemaItem,
|
|
46
|
+
IValueForSQLPartialArgs,
|
|
47
|
+
} from './interfaces';
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import { ConnectionPool, IColumnMetadata, ISqlType } from 'mssql';
|
|
2
|
+
import { DateTimeOptions } from 'luxon';
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Имя поля БД
|
|
6
|
+
*/
|
|
7
|
+
export type TFieldName = string;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Значение ключевого поля записи БД
|
|
11
|
+
*/
|
|
12
|
+
export type TRecordKey = string | number;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Метаинформация о поле БД
|
|
16
|
+
*/
|
|
17
|
+
export interface IFieldSchema {
|
|
18
|
+
index?: number,
|
|
19
|
+
name?: string,
|
|
20
|
+
length?: number,
|
|
21
|
+
type?: any,
|
|
22
|
+
arrayType?: any,
|
|
23
|
+
scale?: number,
|
|
24
|
+
precision?: number,
|
|
25
|
+
nullable?: boolean,
|
|
26
|
+
caseSensitive?: boolean,
|
|
27
|
+
identity?: boolean,
|
|
28
|
+
excludeFromInsert?: boolean,
|
|
29
|
+
readOnly?: boolean,
|
|
30
|
+
inputDateFormat?: string,
|
|
31
|
+
defaultValue?: any,
|
|
32
|
+
noQuotes?: boolean,
|
|
33
|
+
escapeOnlySingleQuotes?: boolean,
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
/**
|
|
37
|
+
* Массив объектов с метаинформацией о полях
|
|
38
|
+
*/
|
|
39
|
+
export type TRecordSchema = IFieldSchema[]
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Метаинформацией о полях, проиндексированная именами полей. (sql.recordset.columns)
|
|
43
|
+
*/
|
|
44
|
+
export interface TRecordSchemaAssoc {
|
|
45
|
+
[fieldName: TFieldName]: IFieldSchema
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Объект корректировки типов полей. Наименованию поля соответствует новый тип.
|
|
50
|
+
*
|
|
51
|
+
* В частности, используется для полей, хранящих знаяения типа json в поле типа varchar(max)
|
|
52
|
+
* тогда необходимо явно задать тип поля "json". Если имя поля заканчивается на _json, коррекция типа произойдет автоматически.
|
|
53
|
+
* Также используется для указания входного формата для преобразования строки в тип datetime (свойство inputDateFormat в схеме поля)
|
|
54
|
+
*/
|
|
55
|
+
export interface TFieldTypeCorrection {
|
|
56
|
+
[fieldName: TFieldName]: IFieldSchema
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// =============================== records =====================================
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Запись БД. Объект, проиндексированный именами полей. Значения - значения полей
|
|
63
|
+
*/
|
|
64
|
+
export interface TDBRecord {
|
|
65
|
+
[fieldName: TFieldName]: any
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Массив записей БД
|
|
70
|
+
*
|
|
71
|
+
* _isPreparedForSQL - Признак того, что значения полей подготовлены для использования в строке SQL
|
|
72
|
+
*/
|
|
73
|
+
export type TRecordSet = TDBRecord[] & { _isPreparedForSQL?: boolean }
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Пакет записей БД.
|
|
77
|
+
* Объект, проиндексированный алиасами. Каждый подобъект содержит TDBRecord.
|
|
78
|
+
*/
|
|
79
|
+
export interface TRecordSetAssoc {
|
|
80
|
+
[recordKey: TRecordKey]: TDBRecord
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
export interface TMergeResult {
|
|
84
|
+
// кол-во затронутых записей
|
|
85
|
+
total: number,
|
|
86
|
+
// кол-во добавленных записей
|
|
87
|
+
inserted: number,
|
|
88
|
+
// кол-во измененных записей
|
|
89
|
+
updated: number,
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Метаинформация для формирования инструкции SQL MERGE
|
|
94
|
+
*/
|
|
95
|
+
export interface TMergeRules {
|
|
96
|
+
// массив имен полей, идентифицирующих запись, используемый в выражении ON в MERGE
|
|
97
|
+
mergeIdentity?: TFieldName[],
|
|
98
|
+
// массив имен полей, исключаемых из списка при вставке в MERGE. Обычно это автоинкрементное поле.
|
|
99
|
+
excludeFromInsert?: TFieldName[],
|
|
100
|
+
// если true - старые не нулевые значения полей не будут перезаписаны нулами при апдейте
|
|
101
|
+
noUpdateIfNull?: boolean,
|
|
102
|
+
correction?: Function,
|
|
103
|
+
withClause?: string,
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface TGetRecordSchemaOptions {
|
|
107
|
+
// массив имен полей, которые нужно удалить из схемы (не уитывается, если asArray = false)
|
|
108
|
+
omitFields?: string[],
|
|
109
|
+
// массив имен полей, которые нужно оставить в схеме
|
|
110
|
+
pickFields?: string[],
|
|
111
|
+
// кол-во измененных записей
|
|
112
|
+
fieldTypeCorrection?: TFieldTypeCorrection,
|
|
113
|
+
mergeRules?: TMergeRules,
|
|
114
|
+
noReturnMergeResult?: boolean,
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export interface TGetPoolConnectionOptions {
|
|
118
|
+
// Префикс в сообщении о закрытии пула (название синхронизации)
|
|
119
|
+
prefix?: string,
|
|
120
|
+
// Что делать при ошибке соединения:
|
|
121
|
+
// 'exit' - завершить скрипт,
|
|
122
|
+
// 'throw' - бросить исключение.
|
|
123
|
+
// Если не задано - только сообщать в консоль.
|
|
124
|
+
onError?: 'exit' | 'throw'
|
|
125
|
+
errorCode?: number
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
export type IDialect = 'mssql' | 'pg';
|
|
129
|
+
|
|
130
|
+
interface IDBConfigCommon {
|
|
131
|
+
dialect: IDialect,
|
|
132
|
+
port: string | number | null,
|
|
133
|
+
database: string,
|
|
134
|
+
user: string,
|
|
135
|
+
password: string,
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
interface IDBConfigMSSQL extends IDBConfigCommon {
|
|
139
|
+
server: string,
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
interface IDBConfigPG extends IDBConfigCommon {
|
|
143
|
+
host: string,
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
export type IDBConfig = IDBConfigMSSQL | IDBConfigPG
|
|
147
|
+
|
|
148
|
+
export interface ISchemaItem {
|
|
149
|
+
index: number;
|
|
150
|
+
name: string;
|
|
151
|
+
length: number;
|
|
152
|
+
type: (() => ISqlType) | ISqlType;
|
|
153
|
+
udt?: any;
|
|
154
|
+
scale?: number | undefined;
|
|
155
|
+
precision?: number | undefined;
|
|
156
|
+
nullable: boolean;
|
|
157
|
+
caseSensitive: boolean;
|
|
158
|
+
identity: boolean;
|
|
159
|
+
readOnly: boolean;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
export interface IPrepareSqlStringArgs {
|
|
163
|
+
// Значение, которое нужно подготовить для передачи в SQL
|
|
164
|
+
value: string | number | null,
|
|
165
|
+
// Значение, которое будет подставлено, если передано null | undefined и nullable = false
|
|
166
|
+
defaultValue?: string | null | undefined,
|
|
167
|
+
// Ограничение на длину поля. Если передано, строка урезается
|
|
168
|
+
length?: number,
|
|
169
|
+
// Подставлять NULL, если значение пусто или пустая строка.
|
|
170
|
+
nullable?: boolean | number,
|
|
171
|
+
noQuotes?: boolean,
|
|
172
|
+
escapeOnlySingleQuotes?: boolean,
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
export interface DateTimeOptionsEx extends DateTimeOptions {
|
|
176
|
+
correctionMillis: number,
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
export interface IValueForSQLPartialArgs {
|
|
180
|
+
dateTimeOptions?: DateTimeOptionsEx,
|
|
181
|
+
dialect?: IDialect
|
|
182
|
+
escapeOnlySingleQuotes?: boolean,
|
|
183
|
+
needValidate?: boolean, // Флаг необходимости валидации значения
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export interface IPrepareRecordParams {
|
|
187
|
+
// Если TRUE - в записи добавляются пропущенные поля со значениями NULL, '', ...
|
|
188
|
+
addMissingFields?: boolean,
|
|
189
|
+
// Для полей, не допускающих NULL будет добавлено наиболее подходящее значение
|
|
190
|
+
addValues4NotNullableFields?: boolean,
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export interface IGetValueForSQLArgs extends IValueForSQLPartialArgs {
|
|
194
|
+
value: any,
|
|
195
|
+
fieldSchema: IFieldSchema | string,
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
export interface IPrepareArgs extends IValueForSQLPartialArgs, IPrepareRecordParams {
|
|
199
|
+
// объект описания структуры таблицы
|
|
200
|
+
recordSchema: TRecordSchema,
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
export interface IGetMergeSQLOptions extends IValueForSQLPartialArgs, IPrepareRecordParams {
|
|
204
|
+
isPrepareForSQL?: boolean,
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export interface TGetRecordSchemaResult {
|
|
208
|
+
|
|
209
|
+
connectionId: string,
|
|
210
|
+
dbConfig: IDBConfig,
|
|
211
|
+
schemaAndTable: string,
|
|
212
|
+
dbSchemaAndTable: string,
|
|
213
|
+
columns: IColumnMetadata,
|
|
214
|
+
schemaAssoc: Partial<IColumnMetadata>,
|
|
215
|
+
schema: ISchemaItem[],
|
|
216
|
+
fields: string[],
|
|
217
|
+
insertFields: string[],
|
|
218
|
+
insertFieldsList: string,
|
|
219
|
+
withClause: string | undefined,
|
|
220
|
+
updateFields: string[],
|
|
221
|
+
mergeIdentity: string[],
|
|
222
|
+
|
|
223
|
+
getMergeSQL: (_packet: TRecordSet, _prepareOptions?: IGetMergeSQLOptions) => string,
|
|
224
|
+
|
|
225
|
+
getInsertSQL: (_packet: TRecordSet, _addOutputInserted?: boolean) => string,
|
|
226
|
+
|
|
227
|
+
getUpdateSQL: (_record: TRecordSet) => string,
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export interface IConnectionPools {
|
|
231
|
+
[poolId: string]: ConnectionPool
|
|
232
|
+
}
|