@cubejs-backend/mssql-driver 1.3.4 → 1.3.6

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.
@@ -1,340 +0,0 @@
1
- /**
2
- * @copyright Cube Dev, Inc.
3
- * @license Apache-2.0
4
- * @fileoverview The `MSSqlDriver` and related types declaration.
5
- */
6
-
7
- const {
8
- getEnv,
9
- assertDataSource,
10
- } = require('@cubejs-backend/shared');
11
- const sql = require('mssql');
12
- const { BaseDriver } = require('@cubejs-backend/base-driver');
13
- const QueryStream = require('./QueryStream');
14
-
15
-
16
- const GenericTypeToMSSql = {
17
- boolean: 'bit',
18
- string: 'nvarchar(max)',
19
- text: 'nvarchar(max)',
20
- timestamp: 'datetime2',
21
- uuid: 'uniqueidentifier'
22
- };
23
-
24
- const MSSqlToGenericType = {
25
- bit: 'boolean',
26
- uniqueidentifier: 'uuid',
27
- datetime2: 'timestamp'
28
- }
29
-
30
- /**
31
- * MS SQL driver class.
32
- */
33
- class MSSqlDriver extends BaseDriver {
34
- /**
35
- * Returns default concurrency value.
36
- */
37
- static getDefaultConcurrency() {
38
- return 2;
39
- }
40
-
41
- /**
42
- * Class constructor.
43
- */
44
- constructor(config = {}) {
45
- super({
46
- testConnectionTimeout: config.testConnectionTimeout,
47
- });
48
-
49
- const dataSource =
50
- config.dataSource ||
51
- assertDataSource('default');
52
-
53
- /**
54
- * @type {import('mssql').config}
55
- */
56
- this.config = {
57
- readOnly: true,
58
- server: getEnv('dbHost', { dataSource }),
59
- database: getEnv('dbName', { dataSource }),
60
- port: getEnv('dbPort', { dataSource }),
61
- user: getEnv('dbUser', { dataSource }),
62
- password: getEnv('dbPass', { dataSource }),
63
- domain: getEnv('dbDomain', { dataSource }),
64
- requestTimeout: getEnv('dbQueryTimeout') * 1000,
65
- options: {
66
- encrypt: getEnv('dbSsl', { dataSource }),
67
- useUTC: false
68
- },
69
- pool: {
70
- max:
71
- config.maxPoolSize ||
72
- getEnv('dbMaxPoolSize', { dataSource }) ||
73
- 8,
74
- min: 0,
75
- idleTimeoutMillis: 30 * 1000,
76
- acquireTimeoutMillis: 20 * 1000
77
- },
78
- ...config
79
- };
80
- const { readOnly, ...poolConfig } = this.config;
81
- this.connectionPool = new sql.ConnectionPool(poolConfig);
82
- this.initialConnectPromise = this.connectionPool.connect();
83
- }
84
-
85
- /**
86
- * Returns the configurable driver options
87
- * Note: It returns the unprefixed option names.
88
- * In case of using multisources options need to be prefixed manually.
89
- */
90
- static driverEnvVariables() {
91
- return [
92
- 'CUBEJS_DB_HOST',
93
- 'CUBEJS_DB_NAME',
94
- 'CUBEJS_DB_PORT',
95
- 'CUBEJS_DB_USER',
96
- 'CUBEJS_DB_PASS',
97
- 'CUBEJS_DB_DOMAIN',
98
- ];
99
- }
100
-
101
- testConnection() {
102
- return this.initialConnectPromise.then((pool) => pool.request().query('SELECT 1 as number'));
103
- }
104
-
105
- /**
106
- * Executes query in streaming mode.
107
- *
108
- * @param {string} query
109
- * @param {Array} values
110
- * @param {{ highWaterMark: number? }} options
111
- * @return {Promise<StreamTableDataWithTypes>}
112
- */
113
- async stream(
114
- query,
115
- values,
116
- options,
117
- ) {
118
- const pool = await this.initialConnectPromise;
119
- const request = pool.request();
120
-
121
- request.stream = true;
122
- (values || []).forEach((v, i) => {
123
- request.input(`_${i + 1}`, v);
124
- });
125
- request.query(query);
126
-
127
- const stream = new QueryStream(request, options?.highWaterMark);
128
- const fields = await new Promise((resolve, reject) => {
129
- request.on('recordset', (columns) => {
130
- resolve(this.mapFields(columns));
131
- });
132
- request.on('error', (err) => {
133
- reject(err);
134
- });
135
- stream.on('error', (err) => {
136
- reject(err);
137
- })
138
- });
139
- return {
140
- rowStream: stream,
141
- types: fields,
142
- release: async () => {
143
- request.cancel();
144
- },
145
- };
146
- }
147
-
148
- /**
149
- * @param {{
150
- * [name: string]: {
151
- * index: number,
152
- * name: string,
153
- * type: *,
154
- * nullable: boolean,
155
- * caseSensitive: boolean,
156
- * identity: boolean,
157
- * readOnly: boolean,
158
- * length: number?,
159
- * scale: number?,
160
- * precision: number?
161
- * }
162
- * }} fields
163
- */
164
- mapFields(fields) {
165
- return Object.keys(fields).map((field) => {
166
- let type;
167
- switch (fields[field].type) {
168
- case sql.Bit:
169
- type = 'boolean';
170
- break;
171
- // integers
172
- case sql.Int:
173
- case sql.SmallInt:
174
- case sql.TinyInt:
175
- case sql.BigInt:
176
- type = 'int';
177
- break;
178
- // float
179
- case sql.Money:
180
- case sql.SmallMoney:
181
- case sql.Numeric:
182
- case sql.Decimal:
183
- type = 'decimal';
184
- break;
185
- // double
186
- case sql.Real:
187
- case sql.Float:
188
- type = 'double';
189
- break;
190
- // strings
191
- case sql.Char:
192
- case sql.NChar:
193
- case sql.Text:
194
- case sql.NText:
195
- case sql.VarChar:
196
- case sql.NVarChar:
197
- case sql.Xml:
198
- type = 'text';
199
- break;
200
- // date and time
201
- case sql.Time:
202
- type = 'time';
203
- break;
204
- case sql.Date:
205
- type = 'timestamp';
206
- break;
207
- case sql.DateTime:
208
- case sql.DateTime2:
209
- case sql.SmallDateTime:
210
- case sql.DateTimeOffset:
211
- type = 'timestamp';
212
- break;
213
- // others
214
- case sql.UniqueIdentifier:
215
- case sql.Variant:
216
- case sql.Binary:
217
- case sql.VarBinary:
218
- case sql.Image:
219
- case sql.UDT:
220
- case sql.Geography:
221
- case sql.Geometry:
222
- case sql.TVP:
223
- type = 'string';
224
- break;
225
- // unknown
226
- default:
227
- type = 'string';
228
- break;
229
- }
230
- return { name: fields[field].name, type: this.toGenericType(type) };
231
- });
232
- }
233
-
234
- query(query, values) {
235
- let cancelFn = null;
236
- const promise = this.initialConnectPromise.then((pool) => {
237
- const request = pool.request();
238
- (values || []).forEach((v, i) => request.input(`_${i + 1}`, v));
239
-
240
- // TODO time zone UTC set in driver ?
241
-
242
- cancelFn = () => request.cancel();
243
- return request.query(query).then(res => res.recordset);
244
- });
245
- promise.cancel = () => cancelFn && cancelFn();
246
- return promise;
247
- }
248
-
249
- param(paramIndex) {
250
- return `@_${paramIndex + 1}`;
251
- }
252
-
253
- async tableColumnTypes(table) {
254
- const [schema, name] = table.split('.');
255
-
256
- const columns = await this.query(
257
- `SELECT column_name as ${this.quoteIdentifier('column_name')},
258
- table_name as ${this.quoteIdentifier('table_name')},
259
- table_schema as ${this.quoteIdentifier('table_schema')},
260
- data_type as ${this.quoteIdentifier('data_type')}
261
- FROM INFORMATION_SCHEMA.COLUMNS
262
- WHERE table_name = ${this.param(0)} AND table_schema = ${this.param(1)}`,
263
- [name, schema]
264
- );
265
-
266
- return columns.map(c => ({ name: c.column_name, type: this.toGenericType(c.data_type) }));
267
- }
268
-
269
- getTablesQuery(schemaName) {
270
- return this.query(
271
- `SELECT table_name FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = ${this.param(0)}`,
272
- [schemaName]
273
- );
274
- }
275
-
276
- createSchemaIfNotExists(schemaName) {
277
- return this.query(
278
- `SELECT schema_name FROM INFORMATION_SCHEMA.SCHEMATA WHERE schema_name = ${this.param(0)}`,
279
- [schemaName]
280
- ).then((schemas) => {
281
- if (schemas.length === 0) {
282
- return this.query(`CREATE SCHEMA ${schemaName}`);
283
- }
284
- return null;
285
- });
286
- }
287
-
288
- informationSchemaQuery() {
289
- // fix The multi-part identifier "columns.data_type" could not be bound
290
- return `
291
- SELECT column_name as ${this.quoteIdentifier('column_name')},
292
- table_name as ${this.quoteIdentifier('table_name')},
293
- table_schema as ${this.quoteIdentifier('table_schema')},
294
- data_type as ${this.quoteIdentifier('data_type')}
295
- FROM INFORMATION_SCHEMA.COLUMNS
296
- WHERE table_schema NOT IN ('information_schema', 'sys')
297
- `;
298
- }
299
-
300
- async downloadQueryResults(query, values, options) {
301
- if ((options || {}).streamImport) {
302
- return this.stream(query, values, options);
303
- }
304
-
305
- const result = await this.query(query, values);
306
- const types = Object.keys(result.columns).map((key) => ({
307
- name: result.columns[key].name,
308
- type: this.toGenericType(result.columns[key].type.declaration),
309
- }));
310
-
311
- return {
312
- rows: result,
313
- types,
314
- };
315
- }
316
-
317
- fromGenericType(columnType) {
318
- return GenericTypeToMSSql[columnType] || super.fromGenericType(columnType);
319
- }
320
-
321
- toGenericType(columnType){
322
- return MSSqlToGenericType[columnType] || super.toGenericType(columnType);
323
- }
324
-
325
- readOnly() {
326
- return !!this.config.readOnly;
327
- }
328
-
329
- wrapQueryWithLimit(query) {
330
- query.query = `SELECT TOP ${query.limit} * FROM (${query.query}) AS t`;
331
- }
332
-
333
- capabilities() {
334
- return {
335
- incrementalSchemaLoading: true,
336
- };
337
- }
338
- }
339
-
340
- module.exports = MSSqlDriver;
@@ -1,62 +0,0 @@
1
- const { Readable } = require('stream');
2
- const { getEnv } = require('@cubejs-backend/shared');
3
-
4
- /**
5
- * MS-SQL query stream class.
6
- */
7
- class QueryStream extends Readable {
8
- request = null;
9
- toRead = 0;
10
-
11
- /**
12
- * @constructor
13
- */
14
- constructor(request, highWaterMark) {
15
- super({
16
- objectMode: true,
17
- highWaterMark:
18
- highWaterMark || getEnv('dbQueryStreamHighWaterMark'),
19
- });
20
- this.request = request;
21
- this.request.on('row', row => {
22
- this.transformRow(row);
23
- const canAdd = this.push(row);
24
- if (this.toRead-- <= 0 || !canAdd) {
25
- this.request.pause();
26
- }
27
- })
28
- this.request.on('done', () => {
29
- this.push(null);
30
- })
31
- this.request.on('error', (err) => {
32
- this.destroy(err);
33
- });
34
- }
35
-
36
- /**
37
- * @override
38
- */
39
- _read(toRead) {
40
- this.toRead += toRead;
41
- this.request.resume();
42
- }
43
-
44
- transformRow(row) {
45
- for (const key in row) {
46
- if (row.hasOwnProperty(key) && row[key] && row[key] instanceof Date) {
47
- row[key] = row[key].toJSON();
48
- }
49
- }
50
- }
51
-
52
- /**
53
- * @override
54
- */
55
- _destroy(error, callback) {
56
- this.request.cancel();
57
- this.request = null;
58
- callback(error);
59
- }
60
- }
61
-
62
- module.exports = QueryStream;
package/driver/index.d.ts DELETED
@@ -1,9 +0,0 @@
1
- import { BaseDriver } from "@cubejs-backend/query-orchestrator";
2
- import { config } from "mssql";
3
-
4
- declare module "@cubejs-backend/mssql-driver" {
5
- export default class MSSqlDriver extends BaseDriver {
6
- constructor(options?: config);
7
- release(): Promise<void>
8
- }
9
- }