Skip to content

Commit 0ebbf7c

Browse files
committed
readme: polish + add install, embedded build, roadmap sections
1 parent 9025cfe commit 0ebbf7c

1 file changed

Lines changed: 105 additions & 33 deletions

File tree

README.md

Lines changed: 105 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -8,12 +8,25 @@
88

99
Julia client for [SurrealDB](https://surrealdb.com). Talks to a remote
1010
`surreal` server over WebSocket or HTTP, or runs the database in-process
11-
via `libsurreal`. Same API for both.
11+
via `libsurreal`. Same API regardless of backend. Runs against SurrealDB
12+
v2 and v3.
1213

13-
Cross-tested against the official [Go](https://github.com/surrealdb/surrealdb.go)
14-
and [Python](https://github.com/surrealdb/surrealdb.py) SDKs: 12 testsets
15-
ported from `surrealdb.go/db_test.go`, plus an interop harness round-tripping
16-
fixtures (Python ↔ Julia, Julia → Go). Runs against SurrealDB v2 and v3.
14+
**Status: alpha.** Pre-1.0. API may break between minor versions
15+
(`0.x``0.(x+1)`). Pin a specific version to avoid breakage between
16+
bumps.
17+
18+
## Install
19+
20+
Not yet in the General registry. Install via the repo URL, pinned to a
21+
tagged release:
22+
23+
```julia
24+
using Pkg
25+
Pkg.add(url="https://github.com/danvinci/surrealdb", rev="v0.2.0-alpha.1")
26+
```
27+
28+
For the embedded backend you also need `libsurreal`. See
29+
[Embedded mode](#embedded-mode) below.
1730

1831
## Quickstart
1932

@@ -53,13 +66,30 @@ The client is closed in a `finally`.
5366
| `mem://` | Embedded | In-memory, in-process via `libsurreal` |
5467
| `surrealkv://path` | Embedded | File-backed, in-process |
5568

56-
Embedded mode needs the `libsurreal` shared library:
69+
The `mem://` and `surrealkv://path` schemes are SDK conventions (not part
70+
of SurrealDB's wire protocol). They tell `connect()` to load `libsurreal`
71+
instead of opening a socket.
72+
73+
### Embedded mode
74+
75+
Requires the `libsurreal` shared library. Build it once from
76+
[`surrealdb/surrealdb.c`](https://github.com/surrealdb/surrealdb.c):
77+
78+
```bash
79+
julia --project=. deps/build_libsurreal.jl
80+
```
81+
82+
Needs a Rust toolchain (`cargo`) and ~15 min of build time. The resulting
83+
`libsurrealdb_c.{so,dylib,dll}` lands at the repo root.
5784

5885
```julia
59-
SurrealDB.libsurreal_load!("/path/to/libsurreal.dylib") # or set $SURREALDB_LIB
86+
SurrealDB.libsurreal_load!("/path/to/libsurrealdb_c.dylib") # or set $SURREALDB_LIB
6087
db = SurrealDB.connect("mem://")
6188
```
6289

90+
A JLL package (`libsurrealdb_c_jll`) for one-line install via the registry
91+
is planned. See [Roadmap](#roadmap).
92+
6393
## Auth
6494

6595
```julia
@@ -100,7 +130,8 @@ alice = SurrealDB.create(db, User, "user",
100130

101131
## Tables.jl
102132

103-
Query results conform to `Tables.jl` (rows and columns):
133+
Query results conform to `Tables.jl`, so they plug into DataFrames, CSV.jl,
134+
Arrow.jl, or anything that consumes the Tables interface:
104135

105136
```julia
106137
using DataFrames
@@ -109,25 +140,28 @@ df = DataFrame(result)
109140
```
110141

111142
`query_one(db, sql)` asserts a single statement and returns one table.
112-
`query_table(db, sql)` keeps multi-statement boundaries on remote (the
113-
embedded backend collapses them).
143+
`query_table(db, sql)` returns one `QueryResultTable` per `;`-separated
144+
statement on remote. The embedded backend flattens them into a single
145+
result.
114146

115147
## Live queries
116148

117149
```julia
118150
sub = SurrealDB.live(db, "user")
119-
@async for n::SurrealDB.LiveNotification in sub
151+
task = @async for n::SurrealDB.LiveNotification in sub
120152
@info "live event" action=n.action record=n.record data=n.result
121153
end
122154

123-
SurrealDB.kill!(sub)
155+
# Stop the subscription:
156+
SurrealDB.kill!(sub) # closes the channel; the @async for-loop exits
157+
wait(task)
124158
```
125159

126160
Each notification is a `LiveNotification` with typed fields
127-
(`action`, `query_id`, `record`, `result`, `session`); it also subtypes
128-
`AbstractDict` so legacy `n["action"]` access keeps working. After a
129-
reconnect the SDK re-issues `LIVE SELECT` and overwrites `sub.query_id`
130-
with the new server-assigned UUID, so caller-held handles keep working.
161+
(`action`, `query_id`, `record`, `result`, `session`). It also subtypes
162+
`AbstractDict`, so `n["action"]` still works. After a reconnect the SDK
163+
re-issues `LIVE SELECT` and overwrites `sub.query_id` with the new
164+
server-assigned UUID, so caller-held handles keep working.
131165

132166
## Running functions
133167

@@ -141,6 +175,8 @@ functions like `type::is::array` are SQL-only and must go through
141175

142176
## Sessions and transactions
143177

178+
For v2 servers, the RPC-level helpers work:
179+
144180
```julia
145181
SurrealDB.begin!(db)
146182
try
@@ -150,27 +186,41 @@ catch
150186
SurrealDB.cancel!(db)
151187
rethrow()
152188
end
189+
```
190+
191+
For **v3+ remote servers**, the `begin!`/`commit!`/`cancel!` RPC methods
192+
expect a session-scoped transaction UUID; prefer raw SurrealQL:
153193

194+
```julia
195+
SurrealDB.query(db, """
196+
BEGIN TRANSACTION;
197+
CREATE user CONTENT { name: 'Bob' };
198+
COMMIT TRANSACTION;
199+
""")
200+
```
201+
202+
Session variables (`let!`/`unset!`) work the same way on both:
203+
204+
```julia
154205
SurrealDB.let!(db, "min_age", 18)
155206
SurrealDB.query(db, "SELECT * FROM user WHERE age >= \$min_age")
156207
SurrealDB.unset!(db, "min_age")
157208
```
158209

159210
## Graph traversal (MetaGraphsNext)
160211

161-
`to_metagraph` loads via a Pkg extension when `MetaGraphsNext` and
162-
`Graphs` are present:
212+
Available via a Pkg extension. Loads automatically when `MetaGraphsNext`
213+
and `Graphs` are present in your environment alongside `SurrealDB`:
163214

164215
```julia
165-
using MetaGraphsNext, Graphs
216+
using SurrealDB, MetaGraphsNext, Graphs
166217
g = SurrealDB.to_metagraph(db,
167218
"SELECT id, name FROM user",
168219
"SELECT id, in, out FROM follows")
169220
```
170221

171222
Vertex labels are `RecordID` strings; vertex and edge data are field
172-
dicts. The SDK does not auto-coerce results into a graph; call
173-
`to_metagraph` when you want one.
223+
dicts. The SDK does not auto-coerce results into a graph.
174224

175225
## Errors
176226

@@ -195,6 +245,9 @@ SurrealError
195245
└── EmbeddedFFIError .op, .message
196246
```
197247

248+
Catch a specific subtype for branch logic, or catch `ServerError` to
249+
handle any server-side failure uniformly:
250+
198251
```julia
199252
try
200253
SurrealDB.create(db, "user:alice", Dict(...))
@@ -205,7 +258,7 @@ catch e::SurrealDB.ServerError
205258
end
206259
```
207260

208-
The wire-format `kind` field maps to the Julia subtype. Legacy servers
261+
The wire-format `kind` field maps to the Julia subtype. Older servers
209262
that emit only a JSON-RPC `code` go through a code-to-kind table.
210263

211264
## Reconnect
@@ -214,28 +267,29 @@ WebSocket connections auto-reconnect on drop. Tune via `connect` kwargs:
214267

215268
```julia
216269
db = SurrealDB.connect("ws://localhost:8000";
217-
reconnect = true, # set false to disable retries
270+
reconnect = true, # false disables retries
218271
reconnect_max_attempts = 10,
219-
reconnect_base_delay = 0.5, # exponential
272+
reconnect_base_delay = 0.5, # seconds; exponential backoff
220273
reconnect_max_delay = 30.0,
221-
reconnect_jitter = 0.1, # [0, 1]
222-
ping_interval = 30.0, # 0 disables keepalive
274+
reconnect_jitter = 0.1, # fraction of delay added randomly (0..1)
275+
ping_interval = 30.0, # seconds; 0 disables keepalive
276+
rpc_timeout = 30.0, # seconds; Inf disables per-RPC timeout
223277
)
224278
```
225279

226280
Subscribe to lifecycle:
227281

228282
```julia
229283
ch = SurrealDB.events(db)
230-
@async for ev in ch
231-
@info "lifecycle" event=ev # STATUS_CONNECTING, STATUS_CONNECTED, STATUS_RECONNECTING, STATUS_DISCONNECTED
284+
@async for ev::SurrealDB.ConnectionStatus in ch
285+
@info "lifecycle" event=ev
286+
# ev ∈ (STATUS_CONNECTING, STATUS_CONNECTED, STATUS_RECONNECTING, STATUS_DISCONNECTED)
232287
end
233288
```
234289

235-
Events are values of the `ConnectionStatus` enum (exported alongside
236-
the four `STATUS_*` constants). `STATUS_CONNECTED` fires after state
237-
replay (`use!`, `authenticate!`, live re-subscription) finishes, not
238-
before.
290+
`STATUS_CONNECTED` fires after state replay (`use!`, `authenticate!`, live
291+
re-subscription) finishes, not before. Observers never see a half-restored
292+
session.
239293

240294
## Debugging
241295

@@ -252,6 +306,7 @@ RPC traces emit on Julia's `@debug` channel. Enable with
252306
- Julia 1.9 or newer
253307
- Remote: SurrealDB server v2.x or v3.x
254308
- Embedded: `libsurreal` from [`surrealdb/surrealdb.c`](https://github.com/surrealdb/surrealdb.c)
309+
(see [Embedded mode](#embedded-mode) for build instructions)
255310

256311
## Testing
257312

@@ -263,9 +318,26 @@ The suite has three layers:
263318

264319
- **Unit** (no network): types, error parser, FFI marshalling,
265320
reconnect state machine, integration tests against an in-process
266-
mock WebSocket server.
321+
mock WebSocket server, MetaGraphsNext extension.
267322
- **Integration** (needs `surreal start --bind 127.0.0.1:8001`):
268323
connection lifecycle, auth, query, methods, sessions, live queries.
269324
- **Embedded** (needs `libsurreal`): full FFI roundtrip.
270325

271326
Layers self-skip when their prerequisite is missing.
327+
328+
Also cross-tested against the official
329+
[Go](https://github.com/surrealdb/surrealdb.go) and
330+
[Python](https://github.com/surrealdb/surrealdb.py) SDKs: 12 testsets
331+
ported from `surrealdb.go/db_test.go`, plus an interop harness
332+
round-tripping fixtures (Python ↔ Julia, Julia → Go).
333+
334+
## Roadmap
335+
336+
- `libsurrealdb_c_jll`: ship pre-built dylibs via Yggdrasil for
337+
one-line `Pkg.add` install and CI speedup.
338+
- CBOR transport: smaller payloads, native Duration/Decimal round-trip.
339+
- General registry submission once API stabilizes.
340+
341+
## License
342+
343+
MIT. See [LICENSE](LICENSE).

0 commit comments

Comments
 (0)