monetdb 1.3.3 → 2.0.0

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 (47) hide show
  1. package/.github/workflows/Linux.yml +45 -0
  2. package/.github/workflows/docs.yml +79 -0
  3. package/.github/workflows/macos.yml +43 -0
  4. package/.github/workflows/monetdb-versions.yml +43 -0
  5. package/README.md +43 -512
  6. package/docs/components/alert.tsx +10 -0
  7. package/docs/components/info.tsx +6 -0
  8. package/docs/next.config.js +24 -0
  9. package/docs/package-lock.json +5069 -0
  10. package/docs/package.json +22 -0
  11. package/docs/pages/_app.js +9 -0
  12. package/docs/pages/_meta.json +16 -0
  13. package/docs/pages/apis/_meta.json +4 -0
  14. package/docs/pages/apis/connection.mdx +60 -0
  15. package/docs/pages/apis/result.mdx +39 -0
  16. package/docs/pages/index.mdx +27 -0
  17. package/docs/theme.config.js +35 -0
  18. package/docs/v1/README.md +532 -0
  19. package/package.json +17 -21
  20. package/src/PrepareStatement.ts +37 -0
  21. package/src/connection.ts +125 -0
  22. package/src/defaults.ts +13 -0
  23. package/src/file-transfer.ts +173 -0
  24. package/src/index.ts +3 -0
  25. package/src/mapi.ts +1016 -0
  26. package/src/monetize.ts +67 -0
  27. package/test/connection.ts +43 -0
  28. package/test/exec-queries.ts +100 -0
  29. package/test/filetransfer.ts +94 -0
  30. package/test/prepare-statement.ts +27 -0
  31. package/test/query-stream.ts +41 -0
  32. package/test/tmp/.gitignore +4 -0
  33. package/tsconfig.json +24 -0
  34. package/.travis.yml +0 -11
  35. package/index.js +0 -5
  36. package/src/mapi-connection.js +0 -784
  37. package/src/monetdb-connection.js +0 -385
  38. package/src/utils.js +0 -27
  39. package/test/common.js +0 -45
  40. package/test/install-monetdb.sh +0 -11
  41. package/test/monetdb_stream.js +0 -106
  42. package/test/start-monetdb.sh +0 -38
  43. package/test/test.js +0 -908
  44. package/test/test_connection.js +0 -290
  45. /package/docs/{README.v0.md → v0/README.v0.md} +0 -0
  46. /package/docs/{MapiConnection.md → v1/MapiConnection.md} +0 -0
  47. /package/docs/{v1-notes.md → v1/v1-notes.md} +0 -0
package/test/test.js DELETED
@@ -1,908 +0,0 @@
1
- var chai = require("chai");
2
- var chaiAsPromised = require("chai-as-promised");
3
- var Q = require("q");
4
-
5
- var should = chai.should();
6
- const expect = chai.expect;
7
- chai.use(chaiAsPromised);
8
-
9
- var mdb = require("../index.js");
10
-
11
- function noop() {}
12
-
13
- function getMDB() {
14
- return mdb({warnings: false, dbname: "test"});
15
- }
16
-
17
- function shouldHaveValidResult(query, nrRows, nrCols, colNames) {
18
- var colObj = colNames.reduce(function(o, v, i) {
19
- o[v] = i;
20
- return o;
21
- }, {});
22
- return Q.all([
23
- query.should.not.be.rejected,
24
- query.should.eventually.have.all.keys(["rows", "cols", "data", "col", "structure", "queryid", "type"]),
25
- query.should.eventually.have.property("rows", nrRows),
26
- query.should.eventually.have.property("cols", nrCols),
27
- query.should.eventually.have.property("col")
28
- .that.is.an("object")
29
- .that.deep.equals(colObj),
30
- query.should.eventually.have.property("queryid")
31
- .that.is.a("number"),
32
- query.should.eventually.have.property("type")
33
- .that.equals("table"),
34
- query.should.eventually.have.property("structure")
35
- .that.is.an("array")
36
- .with.length(nrCols)
37
- .and.has.property("0")
38
- .that.has.all.keys(["table", "column", "type", "typelen", "index"])
39
- ]).then(function() {
40
- return query;
41
- });
42
- }
43
-
44
- // The Javascript built in random function does not offer giving in a seed, making failing test cases
45
- // based on random things a bit annoying to reproduce. Hence, we create a (not so) random function
46
- // that looks random enough for testing purposes, and does offer a seed-based sequence.
47
- var seed = 1;
48
- function notSoRandom() {
49
- var x = Math.sin(seed++) * 10000;
50
- return x - Math.floor(x);
51
- }
52
-
53
- function constructCurTimezoneStr() {
54
- var tzOffset = new Date().getTimezoneOffset();
55
- var negative = tzOffset < 0;
56
- if(negative) tzOffset = -tzOffset;
57
- var tzOffsetHours = Math.floor(tzOffset / 60);
58
- var tzOffsetMinutes = parseInt(tzOffset % 60);
59
- var tzOffsetHoursStr = (tzOffsetHours < 10 ? "0" : "") + tzOffsetHours;
60
- var tzOffsetMinutesStr = (tzOffsetMinutes < 10 ? "0" : "") + tzOffsetMinutes;
61
- return (negative ? "-" : "+") + tzOffsetHoursStr + ":" + tzOffsetMinutesStr;
62
- }
63
-
64
-
65
- describe("#Options", function() {
66
- describe("##Global/Local options", function() {
67
- it("should throw exception when global option has wrong type", function () {
68
- (function () {
69
- mdb({dbname: 2, warnings: false});
70
- }).should.throw(Error);
71
- });
72
-
73
- it("should throw exception when local option has wrong type", function () {
74
- (function () {
75
- new (mdb({warnings: false}))({dbname: 2});
76
- }).should.throw(Error);
77
- });
78
-
79
- it("should not throw exception when global required options are missing", function () {
80
- (function () {
81
- mdb({warnings: false});
82
- }).should.not.throw(Error);
83
- });
84
-
85
- it("should throw exception when local required option is missing", function () {
86
- (function () {
87
- new (mdb({warnings: false}))();
88
- }).should.throw(Error);
89
- });
90
-
91
- it("should not throw exception when local required option was given globally", function () {
92
- (function () {
93
- new (mdb({dbname: "test", warnings: false}))();
94
- }).should.not.throw(Error);
95
- });
96
-
97
- it("should use default if both global and local are not given", function () {
98
- new (mdb({dbname: "test", warnings: false}))()
99
- .option("user").should.equal("monetdb");
100
- });
101
-
102
- it("should use global if global is given but local isn't", function () {
103
- new (mdb({dbname: "test", warnings: false, user: "custom"}))()
104
- .option("user").should.equal("custom");
105
- });
106
-
107
- it("should use local if both global and local are given", function () {
108
- new (mdb({dbname: "test", warnings: false, user: "custom"}))({user: "other"})
109
- .option("user").should.equal("other");
110
- });
111
-
112
- it("should use local if only local is given", function () {
113
- new (mdb({dbname: "test", warnings: false}))({user: "other"})
114
- .option("user").should.equal("other");
115
- });
116
- });
117
-
118
- describe("##MonetDBConnection.option", function() {
119
- var conn = new (mdb({dbname: "test", warnings: false}))();
120
- it("should throw exception on getting unknown option", function () {
121
- (function () {
122
- conn.option("veryinvalidoption");
123
- }).should.throw(Error);
124
- });
125
-
126
- it("should throw exception on setting unknown option", function () {
127
- (function () {
128
- conn.option("veryinvalidoption", "value");
129
- }).should.throw(Error);
130
- });
131
-
132
- it("should properly get option", function () {
133
- conn.option("dbname").should.equal("test");
134
- });
135
-
136
- it("should throw exception on setting unchangeable option", function() {
137
- (function () {
138
- conn.option("dbname", "otherdb");
139
- }).should.throw(Error);
140
- });
141
-
142
- it("should throw exception on setting option with wrong type", function() {
143
- (function () {
144
- conn.option("maxReconnects", "whatever");
145
- }).should.throw(Error);
146
- });
147
-
148
- it("should properly set option", function() {
149
- conn.option("reconnectTimeout", 5000);
150
- conn.option("reconnectTimeout").should.equal(5000);
151
- });
152
- });
153
- });
154
-
155
- describe("#Logging", function() {
156
- // this.timeout(10000);
157
-
158
- let calls = 0;
159
- function increaseCalls() { ++calls; }
160
-
161
- before('Before', function() {
162
- calls = 0;
163
- });
164
-
165
-
166
- it("should give warning for unrecognized options when debug is set to true", function() {
167
- const conn = new (mdb({warningFn: increaseCalls}))({dbname: "test", hopefullyNotAnOption: 1});
168
- calls.should.be.above(0);
169
- conn.close();
170
- });
171
-
172
- it("should be done at least once for debug messages during connect", async function() {
173
- const conn = new (mdb({dbname: "test", logger: increaseCalls, warnings: false, debug: true}))();
174
- await conn.connect();
175
- calls.should.be.above(0);
176
- conn.close();
177
- });
178
-
179
- it("should be done at least once for debugMapi messages during connect", async function() {
180
- calls = 0;
181
- conn = new (mdb({dbname: "test", logger: increaseCalls, warnings: false, debugMapi: true}))();
182
- await conn.connect();
183
- calls.should.be.above(0);
184
- conn.close();
185
- });
186
-
187
- it("should be done at least once for debugRequests messages during connect", async function() {
188
- conn = new (mdb({dbname: "test", logger: increaseCalls, warnings: false, debugRequests: true}))();
189
- await conn.connect();
190
- calls.should.be.above(0);
191
- conn.close();
192
- });
193
-
194
- it("should be done at least once for debugRequests messages on failing query", async function() {
195
- conn = new (mdb({dbname: "test", logger: increaseCalls, warnings: false, debugRequests: true}))();
196
- try {
197
- await conn.connect();
198
- await conn.query("WILL NOT PASS");
199
- } catch(err) {
200
- calls.should.be.above(0);
201
- } finally {
202
- conn.close();
203
- }
204
- });
205
-
206
- // it("should give warning when queries are issued before a call to connect", async function() {
207
- // const conn = new (mdb({warningFn: increaseCalls, warnings: true}))({dbname: "test"});
208
- // try {
209
- // await conn.query("SELECT 42");
210
- // await conn.connect();
211
- // } catch (err) {
212
- // calls.should.be.above(0);
213
- // } finally {
214
- // conn.close();
215
- // }
216
- // });
217
- });
218
-
219
-
220
- describe("#Regular querying", function() {
221
- // this.timeout(10000);
222
-
223
- var MDB = getMDB();
224
- var conn = new MDB();
225
- conn.connect();
226
-
227
- beforeEach("Starting transaction", function() {
228
- return conn.query("START TRANSACTION");
229
- });
230
-
231
- afterEach("Rollback transaction", function() {
232
- return conn.query("ROLLBACK");
233
- });
234
-
235
- after("Destroy connection", function() {
236
- conn.destroy();
237
- });
238
-
239
- it("should yield a valid result", function() {
240
- var query = conn.query(
241
- "CREATE TABLE foo(a INT, b FLOAT, c BLOB);\n" +
242
- "INSERT INTO foo VALUES (42,4.2,'42'),(43,4.3,'43'),(44,4.4,'44'),(45,4.5,'45')"
243
- ).then(function() {
244
- return conn.query("SELECT * FROM foo");
245
- });
246
-
247
- return shouldHaveValidResult(query, 4, 3, ["a", "b", "c"])
248
- .should.eventually.have.property("data")
249
- .that.deep.equals([
250
- [42, 4.2, "42"],
251
- [43, 4.3, "43"],
252
- [44, 4.4, "44"],
253
- [45, 4.5, "45"]
254
- ]);
255
- });
256
-
257
- it("should yield a valid pretty result on demand", function() {
258
- var query = conn.query(
259
- "CREATE TABLE foo(a INT, b FLOAT, c BLOB);\n" +
260
- "INSERT INTO foo VALUES (42,4.2,'42'),(43,4.3,'43'),(44,4.4,'44'),(45,4.5,'45')"
261
- ).then(function() {
262
- return conn.query("SELECT * FROM foo", true);
263
- });
264
-
265
- return shouldHaveValidResult(query, 4, 3, ["a", "b", "c"])
266
- .should.eventually.have.property("data")
267
- .that.deep.equals([
268
- {a: 42, b: 4.2, c: "42"},
269
- {a: 43, b: 4.3, c: "43"},
270
- {a: 44, b: 4.4, c: "44"},
271
- {a: 45, b: 4.5, c: "45"}
272
- ]);
273
- });
274
-
275
- it("should work on queries that exceed mapi block size", function() {
276
- function rep(str,n) {
277
- ret = '';
278
- for (var i = 0; i< n; i++) {
279
- ret += str;
280
- }
281
- return ret;
282
- }
283
- var longstr = rep('ABCDEFGHIJKLMNOP', 10000);
284
- var query = conn.query("SELECT '" + longstr + "' AS longstr");
285
- return shouldHaveValidResult(query, 1, 1, ["longstr"])
286
- .should.eventually.have.property("data")
287
- .that.deep.equals([[longstr]]); // for some reason, if equals fails here, the truncateThreshold is
288
- // ignored and the huge string is printed... let's just
289
- // hope this equals test always passes
290
- });
291
-
292
- it("should fail on invalid queries", function() {
293
- return conn.query("MEHR BIER").should.be.rejected;
294
- });
295
-
296
- it("should properly handle (escaped) quotes", function() {
297
- var query = conn.query("SELECT '\\\\asdf' AS a, '\"' AS b, '\\\"' AS c, '\\\\\"' AS d, '\\'' AS e");
298
- return shouldHaveValidResult(query, 1, 5, ["a", "b", "c", "d", "e"])
299
- .should.eventually.have.property("data")
300
- .that.deep.equals([['\\asdf', '"', '\"', '\\"', "'"]]);
301
- });
302
-
303
- it("should properly store and retrieve escaped values", function() {
304
- var query = conn.query(
305
- "CREATE TABLE foo(a string);\n" +
306
- "INSERT INTO foo VALUES ('\t\n\r\n\tlalala\t\n\r')"
307
- ).then(function() {
308
- return conn.query("SELECT * FROM foo");
309
- });
310
-
311
- return shouldHaveValidResult(query, 1, 1, ["a"])
312
- .should.eventually.have.property("data")
313
- .that.deep.equals([['\t\n\r\n\tlalala\t\n\r']]);
314
- });
315
-
316
- it("should work on many queries", function() {
317
- var qs = [];
318
- for(var i=0; i<1000; ++i) {
319
- qs.push(
320
- conn.query("SELECT " + i + " AS i")
321
- .should.eventually.have.property("data")
322
- .that.deep.equals([[i]])
323
- );
324
- }
325
- return Q.all(qs);
326
- });
327
-
328
- it("should properly rebuild stored JSON", function() {
329
- var json = {a: 9, b: {c: 's'}, c: [1,2,3,{a: 1}]};
330
- var query = conn.query("CREATE TABLE foo (a JSON)").then(function() {
331
- return conn.query("INSERT INTO foo VALUES ('" + JSON.stringify(json) + "')");
332
- }).then(function() {
333
- return conn.query("SELECT * FROM foo");
334
- });
335
- return shouldHaveValidResult(query, 1, 1, ["a"])
336
- .should.eventually.have.property("data")
337
- .that.deep.equals([[json]]);
338
- });
339
-
340
- it("should fail when trying to insert invalid JSON", function() {
341
- return conn.query("CREATE TABLE foo (a JSON)").then(function() {
342
- return conn.query("INSERT INTO foo VALUES ('{someInvalidJSON')");
343
- }).should.be.rejected;
344
- });
345
-
346
- it("should properly convert booleans", function() {
347
- var query = conn.query("CREATE TABLE foo (a BOOLEAN, b BOOLEAN)").then(function() {
348
- return conn.query("INSERT INTO foo VALUES (true, false)");
349
- }).then(function() {
350
- return conn.query("SELECT * FROM foo");
351
- });
352
-
353
- return shouldHaveValidResult(query, 1, 2, ["a", "b"])
354
- .should.eventually.have.property("data")
355
- .that.deep.equals([[true, false]]);
356
- });
357
-
358
- it("should properly handle NULL values", function() {
359
- var query = conn.query("CREATE TABLE foo (a INT)").then(function() {
360
- return conn.query("INSERT INTO foo VALUES (NULL)");
361
- }).then(function() {
362
- return conn.query("SELECT * FROM foo");
363
- });
364
-
365
- return shouldHaveValidResult(query, 1, 1, ["a"])
366
- .should.eventually.have.property("data")
367
- .that.deep.equals([[null]]);
368
- });
369
-
370
- it("should handle NULL as string", async function() {
371
- const sql = `create table null_as_string(i int, s string);
372
- copy 3 records into null_as_string from stdin delimiters ',',E'\n' NULL as '';
373
- ,NULL
374
- 1,NULL
375
- 2,"foo"
376
- `
377
- await conn.query(sql);
378
- let res = await conn.query("select * from null_as_string;");
379
- const expected = [[null, "NULL"], [1, "NULL"], [2, '"foo"']]
380
- res.data.should.deep.equal(expected);
381
- });
382
-
383
- it("should be be fulfiled on procedure call queries", function(){
384
- return conn.query("call sys.clearrejects();").should.be.fulfilled;
385
- });
386
- });
387
-
388
-
389
- // describe("#Inserting data from multiple connections", function() {
390
- // var MDB = getMDB();
391
-
392
- // // creates a connection and executes a query
393
- // // return value is a promise that gets resolved with the query result if getResults is set to true, or
394
- // // resolves when the connection is closed (after executing the query) without an argument.
395
- // function execQuery(sql, i) {
396
- // var conn = new MDB({ // uncomment the following statements to properly debug this functionality
397
- // /*warnings: true
398
- // warningFn: function(logger, msg) {
399
- // logger("[" + i + "] " + msg);
400
- // },
401
- // debug: true,
402
- // debugFn: function(logger, msg) {
403
- // logger("[" + i + "] " + msg);
404
- // },
405
- // debugRequests: true,
406
- // debugRequestFn: function(logger, msg) {
407
- // logger("[" + i + "] " + msg);
408
- // },
409
- // debugMapi: true,
410
- // debugMapiFn: function(logger, side, msg) {
411
- // logger("[" + i + "] " + side + "| " + msg)
412
- // }*/
413
- // });
414
- // conn.connect().then();
415
- // var result = conn.query(sql);
416
- // conn.close();
417
- // return result;
418
- // }
419
-
420
- // beforeEach("Create test table", function() {
421
- // return execQuery("CREATE TABLE foo (a STRING)");
422
- // });
423
-
424
- // afterEach("Remove test table", function() {
425
- // return execQuery("DROP TABLE foo");
426
- // });
427
-
428
- // // it("should have added all data that did not occur any concurrency issues", function() {
429
- // // this.timeout(30000);
430
- // // var nrConnections = 50;
431
- // // var insertionPromises = [];
432
- // // var nrSucceeded = 0;
433
-
434
- // // for(var i=0; i<nrConnections; ++i) {
435
- // // var insertionPromise = execQuery("INSERT INTO foo VALUES('bar')", i).then(function() {
436
- // // // console.log("query ended: " + this.i + " (resolved)");
437
- // // ++nrSucceeded;
438
- // // }.bind({i: i}), function() {
439
- // // // console.log("query ended: " + this.i + " (rejected)");
440
- // // }.bind({i: i}));
441
- // // insertionPromises.push(insertionPromise);
442
- // // }
443
-
444
- // // return Q.allSettled(insertionPromises).then(function() {
445
- // // return execQuery("SELECT * FROM foo").should.eventually.have.property("rows", nrSucceeded);
446
- // // });
447
- // // });
448
- // });
449
-
450
- describe("#Time zone offset", function() {
451
- var baseTimestamp = "2015-10-29 11:31:35.000000";
452
- var MDB = getMDB();
453
-
454
- function setupConnection(timezoneOffset) {
455
- var conn = timezoneOffset !== undefined ? new MDB({timezoneOffset: timezoneOffset}) : new MDB();
456
- conn.connect();
457
- conn.query("START TRANSACTION; CREATE TABLE foo (a TIMESTAMPTZ)");
458
- return conn;
459
- }
460
-
461
- function closeConnection(conn) {
462
- conn.query("ROLLBACK");
463
- conn.destroy();
464
- }
465
-
466
- function testTimezoneOffset(timezoneOffset, timestampIn, timestampOut) {
467
- if(!timestampOut) timestampOut = timestampIn;
468
- var conn = setupConnection(timezoneOffset);
469
- return conn.query("INSERT INTO foo VALUES ('" + timestampIn + "')").then(function() {
470
- return conn.query("SELECT * FROM foo");
471
- }).fin(function() {
472
- closeConnection(conn);
473
- }).should.eventually.have.property("data")
474
- .that.deep.equals([[timestampOut]]);
475
- }
476
-
477
- it("should be automatically set to the current time zone", function() {
478
- var timestampCurTz = baseTimestamp + constructCurTimezoneStr();
479
- return testTimezoneOffset(undefined, timestampCurTz);
480
- });
481
-
482
- it("should be customizable", function() {
483
- var offset2 = 120;
484
- var offset1030 = 630;
485
- var timestampPlus2 = baseTimestamp + "+02:00";
486
- var timestampMinus2 = baseTimestamp + "-02:00";
487
- var timestampPlus1030 = baseTimestamp + "+10:30";
488
- var timestampMinus1030 = baseTimestamp + "-10:30";
489
- return Q.all([
490
- testTimezoneOffset(offset2, timestampPlus2),
491
- testTimezoneOffset(-offset2, timestampMinus2),
492
- testTimezoneOffset(offset1030, timestampPlus1030),
493
- testTimezoneOffset(-offset1030, timestampMinus1030)
494
- ]);
495
- });
496
-
497
- it("should work cross-timezone", function() {
498
- // connection works on timezone +01:00, we give it a timestamp in timezone -01:30
499
- // we expect it to convert it to +01:00, hence adding +02:30 to its time.
500
- var timestampIn = baseTimestamp + "-01:30";
501
- var timestampOut = "2015-10-29 14:01:35.000000+01:00";
502
- return testTimezoneOffset(60, timestampIn, timestampOut);
503
- });
504
- });
505
-
506
- describe("#Prepared queries", function() {
507
- this.timeout(10000);
508
-
509
- const MDB = getMDB();
510
- const conn = new MDB();
511
- conn.connect();
512
-
513
- beforeEach("Starting transaction", function() {
514
- conn.option("prettyResult", false);
515
- return conn.query("START TRANSACTION; CREATE TABLE foo(d INT, e FLOAT, f CHAR(5))");
516
- });
517
-
518
- afterEach("Rollback transaction", function() {
519
- return conn.query("ROLLBACK");
520
- });
521
-
522
- after("Destroy connection", function() {
523
- conn.destroy();
524
- });
525
-
526
- it("should be executable multiple times", function() {
527
- var prepResult;
528
- var query = conn.prepare("INSERT INTO foo VALUES (?, ?, ?)").then(function(prepResult_) {
529
- prepResult = prepResult_;
530
- return Q.all([
531
- prepResult.exec([55, 5.5, "5.5"]),
532
- prepResult.exec([56, 5.6, "5.6"]),
533
- prepResult.exec([57, 5.7, "5.7"]),
534
- prepResult.exec([58, 5.8, "5.8"])
535
- ]);
536
- }).then(function() {
537
- prepResult.release();
538
- return conn.query("SELECT * FROM foo");
539
- });
540
-
541
- return shouldHaveValidResult(query, 4, 3, ["d", "e", "f"])
542
- .should.eventually.have.property("data")
543
- .that.deep.equals([
544
- [55, 5.5, "5.5"],
545
- [56, 5.6, "5.6"],
546
- [57, 5.7, "5.7"],
547
- [58, 5.8, "5.8"]
548
- ]);
549
- });
550
-
551
- it("should be interleavable with normal queries", function() {
552
- var queryFns = [
553
- function() { return conn.query("SELECT COUNT(*) FROM foo"); },
554
- function() { return conn.query("SELECT AVG(d + e) AS avg FROM foo GROUP BY f"); },
555
- null,
556
- null,
557
- null
558
- ];
559
- var query = Q.all([
560
- conn.prepare("INSERT INTO foo VALUES (?, ?, ?)"),
561
- conn.prepare("SELECT COUNT(*) FROM foo WHERE d > ? AND e < ?"),
562
- conn.prepare("DELETE FROM foo WHERE d < ?")
563
- ]).then(function(prepResults) {
564
- queryFns[2] = function() {
565
- return prepResults[0].exec([Math.round(notSoRandom()*10), notSoRandom()*10, 'str']);
566
- };
567
- queryFns[3] = function() {
568
- var a = Math.abs(notSoRandom() * 5);
569
- return prepResults[1].exec([Math.round(a), a + notSoRandom() * 5]);
570
- };
571
- queryFns[4] = function() {
572
- return prepResults[2].exec([Math.round(notSoRandom()*2)]);
573
- };
574
-
575
- var qs = [];
576
- for(var i=0; i<1000; ++i) {
577
- var fnIndex = Math.round(notSoRandom()*(queryFns.length-1));
578
- qs.push(queryFns[fnIndex]());
579
- }
580
- return Q.all(qs);
581
- });
582
-
583
- return query.should.not.be.rejected;
584
- });
585
-
586
- it("should be created automatically when query params are given", function() {
587
- var query = conn.query(
588
- "INSERT INTO foo VALUES (?, ?, ?)",
589
- [8, 8.8, "8.8.8"]
590
- ).then(function() {
591
- return conn.query(
592
- "INSERT INTO foo VALUES (?, ?, ?)",
593
- [9, 9.9, "9.9.9"]
594
- );
595
- }).then(function() {
596
- return conn.query(
597
- "SELECT * FROM foo WHERE d > ?",
598
- [5]
599
- );
600
- });
601
-
602
- return shouldHaveValidResult(query, 2, 3, ["d", "e", "f"])
603
- .should.eventually.have.property("data")
604
- .that.deep.equals([
605
- [8, 8.8, "8.8.8"],
606
- [9, 9.9, "9.9.9"]
607
- ]);
608
- });
609
-
610
- it("should generate pretty results when requested implicitly through query params", function() {
611
- var query = conn.query(
612
- "INSERT INTO foo VALUES (42,4.2,'42'),(43,4.3,'43'),(44,4.4,'44'),(45,4.5,'45')"
613
- ).then(function() {
614
- return conn.query("SELECT * FROM foo WHERE d > ?", [42], true);
615
- });
616
-
617
- return shouldHaveValidResult(query, 3, 3, ["d", "e", "f"])
618
- .should.eventually.have.property("data")
619
- .that.deep.equals([
620
- {d: 43, e: 4.3, f: "43"},
621
- {d: 44, e: 4.4, f: "44"},
622
- {d: 45, e: 4.5, f: "45"}
623
- ]);
624
- });
625
-
626
- it("should generate pretty results when requested explicitly through prepare function", function() {
627
- var query = conn.query(
628
- "INSERT INTO foo VALUES (42,4.2,'42'),(43,4.3,'43'),(44,4.4,'44'),(45,4.5,'45')"
629
- ).then(function() {
630
- return conn.prepare("SELECT * FROM foo WHERE d > ?", true);
631
- }).then(function(prepResult) {
632
- return prepResult.exec([42]);
633
- });
634
-
635
- return shouldHaveValidResult(query, 3, 3, ["d", "e", "f"])
636
- .should.eventually.have.property("data")
637
- .that.deep.equals([
638
- {d: 43, e: 4.3, f: "43"},
639
- {d: 44, e: 4.4, f: "44"},
640
- {d: 45, e: 4.5, f: "45"}
641
- ]);
642
- });
643
-
644
- it("should generate pretty results in .query when pretty option is set", function() {
645
- conn.option("prettyResult", true);
646
- var query = conn.query(
647
- "INSERT INTO foo VALUES (42,4.2,'42'),(43,4.3,'43'),(44,4.4,'44'),(45,4.5,'45')"
648
- ).then(function() {
649
- return conn.query("SELECT * FROM foo WHERE d > ?", [42]);
650
- });
651
-
652
- return shouldHaveValidResult(query, 3, 3, ["d", "e", "f"])
653
- .should.eventually.have.property("data")
654
- .that.deep.equals([
655
- {d: 43, e: 4.3, f: "43"},
656
- {d: 44, e: 4.4, f: "44"},
657
- {d: 45, e: 4.5, f: "45"}
658
- ]);
659
- });
660
-
661
- it("should properly handle json parameters", function() {
662
- var json = {a: 9, b: {c: 's'}, c: [1,2,3,{a: 1}]};
663
- var query = conn.query("CREATE TABLE bar (a JSON)").then(function() {
664
- return conn.query("INSERT INTO bar VALUES (?)", [json]);
665
- }).then(function() {
666
- return conn.query("SELECT * FROM bar");
667
- });
668
-
669
- return shouldHaveValidResult(query, 1, 1, ["a"])
670
- .should.eventually.have.property("data")
671
- .that.deep.equals([[json]]);
672
- });
673
-
674
- it("should properly handle boolean parameters", function() {
675
- var query = conn.query("CREATE TABLE bar (a BOOLEAN, b BOOLEAN)").then(function() {
676
- return conn.query("INSERT INTO bar VALUES (?, ?)", [true, false]);
677
- }).then(function() {
678
- return conn.query("SELECT * FROM bar");
679
- });
680
-
681
- return shouldHaveValidResult(query, 1, 2, ["a", "b"])
682
- .should.eventually.have.property("data")
683
- .that.deep.equals([[true, false]]);
684
- });
685
-
686
- it("should properly handle null parameters", function() {
687
- var query = conn.query("CREATE TABLE bar (a INT)").then(function() {
688
- return conn.query("INSERT INTO bar VALUES (?)", [null]);
689
- }).then(function() {
690
- return conn.query("SELECT * FROM bar");
691
- });
692
-
693
- return shouldHaveValidResult(query, 1, 1, ["a"])
694
- .should.eventually.have.property("data")
695
- .that.deep.equals([[null]]);
696
- });
697
-
698
- it("should properly handle timestamp, timestamptz, date, and uuid", function() {
699
-
700
- var vals = [
701
- "2015-10-29 11:31:35.000000",
702
- "2015-10-29 11:31:35.000000" + constructCurTimezoneStr(),
703
- "2015-10-29",
704
- "422cb031-6329-3b4f-0247-e261db574da6"
705
- ];
706
- var query = conn.query("CREATE TABLE bar (a TIMESTAMP, b TIMESTAMPTZ, c DATE, d UUID)").then(function() {
707
- return conn.query("INSERT INTO bar VALUES (?, ?, ?, ?)", vals);
708
- }).then(function() {
709
- return conn.query("SELECT * FROM bar");
710
- });
711
-
712
- return shouldHaveValidResult(query, 1, 4, ["a", "b", "c", "d"])
713
- .should.eventually.have.property("data")
714
- .that.deep.equals([vals]);
715
- });
716
-
717
- // it("should fail when too few params are given", function(done) {
718
- // return conn.query("INSERT INTO foo VALUES (?, ?, ?)", [2])
719
- // .catch(function() {
720
- // conn.close();
721
- // })
722
- // .should.be.rejected;
723
- // });
724
-
725
- // it("should fail when too many params are given", function() {
726
- // return conn.query("INSERT INTO foo VALUES (?, ?, ?)", [2, 4.5, "s", 2])
727
- // .should.be.rejected;
728
- // });
729
-
730
- it("should fail when too few question marks are in the query", function() {
731
- return conn.query("INSERT INTO foo VALUES (?, ?)", [2, 4.5, "s"])
732
- .should.be.rejected;
733
- });
734
-
735
- it("should fail when too many question marks are in the query", function() {
736
- return conn.query("INSERT INTO foo VALUES (?, ?, ?, ?)", [2, 4.5, "s"])
737
- .should.be.rejected;
738
- });
739
-
740
- // KEEP AROUND this test relates to https://www.monetdb.org/bugzilla/show_bug.cgi?id=6832. Uncommmet when
741
- // prepare statememts fix is available upstream.
742
- //it("should proprely handle failing concurent requests", async function(){
743
- // // need isolated connection for this test
744
- // const conn = new MDB();
745
- // conn.connect();
746
- // const req1 = conn.query("select cast(? as int);", [42])
747
- // .catch(function(err){
748
- // console.error("req1: ", err);
749
- // });
750
- // const req2 = conn.query("select boom;")
751
- // .catch(function(err) {
752
- // console.log("req2: ", err);
753
- // });
754
- // const res1 = await req1;
755
- // const res2 = await req2;
756
- // conn.destroy();
757
- // expect(res1 !== undefined).to.be.true;
758
- //});
759
- });
760
-
761
- describe("#CallbackWrapper", function() {
762
- var MDB = getMDB();
763
-
764
- it("should wrap MonetDBConnection.connect", function(done) {
765
- var conn1 = new MDB().getCallbackWrapper();
766
- conn1.connect(function(err) {
767
- try {
768
- should.not.exist(err);
769
- } catch(e) {
770
- conn1.destroy();
771
- return done(e);
772
- }
773
- var conn2 = new MDB({dbname: "nonexistent"}).getCallbackWrapper();
774
- conn2.connect(function(err) {
775
- try {
776
- should.exist(err);
777
- done();
778
- } catch(e) {
779
- done(e);
780
- }
781
- conn1.destroy();
782
- conn2.destroy();
783
- })
784
- });
785
- });
786
-
787
- it("should wrap succeeding MonetDBConnection.query and .request", function(done) {
788
- var conn = new MDB().getCallbackWrapper();
789
- conn.connect();
790
- conn.query("SELECT 425", function(err, result) {
791
- try {
792
- should.not.exist(err);
793
- result.should.have.property("data").that.deep.equals([[425]]);
794
- done();
795
- } catch(e) {
796
- done(e);
797
- }
798
- conn.close();
799
- })
800
- });
801
-
802
- it("should wrap failing MonetDBConnection.query and .request", function(done) {
803
- var conn = new MDB().getCallbackWrapper();
804
- conn.connect();
805
- conn.query("SELECT will_not_work", function(err) {
806
- try {
807
- should.exist(err);
808
- conn.close();
809
- done();
810
- } catch(e) {
811
- conn.close();
812
- done(e);
813
- }
814
- });
815
- });
816
-
817
- // it("should wrap MonetDBConnection.prepare", function(done) {
818
- // var conn = new MDB().getCallbackWrapper();
819
- // conn.connect();
820
- // conn.prepare("SELECT * FROM sys.tables WHERE id > ?", function(err, prepResult) {
821
- // try {
822
- // should.not.exist(err);
823
- // prepResult.should.have.property("prepare").that.is.an("object");
824
- // prepResult.should.have.property("exec").that.is.a("function");
825
- // prepResult.should.have.property("release").that.is.a("function");
826
- // } catch(e) {
827
- // conn.destroy();
828
- // return done(e);
829
- // }
830
- // prepResult.exec([1], function(err, result) {
831
- // try {
832
- // should.not.exist(err);
833
- // result.should.have.property("rows").that.is.above(0);
834
- // } catch(e) {
835
- // conn.destroy();
836
- // return done(e);
837
- // }
838
- // prepResult.exec(["fail"], function(err) {
839
- // try {
840
- // should.exist(err);
841
- // prepResult.release();
842
- // done();
843
- // } catch(e) {
844
- // conn.destroy();
845
- // done(e);
846
- // }
847
- // })
848
- // .finally(function() {
849
- // conn.close();
850
- // });
851
- // })
852
- // .finally(function() {
853
- // conn.close();
854
- // });
855
- // });
856
- // });
857
-
858
- it("should wrap MonetDBConnection.env", function(done) {
859
- var conn = new MDB().getCallbackWrapper();
860
- conn.connect();
861
- return conn.env(function(err, result) {
862
- try {
863
- should.not.exist(err);
864
- result.should.be.an("object").that.has.property("monet_version").that.is.a("string");
865
- done();
866
- } catch(e) {
867
- done(e);
868
- }
869
- conn.destroy();
870
- });
871
- });
872
-
873
- it("should wrap MonetDBConnection.close", function(done) {
874
- var conn = new MDB().getCallbackWrapper();;
875
- conn.connect();
876
- conn.close(function(err) {
877
- try {
878
- should.not.exist(err);
879
- done();
880
- } catch(e) {
881
- done(e);
882
- }
883
- conn.destroy();
884
- });
885
- });
886
-
887
- it("should enable chaining on all callback based methods", function() {
888
- var conn = new MDB().getCallbackWrapper();
889
- ["connect", "query", "env", "close", "prepare"].forEach(function(chainMethod) {
890
- conn[chainMethod]().should.equal(conn);
891
- });
892
- });
893
-
894
- it("should simply link MonetDBConnection.option, .getState, and .destroy", function() {
895
- var conn = new MDB();
896
- var wrapper = conn.getCallbackWrapper();
897
- ["option", "getState", "destroy"].forEach(function(method) {
898
- conn[method].should.equal(wrapper[method]);
899
- });
900
- });
901
-
902
- it("should have the right aliases", function() {
903
- var conn = new MDB().getCallbackWrapper();
904
- conn.open.should.equal(conn.connect);
905
- conn.request.should.equal(conn.query);
906
- conn.disconnect.should.equal(conn.close);
907
- });
908
- });