Cerial
Field Types

Geometry

Geometry field type in Cerial — GeoJSON-compatible geospatial data with 7 subtypes, point shorthand, and subtype decorators.

Geospatial data stored using SurrealDB's native geometry type. Geometry fields support 7 subtypes — from simple points to complex geometry collections — and follow the GeoJSON standard for data representation.

Schema Syntax

model Location {
  id Record @id
  point Geometry @point
  area Geometry @polygon
  route Geometry @line
  shape Geometry                  # accepts any subtype
  multi Geometry @point @polygon  # accepts point OR polygon
  optionalGeo Geometry? @point
  geoArray Geometry[] @point
}

Subtype Decorators

Use decorators to constrain which geometry types a field accepts:

DecoratorSurrealDB TypeOutput TypeInput Type
@pointgeometry<point>CerialPointCerialPointInput
@linegeometry<line>CerialLineStringCerialLineStringInput
@polygongeometry<polygon>CerialPolygonCerialPolygonInput
@multipointgeometry<multipoint>CerialMultiPointCerialMultiPointInput
@multilinegeometry<multiline>CerialMultiLineStringCerialMultiLineStringInput
@multipolygongeometry<multipolygon>CerialMultiPolygonCerialMultiPolygonInput
@geoCollectiongeometry<collection>CerialGeometryCollectionCerialGeometryCollectionInput
(none)all 7 subtypesCerialGeometryCerialGeometryInput

Multi-Type Fields

Multiple decorators create a union type:

multi Geometry @point @polygon
  • Output: CerialPoint | CerialPolygon
  • Input: CerialPointInput | CerialPolygonInput
  • Migration: geometry<point | polygon>

No Decorator

A bare Geometry field accepts any geometry subtype:

shape Geometry
  • Output: CerialGeometry (abstract base)
  • Input: CerialGeometryInput (union of all input types)

CerialGeometry API

All 7 concrete geometry classes extend the abstract CerialGeometry base:

import {
  CerialGeometry,
  CerialPoint,
  CerialLineString,
  CerialPolygon,
} from 'cerial';

// CerialPoint — from [lon, lat] shorthand
const point = new CerialPoint([1.5, 2.5]);
point.type;                      // 'Point'
point.coordinates;               // [1.5, 2.5]

// CerialPoint — from GeoJSON
const point2 = new CerialPoint({ type: 'Point', coordinates: [10, 20] });

// CerialLineString — from GeoJSON
const line = new CerialLineString({
  type: 'LineString',
  coordinates: [[0, 0], [1, 1], [2, 0]],
});
line.coordinates;                // [[0, 0], [1, 1], [2, 0]]

// CerialPolygon — from GeoJSON
const polygon = new CerialPolygon({
  type: 'Polygon',
  coordinates: [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]]],
});
polygon.coordinates;             // [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]]]

// Common methods (all geometry types)
point.toJSON();                  // { type: 'Point', coordinates: [1.5, 2.5] }
point.toNative();                // SurrealDB SDK GeometryPoint
point.clone();                   // new CerialPoint copy
point.equals(other);             // deep equality check
point.toString();                // JSON string representation

// Static methods
CerialGeometry.is(value);        // type guard: value is CerialGeometry
CerialGeometry.isNative(value);  // type guard: value is SDK Geometry
CerialGeometry.from(input);      // any input → CerialGeometry
CerialGeometry.fromNative(geo);  // SDK Geometry → CerialGeometry

Input Types

Point Input

Only CerialPointInput supports the [lon, lat] tuple shorthand:

  • [lon, lat] — tuple shorthand (two numbers)
  • { type: 'Point', coordinates: [lon, lat] } — GeoJSON
  • CerialPoint — existing instance
  • GeometryPoint — SurrealDB SDK type

Other Subtypes

All other subtypes accept GeoJSON objects, CerialGeometry instances, and SDK types. No shorthand syntax.

Coordinates are [longitude, latitude]

GeoJSON standard uses [longitude, latitude] order — not [latitude, longitude]. If you're used to [lat, lng] conventions (e.g., from Google Maps), the order is reversed:

// ✓ Correct: [longitude, latitude]
const nyc = new CerialPoint([-74.006, 40.7128]);

// ✗ Wrong: [latitude, longitude]
const wrong = new CerialPoint([40.7128, -74.006]);

Create & Update

// Create with [lon, lat] shorthand for points
const loc = await client.db.Location.create({
  data: {
    point: [1.5, 2.5],
    area: {
      type: 'Polygon',
      coordinates: [[[0, 0], [1, 0], [1, 1], [0, 0]]],
    },
    route: {
      type: 'LineString',
      coordinates: [[0, 0], [5, 5]],
    },
    shape: [10, 20],      // point shorthand for bare Geometry
    multi: [3, 4],         // point shorthand (field accepts point | polygon)
  },
});

// Output is typed geometry
loc.point;                 // CerialPoint instance
loc.point.coordinates;     // [1.5, 2.5]

// Create with CerialPoint instance
const loc2 = await client.db.Location.create({
  data: {
    point: new CerialPoint([7, 8]),
    // ...other fields
  },
});

// Update
await client.db.Location.updateUnique({
  where: { id: loc.id },
  data: { point: [99, 99] },
});

Filtering

Geometry fields support equality and set operators only. Comparison operators and string operators are not available.

// Direct equality
const locs = await client.db.Location.findMany({
  where: { point: [1.5, 2.5] },
});

// Equality operators
const match = await client.db.Location.findMany({
  where: { point: { eq: [1.5, 2.5] } },
});

// Set operators
const specific = await client.db.Location.findMany({
  where: {
    point: { in: [[1, 2], [3, 4]] },
  },
});

// Array operators on geometry arrays
const hasPoint = await client.db.Location.findMany({
  where: { geoArray: { has: [1, 2] } },
});

Available Operators

OperatorDescription
eqEqual to
neqNot equal to
inIn a set of values
notInNot in a set of values

Geometry fields do not support comparison operators (gt, gte, lt, lte, between). Only equality and set-based filtering is available.

Spatial operators (nearTo, within, intersects) are also not yet supported — they are planned for a future release.

Conditional Operators

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

OrderBy

Geometry fields are excluded from orderBy — SurrealDB does not support ordering by geometry values.

In Objects and Tuples

object Venue {
  name String
  location Geometry @point
}

model Event {
  id Record @id
  venue Venue
}

Geometry in tuple elements always uses the generic CerialGeometry/CerialGeometryInput types — subtype decorators are not supported on tuple elements.

Gotchas

equals() uses JSON comparison

The equals() method on geometry instances uses JSON.stringify internally. Due to floating-point precision, two geometries with nearly-identical coordinates may fail the equality check:

const a = new CerialPoint([1.0000000001, 2.0]);
const b = new CerialPoint([1.0000000002, 2.0]);
a.equals(b); // false — float precision difference

If you need fuzzy comparison, compare the coordinates manually with an epsilon tolerance.

No @default support

Geometry fields do not support the @default decorator.

Supported Decorators

DecoratorEffect
@point, @line, @polygon, etc.Constrain accepted geometry subtypes
@nullableAllow explicit null
@readonlyWrite-once field
@indexDatabase index
@uniqueUnique constraint

On this page