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:
| Decorator | SurrealDB Type | Output Type | Input Type |
|---|---|---|---|
@point | geometry<point> | CerialPoint | CerialPointInput |
@line | geometry<line> | CerialLineString | CerialLineStringInput |
@polygon | geometry<polygon> | CerialPolygon | CerialPolygonInput |
@multipoint | geometry<multipoint> | CerialMultiPoint | CerialMultiPointInput |
@multiline | geometry<multiline> | CerialMultiLineString | CerialMultiLineStringInput |
@multipolygon | geometry<multipolygon> | CerialMultiPolygon | CerialMultiPolygonInput |
@geoCollection | geometry<collection> | CerialGeometryCollection | CerialGeometryCollectionInput |
| (none) | all 7 subtypes | CerialGeometry | CerialGeometryInput |
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 → CerialGeometryInput Types
Point Input
Only CerialPointInput supports the [lon, lat] tuple shorthand:
[lon, lat]— tuple shorthand (two numbers){ type: 'Point', coordinates: [lon, lat] }— GeoJSONCerialPoint— existing instanceGeometryPoint— 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
| Operator | Description |
|---|---|
eq | Equal to |
neq | Not equal to |
in | In a set of values |
notIn | Not 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
| Operator | Available when | Description |
|---|---|---|
not | ? or @nullable | Negated comparison |
isNone | ? (optional) | true = field is absent |
isNull | @nullable | true = field is null |
isDefined | Always | true = 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 differenceIf 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
| Decorator | Effect |
|---|---|
@point, @line, @polygon, etc. | Constrain accepted geometry subtypes |
@nullable | Allow explicit null |
@readonly | Write-once field |
@index | Database index |
@unique | Unique constraint |