|
1 | 1 | import duckdb from '@duckdb/node-bindings';
|
2 | 2 | import { expect, suite, test } from 'vitest';
|
3 |
| - |
4 |
| -function isValid(validity: BigUint64Array, bit: number): boolean { |
5 |
| - return (validity[Math.floor(bit / 64)] & (1n << BigInt(bit % 64))) !== 0n; |
6 |
| -} |
7 |
| - |
8 |
| -function expectValidity(validity_bytes: Uint8Array, validity: BigUint64Array, bit: number, expected: boolean) { |
9 |
| - expect(duckdb.validity_row_is_valid(validity_bytes, bit)).toBe(expected); |
10 |
| - expect(isValid(validity, bit)).toBe(expected); |
11 |
| -} |
12 |
| - |
13 |
| -/** |
14 |
| - * Gets the bytes either in or referenced by a `duckdb_string_t` |
15 |
| - * that is at `string_byte_offset` of the given `DataView`. |
16 |
| - */ |
17 |
| -function getStringBytes(dv: DataView, string_byte_offset: number): Uint8Array { |
18 |
| - const length_in_bytes = dv.getUint32(string_byte_offset, true); |
19 |
| - if (length_in_bytes <= 12) { |
20 |
| - return new Uint8Array(dv.buffer, dv.byteOffset + string_byte_offset + 4, length_in_bytes); |
21 |
| - } else { |
22 |
| - return duckdb.get_data_from_pointer(dv.buffer, dv.byteOffset + string_byte_offset + 8, length_in_bytes); |
23 |
| - } |
24 |
| -} |
25 |
| - |
26 |
| -const decoder = new TextDecoder(); |
27 |
| - |
28 |
| -/** |
29 |
| - * Gets the UTF-8 string either in or referenced by a `duckdb_string_t` |
30 |
| - * that is at `string_byte_offset` of the given `DataView`. |
31 |
| - */ |
32 |
| -function getVarchar(dv: DataView, string_byte_offset: number): string { |
33 |
| - return decoder.decode(getStringBytes(dv, string_byte_offset)); |
34 |
| -} |
| 3 | +import { expectResult } from './utils/expectResult'; |
| 4 | +import { expectValidity } from './utils/validityTestUtils'; |
| 5 | +import { getVarchar } from './utils/valueTestUtils'; |
| 6 | +import { withConnection } from './utils/withConnection'; |
35 | 7 |
|
36 | 8 | suite('query', () => {
|
37 | 9 | test('basic select', async () => {
|
38 |
| - const db = await duckdb.open(); |
39 |
| - try { |
40 |
| - const con = await duckdb.connect(db); |
| 10 | + await withConnection(async (con) => { |
| 11 | + const res = await duckdb.query(con, 'select 17 as seventeen'); |
41 | 12 | try {
|
42 |
| - const res = await duckdb.query(con, 'select 17 as seventeen'); |
43 |
| - try { |
44 |
| - expect(duckdb.result_statement_type(res)).toBe(duckdb.StatementType.SELECT); |
45 |
| - expect(duckdb.result_return_type(res)).toBe(duckdb.ResultType.QUERY_RESULT); |
46 |
| - expect(duckdb.rows_changed(res)).toBe(0); |
47 |
| - expect(duckdb.column_count(res)).toBe(1); |
48 |
| - expect(duckdb.column_name(res, 0)).toBe('seventeen'); |
49 |
| - expect(duckdb.column_type(res, 0)).toBe(duckdb.Type.INTEGER); |
50 |
| - const col_0_logical_type = duckdb.column_logical_type(res, 0); |
51 |
| - try { |
52 |
| - expect(duckdb.get_type_id(col_0_logical_type)).toBe(duckdb.Type.INTEGER); |
53 |
| - } finally { |
54 |
| - duckdb.destroy_logical_type(col_0_logical_type); |
55 |
| - } |
56 |
| - const chunk = await duckdb.fetch_chunk(res); |
57 |
| - try { |
58 |
| - expect(duckdb.data_chunk_get_column_count(chunk)).toBe(1); |
59 |
| - expect(duckdb.data_chunk_get_size(chunk)).toBe(1); |
60 |
| - const vector = duckdb.data_chunk_get_vector(chunk, 0); |
61 |
| - const logical_type = duckdb.vector_get_column_type(vector); |
62 |
| - expect(duckdb.get_type_id(logical_type)).toBe(duckdb.Type.INTEGER); |
63 |
| - const validityBytes = duckdb.vector_get_validity(vector, 8); |
64 |
| - const validity = new BigUint64Array(validityBytes.buffer, 0, 1); |
65 |
| - const data = duckdb.vector_get_data(vector, 4); |
66 |
| - const dv = new DataView(data.buffer); |
67 |
| - expect(isValid(validity, 0)).toBe(true); |
68 |
| - const value = dv.getInt32(0, true); |
69 |
| - expect(value).toBe(17); |
70 |
| - } finally { |
71 |
| - duckdb.destroy_data_chunk(chunk); |
72 |
| - } |
73 |
| - } finally { |
74 |
| - duckdb.destroy_result(res); |
75 |
| - } |
| 13 | + await expectResult(res, { |
| 14 | + columns: [ |
| 15 | + { name: 'seventeen', type: duckdb.Type.INTEGER }, |
| 16 | + ], |
| 17 | + chunks: [ |
| 18 | + { rowCount: 1, vectors: [{ byteCount: 4, validity: [true], values: [17] }]}, |
| 19 | + ], |
| 20 | + }); |
76 | 21 | } finally {
|
77 |
| - await duckdb.disconnect(con); |
| 22 | + duckdb.destroy_result(res); |
78 | 23 | }
|
79 |
| - } finally { |
80 |
| - await duckdb.close(db); |
81 |
| - } |
| 24 | + }); |
82 | 25 | });
|
83 | 26 | test('basic error', async () => {
|
84 |
| - const db = await duckdb.open(); |
85 |
| - try { |
86 |
| - const con = await duckdb.connect(db); |
87 |
| - try { |
88 |
| - await expect(duckdb.query(con, 'selct 1')).rejects.toThrow('Parser Error'); |
89 |
| - } finally { |
90 |
| - await duckdb.disconnect(con); |
91 |
| - } |
92 |
| - } finally { |
93 |
| - await duckdb.close(db); |
94 |
| - } |
| 27 | + await withConnection(async (con) => { |
| 28 | + await expect(duckdb.query(con, 'selct 1')).rejects.toThrow('Parser Error'); |
| 29 | + }); |
95 | 30 | });
|
96 | 31 | test('test_all_types()', async () => {
|
97 | 32 | const db = await duckdb.open();
|
@@ -409,4 +344,6 @@ suite('query', () => {
|
409 | 344 | await duckdb.close(db);
|
410 | 345 | }
|
411 | 346 | });
|
| 347 | + // TODO: interrupt |
| 348 | + // TODO: query_progress |
412 | 349 | });
|
0 commit comments