monetdb 1.3.4 → 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 (52) hide show
  1. package/.github/workflows/Linux.yml +3 -3
  2. package/.github/workflows/docs.yml +79 -0
  3. package/.github/workflows/macos.yml +3 -3
  4. package/.github/workflows/monetdb-versions.yml +43 -0
  5. package/README.md +41 -511
  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 +16 -20
  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/dist/mapi.d.ts +0 -58
  36. package/dist/mapi.js +0 -250
  37. package/dist/mapi.js.map +0 -1
  38. package/dist/tsconfig.tsbuildinfo +0 -1
  39. package/foo.js +0 -16
  40. package/index.js +0 -5
  41. package/src/mapi-connection.js +0 -784
  42. package/src/monetdb-connection.js +0 -385
  43. package/src/utils.js +0 -27
  44. package/test/common.js +0 -45
  45. package/test/install-monetdb.sh +0 -11
  46. package/test/monetdb_stream.js +0 -106
  47. package/test/start-monetdb.sh +0 -38
  48. package/test/test.js +0 -908
  49. package/test/test_connection.js +0 -290
  50. /package/docs/{README.v0.md → v0/README.v0.md} +0 -0
  51. /package/docs/{MapiConnection.md → v1/MapiConnection.md} +0 -0
  52. /package/docs/{v1-notes.md → v1/v1-notes.md} +0 -0
@@ -0,0 +1,67 @@
1
+ function monetEscape(v: any): string {
2
+ let s = String(v).replace("\\", "\\\\");
3
+ s = s.replace("\'", "\\\'");
4
+ return `'${s}'`;
5
+ }
6
+
7
+ function monetDecimal(v: number, digits?: number, scale?: number): string {
8
+ if (digits && scale)
9
+ return `cast(${monetEscape(v)} as decimal(${digits}, ${scale}))`;
10
+ return `cast(${monetEscape(v)} as decimal)`;
11
+ }
12
+
13
+
14
+ function monetDate(v: string): string {
15
+ return `DATE${monetEscape(v)}`;
16
+ }
17
+
18
+
19
+ function monetTime(v: string): string {
20
+ return `TIME${monetEscape(v)}`;
21
+ }
22
+
23
+
24
+ function monetTimestamp(v: string): string {
25
+ return `TIMESTAMP${monetEscape(v)}`;
26
+ }
27
+
28
+
29
+ function monetTimestampZone(v: string): string {
30
+ return `TIMESTAMPZ${monetEscape(v)}`;
31
+ }
32
+
33
+
34
+ function monetUUID(v: string): string {
35
+ return `UUID${monetEscape(v)}`;
36
+ }
37
+
38
+
39
+ function convert(type: string, v: any, digits?: number, scale?: number): any {
40
+ switch(type) {
41
+ case "smallint":
42
+ case "int":
43
+ case "bigint":
44
+ case "hugeint":
45
+ case "double":
46
+ case "float":
47
+ return Number(v);
48
+ case "decimal":
49
+ return monetDecimal(v, digits, scale);
50
+ case "boolean":
51
+ return Boolean(v);
52
+ case "date":
53
+ return monetDate(v);
54
+ case "time":
55
+ return monetTime(v);
56
+ case "timestamp":
57
+ return monetTimestamp(v);
58
+ case "timestampz":
59
+ return monetTimestampZone(v);
60
+ case "uuid":
61
+ return monetUUID(v);
62
+ default:
63
+ return monetEscape(v);
64
+ }
65
+ }
66
+
67
+ export {convert}
@@ -0,0 +1,43 @@
1
+ import assert from "assert";
2
+ import Connection from "../src/connection";
3
+
4
+ describe("Connection", function () {
5
+ let conn: Connection;
6
+
7
+ it("should connect with default opt", async function () {
8
+ conn = new Connection({ database: "test" });
9
+ const ready = await conn.connect();
10
+ assert(ready, new Error("failed to connect"));
11
+ const closed = await conn.close();
12
+ assert(closed);
13
+ });
14
+
15
+ it("should build Connection from mapi uri default username and password", function () {
16
+ conn = new Connection("mapi:monetdb://foo.com:55555/test");
17
+ assert.strictEqual(conn.mapi.host, "foo.com");
18
+ assert.strictEqual(conn.mapi.port, 55555);
19
+ assert.strictEqual(conn.mapi.username, "monetdb");
20
+ assert.strictEqual(conn.mapi.password, "monetdb");
21
+ assert.strictEqual(conn.mapi.database, "test");
22
+ });
23
+
24
+ it("should build Connection from mapi uri with auth component", function () {
25
+ conn = new Connection(
26
+ "mapi:monetdb://barname:barpassword@foo.com:55555/test"
27
+ );
28
+ assert.strictEqual(conn.mapi.host, "foo.com");
29
+ assert.strictEqual(conn.mapi.port, 55555);
30
+ assert.strictEqual(conn.mapi.username, "barname");
31
+ assert.strictEqual(conn.mapi.password, "barpassword");
32
+ assert.strictEqual(conn.mapi.database, "test");
33
+ });
34
+
35
+ it("should build Connection from mapi uri no port", function () {
36
+ conn = new Connection("mapi:monetdb://foo.com/test");
37
+ assert.strictEqual(conn.mapi.host, "foo.com");
38
+ assert.strictEqual(conn.mapi.port, 50000);
39
+ assert.strictEqual(conn.mapi.username, "monetdb");
40
+ assert.strictEqual(conn.mapi.password, "monetdb");
41
+ assert.strictEqual(conn.mapi.database, "test");
42
+ });
43
+ });
@@ -0,0 +1,100 @@
1
+ import assert from "assert";
2
+ import Connection from "../src/connection";
3
+
4
+ describe("Exec queres", function () {
5
+ let conn: Connection;
6
+ beforeEach(function () {
7
+ conn = new Connection({ database: "test" });
8
+ });
9
+
10
+ afterEach(async function () {
11
+ const closed = await conn.close();
12
+ assert(closed);
13
+ });
14
+
15
+ it("should handle single select query", async function () {
16
+ const ready = await conn.connect();
17
+ assert(ready, new Error("failed to connect"));
18
+ const res = await conn.execute("select * from generate_series(1, 10)");
19
+ assert.equal(res.rowCnt, 9);
20
+ assert.equal(res.data.length, 9);
21
+ });
22
+
23
+ it("should handle many queres", async function () {
24
+ const ready = await conn.connect();
25
+ assert(ready, new Error("failed to connect"));
26
+ const [res1, res2, res3] = await Promise.all([
27
+ conn.execute("select * from generate_series(1, 11)"),
28
+ conn.execute("select * from generate_series(11, 21)"),
29
+ conn.execute("select * from generate_series(21, 31)"),
30
+ ]);
31
+ assert.deepStrictEqual(res1.data, [
32
+ [1],
33
+ [2],
34
+ [3],
35
+ [4],
36
+ [5],
37
+ [6],
38
+ [7],
39
+ [8],
40
+ [9],
41
+ [10],
42
+ ]);
43
+ assert.deepStrictEqual(res2.data, [
44
+ [11],
45
+ [12],
46
+ [13],
47
+ [14],
48
+ [15],
49
+ [16],
50
+ [17],
51
+ [18],
52
+ [19],
53
+ [20],
54
+ ]);
55
+ assert.deepStrictEqual(res3.data, [
56
+ [21],
57
+ [22],
58
+ [23],
59
+ [24],
60
+ [25],
61
+ [26],
62
+ [27],
63
+ [28],
64
+ [29],
65
+ [30],
66
+ ]);
67
+ });
68
+
69
+ it("should handle insert statements", async function () {
70
+ const ready = await conn.connect();
71
+ assert(ready, new Error("failed to connect"));
72
+ let res = await conn.execute("create schema test");
73
+ res = await conn.execute("create table foo(a string)");
74
+ res = await conn.execute("insert into foo values ('foo'), ('bar')");
75
+ res = await conn.execute("select * from foo");
76
+ assert.deepStrictEqual(res.data, [["foo"], ["bar"]]);
77
+ });
78
+
79
+ it("should rollback", async function () {
80
+ const ready = await conn.connect();
81
+ assert(ready, new Error("failed to connect"));
82
+ let res = await conn.execute("create table foo(a string)");
83
+ res = await conn.execute("select name from tables where name='foo'");
84
+ assert.strictEqual(res.rowCnt, 1);
85
+ res = await conn.rollback();
86
+ res = await conn.execute("select name from tables where name='foo'");
87
+ assert.strictEqual(res.rowCnt, 0);
88
+ });
89
+
90
+ it("should handle 2 byte characters exceeding mapi block", async () => {
91
+ let s = "éééééééééééééééééééééééééééé";
92
+ let string = "";
93
+ for (let i = 0; i < 1000; i++) string += s;
94
+ const qry = `select \'${string}\'`;
95
+ const ready = await conn.connect();
96
+ assert(ready, new Error("failed to connect"));
97
+ const res = await conn.execute(qry);
98
+ assert.strictEqual(res.rowCnt, 1);
99
+ });
100
+ });
@@ -0,0 +1,94 @@
1
+ import assert from 'assert';
2
+ import Connection from '../src/connection';
3
+ import fs from 'node:fs/promises';
4
+
5
+ describe('File Transfer', function() {
6
+ let conn: Connection;
7
+ let fooFile = 'test/tmp/foo'
8
+ beforeEach(function() {
9
+ conn = new Connection({database: 'test'});
10
+ });
11
+
12
+ afterEach(async function() {
13
+ const closed = await conn.close();
14
+ assert(closed);
15
+ });
16
+
17
+ it('should upload binary file', async function() {
18
+ const ready = await conn.connect();
19
+ assert(ready, new Error('failed to connect'));
20
+ await conn.execute('create table foo(i int)');
21
+ const f = await fs.open(fooFile, 'w');
22
+ const buff = Buffer.alloc(12);
23
+ buff.writeInt32LE(1, 0);
24
+ buff.writeInt32LE(2, 4);
25
+ buff.writeInt32LE(3, 8);
26
+ f.write(buff);
27
+ await f.close();
28
+ let res = await conn.execute(`copy binary into foo from \'${fooFile}\' on client`);
29
+ res = await conn.execute('select * from foo');
30
+ assert.deepStrictEqual(res.data, [[1], [2], [3]]);
31
+ });
32
+
33
+ it('should upload text file', async function() {
34
+ const ready = await conn.connect();
35
+ assert(ready, new Error('failed to connect'));
36
+ await conn.execute('create table foo(i int, a varchar(10))');
37
+ const f = await fs.open(fooFile, 'w');
38
+ for (let word of ['1|one', '2|two', '3|three']) {
39
+ f.write(word + '\n');
40
+ }
41
+ await f.close();
42
+ let res = await conn.execute(`copy into foo from \'${fooFile}\' on client`);
43
+ res = await conn.execute('select * from foo order by i');
44
+ assert.deepStrictEqual(res.data, [[1, 'one'], [2, 'two'], [3, 'three']]);
45
+ });
46
+
47
+ it('should cancel upload on fewer rows', async function() {
48
+ const ready = await conn.connect();
49
+ assert(ready, new Error('failed to connect'));
50
+ await conn.execute('create table foo(i int, a varchar(10))');
51
+ const f = await fs.open(fooFile, 'w');
52
+ for (let word of ['1|one', '2|two', '3|three', '4|four', '5|five', '6|six']) {
53
+ f.write(word + '\n');
54
+ }
55
+ await f.close();
56
+ let res = await conn.execute(`copy 3 records into foo from \'${fooFile}\' on client`);
57
+ res = await conn.execute('select * from foo order by i');
58
+ assert.deepStrictEqual(res.rowCnt, 3);
59
+ // TODO for some reason fails on MacOSX
60
+ //assert.deepStrictEqual(res.data, [[1, 'one'], [2, 'two'], [3, 'three']]);
61
+ });
62
+
63
+ it('should upload text file skip 2', async function() {
64
+ const ready = await conn.connect();
65
+ assert(ready, new Error('failed to connect'));
66
+ await conn.execute('create table foo(i int, a varchar(10))');
67
+ const f = await fs.open(fooFile, 'w');
68
+ for (let word of ['1|one', '2|two', '3|three', '4|four', '5|five', '6|six']) {
69
+ f.write(word + '\n');
70
+ }
71
+ await f.close();
72
+ let res = await conn.execute(`copy offset 3 into foo from \'${fooFile}\' on client`);
73
+ res = await conn.execute('select * from foo order by i');
74
+ assert.deepStrictEqual(res.rowCnt, 4);
75
+ // TODO for some reason fails on MacOSX
76
+ //assert.deepStrictEqual(res.data, [[3, "three"], [4, "four"], [5, "five"], [6, "six"]]);
77
+ });
78
+
79
+
80
+ it('should download text file', async function() {
81
+ const ready = await conn.connect();
82
+ assert(ready, new Error('failed to connect'));
83
+ let res = await conn.execute('copy (select * from sys.generate_series(1,1001)) into \'test/tmp/foo\' on client');
84
+ assert.strictEqual(res.affectedRows, 1000);
85
+ });
86
+
87
+ it('should fail on forbidden path', async function() {
88
+ const ready = await conn.connect();
89
+ assert(ready, new Error('failed to connect'));
90
+ await conn.execute('create table foo(i varchar(10))');
91
+ await assert.rejects(conn.execute(`copy into foo from \'../../foo\' on client`), Error);
92
+ });
93
+
94
+ });
@@ -0,0 +1,27 @@
1
+ import assert from 'assert';
2
+ import Connection from '../src/connection';
3
+
4
+ describe('Prepare Statement', function() {
5
+ let conn: Connection;
6
+ beforeEach(function() {
7
+ conn = new Connection({database: 'test'});
8
+ });
9
+
10
+ afterEach(async function(){
11
+ const closed = await conn.close();
12
+ assert(closed);
13
+ });
14
+
15
+ it("should prepare inserts", async function() {
16
+ const ready = await conn.connect();
17
+ assert(ready, new Error('failed to connect'));
18
+ let res = await conn.execute('create table foo(a int, b boolean, c string, d date, f decimal)');
19
+ const prepStmt = await conn.prepare('insert into foo values (?, ?, ?, ?, ?)');
20
+ res = await prepStmt.execute(1, true, 'first', '2022-12-12', 1.11);
21
+ res = await prepStmt.execute(2, false, 'second', '2022-12-12', 2.22);
22
+ res = await prepStmt.execute(3, true, 'third', '2022-12-12', 3.33);
23
+ await prepStmt.release();
24
+ res = await conn.execute('select count(*) from foo');
25
+ assert.strictEqual(res.data[0][0], 3);
26
+ });
27
+ });
@@ -0,0 +1,41 @@
1
+ import assert from 'assert';
2
+ import Connection from '../src/connection';
3
+
4
+ describe('Query Stream', function() {
5
+ let conn: Connection;
6
+ beforeEach(function() {
7
+ conn = new Connection({database: 'test'});
8
+ });
9
+
10
+ afterEach(async function(){
11
+ const closed = await conn.close();
12
+ assert(closed);
13
+ });
14
+
15
+ it('should stream response', async function() {
16
+ const ready = await conn.connect();
17
+ assert(ready, new Error('failed to connect'));
18
+ const stream = await conn.execute('select * from generate_series(1, 10000)', true);
19
+ const colInfo = [];
20
+ const data = [];
21
+ return new Promise((resolve, reject) => {
22
+ stream.on('header', (cols: any[]) => {
23
+ for (let col of cols)
24
+ colInfo.push(col);
25
+ });
26
+ stream.on('data', (tuples: any[]) => {
27
+ for (let t of tuples) {
28
+ data.push(t);
29
+ }
30
+ });
31
+ stream.on('error', (err: Error) => {
32
+ reject(err);
33
+ })
34
+ stream.on('end', () => {
35
+ assert.strictEqual(colInfo.length, 1);
36
+ assert.strictEqual(data.length, 9999);
37
+ resolve();
38
+ });
39
+ })
40
+ });
41
+ });
@@ -0,0 +1,4 @@
1
+ # Ignore everything in this directory
2
+ *
3
+ # Except this file
4
+ !.gitignore
package/tsconfig.json ADDED
@@ -0,0 +1,24 @@
1
+ {
2
+ "compilerOptions": {
3
+ "module": "commonjs",
4
+ "esModuleInterop": true,
5
+ "allowSyntheticDefaultImports": true,
6
+ "strict": false,
7
+ "target": "es6",
8
+ "noImplicitAny": false,
9
+ "moduleResolution": "node",
10
+ "sourceMap": true,
11
+ "pretty": true,
12
+ "outDir": "dist",
13
+ "incremental": true,
14
+ "baseUrl": ".",
15
+ "declaration": true,
16
+ "types": [
17
+ "node",
18
+ "mocha"
19
+ ]
20
+ },
21
+ "include": [
22
+ "src/**/*.ts"
23
+ ]
24
+ }
package/.travis.yml DELETED
@@ -1,11 +0,0 @@
1
- language: node_js
2
- node_js:
3
- - "9"
4
- sudo: required
5
- install:
6
- - sudo bash test/install-monetdb.sh
7
- - npm install
8
- before_script:
9
- - bash test/start-monetdb.sh
10
- after_success:
11
- - npm run coveralls
package/dist/mapi.d.ts DELETED
@@ -1,58 +0,0 @@
1
- /// <reference types="node" />
2
- /// <reference types="node" />
3
- /// <reference types="node" />
4
- import { Socket } from 'node:net';
5
- import { EventEmitter } from 'events';
6
- import { Buffer } from 'buffer';
7
- declare enum MAPI_STATE {
8
- INIT = 1,
9
- CONNECTED = 2,
10
- READY = 3
11
- }
12
- declare enum MAPI_LANGUAGE {
13
- SQL = "sql",
14
- MAPI = "mapi",
15
- CONTROL = "control"
16
- }
17
- declare class Store {
18
- buff: Buffer;
19
- offset: number;
20
- segments: Segment[];
21
- constructor(size?: number);
22
- append(data: Buffer): number;
23
- expand(byteCount: number): number;
24
- drain(): string;
25
- isFull(): boolean;
26
- toString(): string;
27
- }
28
- declare class Segment {
29
- offset: number;
30
- bytes: number;
31
- bytesOffset: number;
32
- last: boolean;
33
- constructor(bytes: number, last: boolean, offset: number, bytesOffset: number);
34
- isFull(): boolean;
35
- }
36
- declare class MAPIConnection extends EventEmitter {
37
- state: MAPI_STATE;
38
- socket: Socket;
39
- timeout?: number;
40
- username?: string;
41
- password?: string;
42
- database?: string;
43
- hostname?: string;
44
- language: MAPI_LANGUAGE;
45
- port?: number;
46
- redirects: number;
47
- store: Store;
48
- constructor();
49
- connect(database: string, username?: string, password?: string, hostname?: string, port?: number, timeout?: number, language?: MAPI_LANGUAGE): Promise<any[]>;
50
- disconnect(): void;
51
- private login;
52
- private send;
53
- private handleTimeout;
54
- private handleSocketError;
55
- private recv;
56
- private handleResponse;
57
- }
58
- export default MAPIConnection;