Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,27 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

---

## [1.0.0] — 2026-04-23

### Breaking

- `ValueObject` trait split into two traits: `ValueObject` (construction + destructuring) and `PrimitiveValue` (single-primitive accessor via `.value()`). Types backed by a primitive implement both; composite types implement only `ValueObject`.
- Removed the `sql` feature and all SQLx integration. Database mapping is now the responsibility of the application layer (see the ORM guide in `docs/`).

### Added

- `PrimitiveValue` trait with a `.value() -> &Primitive` accessor for types whose canonical form is a single primitive.
- `TryFrom<String>` and `TryFrom<&str>` implemented for all value objects — ergonomic construction without calling `::new()` explicitly.
- Serde deserialization now runs the full validation pipeline; deserializing an invalid value returns an error instead of producing an invalid object.
- Minimum `serde` version pinned to `1.0.116` (required for the `try_from` container attribute).

### Fixed

- Replaced `once_cell::sync::Lazy` with `std::sync::LazyLock` (stable since Rust 1.80); `once_cell` dependency removed.
- Stale `test-sql` CI job removed; `once_cell` removed from the `contact` feature declaration.

---

## [0.1.1] — 2026-04-17

### Added
Expand Down Expand Up @@ -39,5 +60,7 @@ Versioning follows [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
- `full` meta-feature
- `prelude` module with convenience re-exports

[Unreleased]: https://github.com/codegress-com/arvo/compare/v0.1.0...HEAD
[Unreleased]: https://github.com/codegress-com/arvo/compare/v1.0.0...HEAD
[1.0.0]: https://github.com/codegress-com/arvo/compare/v0.1.1...v1.0.0
[0.1.1]: https://github.com/codegress-com/arvo/compare/v0.1.0...v0.1.1
[0.1.0]: https://github.com/codegress-com/arvo/releases/tag/v0.1.0
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "arvo"
version = "0.9.0"
version = "1.0.0"
license = "MIT"
description = "Validated, immutable value objects for common domain types (email, money, identifiers, …)"
authors = ["Codegress <hello@codegress.com>"]
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ Enable only the modules you need — unused features add zero dependencies.

| Feature | What you get | Extra deps |
|:---|:---|:---|
| `contact` | `EmailAddress`, `CountryCode`, `PhoneNumber`, `PostalAddress`, `Website` | `once_cell`, `regex`, `url` |
| `contact` | `EmailAddress`, `CountryCode`, `PhoneNumber`, `PostalAddress`, `Website` | `regex`, `url` |
| `finance` | `Money`, `CurrencyCode`, `Iban`, `Bic`, `VatNumber`, `Percentage`, `ExchangeRate`, `CreditCardNumber`, `CardExpiryDate` | `rust_decimal`, `chrono` |
| `geo` | `Latitude`, `Longitude`, `Coordinate`, `BoundingBox`, `TimeZone`, `CountryRegion` | — |
| `measurement` | `Length`, `Weight`, `Temperature`, `Volume`, `Area`, `Speed`, `Pressure`, `Energy`, `Power`, `Frequency` | — |
Expand Down
12 changes: 6 additions & 6 deletions docs/contact.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Feature flag: `contact`

```toml
[dependencies]
arvo = { version = "0.9", features = ["contact"] }
arvo = { version = "1.0", features = ["contact"] }
```

---
Expand All @@ -18,7 +18,7 @@ A validated, normalised email address.

```rust,ignore
use arvo::contact::EmailAddress;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let email = EmailAddress::new("User@Example.COM".into())?;
assert_eq!(email.value(), "user@example.com");
Expand Down Expand Up @@ -56,7 +56,7 @@ A validated ISO 3166-1 alpha-2 country code.

```rust,ignore
use arvo::contact::CountryCode;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let code = CountryCode::new("cz".into())?;
assert_eq!(code.value(), "CZ");
Expand Down Expand Up @@ -91,7 +91,7 @@ A validated phone number stored in canonical E.164 format.

```rust,ignore
use arvo::contact::{CountryCode, PhoneNumber, PhoneNumberInput};
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let phone = PhoneNumber::new(PhoneNumberInput {
country_code: CountryCode::new("CZ".into())?,
Expand Down Expand Up @@ -145,7 +145,7 @@ A validated website URL. Accepts `http` and `https` schemes only. Scheme and hos

```rust,ignore
use arvo::contact::Website;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let site = Website::new("https://EXAMPLE.COM/path".into())?;
assert_eq!(site.value(), "https://example.com/path");
Expand Down Expand Up @@ -184,7 +184,7 @@ A validated composite postal address. All text fields are trimmed; empty or whit

```rust,ignore
use arvo::contact::{CountryCode, PostalAddress, PostalAddressInput};
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let addr = PostalAddress::new(PostalAddressInput {
street: "Václavské náměstí 1".into(),
Expand Down
20 changes: 10 additions & 10 deletions docs/finance.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Feature flag: `finance`

```toml
[dependencies]
arvo = { version = "0.9", features = ["finance"] }
arvo = { version = "1.0", features = ["finance"] }
```

---
Expand All @@ -18,7 +18,7 @@ A validated ISO 4217 alphabetic currency code.

```rust,ignore
use arvo::finance::CurrencyCode;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let code = CurrencyCode::new("eur".into())?;
assert_eq!(code.value(), "EUR");
Expand Down Expand Up @@ -54,7 +54,7 @@ A validated monetary amount with an associated currency.

```rust,ignore
use arvo::finance::{CurrencyCode, Money, MoneyInput};
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let money = Money::new(MoneyInput {
amount: "10.50".parse()?,
Expand Down Expand Up @@ -94,7 +94,7 @@ A validated IBAN (International Bank Account Number) using the mod-97 algorithm.

```rust,ignore
use arvo::finance::Iban;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let iban = Iban::new("GB82 WEST 1234 5698 7654 32".into())?;
assert_eq!(iban.value(), "GB82WEST12345698765432");
Expand Down Expand Up @@ -133,7 +133,7 @@ A validated BIC (Bank Identifier Code / SWIFT code).

```rust,ignore
use arvo::finance::Bic;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let bic = Bic::new("DEUTDEDB".into())?;
assert_eq!(bic.bank_code(), "DEUT");
Expand Down Expand Up @@ -166,7 +166,7 @@ A validated EU VAT number.

```rust,ignore
use arvo::finance::VatNumber;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let vat = VatNumber::new("CZ 1234 5678".into())?;
assert_eq!(vat.value(), "CZ12345678");
Expand All @@ -192,7 +192,7 @@ A validated percentage in the range `0.0..=100.0`.

```rust,ignore
use arvo::finance::Percentage;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let p = Percentage::new(42.5)?;
assert_eq!(*p.value(), 42.5);
Expand Down Expand Up @@ -220,7 +220,7 @@ A validated currency exchange rate between two different currencies.

```rust,ignore
use arvo::finance::{CurrencyCode, ExchangeRate, ExchangeRateInput};
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let rate = ExchangeRate::new(ExchangeRateInput {
from: CurrencyCode::new("EUR".into())?,
Expand Down Expand Up @@ -259,7 +259,7 @@ A validated credit card number using the Luhn algorithm.

```rust,ignore
use arvo::finance::CreditCardNumber;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let card = CreditCardNumber::new("4532 0151 1283 0366".into())?;
assert_eq!(card.last_four(), "0366");
Expand Down Expand Up @@ -288,7 +288,7 @@ A validated credit/debit card expiry date that is not in the past.

```rust,ignore
use arvo::finance::CardExpiryDate;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let exp = CardExpiryDate::new("12/28".into())?;
assert_eq!(exp.value(), "12/28");
Expand Down
14 changes: 7 additions & 7 deletions docs/geo.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Feature flag: `geo`

```toml
[dependencies]
arvo = { version = "0.9", features = ["geo"] }
arvo = { version = "1.0", features = ["geo"] }
```

---
Expand All @@ -17,7 +17,7 @@ A validated geographic latitude in decimal degrees.

```rust,ignore
use arvo::geo::Latitude;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let lat = Latitude::new(48.8588)?;
assert_eq!(*lat.value(), 48.8588);
Expand Down Expand Up @@ -50,7 +50,7 @@ A validated geographic longitude in decimal degrees.

```rust,ignore
use arvo::geo::Longitude;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let lng = Longitude::new(14.4208)?;
assert_eq!(*lng.value(), 14.4208);
Expand Down Expand Up @@ -82,7 +82,7 @@ A geographic coordinate (latitude + longitude pair).

```rust,ignore
use arvo::geo::{Coordinate, CoordinateInput, Latitude, Longitude};
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let coord = Coordinate::new(CoordinateInput {
lat: Latitude::new(48.858844)?,
Expand Down Expand Up @@ -122,7 +122,7 @@ A geographic bounding box defined by a south-west and a north-east [`Coordinate`

```rust,ignore
use arvo::geo::{BoundingBox, BoundingBoxInput, Coordinate, CoordinateInput, Latitude, Longitude};
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let sw = Coordinate::new(CoordinateInput {
lat: Latitude::new(48.0)?,
Expand Down Expand Up @@ -173,7 +173,7 @@ A validated IANA timezone name.

```rust,ignore
use arvo::geo::TimeZone;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let tz = TimeZone::new("Europe/Prague".into())?;
assert_eq!(tz.value(), "Europe/Prague");
Expand Down Expand Up @@ -210,7 +210,7 @@ A validated ISO 3166-2 subdivision code.

```rust,ignore
use arvo::geo::CountryRegion;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let region = CountryRegion::new("cz-pr".into())?;
assert_eq!(region.value(), "CZ-PR");
Expand Down
16 changes: 8 additions & 8 deletions docs/identifiers.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Feature flag: `identifiers`

```toml
[dependencies]
arvo = { version = "0.9", features = ["identifiers"] }
arvo = { version = "1.0", features = ["identifiers"] }
```

---
Expand All @@ -18,7 +18,7 @@ A URL-safe slug: lowercase alphanumeric characters and hyphens only.

```rust,ignore
use arvo::identifiers::Slug;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let slug = Slug::new("Hello-World".into())?;
assert_eq!(slug.value(), "hello-world");
Expand Down Expand Up @@ -56,7 +56,7 @@ A validated EAN-13 barcode number.

```rust,ignore
use arvo::identifiers::Ean13;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let ean = Ean13::new("4006381333931".into())?;
assert_eq!(ean.value(), "4006381333931");
Expand Down Expand Up @@ -89,7 +89,7 @@ A validated EAN-8 barcode number.

```rust,ignore
use arvo::identifiers::Ean8;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let ean = Ean8::new("73513537".into())?;
assert_eq!(ean.value(), "73513537");
Expand Down Expand Up @@ -122,7 +122,7 @@ A validated ISBN-13 number.

```rust,ignore
use arvo::identifiers::Isbn13;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let isbn = Isbn13::new("978-0-306-40615-7".into())?;
assert_eq!(isbn.value(), "9780306406157");
Expand Down Expand Up @@ -156,7 +156,7 @@ A validated ISBN-10 number.

```rust,ignore
use arvo::identifiers::Isbn10;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let isbn = Isbn10::new("0-306-40615-2".into())?;
assert_eq!(isbn.value(), "0306406152");
Expand Down Expand Up @@ -190,7 +190,7 @@ A validated ISSN (International Standard Serial Number).

```rust,ignore
use arvo::identifiers::Issn;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let issn = Issn::new("0317-8471".into())?;
assert_eq!(issn.value(), "0317-8471");
Expand Down Expand Up @@ -224,7 +224,7 @@ A validated Vehicle Identification Number (VIN) per ISO 3779.

```rust,ignore
use arvo::identifiers::Vin;
use arvo::traits::ValueObject;
use arvo::traits::{PrimitiveValue, ValueObject};

let vin = Vin::new("1HGBH41JXMN109186".into())?;
assert_eq!(vin.wmi(), "1HG");
Expand Down
Loading
Loading