@cubejs-backend/mssql-driver 0.32.26 → 0.32.29

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/CHANGELOG.md CHANGED
@@ -3,6 +3,25 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ ## [0.32.29](https://github.com/cube-js/cube/compare/v0.32.28...v0.32.29) (2023-04-25)
7
+
8
+ **Note:** Version bump only for package @cubejs-backend/mssql-driver
9
+
10
+
11
+
12
+
13
+
14
+ ## [0.32.28](https://github.com/cube-js/cube/compare/v0.32.27...v0.32.28) (2023-04-19)
15
+
16
+
17
+ ### Bug Fixes
18
+
19
+ * **mssql-driver:** release stream connection ([#6453](https://github.com/cube-js/cube/issues/6453)) ([7113fa1](https://github.com/cube-js/cube/commit/7113fa1247f3761c9fde5f8d1af8de6036350e72))
20
+
21
+
22
+
23
+
24
+
6
25
  ## [0.32.26](https://github.com/cube-js/cube/compare/v0.32.25...v0.32.26) (2023-04-13)
7
26
 
8
27
  **Note:** Version bump only for package @cubejs-backend/mssql-driver
@@ -10,6 +10,7 @@ const {
10
10
  } = require('@cubejs-backend/shared');
11
11
  const sql = require('mssql');
12
12
  const { BaseDriver } = require('@cubejs-backend/base-driver');
13
+ const QueryStream = require('./QueryStream');
13
14
 
14
15
 
15
16
  const GenericTypeToMSSql = {
@@ -93,6 +94,129 @@ class MSSqlDriver extends BaseDriver {
93
94
  return this.initialConnectPromise.then((pool) => pool.request().query('SELECT 1 as number'));
94
95
  }
95
96
 
97
+ /**
98
+ * Executes query in streaming mode.
99
+ *
100
+ * @param {string} query
101
+ * @param {Array} values
102
+ * @param {{ highWaterMark: number? }} options
103
+ * @return {Promise<StreamTableDataWithTypes>}
104
+ */
105
+ async stream(
106
+ query,
107
+ values,
108
+ options,
109
+ ) {
110
+ const pool = await this.initialConnectPromise;
111
+ const request = pool.request();
112
+
113
+ request.stream = true;
114
+ (values || []).forEach((v, i) => {
115
+ request.input(`_${i + 1}`, v);
116
+ });
117
+ request.query(query);
118
+
119
+ const stream = new QueryStream(request, options?.highWaterMark);
120
+ const fields = await new Promise((resolve, reject) => {
121
+ request.on('recordset', (columns) => {
122
+ resolve(this.mapFields(columns));
123
+ });
124
+ request.on('error', (err) => {
125
+ reject(err);
126
+ });
127
+ });
128
+ return {
129
+ rowStream: stream,
130
+ types: fields,
131
+ release: async () => {
132
+ request.cancel();
133
+ },
134
+ };
135
+ }
136
+
137
+ /**
138
+ * @param {{
139
+ * [name: string]: {
140
+ * index: number,
141
+ * name: string,
142
+ * type: *,
143
+ * nullable: boolean,
144
+ * caseSensitive: boolean,
145
+ * identity: boolean,
146
+ * readOnly: boolean,
147
+ * length: number?,
148
+ * scale: number?,
149
+ * precision: number?
150
+ * }
151
+ * }} fields
152
+ */
153
+ mapFields(fields) {
154
+ return Object.keys(fields).map((field) => {
155
+ let type;
156
+ switch (fields[field].type) {
157
+ case sql.Bit:
158
+ type = 'boolean';
159
+ break;
160
+ // integers
161
+ case sql.Int:
162
+ case sql.SmallInt:
163
+ case sql.TinyInt:
164
+ type = 'int';
165
+ break;
166
+ // float
167
+ case sql.Real:
168
+ case sql.Money:
169
+ case sql.SmallMoney:
170
+ case sql.Numeric:
171
+ type = 'float';
172
+ break;
173
+ // double
174
+ case sql.Float:
175
+ case sql.Decimal:
176
+ type = 'double';
177
+ break;
178
+ // strings
179
+ case sql.Char:
180
+ case sql.NChar:
181
+ case sql.Text:
182
+ case sql.VarChar:
183
+ case sql.NVarChar:
184
+ case sql.Xml:
185
+ type = 'text';
186
+ break;
187
+ // date and time
188
+ case sql.Time:
189
+ type = 'date';
190
+ break;
191
+ case sql.Date:
192
+ type = 'date';
193
+ break;
194
+ case sql.DateTime:
195
+ case sql.DateTime2:
196
+ case sql.SmallDateTime:
197
+ case sql.DateTimeOffset:
198
+ type = 'date';
199
+ break;
200
+ // others
201
+ case sql.UniqueIdentifier:
202
+ case sql.Variant:
203
+ case sql.Binary:
204
+ case sql.VarBinary:
205
+ case sql.Image:
206
+ case sql.UDT:
207
+ case sql.Geography:
208
+ case sql.Geometry:
209
+ type = 'string';
210
+ break;
211
+ // unknown
212
+ default:
213
+ type = 'string';
214
+ break;
215
+ }
216
+ return { name: fields[field].name, type };
217
+ });
218
+ }
219
+
96
220
  query(query, values) {
97
221
  let cancelFn = null;
98
222
  const promise = this.initialConnectPromise.then((pool) => {
@@ -159,7 +283,11 @@ class MSSqlDriver extends BaseDriver {
159
283
  `;
160
284
  }
161
285
 
162
- async downloadQueryResults(query, values) {
286
+ async downloadQueryResults(query, values, options) {
287
+ if ((options || {}).streamImport) {
288
+ return this.stream(query, values, options);
289
+ }
290
+
163
291
  const result = await this.query(query, values);
164
292
  const types = Object.keys(result.columns).map((key) => ({
165
293
  name: result.columns[key].name,
@@ -0,0 +1,61 @@
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
+ recordset = [];
10
+ done = false;
11
+
12
+ /**
13
+ * @constructor
14
+ */
15
+ constructor(request, highWaterMark) {
16
+ super({
17
+ objectMode: true,
18
+ highWaterMark:
19
+ highWaterMark || getEnv('dbQueryStreamHighWaterMark'),
20
+ });
21
+ this.request = request;
22
+ this.request.on('row', (row) => {
23
+ this.recordset?.push(row);
24
+ if (this.recordset?.length === getEnv('dbQueryStreamHighWaterMark')) {
25
+ this.request.pause();
26
+ }
27
+ });
28
+ this.request.on('error', (err) => {
29
+ this.destroy(err);
30
+ });
31
+ this.request.on('done', () => {
32
+ this.done = true;
33
+ });
34
+ }
35
+
36
+ /**
37
+ * @override
38
+ */
39
+ _read(highWaterMark) {
40
+ const chunk = this.recordset?.splice(0, highWaterMark);
41
+ chunk?.forEach((row) => {
42
+ this.push(row);
43
+ });
44
+ if (this.recordset?.length === 0 && this.done) {
45
+ this.push(null);
46
+ } else {
47
+ this.request.resume();
48
+ }
49
+ }
50
+
51
+ /**
52
+ * @override
53
+ */
54
+ _destroy(error, callback) {
55
+ this.request = null;
56
+ this.recordset = null;
57
+ callback(error);
58
+ }
59
+ }
60
+
61
+ module.exports = QueryStream;
package/package.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "name": "@cubejs-backend/mssql-driver",
3
3
  "description": "Cube.js MS SQL database driver",
4
4
  "author": "Cube Dev, Inc.",
5
- "version": "0.32.26",
5
+ "version": "0.32.29",
6
6
  "repository": {
7
7
  "type": "git",
8
8
  "url": "https://github.com/cube-js/cube.git",
@@ -13,12 +13,12 @@
13
13
  },
14
14
  "main": "driver/MSSqlDriver.js",
15
15
  "dependencies": {
16
- "@cubejs-backend/base-driver": "^0.32.26",
16
+ "@cubejs-backend/base-driver": "^0.32.29",
17
17
  "mssql": "^6.1.0"
18
18
  },
19
19
  "license": "Apache-2.0",
20
20
  "publishConfig": {
21
21
  "access": "public"
22
22
  },
23
- "gitHead": "5e552433ab582d8f41f272bbee0fd439cc52f8cc"
23
+ "gitHead": "a41aa533c103c818511845b5df727e0502c03114"
24
24
  }