Skip to content

Commit

Permalink
Merge pull request #18 from duckdb/jray/data-chunk-functions-and-tests
Browse files Browse the repository at this point in the history
data chunk functions and tests
  • Loading branch information
jraymakers authored Oct 8, 2024
2 parents 983b77b + 568bce9 commit 17b375e
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 11 deletions.
54 changes: 44 additions & 10 deletions bindings/src/duckdb_node_bindings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2357,7 +2357,14 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
// function create_data_chunk(logical_types: readonly LogicalType[]): DataChunk
Napi::Value create_data_chunk(const Napi::CallbackInfo& info) {
auto env = info.Env();
throw Napi::Error::New(env, "Not implemented yet");
auto types_array = info[0].As<Napi::Array>();
auto types_count = types_array.Length();
std::vector<duckdb_logical_type> types(types_count);
for (uint32_t i = 0; i < types_count; i++) {
types[i] = GetLogicalTypeFromExternal(env, types_array.Get(i));
}
auto data_chunk = duckdb_create_data_chunk(types.data(), types_count);
return CreateExternalForDataChunk(env, data_chunk);
}

// DUCKDB_API void duckdb_destroy_data_chunk(duckdb_data_chunk *chunk);
Expand All @@ -2373,7 +2380,9 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
// function data_chunk_reset(chunk: DataChunk): void
Napi::Value data_chunk_reset(const Napi::CallbackInfo& info) {
auto env = info.Env();
throw Napi::Error::New(env, "Not implemented yet");
auto chunk = GetDataChunkFromExternal(env, info[0]);
duckdb_data_chunk_reset(chunk);
return env.Undefined();
}

// DUCKDB_API idx_t duckdb_data_chunk_get_column_count(duckdb_data_chunk chunk);
Expand Down Expand Up @@ -2408,7 +2417,10 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
// function data_chunk_set_size(chunk: DataChunk, size: number): void
Napi::Value data_chunk_set_size(const Napi::CallbackInfo& info) {
auto env = info.Env();
throw Napi::Error::New(env, "Not implemented yet");
auto chunk = GetDataChunkFromExternal(env, info[0]);
auto size = info[1].As<Napi::Number>().Uint32Value();
duckdb_data_chunk_set_size(chunk, size);
return env.Undefined();
}

// DUCKDB_API duckdb_logical_type duckdb_vector_get_column_type(duckdb_vector vector);
Expand Down Expand Up @@ -2444,14 +2456,20 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
// function vector_ensure_validity_writable(vector: Vector): void
Napi::Value vector_ensure_validity_writable(const Napi::CallbackInfo& info) {
auto env = info.Env();
throw Napi::Error::New(env, "Not implemented yet");
auto vector = GetVectorFromExternal(env, info[0]);
duckdb_vector_ensure_validity_writable(vector);
return env.Undefined();
}

// DUCKDB_API void duckdb_vector_assign_string_element(duckdb_vector vector, idx_t index, const char *str);
// function vector_assign_string_element(vector: Vector, index: number, str: string): void
Napi::Value vector_assign_string_element(const Napi::CallbackInfo& info) {
auto env = info.Env();
throw Napi::Error::New(env, "Not implemented yet");
auto vector = GetVectorFromExternal(env, info[0]);
auto index = info[1].As<Napi::Number>().Uint32Value();
std::string str = info[2].As<Napi::String>();
duckdb_vector_assign_string_element(vector, index, str.c_str());
return env.Undefined();
}

// DUCKDB_API void duckdb_vector_assign_string_element_len(duckdb_vector vector, idx_t index, const char *str, idx_t str_len);
Expand Down Expand Up @@ -2479,14 +2497,20 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
// function list_vector_set_size(vector: Vector, size: number): void
Napi::Value list_vector_set_size(const Napi::CallbackInfo& info) {
auto env = info.Env();
throw Napi::Error::New(env, "Not implemented yet");
auto vector = GetVectorFromExternal(env, info[0]);
auto size = info[1].As<Napi::Number>().Uint32Value();
duckdb_list_vector_set_size(vector, size);
return env.Undefined();
}

// DUCKDB_API duckdb_state duckdb_list_vector_reserve(duckdb_vector vector, idx_t required_capacity);
// function list_vector_reserve(vector: Vector, required_capacity: number): void
Napi::Value list_vector_reserve(const Napi::CallbackInfo& info) {
auto env = info.Env();
throw Napi::Error::New(env, "Not implemented yet");
auto vector = GetVectorFromExternal(env, info[0]);
auto required_capacity = info[1].As<Napi::Number>().Uint32Value();
duckdb_list_vector_reserve(vector, required_capacity);
return env.Undefined();
}

// DUCKDB_API duckdb_vector duckdb_struct_vector_get_child(duckdb_vector vector, idx_t index);
Expand Down Expand Up @@ -2522,21 +2546,31 @@ class DuckDBNodeAddon : public Napi::Addon<DuckDBNodeAddon> {
// function validity_set_row_validity(validity: Uint8Array, row_index: number, valid: boolean): void
Napi::Value validity_set_row_validity(const Napi::CallbackInfo& info) {
auto env = info.Env();
throw Napi::Error::New(env, "Not implemented yet");
auto validity = reinterpret_cast<uint64_t*>(info[0].As<Napi::Uint8Array>().Data());
auto row_index = info[1].As<Napi::Number>().Uint32Value();
auto valid = info[2].As<Napi::Boolean>();
duckdb_validity_set_row_validity(validity, row_index, valid);
return env.Undefined();
}

// DUCKDB_API void duckdb_validity_set_row_invalid(uint64_t *validity, idx_t row);
// function validity_set_row_invalid(validity: Uint8Array, row_index: number): void
Napi::Value validity_set_row_invalid(const Napi::CallbackInfo& info) {
auto env = info.Env();
throw Napi::Error::New(env, "Not implemented yet");
auto validity = reinterpret_cast<uint64_t*>(info[0].As<Napi::Uint8Array>().Data());
auto row_index = info[1].As<Napi::Number>().Uint32Value();
duckdb_validity_set_row_invalid(validity, row_index);
return env.Undefined();
}

// DUCKDB_API void duckdb_validity_set_row_valid(uint64_t *validity, idx_t row);
// function validity_set_row_valid(validity: Uint8Array, row_index: number): void
Napi::Value validity_set_row_valid(const Napi::CallbackInfo& info) {
auto env = info.Env();
throw Napi::Error::New(env, "Not implemented yet");
auto validity = reinterpret_cast<uint64_t*>(info[0].As<Napi::Uint8Array>().Data());
auto row_index = info[1].As<Napi::Number>().Uint32Value();
duckdb_validity_set_row_valid(validity, row_index);
return env.Undefined();
}

// #ifndef DUCKDB_NO_EXTENSION_FUNCTIONS
Expand Down
114 changes: 114 additions & 0 deletions bindings/test/data_chunk.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import duckdb from '@duckdb/node-bindings';
import { expect, suite, test } from 'vitest';
import { expectLogicalType } from './utils/expectLogicalType';
import { INTEGER, VARCHAR } from './utils/expectedLogicalTypes';

suite('data chunk', () => {
test('create', () => {
const int_type = duckdb.create_logical_type(duckdb.Type.INTEGER);
const varchar_type = duckdb.create_logical_type(duckdb.Type.VARCHAR);
try {
const chunk = duckdb.create_data_chunk([int_type, varchar_type]);
try {
expect(duckdb.data_chunk_get_column_count(chunk)).toBe(2);
const vec0 = duckdb.data_chunk_get_vector(chunk, 0);
expectLogicalType(duckdb.vector_get_column_type(vec0), INTEGER);
const vec1 = duckdb.data_chunk_get_vector(chunk, 1);
expectLogicalType(duckdb.vector_get_column_type(vec1), VARCHAR);
} finally {
duckdb.destroy_data_chunk(chunk);
}
} finally {
duckdb.destroy_logical_type(int_type);
duckdb.destroy_logical_type(varchar_type);
}
});
test('change size', () => {
const int_type = duckdb.create_logical_type(duckdb.Type.INTEGER);
try {
const chunk = duckdb.create_data_chunk([int_type]);
try {
expect(duckdb.data_chunk_get_size(chunk)).toBe(0);
duckdb.data_chunk_set_size(chunk, 42);
expect(duckdb.data_chunk_get_size(chunk)).toBe(42);
duckdb.data_chunk_reset(chunk);
expect(duckdb.data_chunk_get_size(chunk)).toBe(0);
} finally {
duckdb.destroy_data_chunk(chunk);
}
} finally {
duckdb.destroy_logical_type(int_type);
}
});
test('write vector validity', () => {
const int_type = duckdb.create_logical_type(duckdb.Type.INTEGER);
try {
const chunk = duckdb.create_data_chunk([int_type]);
try {
duckdb.data_chunk_set_size(chunk, 3);
const vector = duckdb.data_chunk_get_vector(chunk, 0);
duckdb.vector_ensure_validity_writable(vector);
// const data = duckdb.vector_get_data(vector, 3 * 4);
const validity = duckdb.vector_get_validity(vector, 8);
expect(validity[0]).toBe(0b11111111);
duckdb.validity_set_row_validity(validity, 1, false);
expect(validity[0]).toBe(0b11111101);
duckdb.validity_set_row_valid(validity, 1);
expect(validity[0]).toBe(0b11111111);
duckdb.validity_set_row_invalid(validity, 2);
expect(validity[0]).toBe(0b11111011);
} finally {
duckdb.destroy_data_chunk(chunk);
}
} finally {
duckdb.destroy_logical_type(int_type);
}
});
test('write string vector', () => {
const varchar_type = duckdb.create_logical_type(duckdb.Type.VARCHAR);
try {
const chunk = duckdb.create_data_chunk([varchar_type]);
try {
duckdb.data_chunk_set_size(chunk, 3);
const vector = duckdb.data_chunk_get_vector(chunk, 0);
duckdb.vector_assign_string_element(vector, 0, 'ABC');
duckdb.vector_assign_string_element(vector, 1, 'abcdefghijkl');
duckdb.vector_assign_string_element(vector, 2, 'longer than twelve characters');
const data = duckdb.vector_get_data(vector, 3 * 16);
const dv = new DataView(data.buffer);
expect(dv.getUint32(0, true)).toBe(3);
expect([data[4], data[5], data[6]]).toStrictEqual([0x41, 0x42, 0x43]); // A, B, C
expect(dv.getUint32(16, true)).toBe(12);
expect([data[20], data[31]]).toStrictEqual([0x61, 0x6c]); // a, l
expect(dv.getUint32(32, true)).toBe('longer than twelve characters'.length);
expect([data[36], data[37], data[38], data[39]]).toStrictEqual([0x6c, 0x6f, 0x6e, 0x67]); // l, o, n, g
} finally {
duckdb.destroy_data_chunk(chunk);
}
} finally {
duckdb.destroy_logical_type(varchar_type);
}
});
test('set list vector size', () => {
const int_type = duckdb.create_logical_type(duckdb.Type.INTEGER);
try {
const list_type = duckdb.create_list_type(int_type);
try {
const chunk = duckdb.create_data_chunk([list_type]);
try {
duckdb.data_chunk_set_size(chunk, 3);
const vector = duckdb.data_chunk_get_vector(chunk, 0);
duckdb.list_vector_reserve(vector, 7); // can't easily verify that this worked
duckdb.list_vector_set_size(vector, 5);
expect(duckdb.list_vector_get_size(vector)).toBe(5);
} finally {
duckdb.destroy_data_chunk(chunk);
}
} finally {
duckdb.destroy_logical_type(list_type);
}
} finally {
duckdb.destroy_logical_type(int_type);
}
});
});
2 changes: 1 addition & 1 deletion bindings/test/pending.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ suite('pending', () => {
}
});
});
test('interrupt', async () => {
test.skip('interrupt', async () => { // interrupt does not appear to be entirely deterministic
await withConnection(async (connection) => {
const prepared = await duckdb.prepare(connection, 'select count(*) as count from range(10_000)');
try {
Expand Down

0 comments on commit 17b375e

Please sign in to comment.