Skip to content

Commit 6aa0e42

Browse files
committed
Release v0.8.6: preserve relations & typed JSON
Bump crate versions to 0.8.6 and add several fixes and improvements: preserve in-memory relation runtime state when overwriting models from JSON, rework raw SQL -> JSON conversion to decode backend-aware column types (booleans, JSON/JSONB, UUID, date/time, decimals using rust_decimal) instead of relying on probe order, and add Send bounds so NestedSaveBuilder can be moved across await points or into tokio::spawn. Also remove the misleading Model::load_all_translations helper, cache the email validation regex with OnceLock, update docs/examples and changelog, and refresh macro outputs to emit relation-state refreshes. Tests added for raw JSON typed decoding and nested-save spawning; compile-fail snapshots updated accordingly.
1 parent 50b296c commit 6aa0e42

26 files changed

Lines changed: 884 additions & 89 deletions

CHANGELOG.md

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,25 @@ All notable changes to TideORM will be documented in this file.
55
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
66
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
77

8+
## [0.8.6] - 2026-03-21
9+
10+
### Fixed
11+
12+
- Preserved loaded `HasOne`, `HasMany`, `BelongsTo`, and `HasManyThrough` relation runtime state when model helpers overwrite a model from JSON, so translation and file-attachment updates no longer silently discard cached relations.
13+
- Reworked raw SQL JSON row conversion to decode backend-aware column types instead of relying on a fragile probe order, preserving booleans and improving JSON, UUID, date/time, and decimal handling.
14+
- Added `Send` bounds to nested relation save operation erasure so `NestedSaveBuilder` remains `Send` and can safely cross await points or be moved into `tokio::spawn` tasks.
15+
16+
### Changed
17+
18+
- Removed the misleading `Model::load_all_translations()` helper. Use `get_all_translations()`, `get_translations_for_language()`, or `to_json_with_all_translations()` depending on whether you need per-field values, a single-language projection, or full JSON output.
19+
- Cached the email validation regex with `OnceLock` instead of compiling it on every validation call.
20+
- Refreshed dependency examples and macro-crate docs to use the 0.8.6 release version.
21+
22+
### Internal
23+
24+
- Updated relation compile-fail snapshots to match the attribute-macro test fixtures.
25+
- Verified the release prep with `cargo test --all-features`, `cargo clippy --lib --all-features -- -D warnings`, and `mdbook build`.
26+
827
## [0.8.5] - 2026-03-20
928

1029
### Fixed
@@ -587,7 +606,8 @@ This is the first public release of TideORM, a developer-friendly ORM for Rust w
587606
- **Repository:** [https://github.com/mohamadzoh/tideorm](https://github.com/mohamadzoh/tideorm)
588607
- **Documentation:** See README.md and examples/
589608

590-
[Unreleased]: https://github.com/mohamadzoh/tideorm/compare/v0.8.5...HEAD
609+
[Unreleased]: https://github.com/mohamadzoh/tideorm/compare/v0.8.6...HEAD
610+
[0.8.6]: https://github.com/mohamadzoh/tideorm/compare/v0.8.5...v0.8.6
591611
[0.8.5]: https://github.com/mohamadzoh/tideorm/compare/v0.8.4...v0.8.5
592612
[0.8.4]: https://github.com/mohamadzoh/tideorm/compare/v0.8.1...v0.8.4
593613
[0.8.1]: https://github.com/mohamadzoh/tideorm/compare/v0.8.0...v0.8.1

Cargo.lock

Lines changed: 6 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "tideorm"
3-
version = "0.8.5"
3+
version = "0.8.6"
44
edition = "2021"
55
authors = ["Mohamad Al Zohbie <alzoubi528@gmail.com>"]
66
description = "A developer-friendly ORM for Rust with clean, expressive syntax"
@@ -29,7 +29,7 @@ translations = []
2929
fulltext = []
3030

3131
[dependencies]
32-
sea-orm = { version = "2.0.0-rc.37", default-features = false, features = ["macros", "with-chrono", "with-json", "with-uuid", "schema-sync"] }
32+
sea-orm = { version = "2.0.0-rc.37", default-features = false, features = ["macros", "with-chrono", "with-json", "with-rust_decimal", "with-uuid", "schema-sync"] }
3333

3434
# Async runtime
3535
tokio = { version = "1.50.0", features = ["full"], optional = true }
@@ -48,7 +48,7 @@ rust_decimal = { version = "1.40.0", features = ["serde"] }
4848
thiserror = "2.0.18"
4949

5050
# Derive macros (our own crate)
51-
tideorm-macros = { version = "0.8.5", path = "tideorm-macros" }
51+
tideorm-macros = { version = "0.8.6", path = "tideorm-macros" }
5252

5353
# Utils
5454
parking_lot = "0.12.5"

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -192,22 +192,22 @@ let recent_posts = user.posts.load_with(|q| {
192192
```toml
193193
[dependencies]
194194
# PostgreSQL (default)
195-
tideorm = { version = "0.8.5", features = ["postgres"] }
195+
tideorm = { version = "0.8.6", features = ["postgres"] }
196196

197197
# MySQL
198-
tideorm = { version = "0.8.5", features = ["mysql"] }
198+
tideorm = { version = "0.8.6", features = ["mysql"] }
199199

200200
# SQLite
201-
tideorm = { version = "0.8.5", features = ["sqlite"] }
201+
tideorm = { version = "0.8.6", features = ["sqlite"] }
202202

203203
# Enable attachments support explicitly
204-
tideorm = { version = "0.8.5", features = ["postgres", "attachments"] }
204+
tideorm = { version = "0.8.6", features = ["postgres", "attachments"] }
205205

206206
# Enable translations support explicitly
207-
tideorm = { version = "0.8.5", features = ["postgres", "translations"] }
207+
tideorm = { version = "0.8.6", features = ["postgres", "translations"] }
208208

209209
# Enable full-text search support explicitly
210-
tideorm = { version = "0.8.5", features = ["postgres", "fulltext"] }
210+
tideorm = { version = "0.8.6", features = ["postgres", "fulltext"] }
211211
```
212212

213213
### Feature Flags

docs/models.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,8 @@ let (user, related_json) = NestedSaveBuilder::new(user)
906906

907907
`save_with_many` batches related inserts through TideORM's bulk insert path, and `delete_with_many` removes related rows with a single `WHERE IN` delete. `update_with_many` batches existing related rows through an upsert-style write and then reloads them once. If any related model still looks new, `update_with_many` falls back to per-row updates so create-vs-update semantics stay unchanged.
908908

909+
`NestedSaveBuilder` is `Send`, so you can hold it across await points or move it into task executors such as `tokio::spawn` before calling `.save()`.
910+
909911
### Join Result Consolidation
910912

911913
Transform flat JOIN results into nested structures:

docs/queries.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ TideORM provides full-text search capabilities across PostgreSQL (tsvector/tsque
514514
Enable the feature explicitly when you need the full-text search API:
515515

516516
```toml
517-
tideorm = { version = "0.8.5", features = ["postgres", "fulltext"] }
517+
tideorm = { version = "0.8.6", features = ["postgres", "fulltext"] }
518518
```
519519

520520
### Search Basics

docs/relations.md

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -210,7 +210,7 @@ Enable the feature first:
210210

211211
```toml
212212
[dependencies]
213-
tideorm = { version = "0.8.5", features = ["postgres", "attachments"] }
213+
tideorm = { version = "0.8.6", features = ["postgres", "attachments"] }
214214
```
215215

216216
### Model Setup
@@ -545,7 +545,7 @@ Enable the feature first:
545545

546546
```toml
547547
[dependencies]
548-
tideorm = { version = "0.8.5", features = ["postgres", "translations"] }
548+
tideorm = { version = "0.8.6", features = ["postgres", "translations"] }
549549
```
550550

551551
### Model Setup
@@ -617,6 +617,8 @@ let arabic = product.get_translations_for_language("ar")?;
617617
// Returns: {"name": "اسم المنتج", "description": "وصف المنتج"}
618618
```
619619

620+
`Model::load_all_translations()` is no longer available because applying every translation directly onto scalar model fields was misleading and lossy. Use `get_all_translations()` for field-level access, `get_translations_for_language()` for one language at a time, or `to_json_with_all_translations()` when you need a full JSON payload.
621+
620622
### Checking Translations
621623

622624
```rust

0 commit comments

Comments
 (0)