Cerial
Field Types

Decimal

Decimal field type in Cerial — CerialDecimal wrapper with arbitrary-precision arithmetic for financial calculations.

An arbitrary-precision decimal number stored as SurrealDB's native decimal type. Use Decimal for financial calculations, precise measurements, or any value where floating-point rounding errors are unacceptable.

Schema Syntax

model Product {
  id Record @id
  price Decimal
  discount Decimal?
  tax Decimal @nullable
  amounts Decimal[]
}

Types

DirectionType
OutputCerialDecimal
InputCerialDecimalInputnumber | string | CerialDecimal | Decimal (SDK)
SurrealDBdecimal

CerialDecimal API

import { CerialDecimal } from 'cerial';

// Create from number or string
const price = new CerialDecimal(99.99);
const precise = new CerialDecimal('123456789.123456789');

// Static constructors
CerialDecimal.from(input);     // from any CerialDecimalInput
CerialDecimal.parse(input);    // alias for from()

// Arithmetic (immutable — returns new CerialDecimal)
price.add(other);              // addition
price.sub(other);              // subtraction
price.mul(other);              // multiplication
price.div(other);              // division

// Comparison
price.equals(other);           // true if equal
price.compareTo(other);        // negative/zero/positive
price.isZero();                // true if zero
price.isNegative();            // true if negative

// Conversion
price.toString();              // string representation (lossless)
price.toJSON();                // same as toString()
price.toNumber();              // JavaScript number (LOSSY!)
price.valueOf();               // JavaScript number (LOSSY!)

// SDK interop
price.toNative();              // SDK Decimal instance
price.clone();                 // new CerialDecimal copy

// Type guard
CerialDecimal.is(value);      // value is CerialDecimal

Arithmetic methods accept the full CerialDecimalInput union — you can pass numbers, strings, or other CerialDecimal instances:

const total = price.add(10);           // number input
const discounted = price.sub('5.50');  // string input
const doubled = price.mul(other);      // CerialDecimal input

toNumber() and valueOf() are lossy

Both toNumber() and valueOf() truncate to IEEE 754 double precision. For large or high-precision values, this silently loses data:

const big = new CerialDecimal('99999999999999999.123456789');
big.toString();   // '99999999999999999.123456789' ✓ lossless
big.toNumber();   // 100000000000000000 ✗ precision lost

Always use .toString() for lossless serialization. Use .toNumber() only when you need a JavaScript number and accept the precision loss — for example, passing to a charting library.

Numeric coercion (+decimal, decimal * 2) also uses valueOf() and is equally lossy.

Create & Update

// Create with number
const product = await client.db.Product.create({
  data: { price: 29.99, tax: null },
});

// Create with string (preserves precision)
const product2 = await client.db.Product.create({
  data: { price: '99999999.99', tax: '7.5' },
});

// Create with CerialDecimal
const product3 = await client.db.Product.create({
  data: { price: CerialDecimal.from('49.99'), tax: null },
});

// Output is CerialDecimal
product.price;               // CerialDecimal instance
product.price.toString();    // '29.99'

// Update
await client.db.Product.updateUnique({
  where: { id: product.id },
  data: { price: '34.99' },
});

// Array operations
await client.db.Product.updateUnique({
  where: { id: product.id },
  data: { amounts: { push: 4.5 } },
});

Filtering

Decimal fields support comparison, set, and range operators:

// Direct equality
const products = await client.db.Product.findMany({
  where: { price: 29.99 },
});

// Comparison operators
const expensive = await client.db.Product.findMany({
  where: { price: { gt: 100, lte: 500 } },
});

// Range
const midRange = await client.db.Product.findMany({
  where: { price: { between: [10, 100] } },
});

// Set operators
const specific = await client.db.Product.findMany({
  where: { price: { in: [9.99, 19.99, 29.99] } },
});

Available Operators

OperatorDescription
eqEqual to
neqNot equal to
gtGreater than
gteGreater than or equal
ltLess than
lteLess than or equal
betweenWithin a range (inclusive)
inIn a set of values
notInNot in a set of values

Conditional Operators

OperatorAvailable whenDescription
not? or @nullableNegated comparison
isNone? (optional)true = field is absent
isNull@nullabletrue = field is null
isDefinedAlwaystrue = field exists

OrderBy

Decimal fields support orderBy:

const sorted = await client.db.Product.findMany({
  orderBy: { price: 'desc' },
});

In Objects and Tuples

object LineItem {
  quantity Int
  unitPrice Decimal
  total Decimal
}

tuple PriceRange {
  min Decimal,
  max Decimal
}

model Invoice {
  id Record @id
  items LineItem[]
  range PriceRange?
}

Arrays

model Ledger {
  id Record @id
  entries Decimal[]
}

Decimal[] @set is not supported

SurrealDB has a bug with set<decimal> that causes errors. Do not use @set on Decimal[] arrays. Use @distinct and @sort separately if you need deduplication or sorting.

Supported Decorators

DecoratorEffect
@default(value)Default decimal on create
@defaultAlways(value)Reset to value on every write
@nullableAllow explicit null
@readonlyWrite-once field
@indexDatabase index
@uniqueUnique constraint

On this page