Repository: denoland/deno
Pull request: fix(ext/node): napi_get_element and napi_set_element work with objects

This change makes DuckDB example work: https://github.com/denoland/deno/issues/23656.

Changed files:
filename: cli/napi/js_native_api.rs
patch: @@ -1855,11 +1855,11 @@ fn napi_get_element(
   check_env!(env);
   let env = unsafe { &mut *env };
   let object = napi_value_unchecked(object);
-  let Ok(array) = v8::Local::<v8::Array>::try_from(object) else {
+  let Ok(object) = v8::Local::<v8::Object>::try_from(object) else {
     return napi_invalid_arg;
   };
   let value: v8::Local<v8::Value> =
-    array.get_index(&mut env.scope(), index).unwrap();
+    object.get_index(&mut env.scope(), index).unwrap();
   *result = value.into();
   napi_ok
 }
@@ -2521,11 +2521,11 @@ fn napi_set_element(
   check_env!(env);
   let env = unsafe { &mut *env };
   let object = napi_value_unchecked(object);
-  let Ok(array) = v8::Local::<v8::Array>::try_from(object) else {
+  let Ok(object) = v8::Local::<v8::Object>::try_from(object) else {
     return napi_invalid_arg;
   };
   let value = napi_value_unchecked(value);
-  array.set_index(&mut env.scope(), index, value).unwrap();
+  object.set_index(&mut env.scope(), index, value).unwrap();
   napi_ok
 }
 

filename: tests/napi/object_test.js
patch: @@ -0,0 +1,15 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+
+import { assert, assertEquals, loadTestLibrary } from "./common.js";
+
+const object = loadTestLibrary();
+
+Deno.test("napi object", function () {
+  const r = object.test_object_new(1, "hello");
+  assertEquals(typeof r, "object");
+  assertEquals(r[0], 1);
+  assertEquals(r[1], "hello");
+
+  const r1 = object.test_object_get(r);
+  assert(r === r1);
+});

filename: tests/napi/src/lib.rs
patch: @@ -19,6 +19,7 @@ pub mod finalizer;
 pub mod make_callback;
 pub mod mem;
 pub mod numbers;
+pub mod object;
 pub mod object_wrap;
 pub mod primitives;
 pub mod promise;
@@ -164,6 +165,7 @@ unsafe extern "C" fn napi_register_module_v1(
   bigint::init(env, exports);
   symbol::init(env, exports);
   make_callback::init(env, exports);
+  object::init(env, exports);
 
   init_cleanup_hook(env, exports);
 

filename: tests/napi/src/object.rs
patch: @@ -0,0 +1,55 @@
+// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
+
+use crate::assert_napi_ok;
+use crate::napi_get_callback_info;
+use crate::napi_new_property;
+use napi_sys::*;
+use std::ptr;
+
+extern "C" fn test_object_new(
+  env: napi_env,
+  info: napi_callback_info,
+) -> napi_value {
+  let (args, argc, _) = napi_get_callback_info!(env, info, 2);
+  assert_eq!(argc, 2);
+
+  let mut value: napi_value = ptr::null_mut();
+  assert_napi_ok!(napi_create_object(env, &mut value));
+
+  assert_napi_ok!(napi_set_element(env, value, 0, args[0]));
+  assert_napi_ok!(napi_set_element(env, value, 1, args[1]));
+
+  value
+}
+
+extern "C" fn test_object_get(
+  env: napi_env,
+  info: napi_callback_info,
+) -> napi_value {
+  let (args, argc, _) = napi_get_callback_info!(env, info, 1);
+  assert_eq!(argc, 1);
+
+  let obj = args[0];
+  assert_napi_ok!(napi_set_element(env, obj, 0, args[0]));
+
+  let mut value: napi_value = ptr::null_mut();
+  assert_napi_ok!(napi_get_element(env, obj, 0, &mut value));
+  let mut value: napi_value = ptr::null_mut();
+  assert_napi_ok!(napi_get_element(env, obj, 1, &mut value));
+
+  obj
+}
+
+pub fn init(env: napi_env, exports: napi_value) {
+  let properties = &[
+    napi_new_property!(env, "test_object_new", test_object_new),
+    napi_new_property!(env, "test_object_get", test_object_get),
+  ];
+
+  assert_napi_ok!(napi_define_properties(
+    env,
+    exports,
+    properties.len(),
+    properties.as_ptr()
+  ));
+}