Repository: denoland/deno
File: ext/node/ops/sqlite/statement.rs (Rust)

Code before:
          unsafe {
            ffi::sqlite3_bind_int64(raw, param_count + 1, as_int);
          }
          param_count += 1;
        } else if value.is_object() {
          let mut params: HashMap<String, Local<v8::Value>> = HashMap::new();
          let value: v8::Local<v8::Object> = value.try_into().unwrap();
          let maybe_keys =
            value.get_property_names(scope, GetPropertyNamesArgs::default());

          if let Some(keys) = maybe_keys {
            let length = keys.length();
            for i in 0..length {
              if let Some(key) = keys.get_index(scope, i) {
                if let Some(key_str) = key.to_string(scope) {
                  let key_str = key_str.to_rust_string_lossy(scope);
                  if let Some(value) = value.get(scope, key) {
                    params.insert(key_str, value);
                  }
                }
              }
            }
          }
          for (key, value) in params {
            self.bind_params_object(scope, key, value, param_count)?;
            param_count += 1;
          }
        } else {
          return Err(SqliteError::FailedBind("Unsupported type"));
        }
      }
    }

    Ok(())
  }

  //helper function that binds the object attribute to named param
  fn bind_params_object(
    &self,
    scope: &mut v8::HandleScope,
    key: String,
    value: Local<v8::Value>,
    count: i32,
  ) -> Result<(), SqliteError> {
    let raw = self.inner;

    // SAFETY: `self.inner` is a valid pointer to a sqlite3_stmt
    // as it lives as long as the StatementSync instance.
    unsafe {
      ffi::sqlite3_bind_parameter_index(raw, key.as_ptr() as *const _);
    }

Review comment (suggestion):
A single loop should be enough? This saves the Hashmap allocation

```suggestion
          let value: v8::Local<v8::Object> = value.try_into().unwrap();
          let maybe_keys =
            value.get_property_names(scope, GetPropertyNamesArgs::default());

          if let Some(keys) = maybe_keys {
            let length = keys.length();
            for i in 0..length {
              if let Some(key) = keys.get_index(scope, i) {
                if let Some(key_str) = key.to_string(scope) {
                  let key_str = key_str.to_rust_string_lossy(scope);
                  if let Some(value) = value.get(scope, key) {
                    self.bind_params_object(scope, key_str, value, param_count)?;
                    param_count += 1;
                  }
                }
              }
            }
          }
```

Code after:
          unsafe {
            ffi::sqlite3_bind_int64(raw, param_count + 1, as_int);
          }
          param_count += 1;
        } else if value.is_object() {
          let value: v8::Local<v8::Object> = value.try_into().unwrap();
          let maybe_keys =
            value.get_property_names(scope, GetPropertyNamesArgs::default());

          if let Some(keys) = maybe_keys {
            let length = keys.length();
            for i in 0..length {
              if let Some(key) = keys.get_index(scope, i) {
                if let Some(key_str) = key.to_string(scope) {
                  let key_str = key_str.to_rust_string_lossy(scope);
                  if let Some(value) = value.get(scope, key) {
                    self.bind_params_object(
                      scope,
                      key_str,
                      value,
                      param_count,
                    )?;
                    param_count += 1;
                  }
                }
              }
            }
          }
        } else {
          return Err(SqliteError::FailedBind("Unsupported type"));
        }
      }
    }

    Ok(())
  }

  //helper function that binds the object attribute to named param
  fn bind_params_object(
    &self,
    scope: &mut v8::HandleScope,
    key: String,
    value: v8::Local<v8::Value>,
    count: i32,
  ) -> Result<(), SqliteError> {
    let raw = self.inner;

    // SAFETY: `self.inner` is a valid pointer to a sqlite3_stmt
    // as it lives as long as the StatementSync instance.
    unsafe {
      ffi::sqlite3_bind_parameter_index(raw, key.as_ptr() as *const _);