surreal-orm-lite 0.7.0__tar.gz → 0.10.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (22) hide show
  1. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/CHANGELOG.md +104 -0
  2. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/PKG-INFO +164 -57
  3. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/README.md +163 -56
  4. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/pyproject.toml +1 -1
  5. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/src/surreal_orm_lite/__init__.py +5 -1
  6. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/src/surreal_orm_lite/connection_manager.py +57 -1
  7. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/src/surreal_orm_lite/model_base.py +243 -58
  8. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/src/surreal_orm_lite/query_set.py +153 -26
  9. surreal_orm_lite-0.10.0/src/surreal_orm_lite/transaction.py +199 -0
  10. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/.gitignore +0 -0
  11. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/LICENSE +0 -0
  12. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/Makefile +0 -0
  13. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/src/__init__.py +0 -0
  14. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/src/surreal_orm_lite/_sdk.py +0 -0
  15. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/src/surreal_orm_lite/aggregations.py +0 -0
  16. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/src/surreal_orm_lite/constants.py +0 -0
  17. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/src/surreal_orm_lite/enum.py +0 -0
  18. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/src/surreal_orm_lite/exceptions.py +0 -0
  19. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/src/surreal_orm_lite/py.typed +0 -0
  20. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/src/surreal_orm_lite/q.py +0 -0
  21. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/src/surreal_orm_lite/signals.py +0 -0
  22. {surreal_orm_lite-0.7.0 → surreal_orm_lite-0.10.0}/src/surreal_orm_lite/utils.py +0 -0
@@ -5,6 +5,110 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [0.10.0] - 2026-06-07
9
+
10
+ ### Added
11
+
12
+ - **`model.upsert()`** — insert-or-replace by explicit id, backed by the SDK's native
13
+ `upsert()` (`UPSERT $record CONTENT $data`, full REPLACE). Supports `tx=` (buffered onto
14
+ the transaction).
15
+
16
+ ```python
17
+ user = User(id="alice", name="Alice", status="active")
18
+ await user.upsert() # CREATE if absent, full REPLACE if present
19
+ ```
20
+
21
+ - **`QuerySet.update_or_create()` / `QuerySet.get_or_create()`** — Django-style
22
+ criteria-based create-or-update returning `(instance, created)`. Writes route through
23
+ `save()` / `merge()`, so lifecycle signals fire, SDK errors normalise to `SurrealDbError`,
24
+ and the primary key anchors record identity. `update_or_create` does a **partial merge** on
25
+ update — fields outside the criteria/defaults are preserved — while `get_or_create` returns
26
+ an existing match untouched. Non-`exact` lookups (e.g. `name__contains`) drive the lookup
27
+ but are not written. A SELECT-guard raises an explicit `SurrealDbError` when the criteria
28
+ match more than one record.
29
+
30
+ ```python
31
+ user, created = await User.objects().update_or_create(
32
+ email="alice@example.com", defaults={"name": "Alice"}
33
+ )
34
+ user, created = await User.objects().get_or_create(
35
+ email="bob@example.com", defaults={"name": "Bob"}
36
+ )
37
+ ```
38
+
39
+ ### Notes
40
+
41
+ - Behaviour is **identical on SurrealDB 2.6.x and 3.x** (no 3.x-only primitive): the native
42
+ `upsert()` call and the SELECT-guard work the same on both lines (verified by spike).
43
+ - `upsert()` is REPLACE, not merge: fields omitted from the model are dropped. Use `merge()`
44
+ for partial updates.
45
+ - `update_or_create` / `get_or_create` do the lookup and the write in two round-trips
46
+ (SurrealDB 2.6.x exposes no row-locking primitive here), so a small race window exists
47
+ under concurrent writers — the same non-atomic fallback Django documents.
48
+ - Under `objects(tx=)`, `update_or_create` / `get_or_create` participate in the transaction on
49
+ SurrealDB 3.x (interactive); a buffered 2.6.x transaction raises on their lookup read
50
+ (reads inside a buffered transaction are unsupported — consistent with other QuerySet reads).
51
+
52
+ ## [0.9.0] - 2026-06-07
53
+
54
+ ### Added
55
+
56
+ - **Transactions ORM — QuerySet & interactive strategy**: `objects(tx=)` plumbing routes
57
+ `QuerySet` reads (`get`, `first`, `all`, `exec`, `count`, `exists`, aggregations) and bulk
58
+ operations (`bulk_create`, `bulk_update`, `bulk_delete`) through the transaction.
59
+ Example:
60
+
61
+ ```python
62
+ async with SurrealDBConnectionManager.transaction() as tx:
63
+ users = await User.objects(tx=tx).filter(status="active").exec()
64
+ await User.objects(tx=tx).filter(role="guest").bulk_update(role="member")
65
+ ```
66
+
67
+ - **Two transaction strategies** (auto-selected by `transaction()` based on URL + server):
68
+
69
+ - `InteractiveTransaction` (WebSocket + SurrealDB 3.x): uses the SDK's native
70
+ `begin()`/`commit()`/`cancel()` API tagged by `txn_id`. Reads inside the transaction
71
+ see uncommitted writes; `save(tx=)` now supports **auto-generated ids** and `refresh(tx=)`
72
+ works.
73
+ - `BufferedTransaction` (HTTP, or WebSocket on SurrealDB 2.6.x): preserves the v0.8.0
74
+ `BEGIN…COMMIT` batching semantics. Reads inside the transaction still raise.
75
+
76
+ - Exported `BufferedTransaction` and `InteractiveTransaction` (in addition to the `Transaction`
77
+ base type) for typing and inspection.
78
+
79
+ ### Changed
80
+
81
+ - `transaction()` now **cancels** on a commit failure (e.g. server-side rollback surfacing at
82
+ `COMMIT`), so an interactive transaction never leaves the shared connection half-open.
83
+
84
+ ### Fixed
85
+
86
+ - `QuerySet.get(id)` inside an interactive transaction now normalises the SDK's
87
+ `NotFoundError` to `SurrealDbNotFoundError`, matching the non-tx path.
88
+
89
+ ### Notes
90
+
91
+ - `bulk_update()`/`bulk_delete()` return `0` on the buffered strategy (the affected-row
92
+ count is not knowable before commit). On the interactive strategy they return the real
93
+ count.
94
+
95
+ ## [0.8.0] - 2026-06-06
96
+
97
+ ### Added
98
+
99
+ - **Transactions ORM (core)**: `async with SurrealDBConnectionManager.transaction() as tx:`
100
+ context manager plus a `tx=` parameter on `save()`, `update()`, `merge()`, and `delete()`.
101
+ Operations are buffered and committed atomically as a single
102
+ `BEGIN TRANSACTION; … COMMIT TRANSACTION;` query; an exception in the block rolls
103
+ everything back.
104
+ - Exported `Transaction`.
105
+
106
+ ### Notes
107
+
108
+ - Inside a transaction, `save()` requires an explicit record id (auto-generated ids are not
109
+ buffered in this release). Reads/`refresh()` inside a transaction raise a clear error and
110
+ are planned for v0.9.0 (QuerySet `objects(tx=)` + savepoints).
111
+
8
112
  ## [0.7.0] - 2026-06-06
9
113
 
10
114
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: surreal-orm-lite
3
- Version: 0.7.0
3
+ Version: 0.10.0
4
4
  Summary: Lightweight Django-style ORM for SurrealDB using the official Python SDK. Async support with Pydantic validation.
5
5
  Project-URL: Homepage, https://github.com/EulogySnowfall/SurrealDB-ORM-lite
6
6
  Project-URL: Documentation, https://github.com/EulogySnowfall/SurrealDB-ORM-lite
@@ -71,12 +71,12 @@ This ORM is designed to:
71
71
 
72
72
  ## Requirements
73
73
 
74
- | Dependency | Version |
75
- | ------------ | ---------------------------------- |
76
- | Python | 3.11+ |
77
- | SurrealDB | 2.6.x or 3.1.x |
78
- | Official SDK | surrealdb[pydantic]>=2.0.0,<3.0.0 |
79
- | Pydantic | >=2.13.4 |
74
+ | Dependency | Version |
75
+ | ------------ | --------------------------------- |
76
+ | Python | 3.11+ |
77
+ | SurrealDB | 2.6.x or 3.1.x |
78
+ | Official SDK | surrealdb[pydantic]>=2.0.0,<3.0.0 |
79
+ | Pydantic | >=2.13.4 |
80
80
 
81
81
  > **Note**: As of v0.7.0, Surreal ORM Lite targets the SurrealDB Python SDK 2.x (`surrealdb[pydantic]>=2.0.0,<3.0.0`), which supports the SurrealDB 3.x protocol. It is tested against SurrealDB **v2.6.5** and **v3.1.3**.
82
82
 
@@ -203,6 +203,8 @@ results = await User.objects().query(
203
203
  | `-field` ordering | ✅ |
204
204
  | Relations & Graph | ✅ |
205
205
  | FETCH clause | ✅ |
206
+ | Transactions (`tx=`) | ✅ |
207
+ | upsert / get_or_create | ✅ |
206
208
 
207
209
  ### Supported Filter Lookups
208
210
 
@@ -358,6 +360,73 @@ async def time_user_save(sender, instance, **kwargs):
358
360
  print(f"Save took {duration:.3f}s")
359
361
  ```
360
362
 
363
+ ### 11. Transactions (atomic, all-or-nothing)
364
+
365
+ ```python
366
+ from surreal_orm_lite import SurrealDBConnectionManager
367
+
368
+ # All operations commit together, or none do.
369
+ async with SurrealDBConnectionManager.transaction() as tx:
370
+ await User(id="alice", name="Alice").save(tx=tx)
371
+ await Order(id="o1", user="User:alice", total=100).save(tx=tx)
372
+
373
+ # v0.9.0: QuerySet reads & bulk ops participate in the transaction.
374
+ actives = await User.objects(tx=tx).filter(status="active").exec()
375
+ await User.objects(tx=tx).filter(role="guest").bulk_update(role="member")
376
+ # Auto-commit on success; auto-rollback if the block raises.
377
+ ```
378
+
379
+ `transaction()` picks the strategy automatically based on the connection:
380
+
381
+ - **WebSocket + SurrealDB 3.x** → `InteractiveTransaction` (native `begin()`/`commit()`/`cancel()`).
382
+ Reads inside the tx see uncommitted writes; `save(tx=)` supports auto-generated ids;
383
+ `refresh(tx=)` and `QuerySet.objects(tx=)` reads work.
384
+ - **HTTP, or WebSocket on SurrealDB 2.6.x** → `BufferedTransaction`. Writes are buffered and
385
+ flushed as one `BEGIN TRANSACTION; …; COMMIT TRANSACTION;` query at commit; reads inside the
386
+ tx raise; `save(tx=)` requires an explicit `id`. `bulk_update`/`bulk_delete` return `0`
387
+ (the row count is not knowable before commit).
388
+
389
+ ### 12. Upsert & get_or_create / update_or_create
390
+
391
+ ```python
392
+ from surreal_orm_lite import BaseSurrealModel, SurrealConfigDict
393
+
394
+
395
+ class User(BaseSurrealModel):
396
+ model_config = SurrealConfigDict(primary_key="id")
397
+ id: str | None = None
398
+ name: str
399
+ email: str
400
+
401
+
402
+ # Insert-or-replace by explicit id (full REPLACE — omitted fields are dropped).
403
+ # Use merge() instead if you only want a partial update.
404
+ await User(id="alice", name="Alice", email="alice@example.com").upsert()
405
+
406
+ # Criteria-based, Django-style; returns (instance, created).
407
+ # update_or_create: on create, writes criteria + defaults; on update, MERGEs them (a partial
408
+ # update — fields outside the criteria/defaults are preserved). Lifecycle signals fire on both
409
+ # paths, and the primary key anchors the record identity.
410
+ user, created = await User.objects().update_or_create(
411
+ email="alice@example.com", defaults={"name": "Alice"}
412
+ )
413
+
414
+ # get_or_create writes the defaults ONLY when creating; an existing match is returned as-is:
415
+ user, created = await User.objects().get_or_create(
416
+ email="bob@example.com", defaults={"name": "Bob"}
417
+ )
418
+
419
+ # Both participate in a transaction via objects(tx=) (interactive on SurrealDB 3.x):
420
+ async with SurrealDBConnectionManager.transaction() as tx:
421
+ user, created = await User.objects(tx=tx).get_or_create(email="z@x.io", defaults={"name": "Z"})
422
+ ```
423
+
424
+ If the lookup criteria match more than one record, both methods raise `SurrealDbError`
425
+ (the criteria are not unique). Non-`exact` lookups (e.g. `name__contains`) drive the lookup
426
+ but are not written to the record. Without a transaction the behaviour is identical on
427
+ SurrealDB 2.6.x and 3.x; under `objects(tx=)` they participate in the transaction on 3.x,
428
+ while a buffered 2.6.x transaction raises on the lookup (see the behaviour table).
429
+
361
430
  ---
362
431
 
363
432
  ## Configuration Options
@@ -389,12 +458,33 @@ async with SurrealDBConnectionManager():
389
458
 
390
459
  As of v0.7.0, Surreal ORM Lite uses `surrealdb[pydantic]>=2.0.0,<3.0.0` (SurrealDB 3.x protocol) and is tested against both major SurrealDB release lines.
391
460
 
392
- | SurrealDB Version | SDK Version | Status |
393
- | ----------------- | ----------- | ------------------ |
394
- | 3.1.3 | 2.0 | Tested |
395
- | 2.6.5 | 2.0 | Tested |
396
- | 2.6.x | 2.0 | ✅ Compatible |
397
- | < 2.6 or > 3.1 | | ⚠️ Not guaranteed |
461
+ **Compatibility advantage over the full ORM**: ORM-lite runs on **both** SurrealDB **2.6.x and 3.1**, while the full [SurrealDB-ORM](https://github.com/EulogySnowfall/SurrealDB-ORM/) (custom SDK) targets **3.x only**. Lite stays usable on existing 2.6.x deployments without forcing a server upgrade.
462
+
463
+ | SurrealDB Version | SDK Version | Status |
464
+ | ----------------- | ----------- | ----------------- |
465
+ | 3.1.3 | 2.0 | ✅ Tested |
466
+ | 2.6.5 | 2.0 | Tested |
467
+ | 2.6.x | 2.0 | ✅ Compatible |
468
+ | < 2.6 or > 3.1 | — | ⚠️ Not guaranteed |
469
+
470
+ ### ORM behaviour: SurrealDB 2.6.x vs 3.x
471
+
472
+ Surreal ORM Lite runs on both lines; some capabilities differ because they rely on server
473
+ features introduced in SurrealDB 3.x. On 2.6.x the ORM degrades gracefully. Capabilities not
474
+ listed behave the same on both lines.
475
+
476
+ | ORM capability | SurrealDB 2.6.x | SurrealDB 3.x (3.1.3) | Since |
477
+ | -------------- | --------------- | --------------------- | ----- |
478
+ | Transaction strategy auto-selected by `transaction()` | buffered batch (`BEGIN…COMMIT`) | native interactive on WebSocket | v0.9.0 |
479
+ | Reads inside a transaction (`objects(tx=)`) | raise (buffered cannot read) | see uncommitted writes | v0.9.0 |
480
+ | `save(tx=)` with an auto-generated id | raises — explicit id required | supported | v0.9.0 |
481
+ | `refresh(tx=)` inside a transaction | raises | works | v0.9.0 |
482
+ | `bulk_update` / `bulk_delete` row count inside a tx | returns `0` (not knowable pre-commit) | real count | v0.9.0 |
483
+ | "Already exists" error on create | normalised to `SurrealDbError` | normalised to `SurrealDbError` | v0.7.0 |
484
+ | Cleanup on a missing target (`delete_table`, `remove_relation`) | native no-op | ORM makes it a silent no-op | v0.7.0 |
485
+ | Aggregation over an empty set (`NaN` / `±inf`) | returns `0.0` / `None` | ORM normalises to `0.0` / `None` | v0.7.0 |
486
+ | Namespace/db selection (`use()` ordering) | lenient (auto-creates) | strict — ORM signs in before `use()` | v0.7.0 |
487
+ | `upsert()` / `update_or_create()` / `get_or_create()` | same on both lines | same on both lines | v0.10.0 |
398
488
 
399
489
  > **Note on record IDs**: A record loaded from the database has its `id` field set to a native `surrealdb.RecordID` object, not a plain string. Use `model.get_raw_id()` to obtain the bare identifier string (e.g. `"alice"`), or compare directly with `model.id == RecordID("User", "alice")`. In-memory instances you construct yourself retain whatever value you assign.
400
490
 
@@ -414,19 +504,21 @@ Contributions are welcome! Please:
414
504
 
415
505
  ## Roadmap
416
506
 
417
- | Version | Theme | Status |
418
- | ------- | ---------------------------------- | ----------- |
419
- | v0.2.x | Core ORM (CRUD, QuerySet) | ✅ Released |
420
- | v0.3.0 | Aggregations & Utilities | ✅ Released |
421
- | v0.4.0 | Model Signals | ✅ Released |
422
- | v0.5.0 | Bulk Operations & Q Objects | ✅ Released |
423
- | v0.6.0 | Relations & Graph | Released |
424
- | v0.7.0 | SDK 2.0 / SurrealDB 3.x migration | Released |
425
- | v0.8.0 | Transactions ORM | 📋 Planned |
426
- | v0.9.0 | SurrealFunc & Computed Fields | 📋 Planned |
427
- | v0.10.0 | FETCH, Field Aliases & DX | 📋 Planned |
428
- | v0.11.0 | Beta Phase | 📋 Planned |
429
- | v1.0.0 | Production Ready | 📋 Planned |
507
+ | Version | Theme | Status |
508
+ | ----------------- | ------------------------------------------------ | ----------- |
509
+ | v0.2.x – v0.7.0 | Core ORM SDK 2.0 / SurrealDB 3.x migration | ✅ Released |
510
+ | v0.8.0 | Transactions ORM (`tx=`) | ✅ Released |
511
+ | v0.9.0 | Transactions — QuerySet & interactive (3.x) | ✅ Released |
512
+ | v0.10.0 | upsert / update_or_create / get_or_create | ✅ Released |
513
+ | v0.11.0 v0.22.0 | Tier 1 — Core (auth, live, relations, …) | 📋 Planned |
514
+ | v0.23.0 v0.29.0 | Tier 2 — Extended (rich types, geo, subqueries) | 📋 Planned |
515
+ | v0.30.0 – v0.39.0 | Tier 3 — Advanced (search, DDL, migrations, CLI) | 📋 Planned |
516
+ | v0.40.0 | Beta Phase (API freeze, hardening) | 📋 Planned |
517
+ | v2.0.0 | Production / GA (aligned with SDK 2.0) | 📋 Planned |
518
+
519
+ > Every roadmap feature is implementable with the **official SDK 2.0** (native methods or
520
+ > `query()` SurrealQL) — no custom SDK. GA is numbered **v2.0.0** to mirror SDK 2.0; the `1.x`
521
+ > line is intentionally skipped.
430
522
 
431
523
  See [docs/ROADMAP.md](docs/ROADMAP.md) for full details.
432
524
 
@@ -436,37 +528,52 @@ See [docs/ROADMAP.md](docs/ROADMAP.md) for full details.
436
528
 
437
529
  This project prioritizes **stability and compatibility** with the official SurrealDB Python SDK. The full [SurrealDB-ORM](https://github.com/EulogySnowfall/SurrealDB-ORM/) uses a custom SDK for advanced features.
438
530
 
439
- | Feature | ORM-lite (official SDK) | ORM (custom SDK) |
440
- | ------------------------- | ----------------------- | ---------------- |
441
- | CRUD & QuerySet | ✅ | ✅ |
442
- | Aggregations & GROUP BY | ✅ | ✅ |
443
- | Model Signals | | |
444
- | Bulk Operations | | |
445
- | Q Objects (OR/AND/NOT) | | |
446
- | Parameterized Filters | ✅ | ✅ |
447
- | Relations & Graph | ✅ | ✅ |
448
- | FETCH clause | ✅ | ✅ |
449
- | Transactions (tx=) | v0.8.0 | ✅ |
450
- | SurrealFunc & Computed | v0.9.0 | ✅ |
451
- | Field Aliases | v0.10.0 | ✅ |
452
- | Retry, Logging, Metrics | v0.11.0 | ✅ |
453
- | Live Models / CDC | | ✅ |
454
- | Vector / Full-Text Search | | ✅ |
455
- | Hybrid Search (RRF) | | ✅ |
456
- | Migrations & CLI | | ✅ |
457
- | JWT Authentication | | ✅ |
458
- | Schema Introspection | | ✅ |
459
- | Connection Pool | | ✅ |
460
- | CBOR Protocol | | ✅ |
461
- | Subqueries & Query Cache | | ✅ |
462
- | Geospatial Fields | | ✅ |
463
- | DEFINE EVENT | | ✅ |
464
- | Test Fixtures & Factories | | ✅ |
465
- | Atomic Array Operations | | ✅ |
466
-
467
- **Choose ORM-lite** if you want the official SDK, minimal dependencies, and core ORM features.
468
-
469
- **Choose ORM** if you need live queries, migrations, authentication, vector search, or advanced features.
531
+ Both projects target the same feature set; the difference is **how** (official SDK vs custom
532
+ SDK) and **server support**. Everything below is on the lite roadmap via the official SDK 2.0
533
+ only the custom-SDK internals stay exclusive to the full ORM.
534
+
535
+ | Feature | ORM-lite (official SDK) | ORM (custom SDK) |
536
+ | ----------------------------- | ----------------------- | ---------------- |
537
+ | Supported SurrealDB | **2.6.x + 3.1** | 3.x only |
538
+ | CRUD & QuerySet | ✅ | ✅ |
539
+ | Aggregations & GROUP BY | ✅ | ✅ |
540
+ | Model Signals | ✅ | ✅ |
541
+ | Bulk Operations | | ✅ |
542
+ | Q Objects (OR/AND/NOT) | | ✅ |
543
+ | Parameterized Filters | | ✅ |
544
+ | Relations & Graph | | ✅ |
545
+ | FETCH clause | | ✅ |
546
+ | Transactions (tx=) | v0.8 (core), v0.9 QS | ✅ |
547
+ | Interactive tx (3.x native) | ✅ v0.9 | ✅ |
548
+ | upsert / update_or_create | ✅ v0.10.0 | ✅ |
549
+ | Atomic field/array operations | v0.11.0 | ✅ |
550
+ | Retry on conflict | v0.12.0 | ✅ |
551
+ | SurrealFunc & Computed | v0.13 – v0.14 | ✅ |
552
+ | JWT Authentication | v0.16 – v0.17 | ✅ |
553
+ | Field Aliases & DX | v0.18.0 | ✅ |
554
+ | Live Models / CDC | v0.19 – v0.21 | ✅ |
555
+ | Native typed relations | v0.22.0 | ✅ |
556
+ | Rich field types | v0.23.0 | ✅ |
557
+ | Geospatial Fields | v0.24.0 | ✅ |
558
+ | Subqueries & Query Cache | v0.27 – v0.28 | ✅ |
559
+ | Multi-database | v0.29.0 | ✅ |
560
+ | Schema Introspection | v0.30.0 | ✅ |
561
+ | DEFINE EVENT | v0.31.0 | ✅ |
562
+ | Materialized views | v0.32.0 | ✅ |
563
+ | Full-Text Search | v0.34.0 | ✅ |
564
+ | Vector Search (KNN/HNSW) | v0.35.0 | ✅ |
565
+ | Hybrid Search (RRF) | v0.36.0 | ✅ |
566
+ | Migrations & CLI | v0.37 – v0.38 | ✅ |
567
+ | Test Fixtures & Factories | v0.39.0 | ✅ |
568
+ | Retry, Logging, Metrics | v0.40.0 | ✅ |
569
+ | Connection Pool | post-GA (tentative) | ✅ |
570
+ | Custom SDK / CBOR Protocol | ❌ never | ✅ |
571
+
572
+ **Choose ORM-lite** if you want the official SDK, minimal dependencies, support for SurrealDB
573
+ 2.6.x **and** 3.1, and a full feature roadmap built entirely on the official SDK.
574
+
575
+ **Choose ORM** if you need the custom-SDK internals (CBOR protocol, native connection pool)
576
+ or those features available today rather than on the roadmap.
470
577
 
471
578
  - **SurrealDB-ORM GitHub**: [github.com/EulogySnowfall/SurrealDB-ORM](https://github.com/EulogySnowfall/SurrealDB-ORM/)
472
579
  - **SurrealDB-ORM PyPI**: [surrealdb-orm](https://pypi.org/project/surrealdb-orm/)