Skip to content

[bun:sqlite] configurable javascript runtime type for sqlite integers #1536

Closed
@dhbaird

Description

@dhbaird

What is the problem this feature would solve?

I'd like to propose an option for the sqlite API to go beyond the current 32-bit limit that is currently imposed on SELECT queries.

Background: Current API truncates integers to 32-bits when selecting (see below). Can be worked around by CASTing to REAL or TEXT (see below). Proposal objective: eliminate the CAST().

import { Database, constants } from "bun:sqlite";
const db = Database.open(":memory:");
db.exec("CREATE TABLE Test ( x INTEGER )")
const insert = db.prepare("INSERT INTO Test (x) VALUES (?)");
insert.run([2147483647]);
insert.run([2147483648]);
insert.run([2147483649]);

console.log(db.prepare("SELECT x FROM Test").all());
// >>>
// Actual:   [ { x: 2147483647 }, { x: -2147483648 }, { x: -2147483647 } ]
// Desired:  [ { x: 2147483647 }, { x: 2147483648 }, { x: 2147483649 } ]

console.log(db.prepare("SELECT CAST(x AS REAL) x FROM Test").all());
// >>>
// Got and expected (all good): [ { x: 2147483647 }, { x: 2147483648 }, { x: 2147483649 } ]

A common use case (for me): storage of epoch time values in milliseconds, which requires ~41-bits. The intended benefit of this proposal is that it would eliminate the need make query or schema alterations, helping to decouple runtime details of this API from sqlite.

What is the feature you are proposing to solve the problem?

An additional option is proposed to control integer conversion, perhaps as follows,

Choice Behavior Range
AS_INT32 Select out as truncated to 32-bits (current behavior) 32-bits (signed)
AS_REAL Select out as a double + or - 53 bits (i.e. Number.MAX_SAFE_INTEGER / Number.MIN_SAFE_INTEGER)
AS_BIGINT Select out as a 64-bit int, and assign to a JavaScript BigInt 64-bits (signed)

Examples of the concept:

const db = Database.open(":memory:", {
    integerMode: constants.AS_INT32 | constants.AS_REAL | constants.AS_BIGINT });
// or, at query level:
const stmt = db.prepare("SELECT x FROM Test", {
    integerMode: constants.AS_INT32 | constants.AS_REAL | constants.AS_BIGINT });

Relevant lines ultimately impacted by this option are found in constructResultObject() and constructResultRow():

What alternatives have you considered?

Workarounds are possible:

  • Use REAL typed columns in the schema. Or,
  • CAST() to REAL. Or,
  • CAST() to TEXT. And convert result to a BigInt in application code. (If up to the 64-bits is actually needed.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bun:sqliteSomething to do with bun:sqliteenhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions