spatio 0.1.7

A high-performance, embedded spatio-temporal database for modern applications
Documentation

Spatio is a compact and efficient embedded spatio-temporal database written in Rust. It's designed for real-time 2D and 3D location data, with low memory usage, optional persistence, and native Python bindings.

No SQL parser, no external dependencies, and requires no setup.

Quick Start

Python

pip install spatio
import spatio

db = spatio.Spatio.memory()

# Store a point (longitude, latitude)
nyc = spatio.Point(-74.0060, 40.7128)
db.insert_point("cities", nyc, b"New York")

# Find nearby points
nearby = db.query_within_radius("cities", nyc, 100000, 10)

Rust

[dependencies]
spatio = "0.1"
use spatio::prelude::*;

fn main() -> Result<()> {
    let mut db = Spatio::memory()?;

    let nyc = Point::new(-74.0060, 40.7128);
    db.insert_point("cities", &nyc, b"New York", None)?;

    let nearby = db.query_within_radius("cities", &nyc, 100_000.0, 10)?;
    println!("Found {} cities", nearby.len());

    Ok(())
}

Features

Spatial queries: Radius search, bounding box, K-nearest-neighbors, polygon containment 3D support: Full altitude-aware indexing and queries Trajectories: Track movement over time Distance metrics: Haversine, Geodesic, Rhumb, Euclidean TTL: Auto-expire old data Persistence: Snapshots (default) or append-only file (AOF) Namespaces: Logical data separation in one database

Coordinate Order

Important: Spatio uses (longitude, latitude) order everywhere - same as GeoJSON and most GIS tools.

// Correct: lon, lat
let point = Point::new(-74.0060, 40.7128);  // NYC

This matches the mathematical (x, y) convention and makes GeoJSON interop trivial.

Examples

2D Spatial

// Insert points
db.insert_point("pois", &Point::new(-74.0, 40.7), b"Restaurant", None)?;

// Find nearby (within 1km)
let nearby = db.query_within_radius("pois", &center, 1000.0, 10)?;

// Bounding box query
let in_box = db.find_within_bounds("pois", 40.0, -75.0, 41.0, -73.0, 100)?;

// K-nearest neighbors
let nearest = db.knn("pois", &center, 5, 10_000.0, DistanceMetric::Haversine)?;

3D Spatial

use spatio::Point3d;

// Track drones with altitude
let drone = Point3d::new(-74.0060, 40.7128, 100.0);
db.insert_point_3d("drones", &drone, b"Alpha", None)?;

// 3D sphere query
let nearby = db.query_within_sphere_3d("drones", &drone, 200.0, 10)?;

// Cylindrical query (altitude range + radius)
let in_cylinder = db.query_within_cylinder_3d(
    "drones", &drone, 50.0, 150.0, 1000.0, 10
)?;

Trajectories

use spatio::TemporalPoint;

let path = vec![
    TemporalPoint {
        point: Point::new(-74.00, 40.71),
        timestamp: UNIX_EPOCH + Duration::from_secs(100)
    },
    TemporalPoint {
        point: Point::new(-74.01, 40.72),
        timestamp: UNIX_EPOCH + Duration::from_secs(200)
    },
];

db.insert_trajectory("truck:001", &path, None)?;

// Query movement history
let history = db.query_trajectory("truck:001", 100, 300)?;

TTL (Time-To-Live)

use spatio::SetOptions;

// Data expires in 1 hour
let opts = SetOptions::with_ttl(Duration::from_secs(3600));
db.insert("session:123", b"data", Some(opts))?;

// Expired items return None
let value = db.get("session:123")?;  // None if expired

// Clean up expired items manually
let removed = db.cleanup_expired()?;

Important: TTL is lazy - expired items stick around in memory until you call cleanup_expired() or they get overwritten. For long-running apps, clean up periodically or you'll leak memory.

Persistence

Snapshots (default): Point-in-time saves, good for edge devices

let config = Config::default().with_snapshot_auto_ops(1000);
let db = DBBuilder::new()
    .snapshot_path("data.snapshot")
    .config(config)
    .build()?;
// Auto-saves every 1000 operations

AOF (optional): Write-ahead log, good for zero data loss

let db = DBBuilder::new()
    .aof_path("data.aof")
    .build()?;
// Requires --features aof

Platforms

Supported:

  • Linux (x86_64, aarch64)
  • macOS (x86_64, arm64)

Not supported:

  • Windows (use WSL2 or Docker)

See PLATFORMS.md for details.

API Overview

Key-Value:

db.insert(key, value, options)?;
db.get(key)?;
db.delete(key)?;

Spatial:

db.insert_point(namespace, &point, data, options)?;
db.query_within_radius(namespace, &center, radius, limit)?;
db.count_within_radius(namespace, &center, radius)?;
db.contains_point(namespace, &center, radius)?;
db.find_within_bounds(namespace, min_lat, min_lon, max_lat, max_lon, limit)?;
db.knn(namespace, &center, k, max_radius, metric)?;
db.query_within_polygon(namespace, &polygon, limit)?;
db.distance_between(&p1, &p2, metric)?;

3D Spatial:

db.insert_point_3d(namespace, &point3d, data, options)?;
db.query_within_sphere_3d(namespace, &center, radius, limit)?;
db.query_within_cylinder_3d(namespace, &center, min_z, max_z, radius, limit)?;
db.query_within_bbox_3d(namespace, &bbox, limit)?;
db.knn_3d(namespace, &center, k)?;

Trajectories:

db.insert_trajectory(object_id, &points, options)?;
db.query_trajectory(object_id, start_time, end_time)?;

Utility:

db.atomic(|batch| { /* multiple ops */ })?;
db.cleanup_expired()?;
db.count_expired();
db.stats();

Documentation

Status

Current version: 0.1.x (active development)

APIs may change. Check CHANGELOG.md before upgrading.

Contributing

Contributions are welcome! See CONTRIBUTING.md.

License

MIT - see LICENSE

Links