Skip to content

Bug: CBOR encoder/decoder breaks on floats above MAX_SAFE_INTEGER #514

@msanchezdev

Description

@msanchezdev

Look at comments below for latest updates

Describe the bug

Attempting to save or query a value where a number is greater than Number.MAX_SAFE_INTEGER should return a BigInt or maybe an instance of a new Float class similar to Decimal instead of a number as is the behavior with the number data type.

Image

You can also test this in Surrealist. Notice if value is already the max safe integer (9007199254740992) incrementing the value by 1 does nothing. But any more than that and the value is updated but can't be decoded by the CBOR driver.

Image

The value shows properly in the REPL though, this is proably just a Javascript problem.

Image

Steps to reproduce

The following script can run in Bun to test the behavior. It outputs the screenshot above.

const surreal = new Surreal({
  engines: createNodeEngines(),
});
await surreal.connect("mem://");

function plus(n: number) {
  return `${BigInt(Number.MAX_SAFE_INTEGER) + BigInt(n)}`.replace(/n$/, "");
}

function format(value: string | number | bigint | Decimal) {
  const suffix =
    value instanceof Decimal ? "dec" : typeof value === "bigint" ? "n" : "";
  return `\x1b[33m${value}${suffix}\x1b[0m`;
}

async function test(value: string, expected: number | bigint | Decimal) {
  const [result] = await surreal
    .query(`${value}`)
    .collect<[string | number | bigint | Decimal]>();

  const matches =
    result instanceof Decimal ? result.equals(expected) : result === expected;

  console.log(
    "for",
    format(value),
    "surreal returned",
    format(result),
    matches
      ? "\x1b[32mis correctly returned as\x1b[0m"
      : "\x1b[31mshould be instead\x1b[0m",
    format(expected),
  );
}

console.log(`MAX_SAFE_INTEGER: ${Number.MAX_SAFE_INTEGER}`);
await test(`9007199254740991`, 9007199254740991);
await test(`9007199254740991f`, 9007199254740991);
await test(`9007199254740991dec`, new Decimal("9007199254740991"));
console.log();

console.log(`MAX_SAFE_INTEGER + 1: ${plus(1)}`);
await test(`9007199254740992`, 9007199254740992);
await test(`9007199254740992f`, 9007199254740992);
await test(`9007199254740992dec`, new Decimal("9007199254740992"));
console.log();

console.log(`MAX_SAFE_INTEGER + 2: ${plus(2)}`);
await test(`9007199254740993`, 9007199254740993n);
await test(
  `9007199254740993f`,
  9007199254740993n,
); /* or maybe a new float class? */
await test(`9007199254740993dec`, new Decimal("9007199254740993"));
console.log();

console.log(`MAX_SAFE_INTEGER + 3: ${plus(3)}`);
await test(`9007199254740994`, 9007199254740994n);
await test(`9007199254740994f`, 9007199254740994n);
await test(`9007199254740994dec`, new Decimal("9007199254740994"));
console.log();

console.log(`MAX_SAFE_INTEGER + 4: ${plus(4)}`);
await test(`9007199254740995`, 9007199254740995n);
await test(`9007199254740995f`, 9007199254740995n);
await test(`9007199254740995dec`, new Decimal("9007199254740995"));
console.log();

console.log(`MAX_SAFE_INTEGER + 5: ${plus(5)}`);
await test(`9007199254740996`, 9007199254740996n);
await test(`9007199254740996f`, 9007199254740996n);
await test(`9007199254740996dec`, new Decimal("9007199254740996"));

Expected behaviour


SurrealDB version

3.0.0-alpha.17+20251209.85f189b for linux on x86_64

JavaScript SDK version

2.0.0-alpha.14

Contact Details

[email protected]

Is there an existing issue for this?

  • I have searched the existing issues

Code of Conduct (repository /surrealdb.js)

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions