diff --git a/api/pkgs/@duckdb/node-api/README.md b/api/pkgs/@duckdb/node-api/README.md index da716d7f..23af0630 100644 --- a/api/pkgs/@duckdb/node-api/README.md +++ b/api/pkgs/@duckdb/node-api/README.md @@ -644,7 +644,7 @@ await connection.run( `create or replace table target_table(i integer, v varchar)` ); -const appender = await connection.createAppender('main', 'target_table'); +const appender = await connection.createAppender('target_table'); appender.appendInteger(42); appender.appendVarchar('duck'); @@ -670,7 +670,7 @@ await connection.run( `create or replace table target_table(i integer, v varchar)` ); -const appender = await connection.createAppender('main', 'target_table'); +const appender = await connection.createAppender('target_table'); const chunk = DuckDBDataChunk.create([INTEGER, VARCHAR]); chunk.setColumns([ diff --git a/api/src/DuckDBConnection.ts b/api/src/DuckDBConnection.ts index a052b109..6c7f103f 100644 --- a/api/src/DuckDBConnection.ts +++ b/api/src/DuckDBConnection.ts @@ -161,11 +161,17 @@ export class DuckDBConnection { ); } public async createAppender( - schema: string, - table: string + table: string, + schema?: string | null, + catalog?: string | null ): Promise { return new DuckDBAppender( - duckdb.appender_create(this.connection, schema, table) + duckdb.appender_create_ext( + this.connection, + catalog ?? null, + schema ?? null, + table + ) ); } } diff --git a/api/test/api.test.ts b/api/test/api.test.ts index 6e163126..27a8a7de 100644 --- a/api/test/api.test.ts +++ b/api/test/api.test.ts @@ -1374,7 +1374,7 @@ describe('api', () => { chunk.setColumnValues(0, values); await connection.run('create table target(col0 int)'); - const appender = await connection.createAppender('main', 'target'); + const appender = await connection.createAppender('target'); appender.appendDataChunk(chunk); appender.flush(); @@ -1408,7 +1408,7 @@ describe('api', () => { } await connection.run('create table target1(col0 int)'); - const appender1 = await connection.createAppender('main', 'target1'); + const appender1 = await connection.createAppender('target1'); appender1.appendDataChunk(chunk); appender1.flush(); @@ -1425,7 +1425,7 @@ describe('api', () => { vector.flush(); await connection.run('create table target2(col0 int)'); - const appender2 = await connection.createAppender('main', 'target2'); + const appender2 = await connection.createAppender('target2'); appender2.appendDataChunk(chunk); appender2.flush(); @@ -1447,7 +1447,7 @@ describe('api', () => { chunk.setColumnValues(0, values); await connection.run('create table target(col0 varchar)'); - const appender = await connection.createAppender('main', 'target'); + const appender = await connection.createAppender('target'); appender.appendDataChunk(chunk); appender.flush(); @@ -1483,7 +1483,7 @@ describe('api', () => { chunk.setColumnValues(0, values); await connection.run('create table target(col0 blob)'); - const appender = await connection.createAppender('main', 'target'); + const appender = await connection.createAppender('target'); appender.appendDataChunk(chunk); appender.flush(); @@ -1510,7 +1510,7 @@ describe('api', () => { chunk.setColumnValues(0, values); await connection.run('create table target(col0 integer[])'); - const appender = await connection.createAppender('main', 'target'); + const appender = await connection.createAppender('target'); appender.appendDataChunk(chunk); appender.flush(); @@ -1557,7 +1557,7 @@ describe('api', () => { ]); await connection.run('create table target(col0 integer[][])'); - const appender = await connection.createAppender('main', 'target'); + const appender = await connection.createAppender('target'); appender.appendDataChunk(chunk); appender.flush(); @@ -1584,7 +1584,7 @@ describe('api', () => { chunk.setColumnValues(0, values); await connection.run('create table target(col0 integer[3])'); - const appender = await connection.createAppender('main', 'target'); + const appender = await connection.createAppender('target'); appender.appendDataChunk(chunk); appender.flush(); @@ -1611,7 +1611,7 @@ describe('api', () => { chunk.setColumnValues(0, values); await connection.run('create table target(col0 varchar[3])'); - const appender = await connection.createAppender('main', 'target'); + const appender = await connection.createAppender('target'); appender.appendDataChunk(chunk); appender.flush(); @@ -1643,7 +1643,7 @@ describe('api', () => { await connection.run( 'create table target(col0 struct(num integer, str varchar))' ); - const appender = await connection.createAppender('main', 'target'); + const appender = await connection.createAppender('target'); appender.appendDataChunk(chunk); appender.flush(); @@ -1683,7 +1683,7 @@ describe('api', () => { int integer\ )' ); - const appender = await connection.createAppender('main', 'target'); + const appender = await connection.createAppender('target'); appender.appendDataChunk(chunk); appender.flush(); @@ -1720,7 +1720,7 @@ describe('api', () => { .map(({ name, type }) => `"${name.replace(`"`, `""`)}" ${type}`) .join(', ')})` ); - const appender = await connection.createAppender('main', 'target'); + const appender = await connection.createAppender('target'); appender.appendDataChunk(chunk); appender.flush(); diff --git a/api/test/bench/read.bench.ts b/api/test/bench/read.bench.ts index f3b65ee7..c47400c2 100644 --- a/api/test/bench/read.bench.ts +++ b/api/test/bench/read.bench.ts @@ -100,7 +100,7 @@ for (const full of [false, true]) { }, { setup, - iterations: 200, + iterations: 20, } ); bench( @@ -126,7 +126,7 @@ for (const full of [false, true]) { }, { setup, - iterations: 200, + iterations: 20, } ); bench( @@ -160,7 +160,7 @@ for (const full of [false, true]) { }, { setup, - iterations: 200, + iterations: 20, } ); @@ -179,7 +179,7 @@ for (const full of [false, true]) { }, { setup, - iterations: 200, + iterations: 20, } ); bench( @@ -205,7 +205,7 @@ for (const full of [false, true]) { }, { setup, - iterations: 200, + iterations: 20, } ); bench( @@ -239,7 +239,7 @@ for (const full of [false, true]) { }, { setup, - iterations: 200, + iterations: 20, } ); bench( @@ -265,7 +265,7 @@ for (const full of [false, true]) { }, { setup, - iterations: 200, + iterations: 20, } ); bench( @@ -291,7 +291,7 @@ for (const full of [false, true]) { }, { setup, - iterations: 200, + iterations: 20, } ); }); diff --git a/api/test/bench/write.bench.ts b/api/test/bench/write.bench.ts index 51de4adf..94d1d353 100644 --- a/api/test/bench/write.bench.ts +++ b/api/test/bench/write.bench.ts @@ -1,9 +1,9 @@ -import { bench, describe } from "vitest"; +import { bench, describe } from 'vitest'; import { DuckDBConnection, DuckDBInstance, DuckDBTimestampValue, -} from "../../src"; +} from '../../src'; let instance: DuckDBInstance; let connection: DuckDBConnection; @@ -26,7 +26,7 @@ for (const batchSize of [1, 1000]) { `${batchSize} insert bind`, async () => { const query = await connection.prepare( - "INSERT INTO test (timestamp, value) VALUES ($1, $2);" + 'INSERT INTO test (timestamp, value) VALUES ($1, $2);' ); for (let index = 0; index < batchSize; index++) { @@ -46,7 +46,7 @@ for (const batchSize of [1, 1000]) { bench( `${batchSize} row append`, async () => { - const appender = await connection.createAppender("main", "test"); + const appender = await connection.createAppender('test'); for (let index = 0; index < batchSize; index++) { appender.appendTimestamp( diff --git a/bindings/pkgs/@duckdb/node-bindings/duckdb.d.ts b/bindings/pkgs/@duckdb/node-bindings/duckdb.d.ts index c2fc57ec..79c7e568 100644 --- a/bindings/pkgs/@duckdb/node-bindings/duckdb.d.ts +++ b/bindings/pkgs/@duckdb/node-bindings/duckdb.d.ts @@ -1054,9 +1054,10 @@ export function validity_set_row_valid(validity: Uint8Array, row_index: number): // DUCKDB_API duckdb_profiling_info duckdb_profiling_info_get_child(duckdb_profiling_info info, idx_t index); // DUCKDB_API duckdb_state duckdb_appender_create(duckdb_connection connection, const char *schema, const char *table, duckdb_appender *out_appender); -export function appender_create(connection: Connection, schema: string, table: string): Appender; +export function appender_create(connection: Connection, schema: string | null, table: string): Appender; // DUCKDB_API duckdb_state duckdb_appender_create_ext(duckdb_connection connection, const char *catalog, const char *schema, const char *table, duckdb_appender *out_appender); +export function appender_create_ext(connection: Connection, catalog: string | null, schema: string | null, table: string): Appender; // DUCKDB_API idx_t duckdb_appender_column_count(duckdb_appender appender); export function appender_column_count(appender: Appender): number; diff --git a/bindings/src/duckdb_node_bindings.cpp b/bindings/src/duckdb_node_bindings.cpp index 10d86167..cb02fedf 100644 --- a/bindings/src/duckdb_node_bindings.cpp +++ b/bindings/src/duckdb_node_bindings.cpp @@ -1273,6 +1273,7 @@ class DuckDBNodeAddon : public Napi::Addon { InstanceMethod("validity_set_row_valid", &DuckDBNodeAddon::validity_set_row_valid), InstanceMethod("appender_create", &DuckDBNodeAddon::appender_create), + InstanceMethod("appender_create_ext", &DuckDBNodeAddon::appender_create_ext), InstanceMethod("appender_column_count", &DuckDBNodeAddon::appender_column_count), InstanceMethod("appender_column_type", &DuckDBNodeAddon::appender_column_type), InstanceMethod("appender_flush", &DuckDBNodeAddon::appender_flush), @@ -3707,17 +3708,24 @@ class DuckDBNodeAddon : public Napi::Addon { // DUCKDB_API duckdb_profiling_info duckdb_profiling_info_get_child(duckdb_profiling_info info, idx_t index); // DUCKDB_API duckdb_state duckdb_appender_create(duckdb_connection connection, const char *schema, const char *table, duckdb_appender *out_appender); - // function appender_create(connection: Connection, schema: string, table: string): Appender + // function appender_create(connection: Connection, schema: string | null, table: string): Appender Napi::Value appender_create(const Napi::CallbackInfo& info) { auto env = info.Env(); auto connection = GetConnectionFromExternal(env, info[0]); if (!connection) { throw Napi::Error::New(env, "Failed to create appender: connection disconnected"); } - std::string schema = info[1].As(); + std::string schema = info[1].IsNull() ? std::string() : info[1].As(); std::string table = info[2].As(); duckdb_appender appender; - if (duckdb_appender_create(connection, schema.c_str(), table.c_str(), &appender)) { + if ( + duckdb_appender_create( + connection, + info[1].IsNull() ? nullptr : schema.c_str(), + table.c_str(), + &appender + ) + ) { std::string error = duckdb_appender_error(appender); duckdb_appender_destroy(&appender); throw Napi::Error::New(env, error); @@ -3726,6 +3734,32 @@ class DuckDBNodeAddon : public Napi::Addon { } // DUCKDB_API duckdb_state duckdb_appender_create_ext(duckdb_connection connection, const char *catalog, const char *schema, const char *table, duckdb_appender *out_appender); + // function appender_create_ext(connection: Connection, catalog: string | null, schema: string | null, table: string): Appender + Napi::Value appender_create_ext(const Napi::CallbackInfo& info) { + auto env = info.Env(); + auto connection = GetConnectionFromExternal(env, info[0]); + if (!connection) { + throw Napi::Error::New(env, "Failed to create appender: connection disconnected"); + } + std::string catalog = info[1].IsNull() ? std::string() : info[1].As(); + std::string schema = info[2].IsNull() ? std::string() : info[2].As(); + std::string table = info[3].As(); + duckdb_appender appender; + if ( + duckdb_appender_create_ext( + connection, + info[1].IsNull() ? nullptr : catalog.c_str(), + info[2].IsNull() ? nullptr : schema.c_str(), + table.c_str(), + &appender + ) + ) { + std::string error = duckdb_appender_error(appender); + duckdb_appender_destroy(&appender); + throw Napi::Error::New(env, error); + } + return CreateExternalForAppender(env, appender); + } // DUCKDB_API idx_t duckdb_appender_column_count(duckdb_appender appender); // function appender_column_count(appender: Appender): number @@ -4183,7 +4217,7 @@ NODE_API_ADDON(DuckDBNodeAddon) --- 411 total functions - 237 instance methods + 238 instance methods 3 unimplemented instance cache functions 1 unimplemented logical type function 13 unimplemented scalar function functions @@ -4196,7 +4230,7 @@ NODE_API_ADDON(DuckDBNodeAddon) 5 unimplemented function info functions 4 unimplemented replacement scan functions 5 unimplemented profiling info functions - 5 unimplemented appender functions + 4 unimplemented appender functions 6 unimplemented table description functions 8 unimplemented tasks functions 12 unimplemented cast function functions diff --git a/bindings/test/appender.test.ts b/bindings/test/appender.test.ts index c8bc8ef3..9b2909ad 100644 --- a/bindings/test/appender.test.ts +++ b/bindings/test/appender.test.ts @@ -9,7 +9,7 @@ import { data } from './utils/expectedVectors'; suite('appender', () => { test('error: no table', async () => { await withConnection(async (connection) => { - expect(() => duckdb.appender_create(connection, 'main', 'bogus_table')) + expect(() => duckdb.appender_create_ext(connection, 'memory', 'main', 'bogus_table')) .toThrowError(`Table "main.bogus_table" could not be found`); }); }); @@ -27,7 +27,7 @@ suite('appender', () => { chunks: [], }); - const appender = duckdb.appender_create(connection, 'main', 'appender_target'); + const appender = duckdb.appender_create_ext(connection, 'memory', 'main', 'appender_target'); expect(duckdb.appender_column_count(appender)).toBe(1); const column_type = duckdb.appender_column_type(appender, 0); expectLogicalType(column_type, INTEGER); @@ -92,7 +92,7 @@ suite('appender', () => { }); - const appender = duckdb.appender_create(connection, 'main', 'appender_target'); + const appender = duckdb.appender_create_ext(connection, 'memory', 'main', 'appender_target'); expect(duckdb.appender_column_count(appender)).toBe(21); const expectedLogicalTypes = [ @@ -222,7 +222,7 @@ suite('appender', () => { chunks: [], }); - const appender = duckdb.appender_create(connection, 'main', 'appender_target'); + const appender = duckdb.appender_create_ext(connection, 'memory', 'main', 'appender_target'); expect(duckdb.appender_column_count(appender)).toBe(2); const source_result = await duckdb.query(connection, 'select int, varchar from test_all_types()');