diff --git a/generate-wrapper.py b/generate-wrapper.py index f19f2c53..ba630bd1 100644 --- a/generate-wrapper.py +++ b/generate-wrapper.py @@ -127,7 +127,7 @@ def visit_TypeDecl(self, node): return if isinstance(node.type, pycparser.c_ast.Struct): - self.cpp_result += f'exports.Set(Napi::String::New(env, "{name}"), duckdb_node::PointerHolder<{name}>::Init(env, "{name}")->Value());\n' + self.cpp_result += f'duckdb_node::PointerHolder<{name}>::Init(env, exports, "{name}");\n' self.types_result += f'export class {name} {{}}\n' self.c_type_to_ts_type[name] = name self.c_type_to_ts_type[f'{name}*'] = name @@ -263,11 +263,11 @@ def create_func_defs(filename): types_out = open('lib/duckdb.d.ts', 'wb') types_out.write('// placeholder interfaces for pointer types\n'.encode()) - types_out.write('export interface pointer {}\n'.encode()) - types_out.write('export interface uint64_pointer extends pointer {}\n'.encode()) types_out.write('export interface idx_pointer extends pointer {}\n'.encode()) types_out.write('// bindings-defined types\n'.encode()) + types_out.write('export class pointer {}\n'.encode()) + types_out.write('export class uint64_pointer {}\n'.encode()) types_out.write('export class out_string_wrapper {}\n'.encode()) types_out.write('// generated types and functions\n'.encode()) diff --git a/lib/duckdb.d.ts b/lib/duckdb.d.ts index 06e9220a..08b431b0 100644 --- a/lib/duckdb.d.ts +++ b/lib/duckdb.d.ts @@ -1,8 +1,8 @@ // placeholder interfaces for pointer types -export interface pointer {} -export interface uint64_pointer extends pointer {} export interface idx_pointer extends pointer {} // bindings-defined types +export class pointer {} +export class uint64_pointer {} export class out_string_wrapper {} // generated types and functions export enum duckdb_type { diff --git a/src/duckdb_node.cpp b/src/duckdb_node.cpp index 0eda137e..2cbcb1fa 100644 --- a/src/duckdb_node.cpp +++ b/src/duckdb_node.cpp @@ -56,16 +56,17 @@ class DuckDBNodeNative : public Napi::Addon { DuckDBNodeNative(Napi::Env env, Napi::Object exports) { RegisterGenerated(env, exports); - exports.Set(Napi::String::New(env, "sizeof_bool"), Napi::Number::New(env, sizeof(bool))); + duckdb_node::PointerHolder::Init(env, exports, "pointer"); + duckdb_node::PointerHolder::Init(env, exports, "uint64_pointer"); + // TODO: add idx_pointer? + duckdb_node::PointerHolder::Init(env, exports, "out_string_wrapper"); + exports.Set(Napi::String::New(env, "sizeof_bool"), Napi::Number::New(env, sizeof(bool))); exports.Set(Napi::String::New(env, "copy_buffer"), Napi::Function::New(env)); - exports.Set(Napi::String::New(env, "copy_buffer_double"), Napi::Function::New(env)); - - exports.Set( - Napi::String::New(env, "out_string_wrapper"), - duckdb_node::PointerHolder::Init(env, "out_string_wrapper")->Value()); exports.Set(Napi::String::New(env, "out_get_string"), Napi::Function::New(env)); + + // for binding; not exposed in TypeScript exports.Set(Napi::String::New(env, "initialize"), Napi::Function::New(env)); } }; diff --git a/src/duckdb_node_generated.cpp b/src/duckdb_node_generated.cpp index 82e3ab97..5549f56c 100644 --- a/src/duckdb_node_generated.cpp +++ b/src/duckdb_node_generated.cpp @@ -93,76 +93,40 @@ static void RegisterGenerated(Napi::Env env, Napi::Object exports) { exports.DefineProperty( Napi::PropertyDescriptor::Value("duckdb_statement_type", duckdb_statement_type_enum, static_cast(napi_enumerable | napi_configurable))); - exports.Set(Napi::String::New(env, "duckdb_date"), - duckdb_node::PointerHolder::Init(env, "duckdb_date")->Value()); - exports.Set(Napi::String::New(env, "duckdb_date_struct"), - duckdb_node::PointerHolder::Init(env, "duckdb_date_struct")->Value()); - exports.Set(Napi::String::New(env, "duckdb_time"), - duckdb_node::PointerHolder::Init(env, "duckdb_time")->Value()); - exports.Set(Napi::String::New(env, "duckdb_time_struct"), - duckdb_node::PointerHolder::Init(env, "duckdb_time_struct")->Value()); - exports.Set(Napi::String::New(env, "duckdb_time_tz"), - duckdb_node::PointerHolder::Init(env, "duckdb_time_tz")->Value()); - exports.Set(Napi::String::New(env, "duckdb_time_tz_struct"), - duckdb_node::PointerHolder::Init(env, "duckdb_time_tz_struct")->Value()); - exports.Set(Napi::String::New(env, "duckdb_timestamp"), - duckdb_node::PointerHolder::Init(env, "duckdb_timestamp")->Value()); - exports.Set(Napi::String::New(env, "duckdb_timestamp_struct"), - duckdb_node::PointerHolder::Init(env, "duckdb_timestamp_struct")->Value()); - exports.Set(Napi::String::New(env, "duckdb_interval"), - duckdb_node::PointerHolder::Init(env, "duckdb_interval")->Value()); - exports.Set(Napi::String::New(env, "duckdb_hugeint"), - duckdb_node::PointerHolder::Init(env, "duckdb_hugeint")->Value()); - exports.Set(Napi::String::New(env, "duckdb_uhugeint"), - duckdb_node::PointerHolder::Init(env, "duckdb_uhugeint")->Value()); - exports.Set(Napi::String::New(env, "duckdb_decimal"), - duckdb_node::PointerHolder::Init(env, "duckdb_decimal")->Value()); - exports.Set( - Napi::String::New(env, "duckdb_query_progress_type"), - duckdb_node::PointerHolder::Init(env, "duckdb_query_progress_type")->Value()); - exports.Set(Napi::String::New(env, "duckdb_string_t"), - duckdb_node::PointerHolder::Init(env, "duckdb_string_t")->Value()); - exports.Set(Napi::String::New(env, "duckdb_list_entry"), - duckdb_node::PointerHolder::Init(env, "duckdb_list_entry")->Value()); - exports.Set(Napi::String::New(env, "duckdb_column"), - duckdb_node::PointerHolder::Init(env, "duckdb_column")->Value()); - exports.Set(Napi::String::New(env, "duckdb_vector"), - duckdb_node::PointerHolder::Init(env, "duckdb_vector")->Value()); - exports.Set(Napi::String::New(env, "duckdb_string"), - duckdb_node::PointerHolder::Init(env, "duckdb_string")->Value()); - exports.Set(Napi::String::New(env, "duckdb_blob"), - duckdb_node::PointerHolder::Init(env, "duckdb_blob")->Value()); - exports.Set(Napi::String::New(env, "duckdb_result"), - duckdb_node::PointerHolder::Init(env, "duckdb_result")->Value()); - exports.Set(Napi::String::New(env, "duckdb_database"), - duckdb_node::PointerHolder::Init(env, "duckdb_database")->Value()); - exports.Set(Napi::String::New(env, "duckdb_connection"), - duckdb_node::PointerHolder::Init(env, "duckdb_connection")->Value()); - exports.Set(Napi::String::New(env, "duckdb_prepared_statement"), - duckdb_node::PointerHolder::Init(env, "duckdb_prepared_statement")->Value()); - exports.Set( - Napi::String::New(env, "duckdb_extracted_statements"), - duckdb_node::PointerHolder::Init(env, "duckdb_extracted_statements")->Value()); - exports.Set(Napi::String::New(env, "duckdb_pending_result"), - duckdb_node::PointerHolder::Init(env, "duckdb_pending_result")->Value()); - exports.Set(Napi::String::New(env, "duckdb_appender"), - duckdb_node::PointerHolder::Init(env, "duckdb_appender")->Value()); - exports.Set(Napi::String::New(env, "duckdb_config"), - duckdb_node::PointerHolder::Init(env, "duckdb_config")->Value()); - exports.Set(Napi::String::New(env, "duckdb_logical_type"), - duckdb_node::PointerHolder::Init(env, "duckdb_logical_type")->Value()); - exports.Set(Napi::String::New(env, "duckdb_data_chunk"), - duckdb_node::PointerHolder::Init(env, "duckdb_data_chunk")->Value()); - exports.Set(Napi::String::New(env, "duckdb_value"), - duckdb_node::PointerHolder::Init(env, "duckdb_value")->Value()); - exports.Set(Napi::String::New(env, "duckdb_arrow"), - duckdb_node::PointerHolder::Init(env, "duckdb_arrow")->Value()); - exports.Set(Napi::String::New(env, "duckdb_arrow_stream"), - duckdb_node::PointerHolder::Init(env, "duckdb_arrow_stream")->Value()); - exports.Set(Napi::String::New(env, "duckdb_arrow_schema"), - duckdb_node::PointerHolder::Init(env, "duckdb_arrow_schema")->Value()); - exports.Set(Napi::String::New(env, "duckdb_arrow_array"), - duckdb_node::PointerHolder::Init(env, "duckdb_arrow_array")->Value()); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_date"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_date_struct"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_time"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_time_struct"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_time_tz"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_time_tz_struct"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_timestamp"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_timestamp_struct"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_interval"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_hugeint"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_uhugeint"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_decimal"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_query_progress_type"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_string_t"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_list_entry"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_column"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_vector"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_string"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_blob"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_result"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_database"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_connection"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_prepared_statement"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_extracted_statements"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_pending_result"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_appender"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_config"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_logical_type"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_data_chunk"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_value"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_arrow"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_arrow_stream"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_arrow_schema"); + duckdb_node::PointerHolder::Init(env, exports, "duckdb_arrow_array"); exports.Set(Napi::String::New(env, "duckdb_open"), Napi::Function::New>(env)); diff --git a/src/value_conversion.hpp b/src/value_conversion.hpp index 8b1a0bc6..f6b6a80d 100644 --- a/src/value_conversion.hpp +++ b/src/value_conversion.hpp @@ -28,12 +28,14 @@ static Napi::Value GetValue(const Napi::CallbackInfo &info, size_t offset) { template class PointerHolder : public Napi::ObjectWrap> { public: - static Napi::FunctionReference *Init(Napi::Env env, const char *name) { + static void Init(Napi::Env env, Napi::Object exports, const char *name) { auto func = Napi::ObjectWrap>::DefineClass(env, name, {}); - auto constructor = new Napi::FunctionReference(); - *constructor = Napi::Persistent(func); // weird - env.SetInstanceData(constructor); // is this so this is eventually freed? - return constructor; + constructor = Napi::Persistent(func); // set initial reference count to 1 + exports.Set(name, func); + // How does the following interact with the static storage of constructor? + // Does not doing this create problems for multiple instance of this add-on, in multiple worker threads? + // See: https://github.com/nodejs/node-addon-api/blob/main/doc/object_wrap.md#example + // env.SetInstanceData(&constructor); // is this so this is eventually freed? } PointerHolder(const Napi::CallbackInfo &info) : Napi::ObjectWrap>(info) { @@ -45,8 +47,7 @@ class PointerHolder : public Napi::ObjectWrap> { } static Napi::Value NewAndSet(Napi::Env &env, T val) { - // TODO use actual constructor here ? - auto res = PointerHolder::DefineClass(env, "duckdb_pointer_holder", {}, nullptr).New({}); + auto res = constructor.New({}); Napi::ObjectWrap>::Unwrap(res)->Set(val); return res; } @@ -59,9 +60,12 @@ class PointerHolder : public Napi::ObjectWrap> { } private: + static Napi::FunctionReference constructor; std::unique_ptr ptr; }; +template Napi::FunctionReference PointerHolder::constructor; + struct out_string_wrapper { const char *ptr; };