static JSC::JSValue rebindObject()

in src/bun.js/bindings/sqlite/JSSQLStatement.cpp [828:985]


static JSC::JSValue rebindObject(JSC::JSGlobalObject* globalObject, SQLiteBindingsMap& bindings, JSC::JSObject* target, JSC::ThrowScope& scope, sqlite3* db, sqlite3_stmt* stmt, bool clone, bool safeIntegers)
{
    int count = 0;

    JSC::VM& vm = globalObject->vm();
    auto& structure = *target->structure();
    bindings.ensureNamesLoaded(vm, stmt);
    const auto& bindingNames = bindings.bindingNames;
    size_t size = bindings.count;

    const bool trimLeadingPrefix = bindings.trimLeadingPrefix;
    const bool throwOnMissing = trimLeadingPrefix;

    // Did they reorder the columns?
    //
    // { ?2: "foo", ?1: "bar" }
    //
    if (UNLIKELY(bindings.hasOutOfOrderNames)) {

        const auto& getValue = [&](const char* name, size_t i) -> JSValue {
            JSValue value = {};
            if (name == nullptr) {
                return target->getDirectIndex(globalObject, i);
            }

            if (trimLeadingPrefix) {
                name += 1;
            }

            const WTF::String str = WTF::String::fromUTF8ReplacingInvalidSequences({ reinterpret_cast<const unsigned char*>(name), strlen(name) });

            if (trimLeadingPrefix && name[0] >= '0' && name[0] <= '9') {
                auto integer = WTF::parseInteger<int32_t>(str, 10);
                if (integer.has_value()) {
                    return target->getDirectIndex(globalObject, integer.value() - 1);
                }
            }

            const auto identifier = Identifier::fromString(vm, str);
            PropertySlot slot(target, PropertySlot::InternalMethodType::GetOwnProperty);
            if (!target->getOwnNonIndexPropertySlot(vm, &structure, identifier, slot)) {
                return JSValue();
            }

            if (LIKELY(!slot.isTaintedByOpaqueObject())) {
                return slot.getValue(globalObject, identifier);
            }

            return target->get(globalObject, identifier);
        };

        for (size_t i = 0; i < size; i++) {
            auto* name = sqlite3_bind_parameter_name(stmt, i + 1);

            JSValue value = getValue(name, i);
            if (!value && !scope.exception()) {
                if (throwOnMissing) {
                    throwException(globalObject, scope, createError(globalObject, makeString("Missing parameter \""_s, reinterpret_cast<const unsigned char*>(name), "\""_s)));
                } else {
                    continue;
                }
            }
            RETURN_IF_EXCEPTION(scope, JSValue());

            if (!rebindValue(globalObject, db, stmt, i + 1, value, scope, clone, safeIntegers)) {
                return JSValue();
            }

            RETURN_IF_EXCEPTION(scope, {});
            count++;
        }
    }
    // Does it only contain indexed properties?
    //
    // { 0: "foo", 1: "bar", "2": "baz" }
    //
    else if (UNLIKELY(bindings.isOnlyIndexed)) {
        for (size_t i = 0; i < size; i++) {
            JSValue value = target->getDirectIndex(globalObject, i);
            if (!value && !scope.exception()) {
                if (throwOnMissing) {
                    throwException(globalObject, scope, createError(globalObject, makeString("Missing parameter \""_s, i + 1, "\""_s)));
                } else {
                    continue;
                }
            }

            RETURN_IF_EXCEPTION(scope, JSValue());

            if (!rebindValue(globalObject, db, stmt, i + 1, value, scope, clone, safeIntegers)) {
                return JSValue();
            }

            RETURN_IF_EXCEPTION(scope, {});
            count++;
        }
    }
    // Is it a simple object with no getters or setters?
    //
    // { foo: "bar", baz: "qux" }
    //
    else if (target->canUseFastGetOwnProperty(structure)) {
        for (size_t i = 0; i < size; i++) {
            const auto& property = bindingNames[i];
            JSValue value = property.isEmpty() ? target->getDirectIndex(globalObject, i) : target->fastGetOwnProperty(vm, structure, bindingNames[i]);
            if (!value && !scope.exception()) {
                if (throwOnMissing) {
                    throwException(globalObject, scope, createError(globalObject, makeString("Missing parameter \""_s, property.isEmpty() ? String::number(i) : property.string(), "\""_s)));
                } else {
                    continue;
                }
            }

            RETURN_IF_EXCEPTION(scope, JSValue());

            if (!rebindValue(globalObject, db, stmt, i + 1, value, scope, clone, safeIntegers)) {
                return JSValue();
            }

            RETURN_IF_EXCEPTION(scope, {});
            count++;
        }
    } else {
        for (size_t i = 0; i < size; i++) {
            PropertySlot slot(target, PropertySlot::InternalMethodType::GetOwnProperty);
            const auto& property = bindingNames[i];
            bool hasProperty = property.isEmpty() ? target->methodTable()->getOwnPropertySlotByIndex(target, globalObject, i, slot) : target->methodTable()->getOwnPropertySlot(target, globalObject, property, slot);
            if (!hasProperty && !scope.exception()) {
                if (throwOnMissing) {
                    throwException(globalObject, scope, createError(globalObject, makeString("Missing parameter \""_s, property.isEmpty() ? String::number(i) : property.string(), "\""_s)));
                } else {
                    continue;
                }
            }

            RETURN_IF_EXCEPTION(scope, JSValue());

            JSValue value;
            if (LIKELY(!slot.isTaintedByOpaqueObject()))
                value = slot.getValue(globalObject, property);
            else {
                value = target->get(globalObject, property);
                RETURN_IF_EXCEPTION(scope, JSValue());
            }

            RETURN_IF_EXCEPTION(scope, JSValue());

            if (!rebindValue(globalObject, db, stmt, i + 1, value, scope, clone, safeIntegers)) {
                return JSValue();
            }

            RETURN_IF_EXCEPTION(scope, {});
            count++;
        }
    }

    return jsNumber(count);
}