@miatechnet/node-odbc 2.4.10-multiresult.1

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/binding.gyp ADDED
@@ -0,0 +1,100 @@
1
+ {
2
+ 'targets' : [
3
+ {
4
+ 'target_name' : 'odbc',
5
+ 'sources' : [
6
+ 'src/odbc.cpp',
7
+ 'src/odbc_connection.cpp',
8
+ 'src/odbc_statement.cpp',
9
+ 'src/odbc_cursor.cpp',
10
+ 'src/dynodbc.cpp'
11
+ ],
12
+ 'cflags' : ['-Wall', '-Wextra', '-Wno-unused-parameter', '-DNAPI_DISABLE_CPP_EXCEPTIONS'],
13
+ 'include_dirs': [
14
+ '<!@(node -p "require(\'node-addon-api\').include")'
15
+ ],
16
+ 'defines' : [
17
+ 'NAPI_VERSION=<(napi_build_version)'
18
+ ],
19
+ 'conditions' : [
20
+ [ 'OS == "linux"', {
21
+ 'libraries' : [
22
+ '-lodbc'
23
+ ],
24
+ 'cflags' : [
25
+ '-g'
26
+ ]
27
+ }],
28
+ [ 'OS == "mac"', {
29
+ 'conditions': [
30
+ [ 'target_arch=="arm64"', {
31
+ 'include_dirs': [
32
+ '/opt/homebrew/include'
33
+ ],
34
+ 'libraries' : [
35
+ '-L/opt/homebrew/lib',
36
+ '-lodbc'
37
+ ],
38
+ }], ['target_arch=="x64"', {
39
+ 'include_dirs': [
40
+ '/usr/local/include',
41
+ ],
42
+ 'libraries' : [
43
+ '-L/usr/local/lib',
44
+ '-lodbc'
45
+ ],
46
+ }],
47
+ ],
48
+ 'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ]
49
+ }],
50
+ [ 'OS == "freebsd"', {
51
+ 'include_dirs': [
52
+ '/usr/local/include'
53
+ ],
54
+ 'libraries' : [
55
+ '-L/usr/local/lib',
56
+ '-lodbc'
57
+ ],
58
+ 'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS' ]
59
+ }],
60
+ [ 'OS=="win"', {
61
+ 'sources' : [
62
+ 'src/odbc.cpp'
63
+ ],
64
+ 'libraries' : [
65
+ '-lodbccp32.lib'
66
+ ],
67
+ 'defines': [ 'NAPI_DISABLE_CPP_EXCEPTIONS', 'UNICODE' ]
68
+ }],
69
+ [ 'OS=="aix"', {
70
+ 'variables': {
71
+ 'os_name': '<!(uname -s)',
72
+ },
73
+ 'conditions': [
74
+ [ '"<(os_name)"=="OS400"', {
75
+ 'ldflags': [
76
+ '-Wl,-brtl,-blibpath:/QOpenSys/pkgs/lib,-lodbc'
77
+ ],
78
+ 'cflags' : ['-std=c++0x', '-DNAPI_DISABLE_CPP_EXCEPTIONS', '-Wall', '-Wextra', '-Wno-unused-parameter', '-I/QOpenSys/usr/include', '-I/QOpenSys/pkgs/include']
79
+ }]
80
+ ]
81
+ }],
82
+ [ 'OS=="os400"', {
83
+ 'ldflags': ['-Wl,-blibpath:/QOpenSys/pkgs/lib', '-lodbc'],
84
+ 'cflags' : ['-std=c++0x', '-DNAPI_DISABLE_CPP_EXCEPTIONS', '-Wall', '-Wextra', '-Wno-unused-parameter', '-I/QOpenSys/usr/include', '-I/QOpenSys/pkgs/include']
85
+ }]
86
+ ]
87
+ },
88
+ {
89
+ "target_name": "action_after_build",
90
+ "type": "none",
91
+ "dependencies": [ "<(module_name)" ],
92
+ "copies": [
93
+ {
94
+ "files": [ "<(PRODUCT_DIR)/<(module_name).node" ],
95
+ "destination": "<(module_path)"
96
+ }
97
+ ]
98
+ }
99
+ ]
100
+ }
@@ -0,0 +1,521 @@
1
+ const { Statement } = require('./Statement');
2
+ const { Cursor } = require('./Cursor');
3
+
4
+ class Connection {
5
+
6
+ CONNECTION_CLOSED_ERROR = 'Connection has already been closed!';
7
+
8
+ /**
9
+ * An open connection to the database made through an ODBC driver
10
+ * @constructor
11
+ * @param {string|object} connectionString - The connection string to connect using the DSN
12
+ * defined in odbc.ini, or an odbcConnection object
13
+ */
14
+ constructor(odbcConnection) {
15
+ this.odbcConnection = odbcConnection;
16
+ }
17
+
18
+ get connected() {
19
+ if (!this.odbcConnection)
20
+ {
21
+ return false;
22
+ }
23
+ return this.odbcConnection.connected;
24
+ }
25
+
26
+ get autocommit() {
27
+ if (!this.odbcConnection)
28
+ {
29
+ throw new Error(CONNECTION_CLOSED_ERROR);
30
+ }
31
+ return this.odbcConnection.autocommit;
32
+ }
33
+
34
+ // TODO: Write the documentation
35
+ /**
36
+ *
37
+ * @param {*} sql
38
+ * @param {*} params
39
+ * @param {*} cb
40
+ */
41
+ query(sql, params, opts, cb) {
42
+ // accepted parameter signatures:
43
+ // sql
44
+ // sql, params
45
+ // sql, opts
46
+ // sql, params, opts
47
+ // sql, cb
48
+ // sql, params, cb
49
+ // sql, opts, cb
50
+ // sql, params, opts, cb
51
+
52
+ let callback = cb;
53
+ let parameters = params;
54
+ let options = opts;
55
+
56
+ // If callback is undefined, search for a function in another position
57
+ if (typeof callback === 'undefined')
58
+ {
59
+ if (typeof options === 'function')
60
+ {
61
+ callback = options;
62
+ options = undefined;
63
+ }
64
+ else if(typeof parameters === 'function')
65
+ {
66
+ callback = parameters;
67
+ options = undefined;
68
+ parameters = undefined;
69
+ }
70
+ }
71
+
72
+ if (typeof options === 'undefined')
73
+ {
74
+ if (typeof parameters === 'object' && parameters !== null && !Array.isArray(parameters))
75
+ {
76
+ options = parameters;
77
+ parameters = null;
78
+ } else {
79
+ options = null;
80
+ }
81
+ }
82
+
83
+ // if explicitly passing undefined into parameters, need to change to null
84
+ if (typeof parameters === 'undefined') {
85
+ parameters = null;
86
+ }
87
+
88
+ if (
89
+ typeof sql !== 'string' ||
90
+ (parameters !== null && !Array.isArray(parameters)) ||
91
+ (options !== null && typeof options !== 'object') ||
92
+ (typeof callback !== 'function' && typeof callback !== 'undefined')
93
+ )
94
+ {
95
+ throw new TypeError('[node-odbc]: Incorrect function signature for call to connection.query({string}, {array}[optional], {object}[optional], {function}[optional]).');
96
+ }
97
+
98
+ if (typeof callback !== 'function') {
99
+ if (!this.odbcConnection)
100
+ {
101
+ throw new Error(Connection.CONNECTION_CLOSED_ERROR);
102
+ }
103
+ return new Promise((resolve, reject) => {
104
+ this.odbcConnection.query(sql, parameters, options, (error, result) => {
105
+ if (error) {
106
+ reject(error);
107
+ } else {
108
+ if (options &&
109
+ (
110
+ options.hasOwnProperty('fetchSize') ||
111
+ options.hasOwnProperty('cursor')
112
+ )
113
+ )
114
+ {
115
+ const cursor = new Cursor(result);
116
+ resolve(cursor);
117
+ }
118
+ else
119
+ {
120
+ resolve(result);
121
+ }
122
+ }
123
+ });
124
+ });
125
+ }
126
+
127
+ if (!this.odbcConnection) {
128
+ callback(new Error(Connection.CONNECTION_CLOSED_ERROR));
129
+ } else {
130
+ process.nextTick(() => {
131
+ if (options &&
132
+ (
133
+ options.hasOwnProperty('fetchSize') ||
134
+ options.hasOwnProperty('cursor')
135
+ )
136
+ )
137
+ {
138
+ this.odbcConnection.query(sql, parameters, options, (error, result) => {
139
+ if (error) {
140
+ return callback(error);
141
+ }
142
+
143
+ const cursor = new Cursor(result);
144
+ return callback(error, cursor);
145
+ });
146
+ }
147
+ else
148
+ {
149
+ this.odbcConnection.query(sql, parameters, options, callback);
150
+ }
151
+ });
152
+ }
153
+ }
154
+
155
+ /**
156
+ *
157
+ * @param {string} name
158
+ * @param {Array} parameters
159
+ * @param {function} [cb]
160
+ */
161
+ callProcedure(catalog, schema, name, params = undefined, cb = undefined) {
162
+ // name
163
+ // name, params
164
+ // name, cb
165
+ // name, params, cb
166
+
167
+ let callback = cb;
168
+ let parameters = params;
169
+
170
+ if (typeof callback === 'undefined') {
171
+ if (typeof parameters === 'function') {
172
+ callback = parameters;
173
+ parameters = null;
174
+ } else if (typeof parameters === 'undefined') {
175
+ parameters = null;
176
+ }
177
+ }
178
+
179
+ // if explicitly passing undefined into parameters, need to change to null
180
+ if (typeof parameters === 'undefined') {
181
+ parameters = null;
182
+ }
183
+
184
+ if (typeof name !== 'string'
185
+ || (parameters !== null && !Array.isArray(parameters))
186
+ || (typeof callback !== 'function' && typeof callback !== 'undefined')) {
187
+ throw new TypeError('[node-odbc]: Incorrect function signature for call to connection.query({string}, {array}[optional], {function}[optional]).');
188
+ }
189
+
190
+ // promise...
191
+ if (callback === undefined) {
192
+ if (!this.odbcConnection)
193
+ {
194
+ throw new Error(Connection.CONNECTION_CLOSED_ERROR);
195
+ }
196
+ return new Promise((resolve, reject) => {
197
+ this.odbcConnection.callProcedure(catalog, schema, name, parameters, (error, result) => {
198
+ if (error) {
199
+ reject(error);
200
+ } else {
201
+ resolve(result);
202
+ }
203
+ });
204
+ });
205
+ }
206
+
207
+ // ...or callback
208
+ if (!this.odbcConnection) {
209
+ callback(new Error(Connection.CONNECTION_CLOSED_ERROR));
210
+ } else {
211
+ this.odbcConnection.callProcedure(catalog, schema, name, parameters, callback);
212
+ }
213
+ }
214
+
215
+ // TODO: Write the documentation
216
+ /**
217
+ *
218
+ * @param {*} callback
219
+ */
220
+ createStatement(callback = undefined) {
221
+ // type-checking
222
+ if (typeof callback !== 'function' && typeof callback !== 'undefined') {
223
+ throw new TypeError('[node-odbc]: Incorrect function signature for call to connection.createStatement({function}[optional]).');
224
+ }
225
+
226
+ // promise...
227
+ if (callback === undefined) {
228
+ if (!this.odbcConnection)
229
+ {
230
+ throw new Error(Connection.CONNECTION_CLOSED_ERROR);
231
+ }
232
+ return new Promise((resolve, reject) => {
233
+ this.odbcConnection.createStatement((error, odbcStatement) => {
234
+ if (error) {
235
+ reject(error);
236
+ } else {
237
+ const statement = new Statement(odbcStatement);
238
+ resolve(statement);
239
+ }
240
+ });
241
+ });
242
+ }
243
+
244
+
245
+ // ...or callback
246
+ if (!this.odbcConnection) {
247
+ callback(new Error(Connection.CONNECTION_CLOSED_ERROR));
248
+ } else {
249
+ this.odbcConnection.createStatement((error, odbcStatement) => {
250
+ if (error) { return callback(error, null); }
251
+
252
+ const statement = new Statement(odbcStatement);
253
+ callback(null, statement);
254
+ });
255
+ }
256
+ }
257
+
258
+ /** TODO:
259
+ * Get the value of the passed attribute from the connection. Asynchronous, can be used either
260
+ * with a callback function or a Promise.
261
+ * @param {string} attribute - The title of the book.
262
+ * @param {function} [callback] - Callback function. If not passed, a Promise will be returned.
263
+ */
264
+ close(callback = undefined) {
265
+ // type-checking
266
+ if (typeof callback !== 'function' && typeof callback !== 'undefined') {
267
+ throw new TypeError('[node-odbc]: Incorrect function signature for call to connection.close({function}[optional]).');
268
+ }
269
+
270
+ // promise...
271
+ if (callback === undefined) {
272
+ if (!this.odbcConnection)
273
+ {
274
+ throw new Error(Connection.CONNECTION_CLOSED_ERROR);
275
+ }
276
+ return new Promise((resolve, reject) => {
277
+ this.odbcConnection.close((error) => {
278
+ if (error) {
279
+ reject(error);
280
+ } else {
281
+ this.odbcConnection = null;
282
+ resolve();
283
+ }
284
+ });
285
+ });
286
+ }
287
+
288
+ // ...or callback
289
+ return this.odbcConnection.close((error) => {
290
+ if (!error)
291
+ {
292
+ this.odbcConnection = null;
293
+ }
294
+ return callback(error);
295
+ });
296
+ }
297
+
298
+ // TODO: Documentation
299
+ primaryKeys(catalog, schema, table, callback = undefined) {
300
+ // promise...
301
+ if (callback === undefined) {
302
+ if (!this.odbcConnection)
303
+ {
304
+ throw new Error(Connection.CONNECTION_CLOSED_ERROR);
305
+ }
306
+ return new Promise((resolve, reject) => {
307
+ this.odbcConnection.primaryKeys(catalog, schema, table, (error, result) => {
308
+ if (error) {
309
+ reject(error);
310
+ } else {
311
+ resolve(result);
312
+ }
313
+ });
314
+ });
315
+ }
316
+
317
+ // ...or callback
318
+ if (!this.odbcConnection) {
319
+ callback(new Error(Connection.CONNECTION_CLOSED_ERROR));
320
+ } else {
321
+ this.odbcConnection.primaryKeys(catalog, schema, table, callback);
322
+ }
323
+ }
324
+
325
+ // TODO: Documentation
326
+ foreignKeys(catalog, schema, table, fkCatalog, fkSchema, fkTable, callback = undefined) {
327
+ // promise...
328
+ if (callback === undefined) {
329
+ if (!this.odbcConnection)
330
+ {
331
+ throw new Error(Connection.CONNECTION_CLOSED_ERROR);
332
+ }
333
+ return new Promise((resolve, reject) => {
334
+ this.odbcConnection.foreignKeys(catalog, schema, table, fkCatalog, fkSchema, fkTable, (error, result) => {
335
+ if (error) {
336
+ reject(error);
337
+ } else {
338
+ resolve(result);
339
+ }
340
+ });
341
+ });
342
+ }
343
+
344
+ // ...or callback
345
+ if (!this.odbcConnection) {
346
+ callback(new Error(Connection.CONNECTION_CLOSED_ERROR));
347
+ } else {
348
+ this.odbcConnection.foreignKeys(catalog, schema, table, fkCatalog, fkSchema, fkTable, callback);
349
+ }
350
+ }
351
+
352
+ // TODO: Documentation
353
+ columns(catalog, schema, table, type, callback = undefined) {
354
+ // promise...
355
+ if (callback === undefined) {
356
+ if (!this.odbcConnection)
357
+ {
358
+ throw new Error(Connection.CONNECTION_CLOSED_ERROR);
359
+ }
360
+ return new Promise((resolve, reject) => {
361
+ this.odbcConnection.columns(catalog, schema, table, type, (error, result) => {
362
+ if (error) {
363
+ reject(error);
364
+ } else {
365
+ resolve(result);
366
+ }
367
+ });
368
+ });
369
+ }
370
+
371
+ // ...or callback
372
+ if (!this.odbcConnection) {
373
+ callback(new Error(Connection.CONNECTION_CLOSED_ERROR));
374
+ } else {
375
+ this.odbcConnection.columns(catalog, schema, table, type, callback);
376
+ }
377
+ }
378
+
379
+ // TODO: Documentation
380
+ tables(catalog, schema, table, type, callback = undefined) {
381
+ // promise...
382
+ if (callback === undefined) {
383
+ if (!this.odbcConnection)
384
+ {
385
+ throw new Error(Connection.CONNECTION_CLOSED_ERROR);
386
+ }
387
+ return new Promise((resolve, reject) => {
388
+ this.odbcConnection.tables(catalog, schema, table, type, (error, result) => {
389
+ if (error) {
390
+ reject(error);
391
+ } else {
392
+ resolve(result);
393
+ }
394
+ });
395
+ });
396
+ }
397
+
398
+ // ...or callback
399
+ if (!this.odbcConnection) {
400
+ callback(new Error(Connection.CONNECTION_CLOSED_ERROR));
401
+ } else {
402
+ this.odbcConnection.tables(catalog, schema, table, type, callback);
403
+ }
404
+ }
405
+
406
+ // TODO: Documentation
407
+ setIsolationLevel(isolationLevel, callback = undefined) {
408
+ // promise...
409
+ if (callback === undefined) {
410
+ if (!this.odbcConnection)
411
+ {
412
+ throw new Error(Connection.CONNECTION_CLOSED_ERROR);
413
+ }
414
+ return new Promise((resolve, reject) => {
415
+ this.odbcConnection.setIsolationLevel(isolationLevel, (error) => {
416
+ if (error) {
417
+ reject(error);
418
+ } else {
419
+ resolve();
420
+ }
421
+ });
422
+ });
423
+ }
424
+
425
+ // ...or callback
426
+ if (!this.odbcConnection) {
427
+ callback(new Error(Connection.CONNECTION_CLOSED_ERROR));
428
+ } else {
429
+ this.odbcConnection.setIsolationLevel(isolationLevel, callback);
430
+ }
431
+ }
432
+
433
+ /**
434
+ * Begins a transaction, turning off auto-commit. Transaction is ended with commit() or
435
+ * rollback().
436
+ * @param {function} [callback] - Callback function. If not passed, a Promise will be returned.
437
+ */
438
+ beginTransaction(callback = undefined) {
439
+ // promise...
440
+ if (callback === undefined) {
441
+ if (!this.odbcConnection)
442
+ {
443
+ throw new Error(Connection.CONNECTION_CLOSED_ERROR);
444
+ }
445
+ return new Promise((resolve, reject) => {
446
+ this.odbcConnection.beginTransaction((error, result) => {
447
+ if (error) {
448
+ reject(error);
449
+ } else {
450
+ resolve(result);
451
+ }
452
+ });
453
+ });
454
+ }
455
+
456
+ // ...or callback
457
+ if (!this.odbcConnection) {
458
+ callback(new Error(Connection.CONNECTION_CLOSED_ERROR));
459
+ } else {
460
+ this.odbcConnection.beginTransaction(callback);
461
+ }
462
+ }
463
+
464
+ /**
465
+ * Asynchronously ends the transaction with a commit.
466
+ * @param {function} [callback] - Callback function. If not passed, a Promise will be returned.
467
+ */
468
+ commit(callback = undefined) {
469
+ if (callback === undefined) {
470
+ if (!this.odbcConnection)
471
+ {
472
+ throw new Error(Connection.CONNECTION_CLOSED_ERROR);
473
+ }
474
+ return new Promise((resolve, reject) => {
475
+ this.odbcConnection.commit((error) => {
476
+ if (error) {
477
+ reject(error);
478
+ } else {
479
+ resolve();
480
+ }
481
+ });
482
+ });
483
+ }
484
+
485
+ if (!this.odbcConnection) {
486
+ callback(new Error(Connection.CONNECTION_CLOSED_ERROR));
487
+ } else {
488
+ this.odbcConnection.commit(callback);
489
+ }
490
+ }
491
+
492
+ /**
493
+ * Asynchronously ends the transaction with a rollback.
494
+ * @param {function} [callback] - Callback function. If not passed, a Promise will be returned.
495
+ */
496
+ rollback(callback = undefined) {
497
+ if (callback === undefined) {
498
+ if (!this.odbcConnection)
499
+ {
500
+ throw new Error(Connection.CONNECTION_CLOSED_ERROR);
501
+ }
502
+ return new Promise((resolve, reject) => {
503
+ this.odbcConnection.rollback((error) => {
504
+ if (error) {
505
+ reject(error);
506
+ } else {
507
+ resolve();
508
+ }
509
+ });
510
+ });
511
+ }
512
+
513
+ if (!this.odbcConnection) {
514
+ callback(new Error(Connection.CONNECTION_CLOSED_ERROR));
515
+ } else {
516
+ this.odbcConnection.rollback(callback);
517
+ }
518
+ }
519
+ }
520
+
521
+ module.exports.Connection = Connection;
package/lib/Cursor.js ADDED
@@ -0,0 +1,92 @@
1
+ class Cursor {
2
+
3
+ static CURSOR_CLOSED_ERROR = 'Cursor has already been closed!';
4
+
5
+ /**
6
+ * An cursor created following the execution of query that is ready to return a result set
7
+ * @constructor
8
+ * @param {object} odbcCursor - an odbcCursor object, defined in src/odbc_cursor.h/.cpp
9
+ */
10
+ constructor(odbcCursor) {
11
+ this.odbcCursor = odbcCursor;
12
+ }
13
+
14
+ /**
15
+ * Return whether or not a call to SQLFetch has returned SQL_NO_DATA
16
+ * @returns {boolean}
17
+ *
18
+ */
19
+ get noData() {
20
+ if (!this.odbcCursor)
21
+ {
22
+ throw new Error(Cursor.CURSOR_CLOSED_ERROR);
23
+ }
24
+ return this.odbcCursor.noData;
25
+ }
26
+
27
+ /**
28
+ * Calls SQL_FETCH and returns the next result set
29
+ * @param {function} [cb] - The callback function to return an error and a result. If the callback is ommited, a Promise is returned.
30
+ * @returns {undefined|Promise}
31
+ */
32
+ fetch(cb) {
33
+
34
+ let callback = cb;
35
+
36
+ if (typeof callback !== 'function') {
37
+ if (!this.odbcCursor) {
38
+ throw new Error(Cursor.CURSOR_CLOSED_ERROR);
39
+ }
40
+ return new Promise((resolve, reject) => {
41
+ this.odbcCursor.fetch((error, result) => {
42
+ if (error) {
43
+ reject(error);
44
+ } else {
45
+ resolve(result);
46
+ }
47
+ });
48
+ });
49
+ }
50
+
51
+ if (!this.odbcCursor) {
52
+ callback(new Error(Cursor.CURSOR_CLOSED_ERROR));
53
+ } else {
54
+ this.odbcCursor.fetch(callback);
55
+ }
56
+ }
57
+
58
+ /**
59
+ * Closes the cursor and the underlying SQLHSTMT, freeing all memory
60
+ * @param {function} [callback] - The callback function to return an error. If the callback is ommited, a Promise is returned.
61
+ * @returns {undefined|Promise}
62
+ */
63
+ close(callback = undefined) {
64
+
65
+ // promise...
66
+ if (typeof callback !== 'function') {
67
+ if (!this.odbcCursor) {
68
+ throw new Error(Cursor.CURSOR_CLOSED_ERROR);
69
+ }
70
+ return new Promise((resolve, reject) => {
71
+ this.odbcCursor.close((error) => {
72
+ if (error) {
73
+ reject(error);
74
+ } else {
75
+ this.odbcCursor = null;
76
+ resolve();
77
+ }
78
+ });
79
+ });
80
+ }
81
+
82
+ // ...or callback
83
+ this.odbcCursor.close((error) => {
84
+ if (!error) {
85
+ this.odbcCursor = null;
86
+ }
87
+ callback(error);
88
+ });
89
+ }
90
+ }
91
+
92
+ module.exports.Cursor = Cursor;