Skip to content

Commit 94407af

Browse files
committed
docs: align SQL DDL syntax, HTTP routes, and protocol handshake with current API
Update all examples and reference tables to reflect the current engine selector syntax (`WITH (engine='...')` instead of `TYPE X`), the `/v1/` route prefix for all data endpoints, versioned Content-Type headers, the corrected health probe paths (`/healthz`, `/health/live`, `/health/ready`), and the native protocol handshake/limits/capabilities documentation. Also adds a PostgreSQL compatibility section to the SQL overview, expands the vector-search page with hybrid and multi-vector query patterns, and documents the DDL constraint policy.
1 parent bc85434 commit 94407af

22 files changed

Lines changed: 307 additions & 90 deletions

docs/administration/authentication.rdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ DROP API KEY 'my-service';
2626
```
2727

2828
```bash
29-
curl -H "Authorization: Bearer <api-key>" http://localhost:6480/query
29+
curl -H "Authorization: Bearer <api-key>" http://localhost:6480/v1/query
3030
```
3131

3232
## JWKS (JWT)

docs/administration/monitoring.rdx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,8 @@ Feature-gated: `--features otel`, `--features promql`, `--features monitoring`.
3838
## Health Checks
3939

4040
```bash
41-
curl http://localhost:6480/health # basic health
41+
curl http://localhost:6480/healthz # k8s readiness — 503 until startup completes
42+
curl http://localhost:6480/health/live # liveness probe
4243
curl http://localhost:6480/health/ready # WAL recovered, ready for queries
4344
```
4445

docs/architecture/overview.rdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ If code needs to cross a plane boundary, it goes through the SPSC bridge (Contro
3939
**SQL path** — All user-facing interfaces accept SQL. The Control Plane parses via sqlparser, plans via EngineRules, and dispatches a `SqlPlan` through the SPSC bridge to the Data Plane.
4040

4141
```
42-
psql / ndb CLI / HTTP /query
42+
psql / ndb CLI / HTTP /v1/query
4343
→ SQL parser (sqlparser-rs)
4444
→ EngineRules::plan_*()
4545
→ SqlPlan → SPSC Bridge → Data Plane

docs/columnar-profiles/spatial.rdx

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ Spatial is a columnar profile. Collections with a `SPATIAL_INDEX` column modifie
1010
## DDL
1111

1212
```sql
13-
-- Columnar with spatial index
14-
CREATE COLLECTION restaurants TYPE COLUMNAR (
13+
-- Spatial peer engine (R-tree + geohash + OGC predicates)
14+
CREATE COLLECTION restaurants (
1515
location GEOMETRY SPATIAL_INDEX,
1616
name VARCHAR,
1717
cuisine VARCHAR,
1818
rating FLOAT
19-
);
19+
) WITH (engine='spatial');
2020

2121
-- Or add a spatial index to any collection
2222
CREATE COLLECTION restaurants;
@@ -66,10 +66,10 @@ WKB, WKT, and GeoJSON interchange. GeoParquet v1.1.0 and GeoArrow metadata for b
6666

6767
```sql
6868
-- Fleet tracking: spatial + time
69-
CREATE COLLECTION fleet TYPE COLUMNAR (
69+
CREATE COLLECTION fleet (
7070
ts TIMESTAMP TIME_KEY,
7171
vehicle_id VARCHAR,
7272
position GEOMETRY SPATIAL_INDEX,
7373
speed FLOAT
74-
) WITH profile = 'timeseries', partition_by = '1d';
74+
) WITH (engine='timeseries', partition_by='1d');
7575
```

docs/columnar-profiles/timeseries.rdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,13 @@ Timeseries is a columnar profile. It extends the columnar engine with retention
1010
## DDL
1111

1212
```sql
13-
CREATE COLLECTION cpu_metrics TYPE COLUMNAR (
13+
CREATE COLLECTION cpu_metrics (
1414
ts TIMESTAMP TIME_KEY,
1515
host VARCHAR,
1616
region VARCHAR,
1717
cpu_usage FLOAT,
1818
mem_usage FLOAT
19-
) WITH profile = 'timeseries', partition_by = '1d', retention = '90d';
19+
) WITH (engine='timeseries', partition_by='1d', retention='90d');
2020

2121
-- Convenience alias
2222
CREATE TIMESERIES cpu_metrics;

docs/connectivity/http-api.rdx

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -12,23 +12,25 @@ REST API on port 6480 for web clients and services.
1212
### Execute SQL
1313

1414
```bash
15-
curl -X POST http://localhost:6480/query \
15+
curl -X POST http://localhost:6480/v1/query \
1616
-H "Authorization: Bearer ndb_..." \
1717
-H "Content-Type: application/json" \
18+
-H "Accept: application/vnd.nodedb.v1+json" \
1819
-d '{"sql": "SELECT * FROM users LIMIT 10"}'
1920
```
2021

2122
### Stream Results (NDJSON)
2223

2324
```bash
24-
curl -X POST http://localhost:6480/query/stream \
25+
curl -X POST http://localhost:6480/v1/query/stream \
2526
-d '{"sql": "SELECT * FROM large_table"}'
2627
```
2728

2829
### Health & Readiness
2930

3031
```bash
31-
curl http://localhost:6480/health # basic health
32+
curl http://localhost:6480/healthz # k8s readiness — 503 until startup completes
33+
curl http://localhost:6480/health/live # liveness probe
3234
curl http://localhost:6480/health/ready # WAL recovered, ready for queries
3335
```
3436

@@ -43,7 +45,7 @@ curl http://localhost:6480/metrics
4345
### PromQL
4446

4547
```
46-
http://localhost:6480/obsv/api
48+
http://localhost:6480/v1/obsv/api
4749
```
4850

4951
Full Prometheus query engine. Point Grafana at this URL as a Prometheus data source.
@@ -57,4 +59,8 @@ GET /v1/streams/{stream}/poll?group={group} # Long-poll
5759

5860
### WebSocket
5961

60-
`/ws` endpoint for JSON-RPC: SQL execution, LIVE SELECT delivery, session reconnect.
62+
`/v1/ws` endpoint for JSON-RPC: SQL execution, LIVE SELECT delivery, session reconnect.
63+
64+
## Versioning
65+
66+
All non-probe routes are under the `/v1/` prefix. JSON responses carry `Content-Type: application/vnd.nodedb.v1+json; charset=utf-8`. Clients may opt into version negotiation by sending `Accept: application/vnd.nodedb.v1+json`; sending only an unsupported `application/vnd.nodedb.vN+json` returns `406 Not Acceptable`. Probe routes (`/healthz`, `/health/*`, `/metrics`) are unversioned and always reachable, including during startup.

docs/connectivity/native-protocol.rdx

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,67 @@ Both modes produce the same `PhysicalPlan` and execute identically.
3232
./target/release/ndb
3333
./target/release/ndb --host localhost --port 6433
3434
```
35+
36+
## Handshake
37+
38+
Every native connection performs a versioned handshake before any opcode frame. SDKs do this automatically on first use; you only need this section if you're implementing a wire-level client.
39+
40+
### `HelloFrame` (client → server)
41+
42+
| Field | Width | Value |
43+
| -------------- | ----- | --------------------------------------- |
44+
| `magic` | 4 B | `NDBH` |
45+
| `proto_min` | u16 | Minimum protocol version client accepts |
46+
| `proto_max` | u16 | Maximum protocol version client supports |
47+
| `capabilities` | u64 | Bitmask of optional features (send `0` for none; unknown bits ignored by server) |
48+
49+
### `HelloAckFrame` (server → client)
50+
51+
| Field | Width | Value |
52+
| ---------------- | -------------------- | ----------------------------------------------------- |
53+
| `magic` | 4 B | `NDBA` |
54+
| `proto_version` | u16 | Negotiated version (`max(proto_min_client, proto_min_server) ≤ v ≤ min(proto_max_client, proto_max_server)`) |
55+
| `capabilities` | u64 | Server-side capability bitmask |
56+
| `server_version` | length-prefixed UTF-8 | Build identifier (e.g. `"nodedb 0.1.0+abc123"`) |
57+
| `limits` | `Limits` struct | Per-op caps the server enforces (see below) |
58+
59+
### `HelloErrorFrame`
60+
61+
Returned when no protocol version overlaps. Carries a typed `code` (`VersionMismatch`) and a UTF-8 reason. The connection is closed after the frame is sent.
62+
63+
### Server-enforced `Limits`
64+
65+
The `HelloAckFrame` carries the server's per-op caps. SDKs surface these via `client.limits()`. Sending a request that exceeds a cap returns a typed `LimitExceeded { limit_name, value, max }` error.
66+
67+
| Field | Type | Caps |
68+
| ---------------------- | ------------- | ----------------------------------------------- |
69+
| `max_vector_dim` | `Option<u32>` | Vector embedding dimensionality |
70+
| `max_top_k` | `Option<u32>` | `top_k` for any retrieval op |
71+
| `max_scan_limit` | `Option<u32>` | Result set size for scans |
72+
| `max_batch_size` | `Option<u32>` | Rows per batch INSERT/UPSERT |
73+
| `max_crdt_delta_bytes` | `Option<u32>` | Single CRDT delta payload |
74+
| `max_query_text_bytes` | `Option<u32>` | SQL text length |
75+
| `max_graph_depth` | `Option<u32>` | `MAX_DEPTH` for graph traversal |
76+
77+
`None` means uncapped. Defaults are uncapped — operators set caps via configuration.
78+
79+
## Capabilities
80+
81+
`Capabilities` is a typed wrapper around the `u64` bitmask returned in `HelloAckFrame`. SDK consumers query specific features via accessor methods rather than testing raw bits, so feature additions never break clients:
82+
83+
```rust
84+
let caps = client.capabilities();
85+
if caps.has_graphrag_fusion() { ... }
86+
if caps.has_continuous_aggregates() { ... }
87+
```
88+
89+
The `Capabilities::has(bit)` escape hatch is available for forward compatibility, but typed accessors are preferred.
90+
91+
## Server Identity
92+
93+
```rust
94+
client.proto_version() // u16 — negotiated protocol version
95+
client.server_version() // String — server build identifier
96+
client.limits() // &Limits — per-op caps
97+
client.capabilities() // Capabilities — typed feature flags
98+
```

docs/data-modeling/collections.rdx

Lines changed: 24 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -14,41 +14,46 @@ A collection is NodeDB's top-level data container — analogous to a table in Po
1414
CREATE COLLECTION users;
1515

1616
-- Strict document (schema-enforced)
17-
CREATE COLLECTION orders TYPE DOCUMENT STRICT (
17+
CREATE COLLECTION orders (
1818
id UUID DEFAULT gen_uuid_v7(),
1919
customer_id UUID NOT NULL,
2020
total DECIMAL NOT NULL,
2121
status STRING DEFAULT 'pending'
22-
);
22+
) WITH (engine='document_strict');
2323

2424
-- Columnar (analytics)
25-
CREATE COLLECTION events TYPE COLUMNAR (
25+
CREATE COLLECTION events (
2626
ts TIMESTAMP TIME_KEY,
2727
user_id UUID,
2828
event VARCHAR,
2929
duration_ms INT
30-
);
30+
) WITH (engine='columnar');
3131

3232
-- Key-Value
33-
CREATE COLLECTION sessions TYPE KEY_VALUE (key TEXT PRIMARY KEY);
33+
CREATE COLLECTION sessions (key TEXT PRIMARY KEY) WITH (engine='kv');
3434
```
3535

3636
## Storage Engines
3737

38-
| Type | DDL | Best for |
39-
| ----------------- | ----------------------- | ----------------------------------------------- |
40-
| Document | `CREATE COLLECTION x` | Flexible data, prototyping, agent state |
41-
| Document (strict) | `TYPE DOCUMENT STRICT` | OLTP, transactions, known schemas |
42-
| Columnar | `TYPE COLUMNAR` | Analytics, reporting, scan-heavy workloads |
43-
| Key-Value | `TYPE KEY_VALUE` | Sessions, caches, counters, key-dominant access |
38+
NodeDB has seven peer engines. Pick one per collection via `WITH (engine='<name>')`. The default (no `engine=`) is `document_schemaless`.
4439

45-
Columnar collections can specialize via profiles:
40+
| Engine | Selector | Best for |
41+
| --------------------- | ----------------------------------- | ------------------------------------------------- |
42+
| `document_schemaless` | (default) | Flexible data, prototyping, agent state |
43+
| `document_strict` | `WITH (engine='document_strict')` | OLTP, transactions, known schemas |
44+
| `columnar` | `WITH (engine='columnar')` | Analytics, reporting, scan-heavy workloads |
45+
| `timeseries` | `WITH (engine='timeseries')` | Append-only metrics, retention, continuous aggs |
46+
| `spatial` | `WITH (engine='spatial')` | Geo-primary workloads, R*-tree, OGC predicates |
47+
| `kv` | `WITH (engine='kv')` | Sessions, caches, counters, key-dominant access |
48+
| `vector` | `WITH (engine='vector', vector_field='emb')` | Vector-primary collections |
4649

47-
| Profile | Column Modifier | Extra capabilities |
48-
| ---------- | ---------------- | ------------------------------------------------- |
49-
| Plain | (none) | Full UPDATE/DELETE, general analytics |
50-
| Timeseries | `TIME_KEY` | Retention, continuous aggregation, ILP ingest |
51-
| Spatial | `SPATIAL_INDEX` | R*-tree indexing, OGC predicates |
50+
Column modifiers add capabilities to any engine:
51+
52+
| Modifier | Effect |
53+
| ---------------- | ----------------------------------------------------------------- |
54+
| `TIME_KEY` | Marks the time column (used by timeseries engine, allowed elsewhere) |
55+
| `SPATIAL_INDEX` | R*-tree index on a `GEOMETRY` column |
56+
| `PRIMARY KEY` | Row identity column (inline only — table-level not supported) |
5257

5358
## Cross-Engine Indexes
5459

@@ -75,10 +80,9 @@ GRAPH INSERT EDGE IN 'products' FROM 'products:p1' TO 'products:p2' TYPE 'simila
7580
Collections can be converted at any time without data loss:
7681

7782
```sql
78-
CONVERT COLLECTION users TO strict;
79-
CONVERT COLLECTION logs TO columnar;
83+
CONVERT COLLECTION users TO document_strict;
8084
CONVERT COLLECTION cache TO kv;
81-
CONVERT COLLECTION events TO document;
85+
CONVERT COLLECTION events TO document_schemaless;
8286
```
8387

8488
NodeDB infers the schema from existing documents when converting to strict mode.

docs/data-modeling/schemas-types.rdx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ description: Data types, schema enforcement, typeguards, and schema evolution.
2727

2828
**Schemaless** — No schema required. Fields can vary between documents. Types are inferred on insert. This is the default when you `CREATE COLLECTION x`.
2929

30-
**Strict** — Schema is defined at creation time and enforced on every write. O(1) field extraction via binary tuple format. Created with `TYPE DOCUMENT STRICT (...)`.
30+
**Strict** — Schema is defined at creation time and enforced on every write. O(1) field extraction via binary tuple format. Created with `(...) WITH (engine='document_strict')`.
3131

3232
## Typeguards (Schemaless Validation)
3333

@@ -58,7 +58,7 @@ ALTER TYPEGUARD ON users DROP age;
5858
VALIDATE TYPEGUARD ON users;
5959

6060
-- Graduate to strict schema
61-
CONVERT COLLECTION users TO strict;
61+
CONVERT COLLECTION users TO document_strict;
6262
```
6363

6464
## Schema Evolution (Strict Mode)

docs/indexes/hash-index.rdx

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ Keys are hashed to locate the value directly — no tree traversal. This provide
1414
## Creating a KV Collection
1515

1616
```sql
17-
CREATE COLLECTION sessions TYPE KEY_VALUE (key TEXT PRIMARY KEY);
17+
CREATE COLLECTION sessions (key TEXT PRIMARY KEY) WITH (engine='kv');
1818
```
1919

2020
The `PRIMARY KEY` column is automatically hash-indexed.

0 commit comments

Comments
 (0)