diff --git a/javascript/lib.cpp b/javascript/lib.cpp index 5034dd5f..afdb1bb6 100644 --- a/javascript/lib.cpp +++ b/javascript/lib.cpp @@ -37,6 +37,8 @@ class Index : public Napi::ObjectWrap { void Add(Napi::CallbackInfo const& ctx); Napi::Value Search(Napi::CallbackInfo const& ctx); + Napi::Value Remove(Napi::CallbackInfo const& ctx); + Napi::Value Contains(Napi::CallbackInfo const& ctx); std::unique_ptr native_; }; @@ -51,6 +53,8 @@ Napi::Object Index::Init(Napi::Env env, Napi::Object exports) { InstanceMethod("connectivity", &Index::GetConnectivity), InstanceMethod("add", &Index::Add), InstanceMethod("search", &Index::Search), + InstanceMethod("remove", &Index::Remove), + InstanceMethod("contains", &Index::Contains), InstanceMethod("save", &Index::Save), InstanceMethod("load", &Index::Load), InstanceMethod("view", &Index::View), @@ -291,6 +295,64 @@ Napi::Value Index::Search(Napi::CallbackInfo const& ctx) { } } +Napi::Value Index::Remove(Napi::CallbackInfo const& ctx) { + Napi::Env env = ctx.Env(); + if (ctx.Length() < 1 || !ctx[0].IsBigInt()) { + Napi::TypeError::New(env, "Expects an entry identifier").ThrowAsJavaScriptException(); + return {}; + } + + Napi::BigInt key_js = ctx[0].As(); + bool lossless = true; + std::uint64_t key = key_js.Uint64Value(&lossless); + if (!lossless) { + Napi::TypeError::New(env, "Identifier must be an unsigned integer").ThrowAsJavaScriptException(); + return {}; + } + + try { + auto result = native_->remove(key); + if (!result) { + Napi::TypeError::New(env, "Removal has failed").ThrowAsJavaScriptException(); + return {}; + } + return Napi::Boolean::New(env, result.completed); + } catch (std::bad_alloc const&) { + Napi::TypeError::New(env, "Out of memory").ThrowAsJavaScriptException(); + return {}; + } catch (...) { + Napi::TypeError::New(env, "Search failed").ThrowAsJavaScriptException(); + return {}; + } +} + +Napi::Value Index::Contains(Napi::CallbackInfo const& ctx) { + Napi::Env env = ctx.Env(); + if (ctx.Length() < 1 || !ctx[0].IsBigInt()) { + Napi::TypeError::New(env, "Expects an entry identifier").ThrowAsJavaScriptException(); + return {}; + } + + Napi::BigInt key_js = ctx[0].As(); + bool lossless = true; + std::uint64_t key = key_js.Uint64Value(&lossless); + if (!lossless) { + Napi::TypeError::New(env, "Identifier must be an unsigned integer").ThrowAsJavaScriptException(); + return {}; + } + + try { + bool result = native_->contains(key); + return Napi::Boolean::New(env, result); + } catch (std::bad_alloc const&) { + Napi::TypeError::New(env, "Out of memory").ThrowAsJavaScriptException(); + return {}; + } catch (...) { + Napi::TypeError::New(env, "Search failed").ThrowAsJavaScriptException(); + return {}; + } +} + Napi::Object InitAll(Napi::Env env, Napi::Object exports) { return Index::Init(env, exports); } NODE_API_MODULE(usearch, InitAll) diff --git a/javascript/test.js b/javascript/test.js index a6332ca8..f190af89 100644 --- a/javascript/test.js +++ b/javascript/test.js @@ -11,6 +11,7 @@ assert.equal(index.size(), 0n, 'initial size should be 0'); index.add(15n, new Float32Array([10, 20])); index.add(16n, new Float32Array([10, 25])); assert.equal(index.size(), 2n, 'size after adding elements should be 2'); +assert.equal(index.contains(15n), true, 'entry must be present after insertion'); var results = index.search(new Float32Array([13, 14]), 2n); assert.deepEqual(results.keys, new BigUint64Array([15n, 16n]), 'keys should be 15 and 16'); diff --git a/javascript/usearch.d.ts b/javascript/usearch.d.ts index 50cb411a..bd7a6bd1 100644 --- a/javascript/usearch.d.ts +++ b/javascript/usearch.d.ts @@ -11,7 +11,7 @@ export interface Matches { /** K-Approximate Nearest Neighbors search index. */ export class Index { - + /** * Constructs a new index. * @@ -42,7 +42,7 @@ export class Index { * @return {bigints} The capacity of index. */ capacity(): bigint; - + /** * Returns connectivity. * @return {bigint} The connectivity of index. @@ -84,4 +84,19 @@ export class Index { * @return {Matches} Output of the search result. */ search(mat: Float32Array, k: bigint): Matches; + + /** + * Check if an entry is contained in the index. + * + * @param {bigint} key Identifier to look up. + */ + contains(key: bigint): boolean; + + /** + * Remove a vector from the index. + * + * @param {bigint} key Input identifier for every vector to be removed. + */ + remove(key: bigint): boolean; + } \ No newline at end of file