Implement JavaScript bindings with minimal Rust core

This rewrites the JavaScript bindings completely by exposing only
primitive operations from Rust NAPI-RS code. For example, there is
prepare(), bind(), and step(), but high level interfaces like all() and
get() are implemented in JavaScript.

We're doing this so that we can implement async interfaces in the
JavaScript layer instead of having to bring in Tokio.
This commit is contained in:
Pekka Enberg
2025-07-31 14:56:04 +03:00
parent fedd70f60e
commit 02db72cc2c
7 changed files with 614 additions and 663 deletions

View File

@@ -0,0 +1,70 @@
// Bind parameters to a statement.
//
// This function is used to bind parameters to a statement. It supports both
// named and positional parameters, and nested arrays.
//
// The `stmt` parameter is a statement object.
// The `params` parameter is an array of parameters.
//
// The function returns void.
function bindParams(stmt, params) {
const len = params?.length;
if (len === 0) {
return;
}
if (len === 1) {
const param = params[0];
if (isPlainObject(param)) {
bindNamedParams(stmt, param);
return;
}
bindValue(stmt, 1, param);
return;
}
bindPositionalParams(stmt, params);
}
// Check if object is plain (no prototype chain)
function isPlainObject(obj) {
if (!obj || typeof obj !== 'object') return false;
const proto = Object.getPrototypeOf(obj);
return proto === Object.prototype || proto === null;
}
// Handle named parameters
function bindNamedParams(stmt, paramObj) {
const paramCount = stmt.parameterCount();
for (let i = 1; i <= paramCount; i++) {
const paramName = stmt.parameterName(i);
if (paramName) {
const key = paramName.substring(1); // Remove ':' or '$' prefix
const value = paramObj[key];
if (value !== undefined) {
bindValue(stmt, i, value);
}
}
}
}
// Handle positional parameters (including nested arrays)
function bindPositionalParams(stmt, params) {
let bindIndex = 1;
for (let i = 0; i < params.length; i++) {
const param = params[i];
if (Array.isArray(param)) {
for (let j = 0; j < param.length; j++) {
bindValue(stmt, bindIndex++, param[j]);
}
} else {
bindValue(stmt, bindIndex++, param);
}
}
}
function bindValue(stmt, index, value) {
stmt.bindAt(index, value);
}
module.exports = { bindParams };