Skip to content

API Reference

/

Values

Sized numbers and BigDecimal

SurrealDB stores a plain number as a 64-bit int, a 64-bit float or a decimal. SurrealDB 4.0 adds sized integers and floats, such as u8 and f32, and bigdecimal, a decimal with no fixed limit on its digits. This page documents the Python classes for the SurrealDB 4.0 number types, and the limits of a plain int and a Decimal.

Import
from surrealdb import (
    F16, F32, I8, I16, I32, U8, U16, U32, U64,
    BigDecimal, SizedFloat, SizedInt,
)

Source: sized.py, big_decimal.py

PythonSurrealDBRead back as
intintint
floatfloatfloat
decimal.DecimaldecimalDecimal

SurrealDB stores an int as a signed 64-bit integer, from -9223372036854775808 to 9223372036854775807. The SDK raises ValueError for an int outside that range before anything is sent, because the server would store a different number. For a larger whole number, send a Decimal, or a U64 up to 18446744073709551615.

A SurrealDB decimal holds up to 28 digits after the decimal point, and the server rounds a value with more. SurrealDB 3.0 and later also drop trailing zeros, so Decimal("19.90") reads back as Decimal('19.9'). The SDK sends a Decimal in plain notation, such as 0.0000001 rather than 1E-7.

from decimal import Decimal
from surrealdb import Surreal

with Surreal("ws://localhost:8000") as db:
    db.signin({"username": "root", "password": "secret"})
    db.use("surrealdb", "docs")

    values = {"price": Decimal("19.90"), "rate": Decimal("1E-29")}
    print(db.query("RETURN [$price, $rate]", values).first())
Output
[Decimal('19.9'), Decimal('0')]

The rate has 29 digits after the point, so the server rounds it to zero. For more digits, or to keep trailing zeros, use a BigDecimal with SurrealDB 4.0.

Each sized number class is a subclass of int or float for one SurrealDB 4.0 number type. It refuses a value outside the range of its type when it is made.

ClassSurrealDB typeValues
I8i8-128 to 127
U8u80 to 255
I16i16-32768 to 32767
U16u160 to 65535
I32i32-2147483648 to 2147483647
U32u320 to 4294967295
U64u640 to 18446744073709551615
F16f16Half-precision floats, up to 65504
F32f32Single-precision floats
Syntax
I8(value=0)
F32(value=0.0)

Parameter

Type

Description

valueint | float | str

The number, as for

int()

or

float()

. Defaults to

0

. An integer class also takes a

float

with no fraction, such as

2.0

.

An integer class raises ValueError for a value outside its range or a value with a fraction. Each integer class has MIN and MAX class attributes that give its range. F16 and F32 round the value to the nearest number of their width, as a cast to that width does, and raise ValueError for a finite value that is too large for the width.

print(F32(1.1), F16(1.1))
print(U8.MIN, U8.MAX)
print(I8(5) == 5, type(I8(5) + 1).__name__)
Output
F32(1.100000023841858) F16(1.099609375)
0 255
True int
I8(200)
Error output
ValueError: 200 is outside the I8 range (-128 to 127); use a wider kind or a plain int

A sized number works anywhere a number does. I8(5) == 5 is true, and arithmetic gives back a plain int or float, so compare type() to tell a sized number from a plain one. SizedInt and SizedFloat are the base classes, for isinstance() checks; construct one of the subclasses. str() gives the same text as repr(), such as I8(5), so pass int(value) or float(value) to format the number alone.

Over cbor.2, which SurrealDB 4.0 servers speak, a sized number is sent as its own type and reads back as the same class. A field defined with a sized type also stores a plain int that fits as that type. Servers before 4.0 speak plain cbor, which has no sized types, so the SDK sends the nearest type that the server has.

PythonOver cbor.2 (SurrealDB 4.0)Over cbor (earlier servers)
I8, U8, I16, U16, I32, U32Their own type, read back as the same classint, read back as int
U64u64, read back as U64int, or decimal above 9223372036854775807, read back as int or Decimal
F16, F32Their own type, read back as the same classfloat, read back as float

db.wire_format tells you which format a connection uses. This example needs SurrealDB 4.0:

from surrealdb import F32, RecordID, Surreal

with Surreal("ws://localhost:8000") as db:
    db.signin({"username": "root", "password": "secret"})
    db.use("surrealdb", "docs")

    db.query("DEFINE FIELD age ON person TYPE u8").execute()
    person = db.create(RecordID("person", "tobie"), {
        "age": 30,
        "score": F32(0.1),
    })
    print(person["age"], person["score"])
Output
U8(30) F32(0.10000000149011612)

A BigDecimal is a decimal.Decimal that SurrealDB 4.0 stores as a bigdecimal rather than a decimal. A bigdecimal holds up to 131072 digits before the decimal point and 16383 after it, and keeps its scale as written, so BigDecimal("1.50") keeps its trailing zero.

Syntax
BigDecimal(value="0", context=None)

Parameter

Type

Description

valueDecimal | int | float | str

The number, as for

Decimal()

. Defaults to

"0"

.

contextdecimal.Context | None

The

decimal

context to build the value with.

The constructor raises ValueError for text that is not a number, for NaN or an infinity, and for a value with more digits than a bigdecimal holds.

from surrealdb import BigDecimal

price = BigDecimal("1.50")
print(repr(price), price == BigDecimal("1.5"))
print(repr(price * 2))
Output
BigDecimal('1.50') True
Decimal('3.00')

A BigDecimal is a Decimal in every other way. Values that differ only in scale are equal, and arithmetic gives back a plain Decimal, rounded to the precision of the current decimal context: 28 significant digits by default. To calculate with larger numbers, raise decimal.getcontext().prec, and wrap the result in BigDecimal to send it as a bigdecimal.

Over cbor.2 (SurrealDB 4.0)Over cbor (earlier servers)
bigdecimal with its scale, read back as BigDecimaldecimal when the value fits one, read back as Decimal; otherwise its text as a string, read back as str

Was this page helpful?