diff --git a/Cargo.toml b/Cargo.toml index 27ce93d..746dd3f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "ragkit_convex_macros" description = "Macros to help make Convex in Rust nice" -authors = ["Ragkit "] -version = "0.0.2" +authors = ["Ragkit "] +version = "0.0.4" edition = "2021" license = "MIT" -documentation = "https://github.com/ragkit/convex-macros" +documentation = "https://docs.rs/ragkit_convex_macros/latest/ragkit_convex_macros/" repository = "https://github.com/ragkit/convex-macros" homepage = "https://github.com/ragkit/convex-macros" diff --git a/README.md b/README.md index 171518e..58ee95f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # convex-macros -[![CI Badge](https://github.com/ragkit/convex-macros/actions/workflows/ci.yml/badge.svg)](https://github.com/ragkit/convex-macros/actions/workflows/ci.yml) +[![CI Badge](https://github.com/ragkit/convex-macros/actions/workflows/ci.yml/badge.svg)](https://github.com/ragkit/convex-macros/actions/workflows/ci.yml) [![License Badge](https://img.shields.io/badge/license-MIT-blue)](./LICENSE) [![Crates.io Badge](https://img.shields.io/crates/v/ragkit_convex_macros)](https://img.shields.io/crates/v/ragkit_convex_macros) Macros to help make Convex in Rust nice @@ -8,7 +8,7 @@ Macros to help make Convex in Rust nice ```toml [dependencies] -ragkit_convex_macros = "0.0.2" +ragkit_convex_macros = "0.0.4" # Required by code this macro generates. anyhow = "1.0.80" @@ -71,10 +71,27 @@ assert_eq!( ## Features -- `let user = User::from_convex_value(value)?;` to parse a value from Convex client -- `json!(user)` to serialize as json -- Discriminated unions are automatically handled -- Helper functions for each branch are also exposed: `user.platform.as_2()?.username` +- `let user = User::from_convex_value(value)?;` to parse a value from Convex client. +- `json!(user)` to serialize as json. +- Discriminated unions are automatically handled. +- Helper functions for each union branch: `user.platform.as_2()?.username`. + +## Validator List + +| Validator Name | Rust Type | Notes | +| ------------------------ | ------------------ | ------------------------------------------------ | +| `v.string()` | `String` | | +| `v.id("tableName")` | `String` | Ids are not validated against your tables | +| `v.null()` | `()` | | +| `v.int64()` | `i64` | | +| `v.number()` | `f64` | | +| `v.boolean()` | `bool` | | +| `v.optional(...)` | `Option` | | +| `v.union(...)` | Generated `enum` | | +| `v.object({field: ...})` | Generated `struct` | Field names can't be rust keywords (like `type`) | +| `v.bytes()` | not implemented | | +| `v.array(values)` | not implemented | | +| `v.any()` | not implemented | | ## Limitations @@ -84,6 +101,7 @@ assert_eq!( - Union variant names are always named like: `Variant1`, `Variant2`, etc. - The first acceptable union branch will be used if there are multiples that could validly parse data. - This package generates code that expects `anyhow`, `convex`, `serde`, and `serde_json` to be available. +- Ints and Floats may be coerced into each other. Please test out your use cases and open an issue if you believe the behavior should change. # License diff --git a/src/lib.rs b/src/lib.rs index 2bda39f..637a147 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -6,6 +6,55 @@ use syn::parse_macro_input; mod model; +/// Create models using the same [Convex validator](https://docs.convex.dev/functions/args-validation#convex-values) syntax as your schema definition. +/// +/// ```ignore +/// convex_model!(User { +/// _id: v.id("users"), +/// name: v.string(), +/// age: v.optional(v.int64()), +/// platform: v.union( +/// v.object({ +/// platform: v.literal("google"), +/// verified: v.boolean(), +/// }), +/// v.object({ +/// platform: v.literal("github"), +/// username: v.string(), +/// }), +/// ), +/// }); +/// ``` +/// +/// This generates `pub struct User {}` with various methods to convert from [`convex::Value`](https://docs.rs/convex/0.6.0/convex/enum.Value.html) and to [`serde_json::Value`](https://docs.rs/serde_json/latest/serde_json/enum.Value.html). +/// +/// ```ignore +/// let user = User::from_convex_value(&Value::Object(btreemap! { +/// "_id".into() => Value::String("1234".into()), +/// "name".into() => Value::String("Alice".into()), +/// "age".into() => Value::Int64(42), +/// "platform".into() => Value::Object(btreemap! { +/// "platform".into() => Value::String("github".into()), +/// "username".into() => Value::String("alicecodes".into()), +/// }), +/// })) +/// .expect("it should parse"); +/// +/// assert_eq!("1234", user._id); +/// assert_eq!("alicecodes", user.platform.as_2().unwrap().username); +/// assert_eq!( +/// json!({ +/// "_id": "1234", +/// "name": "Alice", +/// "age": 42, +/// "platform": { +/// "platform": "github", +/// "username": "alicecodes", +/// }, +/// }), +/// json!(user), +/// ); +/// ``` #[proc_macro] pub fn convex_model(input: TokenStream) -> TokenStream { let input = parse_macro_input!(input as ConvexField);