diff --git a/Cargo.lock b/Cargo.lock index 87ea78e..590e174 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -409,9 +409,9 @@ dependencies = [ [[package]] name = "brotli-decompressor" -version = "4.0.1" +version = "4.0.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a45bd2e4095a8b518033b128020dd4a55aab1c0a381ba4404a472630f4bc362" +checksum = "74fa05ad7d803d413eb8380983b092cbbaf9a85f151b871360e7b00cd7060b37" dependencies = [ "alloc-no-stdlib", "alloc-stdlib", @@ -419,9 +419,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "bytemuck" @@ -458,9 +458,9 @@ checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5" [[package]] name = "cc" -version = "1.2.9" +version = "1.2.10" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8293772165d9345bdaaa39b45b2109591e63fe5e6fbc23c6ff930a048aa310b" +checksum = "13208fcbb66eaeffe09b99fffbe1af420f00a7b35aa99ad683dfc1aa76145229" dependencies = [ "jobserver", "libc", @@ -486,6 +486,7 @@ dependencies = [ "scylla", "serde", "serde_json", + "strum", "tokio", "uuid", ] @@ -497,7 +498,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "218e5df24a1126d32f77664244aa589ea5bca70ed32e51528a3cc45148ec6fd6" dependencies = [ "bigdecimal", - "charybdis-migrate 0.7.11", + "charybdis-migrate 0.7.12 (registry+https://github.com/rust-lang/crates.io-index)", "charybdis_macros 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", "chrono", "colored", @@ -510,11 +511,9 @@ dependencies = [ [[package]] name = "charybdis-migrate" -version = "0.7.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e94b49003b4bc27397b8b2fb71677366c99df75c592365188f057ea43f16873f" +version = "0.7.12" dependencies = [ - "charybdis_parser 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", + "charybdis_parser 0.7.11", "clap", "colored", "openssl", @@ -527,8 +526,10 @@ dependencies = [ [[package]] name = "charybdis-migrate" version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f75b3e2a5ce926a260846a3bb1ae907d1c1e2b6072185ac3c52b525cecd4d619" dependencies = [ - "charybdis_parser 0.7.11", + "charybdis_parser 0.7.11 (registry+https://github.com/rust-lang/crates.io-index)", "clap", "colored", "openssl", @@ -655,9 +656,9 @@ dependencies = [ [[package]] name = "clap" -version = "4.5.26" +version = "4.5.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a8eb5e908ef3a6efbe1ed62520fb7287959888c88485abe072543190ecc66783" +checksum = "769b0145982b4b48713e01ec42d61614425f27b7058bda7180a3a41f30104796" dependencies = [ "clap_builder", "clap_derive", @@ -665,9 +666,9 @@ dependencies = [ [[package]] name = "clap_builder" -version = "4.5.26" +version = "4.5.27" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "96b01801b5fc6a0a232407abc821660c9c6d25a1cafc0d4f85f29fb8d9afc121" +checksum = "1b26884eb4b57140e4d2d93652abfa49498b938b3c9179f9fc487b0acc3edad7" dependencies = [ "anstream", "anstyle", @@ -734,9 +735,9 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "cpufeatures" -version = "0.2.16" +version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "16b80225097f2e5ae4e7179dd2266824648f3e2f49d9134d584b76389d31c4c3" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" dependencies = [ "libc", ] @@ -813,9 +814,9 @@ checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" [[package]] name = "crunchy" -version = "0.2.2" +version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7a81dae078cea95a014a339291cec439d2f232ebe854a9d672b796c6afafa9b7" +checksum = "43da5946c66ffcc7745f48db692ffbb10a83bfe0afd96235c5c2a4fb23994929" [[package]] name = "crypto-common" @@ -1171,9 +1172,9 @@ dependencies = [ [[package]] name = "httparse" -version = "1.9.5" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d71d3574edd2771538b901e6549113b4006ece66150fb69c0fb6d9a2adae946" +checksum = "f2d708df4e7140240a16cd6ab0ab65c972d7433ab77819ea693fde9c43811e2a" [[package]] name = "httpdate" @@ -1357,9 +1358,9 @@ checksum = "e8a5a9a0ff0086c7a148acb942baaabeadf9504d10400b5a05645853729b9cd2" [[package]] name = "indexmap" -version = "2.7.0" +version = "2.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62f822373a4fe84d4bb149bf54e584a7f4abec90e072ed49cda0edea5b95471f" +checksum = "8c9c992b02b5b4c94ea26e32fe5bccb7aa7d9f390ab5c1221ff895bc7ea8b652" dependencies = [ "equivalent", "hashbrown 0.15.2", @@ -1367,13 +1368,13 @@ dependencies = [ [[package]] name = "is-terminal" -version = "0.4.13" +version = "0.4.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "261f68e344040fbd0edea105bef17c66edf46f984ddb1115b775ce31be948f4b" +checksum = "e19b23d53f35ce9f56aebc7d1bb4e6ac1e9c0db7ac85c8d1760c04379edced37" dependencies = [ "hermit-abi", "libc", - "windows-sys 0.52.0", + "windows-sys 0.59.0", ] [[package]] @@ -1598,9 +1599,9 @@ checksum = "b410bbe7e14ab526a0e86877eb47c6996a2bd7746f027ba551028c925390e4e9" [[package]] name = "openssl" -version = "0.10.68" +version = "0.10.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6174bc48f102d208783c2c84bf931bb75927a617866870de8a4ea85597f871f5" +checksum = "f5e534d133a060a3c19daec1eb3e98ec6f4685978834f2dbadfe2ec215bab64e" dependencies = [ "bitflags", "cfg-if", @@ -1890,9 +1891,9 @@ checksum = "f7c45b9784283f1b2e7fb61b42047c2fd678ef0960d4f6f1eba131594cc369d4" [[package]] name = "ryu" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "6ea1a2d0a644769cc99faa24c3ad26b379b786fe7c36fd3c546254801650e6dd" [[package]] name = "same-file" @@ -1990,9 +1991,9 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.24" +version = "1.0.25" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3cb6eb87a131f756572d7fb904f6e7b68633f09cca868c5df1c4b8d1a694bbba" +checksum = "f79dfe2d285b0488816f30e700a7438c5a73d816b5b7d3ac72fbc48b0d185e03" [[package]] name = "serde" @@ -2016,9 +2017,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.135" +version = "1.0.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b0d7ba2887406110130a978386c4e1befb98c674b4fba677954e4db976630d9" +checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" dependencies = [ "itoa", "memchr", @@ -2127,6 +2128,9 @@ name = "strum" version = "0.26.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] [[package]] name = "strum_macros" @@ -2337,9 +2341,9 @@ checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" [[package]] name = "unicode-ident" -version = "1.0.14" +version = "1.0.16" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "adb9e6ca4f869e1180728b7950e35922a7fc6397f7b641499e8f3ef06e50dc83" +checksum = "a210d160f08b701c8721ba1c726c11662f877ea6b7094007e1ca9a1041945034" [[package]] name = "url" @@ -2372,9 +2376,9 @@ checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] name = "uuid" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "744018581f9a3454a9e15beb8a33b017183f1e7c0cd170232a2d1453b23a51c4" +checksum = "b3758f5e68192bb96cc8f9b7e2c2cfdabb435499a28499a42f8f984092adad4b" dependencies = [ "atomic", "getrandom", diff --git a/charybdis-macros/src/lib.rs b/charybdis-macros/src/lib.rs index b0d0d22..ef50ff7 100644 --- a/charybdis-macros/src/lib.rs +++ b/charybdis-macros/src/lib.rs @@ -232,7 +232,10 @@ pub fn charybdis_view_model(args: TokenStream, input: TokenStream) -> TokenStrea #[proc_macro_attribute] pub fn charybdis_udt_model(_: TokenStream, input: TokenStream) -> TokenStream { - let input = parse_macro_input!(input as DeriveInput); + let mut input = parse_macro_input!(input as DeriveInput); + + CharybdisFields::proxy_charybdis_attrs_to_scylla(&mut input); + CharybdisFields::strip_charybdis_attributes(&mut input); let gen = quote! { #[derive(charybdis::macros::scylla::SerializeValue)] diff --git a/charybdis-migrate/src/args.rs b/charybdis-migrate/src/args.rs index 6c3fce3..ae40d89 100644 --- a/charybdis-migrate/src/args.rs +++ b/charybdis-migrate/src/args.rs @@ -1,6 +1,5 @@ use clap::Parser; use std::env; -use std::path::PathBuf; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] @@ -67,5 +66,7 @@ impl Default for Args { pub(crate) fn get_current_dir() -> String { let path = env::current_dir().expect("Failed to find project root: Could not get current directory"); - PathBuf::from(path).to_str().unwrap().to_string() + path.to_str() + .expect("Failed to find project root: Could not convert path to string") + .to_string() } diff --git a/charybdis-parser/src/fields.rs b/charybdis-parser/src/fields.rs index 83c1067..6a71f23 100644 --- a/charybdis-parser/src/fields.rs +++ b/charybdis-parser/src/fields.rs @@ -1,4 +1,5 @@ use std::collections::{HashMap, HashSet}; +use std::str::FromStr; use darling::FromAttributes; use syn::spanned::Spanned; @@ -44,6 +45,9 @@ pub enum CqlType { pub struct FieldAttributes { #[darling(default)] pub ignore: Option, + + #[darling(default)] + pub column_type: Option, } pub struct Field<'a> { @@ -52,6 +56,7 @@ pub struct Field<'a> { pub ty: Type, pub ty_path: syn::TypePath, pub outer_type: CqlType, + pub column_type_override: Option, pub span: proc_macro2::Span, pub attrs: &'a Vec, pub ignore: bool, @@ -107,6 +112,14 @@ impl<'a> Field<'a> { FieldAttributes::from_attributes(&field.attrs) .map(|char_attrs| { let ignore = char_attrs.ignore.unwrap_or(false); + let column_type = + char_attrs + .column_type + .as_ref() + .map_or(Field::outer_type(&field.ty, ignore), |tname| { + let error = format!("Unknown column type: {}", tname); + CqlType::from_str(tname.as_str()).expect(&error) + }); let ident = field.ident.clone().unwrap(); Field { @@ -117,7 +130,8 @@ impl<'a> Field<'a> { Type::Path(type_path) => type_path.clone(), _ => panic!("Only type path is supported!"), }, - outer_type: Field::outer_type(&field.ty, ignore), + outer_type: column_type, + column_type_override: char_attrs.column_type, span: field.span(), attrs: &field.attrs, ignore, diff --git a/charybdis-parser/src/schema/code_schema/parser.rs b/charybdis-parser/src/schema/code_schema/parser.rs index b28cd35..184443f 100644 --- a/charybdis-parser/src/schema/code_schema/parser.rs +++ b/charybdis-parser/src/schema/code_schema/parser.rs @@ -101,7 +101,9 @@ fn extract_schema_object(item_struct: &ItemStruct, model_macro: &ModelMacro) -> for field in db_fields { let field_name = field.ident.to_string(); - let field_type = type_with_arguments(&field.ty_path); + let field_type = field + .column_type_override + .unwrap_or_else(|| type_with_arguments(&field.ty_path)); let is_static = schema_object.static_columns.contains(&field_name); schema_object.push_field(field_name, field_type, is_static); diff --git a/charybdis/Cargo.toml b/charybdis/Cargo.toml index 6c6956d..6458746 100644 --- a/charybdis/Cargo.toml +++ b/charybdis/Cargo.toml @@ -22,11 +22,15 @@ serde = { version = "1.0.200", features = ["derive"] } colored = "2.1.0" bigdecimal = { version = "0.4.3", features = ["serde"] } + [features] migrate = ["charybdis-migrate"] [dev-dependencies] tokio = "1.42.0" +strum = { version = "0.26.3", features = ["derive"] } +serde = "1.0" +serde_json = "1.0" [lints] workspace = true diff --git a/charybdis/README.md b/charybdis/README.md index 10c167d..4d11bbd 100644 --- a/charybdis/README.md +++ b/charybdis/README.md @@ -834,3 +834,29 @@ pub struct User { So field `organization` will be ignored in all operations and default value will be used when deserializing from other data sources. It can be used to hold data that is not persisted in database. + +## Custom Fields + +Any rust type can be used directly in table or UDT definition. +User must choose a ScyllaDB backing type (such as "TinyInt" or "Text") +and implement `SerializeValue` and `DeserializeValue` traits: + + +```rust +#[charybdis_model(...)] +pub struct User { + id: Uuid, + #[charybdis(column_type = "Text")] + extra_data: CustomField, +} + +impl<'frame, 'metadata> DeserializeValue<'frame, 'metadata> for CustomField { + ... +} + +impl SerializeValue for CustomField { + ... +} +``` + +See `custom_field.rs` integration test for examples using int and text encoding. diff --git a/charybdis/tests/integrations/custom_fields.rs b/charybdis/tests/integrations/custom_fields.rs new file mode 100644 index 0000000..7c5abab --- /dev/null +++ b/charybdis/tests/integrations/custom_fields.rs @@ -0,0 +1,100 @@ +use charybdis::scylla::SerializeValue; +use charybdis::types::Text; +use scylla::_macro_internal::{CellWriter, ColumnType, WrittenCellProof}; +use scylla::deserialize::{DeserializationError, DeserializeValue, FrameSlice, TypeCheckError}; +use scylla::serialize::SerializationError; + +#[derive(Debug, Default, Clone, PartialEq, strum::FromRepr)] +#[repr(i8)] +pub enum AddressTypeCustomField { + #[default] + HomeAddress = 0, + WorkAddress = 1, +} + +#[derive(Debug)] +struct AddressTypeCustomDeserializeErr(i8); +impl std::fmt::Display for AddressTypeCustomDeserializeErr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "AddressTypeCustomDeserializeErr({})", self.0) + } +} +impl std::error::Error for AddressTypeCustomDeserializeErr {} + +impl<'frame, 'metadata> DeserializeValue<'frame, 'metadata> for AddressTypeCustomField { + fn type_check(typ: &ColumnType) -> Result<(), TypeCheckError> { + >::type_check(typ) + } + + fn deserialize( + typ: &'metadata ColumnType<'metadata>, + v: Option>, + ) -> Result { + let si8 = >::deserialize(typ, v)?; + let s = Self::from_repr(si8); + s.ok_or_else(|| DeserializationError::new(AddressTypeCustomDeserializeErr(si8))) + } +} + +impl SerializeValue for AddressTypeCustomField { + fn serialize<'b>( + &self, + typ: &ColumnType, + writer: CellWriter<'b>, + ) -> Result, SerializationError> { + let disc = self.clone() as i8; + + let v = ::serialize(&disc, typ, writer)?; + Ok(v) + } +} + +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct UserExtraDataCustomField { + pub user_tags: Vec<(String, String)>, +} + +impl Default for UserExtraDataCustomField { + fn default() -> Self { + Self { + user_tags: vec![("some_key".to_string(), "some_value".to_string())], + } + } +} + +#[derive(Debug)] +struct UserExtraDataDeserializeErr(String); +impl std::fmt::Display for UserExtraDataDeserializeErr { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "UserExtraDataDeserializeErr({})", self.0) + } +} +impl std::error::Error for UserExtraDataDeserializeErr {} + +impl<'frame, 'metadata> DeserializeValue<'frame, 'metadata> for UserExtraDataCustomField { + fn type_check(typ: &ColumnType) -> Result<(), TypeCheckError> { + >::type_check(typ) + } + + fn deserialize( + typ: &'metadata ColumnType<'metadata>, + v: Option>, + ) -> Result { + let si8 = >::deserialize(typ, v)?; + serde_json::from_str::(&si8) + .map_err(|_e| DeserializationError::new(UserExtraDataDeserializeErr(si8))) + } +} + +impl SerializeValue for UserExtraDataCustomField { + fn serialize<'b>( + &self, + typ: &ColumnType, + writer: CellWriter<'b>, + ) -> Result, SerializationError> { + let disc = serde_json::to_string(&self).map_err(|_e| SerializationError::new(_e))?; + + let v = ::serialize(&disc, typ, writer)?; + Ok(v) + } +} diff --git a/charybdis/tests/integrations/main.rs b/charybdis/tests/integrations/main.rs index 9e3d6b7..2ad20c2 100644 --- a/charybdis/tests/integrations/main.rs +++ b/charybdis/tests/integrations/main.rs @@ -1,3 +1,4 @@ mod common; +mod custom_fields; mod model; mod query; diff --git a/charybdis/tests/integrations/model.rs b/charybdis/tests/integrations/model.rs index d6b23e8..e2ff257 100644 --- a/charybdis/tests/integrations/model.rs +++ b/charybdis/tests/integrations/model.rs @@ -1,4 +1,6 @@ use crate::common::db_session; +use crate::custom_fields::{AddressTypeCustomField, UserExtraDataCustomField}; + use charybdis::batch::ModelBatch; use charybdis::errors::CharybdisError; use charybdis::model::{BaseModel, Model}; @@ -14,6 +16,8 @@ pub struct Address { pub state: Text, pub zip: Text, pub country: Text, + #[charybdis(column_type = "TinyInt")] + pub addr_type: AddressTypeCustomField, } #[charybdis_model( @@ -33,6 +37,8 @@ pub struct User { pub bio: Option, pub address: Option
, pub is_confirmed: Boolean, + #[charybdis(column_type = "Text")] + pub user_extra_data: UserExtraDataCustomField, } partial_user!(UpdateUsernameUser, id, username); @@ -72,8 +78,10 @@ impl User { state: "Illinois".to_string(), zip: "62701".to_string(), country: "USA".to_string(), + addr_type: AddressTypeCustomField::WorkAddress, }), is_confirmed: true, + user_extra_data: UserExtraDataCustomField::default(), } } } @@ -83,38 +91,38 @@ async fn user_model_queries() { assert_eq!(User::DB_MODEL_NAME, "users"); assert_eq!( User::FIND_ALL_QUERY, - "SELECT id, username, password, email, first_name, last_name, bio, address, is_confirmed FROM users" + "SELECT id, username, password, email, first_name, last_name, bio, address, is_confirmed, user_extra_data FROM users" ); assert_eq!( User::FIND_BY_PRIMARY_KEY_QUERY, "SELECT id, username, password, email, \ - first_name, last_name, bio, address, is_confirmed FROM users WHERE id = ?" + first_name, last_name, bio, address, is_confirmed, user_extra_data FROM users WHERE id = ?" ); assert_eq!( User::FIND_BY_PARTITION_KEY_QUERY, "SELECT id, username, password, email, \ - first_name, last_name, bio, address, is_confirmed FROM users WHERE id = ?" + first_name, last_name, bio, address, is_confirmed, user_extra_data FROM users WHERE id = ?" ); assert_eq!( User::FIND_FIRST_BY_PARTITION_KEY_QUERY, "SELECT id, username, password, email, \ - first_name, last_name, bio, address, is_confirmed FROM users WHERE id = ? LIMIT 1" + first_name, last_name, bio, address, is_confirmed, user_extra_data FROM users WHERE id = ? LIMIT 1" ); assert_eq!( User::INSERT_QUERY, - "INSERT INTO users (id, username, password, email, first_name, last_name, bio, address, is_confirmed) \ - VALUES (:id, :username, :password, :email, :first_name, :last_name, :bio, :address, :is_confirmed)" + "INSERT INTO users (id, username, password, email, first_name, last_name, bio, address, is_confirmed, user_extra_data) \ + VALUES (:id, :username, :password, :email, :first_name, :last_name, :bio, :address, :is_confirmed, :user_extra_data)" ); assert_eq!( User::INSERT_IF_NOT_EXIST_QUERY, - "INSERT INTO users (id, username, password, email, first_name, last_name, bio, address, is_confirmed) \ - VALUES (:id, :username, :password, :email, :first_name, :last_name, :bio, :address, :is_confirmed) \ + "INSERT INTO users (id, username, password, email, first_name, last_name, bio, address, is_confirmed, user_extra_data) \ + VALUES (:id, :username, :password, :email, :first_name, :last_name, :bio, :address, :is_confirmed, :user_extra_data) \ IF NOT EXISTS" ); assert_eq!( User::UPDATE_QUERY, "UPDATE users SET username = :username, password = :password, email = :email, first_name = :first_name, \ - last_name = :last_name, bio = :bio, address = :address, is_confirmed = :is_confirmed WHERE id = :id" + last_name = :last_name, bio = :bio, address = :address, is_confirmed = :is_confirmed, user_extra_data = :user_extra_data WHERE id = :id" ); assert_eq!(User::DELETE_QUERY, "DELETE FROM users WHERE id = ?"); assert_eq!(User::DELETE_BY_PARTITION_KEY_QUERY, "DELETE FROM users WHERE id = ?"); diff --git a/charybdis/tests/integrations/query.rs b/charybdis/tests/integrations/query.rs index 67a8d0d..3966727 100644 --- a/charybdis/tests/integrations/query.rs +++ b/charybdis/tests/integrations/query.rs @@ -1,4 +1,5 @@ use crate::common::db_session; +use crate::custom_fields::AddressTypeCustomField; use crate::model::{Post, User}; use charybdis::batch::ModelBatch; use charybdis::errors::CharybdisError; @@ -27,6 +28,9 @@ async fn model_mutation() { assert_eq!(user, new_user); user.bio = Some("I like beer".to_string()); + user.address.as_mut().expect("homer should have address").addr_type = AddressTypeCustomField::HomeAddress; + let tag = ("Second Key".to_string(), "Second Value".to_string()); + user.user_extra_data.user_tags.push(tag.clone()); user.update().execute(&db_session).await.expect("Failed to update user"); @@ -36,6 +40,11 @@ async fn model_mutation() { .expect("Failed to find user"); assert_eq!(user.bio, Some("I like beer".to_string())); + assert_eq!( + user.address.as_ref().expect("homer should have address").addr_type, + AddressTypeCustomField::HomeAddress + ); + assert_eq!(user.user_extra_data.user_tags.last().cloned(), Some(tag)); user.delete().execute(&db_session).await.expect("Failed to delete user"); }