Skip to content

Geospatial Types

Chronicle has built-in support for geospatial types from Cratis.Fundamentals: Point, LineString, and Polygon. You can use them directly in events, read models, reducers, and projections without any extra setup.

The three geospatial types are records defined in the Cratis.Geospatial namespace:

using Cratis.Geospatial;
public static class GeospatialTypeExamples
{
public static Point CreatePoint() => new(10.456, 42.123);
public static LineString CreatePath() => new([
new Point(10.456, 42.123),
new Point(11.789, 43.456)
]);
public static Polygon CreateBoundary() => new(
Shell: new LinearRing([
new Point(0, 0),
new Point(10, 0),
new Point(10, 10),
new Point(0, 10),
new Point(0, 0)
]),
Holes: []);
}
  • Point represents a single geographic location in longitude-then-latitude order (GeoJSON standard).
  • LineString represents a connected series of points forming a line or path.
  • Polygon represents an enclosed area with a shell (outer boundary) and optional holes (inner boundaries).
  • LinearRing is an array of points that form a closed loop (used by Polygon).

Using Geospatial Types in Events and Read Models

Section titled “Using Geospatial Types in Events and Read Models”

Import the namespace and use the geospatial types as any other property type:

using Cratis.Chronicle.Events;
using Cratis.Geospatial;
[EventType]
public record GeospatialAssetLocationUpdated(Point Location);
[EventType]
public record GeospatialRouteCreated(LineString Path);
[EventType]
public record GeospatialZoneEstablished(Polygon Boundaries);
public record GeospatialAssetReadModel(Guid Id, Point Location);
public record GeospatialRouteReadModel(Guid Id, LineString Path);
public record GeospatialZoneReadModel(Guid Id, Polygon Boundaries);

Projections and reducers handle geospatial types like any other value type. AutoMap picks them up automatically:

using Cratis.Chronicle.Events;
using Cratis.Chronicle.Projections;
using Cratis.Geospatial;
[EventType]
public record GeospatialProjAssetLocationUpdated(Point Location);
public record GeospatialProjAssetReadModel(Guid Id, Point Location);
public class GeospatialProjAssetProjection : IProjectionFor<GeospatialProjAssetReadModel>
{
// AutoMap picks up the Point-typed property automatically — no manual mapping needed
public void Define(IProjectionBuilderFor<GeospatialProjAssetReadModel> builder) => builder
.From<GeospatialProjAssetLocationUpdated>();
}

When Chronicle generates the JSON schema, geospatial types are annotated with their GeoJSON-compatible formats:

Point: Generates as an object with longitude and latitude properties, marked with "format": "point"

{
"type": "object",
"format": "point",
"properties": {
"longitude": { "type": "number" },
"latitude": { "type": "number" }
}
}

LineString: Generates as an array of point objects, marked with "format": "linestring"

{
"type": "array",
"format": "linestring",
"items": {
"type": "object",
"properties": {
"longitude": { "type": "number" },
"latitude": { "type": "number" }
}
}
}

Polygon: Generates as an object with shell and holes, marked with "format": "polygon"

{
"type": "object",
"format": "polygon",
"properties": {
"shell": {
"type": "array",
"items": {
"type": "object",
"properties": {
"longitude": { "type": "number" },
"latitude": { "type": "number" }
}
}
},
"holes": {
"type": "array",
"items": {
"type": "array",
"items": {
"type": "object",
"properties": {
"longitude": { "type": "number" },
"latitude": { "type": "number" }
}
}
}
}
}
}

This lets consumers inspect the schema and know the field contains geographic data, and the format annotations make it possible for tools like the Workbench to recognize and properly display geographic values.

Chronicle stores geospatial values in BSON format:

Point: Flat document with longitude and latitude

{ "longitude": 10.456, "latitude": 42.123 }

LineString: Array of points

[
{ "longitude": 10.456, "latitude": 42.123 },
{ "longitude": 11.789, "latitude": 43.456 }
]

Polygon: Document with shell (outer ring) and holes (inner rings)

{
"shell": [
{ "longitude": 0, "latitude": 0 },
{ "longitude": 10, "latitude": 0 },
{ "longitude": 10, "latitude": 10 },
{ "longitude": 0, "latitude": 10 },
{ "longitude": 0, "latitude": 0 }
],
"holes": []
}

BSON serializers are registered automatically — no configuration required.

Geospatial types generate as JSON objects in the schema, so the SQL sink stores them as JSON columns. No migration or configuration changes are required.

The Chronicle Workbench recognizes geospatial format markers in event schemas and renders them as human-readable strings rather than expanding nested structures:

Point: lat: 42.123, long: 10.456
LineString: [lat: 42.123, long: 10.456], [lat: 43.456, long: 11.789]
Polygon: shell with 5 points, 0 holes