#convex #macro #models #validation #generate #help #nice

macro ragkit_convex_macros

Macros to help make Convex in Rust nice

4 releases

0.0.4 Mar 19, 2024
0.0.3 Mar 19, 2024
0.0.2 Mar 19, 2024
0.0.1 Mar 19, 2024

#283 in Procedural macros

30 downloads per month

MIT license

37KB
807 lines

convex-macros

CI Badge License Badge Crates.io Badge

Macros to help make Convex in Rust nice

Installation

[dependencies]
ragkit_convex_macros = "0.0.4"

# Required by code this macro generates.
anyhow = "1.0.80"
convex = "0.6.0"
serde = "1.0.185"
serde_json = "1.0"

Usage

Create models using the same Convex validator syntax as your schema definition.

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 and to serde_json::Value.

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),
);

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 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<T>
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

  • This is experimental and may not be "production quality", use with caution.
  • v.bytes(), v.array(), v.any() are not yet supported.
  • Field names must be valid Rust identifiers, so keywords like type cannot be a field name. Map it to _type, kind, t, etc.
  • 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

MIT

Dependencies

~225–670KB
~16K SLoC