Rust ORM for ScyllaDB and Apache Cassandra
MIT License
Bot releases are hidden (Show)
project_root
option in MigrationBuilder
by @Michal-pythonSerializeCql
is now SerializeValue
execute
fn is replace with appropriate execute_unpaged
, execute_iter
, or execute_single_page
find_paged
no longer takes Option<Bytes>
but PagingState
from driver itselfFull Changelog: https://github.com/nodecosmos/charybdis/compare/v0.7.5...v0.7.7
Published by GoranBrkuljan about 2 months ago
feat: Expose the charybdis-migrate package for programmatic control over migrations by @Michal-python in #47
use migrate::MigrationBuilder;
let migration = MigrationBuilder::new()
.keyspace("test")
.drop_and_replace(true)
.build(&session)
.await;
migration.run().await;
refactor: code formatting cleanup #47
update: DRY-up migration builder #48
Full Changelog: https://github.com/nodecosmos/charybdis/compare/v0.7.3...v0.7.5
Published by GoranBrkuljan 3 months ago
migrate --keyspace nodecosmos --host 127.0.1:9042 --ca ca.crt --cert client.crt --key client.key
Published by GoranBrkuljan 4 months ago
update: use owned value instead of ref for find_by_pk
functions #39
now if we have model:
#[charybdis_model(
table_name = posts,
partition_keys = [category_id],
clustering_keys = [id],
)]
pub struct Post {
pub category_id: Uuid,
pub id: Uuid,
pub content: Text,
}
Instead of:
Post::find_by_partition_key_value(&(category_id,)).execute(db_session).await?;
Post::find_by_primary_key_value(&(category_id, id)).execute(db_session).await?;
we do:
Post::find_by_partition_key_value((category_id,)).execute(db_session).await?;
Post::find_by_primary_key_value((category_id, id)).execute(db_session).await?;
feat: add find_by_partition_key_value_paged
let (post_res, paging_state) = Post::find_by_partition_key_value_paged((category_id,))
.page_size(10)
.paging_state(None)
.execute(db_session)
.await?;
let posts: Result<Vec<Post>, CharybdisError> = post_res.collect();
Published by GoranBrkuljan 5 months ago
Now for collection fields we get additional push/pull if exists constants and methods
#[charybdis_model(
table_name = users,
partition_keys = [id],
clustering_keys = []
)]
pub struct User {
id: Uuid,
tags: Set<Text>,
}
// constants
impl User {
const PUSH_TAGS_IF_EXISTS_QUERY: &'static str = "UPDATE users SET tags = tags + ? WHERE id = ? IF EXISTS";
const PULL_POST_IDS_IF_EXISTS_QUERY: &'static str = "UPDATE users SET post_ids = post_ids - ? WHERE id = ? IF EXISTS";
}
// methods
let user = User::new();
user.push_tags_if_exists(tags: HashSet<T>).execute(&session).await;
user.pull_tags_if_exists(tags: HashSet<T>).execute(&session).await;
Published by GoranBrkuljan 5 months ago
Published by GoranBrkuljan 6 months ago
fix: Batch::chunked_statements
- correctly append raw statements to the batch
Published by GoranBrkuljan 6 months ago
fix: field order requirement - now struct fields don't have to be in the same order as they are in macro arguments
Published by GoranBrkuljan 6 months ago
Published by GoranBrkuljan 6 months ago
charybdis-migrate
: use --verbose
flag to print alter table option statements.charybdis-migrate
: parse all files on migration and generate diff between model definition and databaseIn the previous versions, migration files were parsed specifically from the src/models
directories, and it was necessary to have only one model per file to ensure correct migration processing. However, the updated migration tool has enhanced capabilities. It can now analyze and parse multiple models from a single file, and they can be located in any directory in the project root.
Published by GoranBrkuljan 6 months ago
fix #22 : generate functions based on order defined in macro args
perf: use field refs instead of clones for macro parser
fix #24: composite partition key materialized view migrations https://github.com/nodecosmos/charybdis/pull/23
fix: query charybdis batch:
let node = Node {
id: node_id,
..Default::default()
};
let delete_likes = Like {
object_id: node_id,
..Default::default()
};
let mut batch = CharybdisBatch::new();
batch
.append(node.delete())
.append(delete_likes.delete_by_partition_key())
.execute(db_session)
.await?;
Published by GoranBrkuljan 6 months ago
feat#types: add support for Duration https://github.com/nodecosmos/charybdis/pull/21
fix#types: use correct type for Time https://github.com/nodecosmos/charybdis/pull/21
fix#types: use BigDecimal for Decimal
fix#migration: schema_json generation
fix#finds: require complete partition keys for automatically generated functions a7aa2123e294f489e273fe39dcfe451262b85389
feat#find: add find by global secondary indexes functions https://github.com/nodecosmos/charybdis/pull/21
#[charybdis_model(
table_name = posts,
partition_keys = [...],
clustering_keys = [...],
global_secondary_indexes = [category_id]
)]
pub struct Post {...}
let posts: CharybdisModelStream<Post> = Post::find_by_category_id(category_id).execute(db_session).await?;
let post: Post = Post::find_first_by_category_id(category_id).execute(db_session).await?;
let post: Option<Post> = Post::maybe_find_first_by_category_id(category_id).execute(db_session).await?;
Published by GoranBrkuljan 6 months ago
#[charybdis_model(
table_name = user_messages,
partition_keys = [user_id],
clustering_keys = [],
static_columns = [username, email]
)]
pub struct UserMessage {
pub user_id: Uuid,
pub content: Text,
pub username: Text,
pub email: Text,
}
Published by GoranBrkuljan 6 months ago
0.4.13
UDT fields must be in the same order as they are in the database. This is due to scylla driver limitation that does not support named bind values. Earlier versions would automatically order fields by name (in app and on migration), but this is no longer the case as ORM could not work with exiting UDTs.Published by GoranBrkuljan 6 months ago
fix: prevent frozen types from having push/pull methods/constants in https://github.com/nodecosmos/charybdis/pull/15
feature: add push/pull map fields features
#[charybdis_model(
table_name = users,
partition_keys = [id],
clustering_keys = []
)]
pub struct User {
id: Uuid,
tags: Set<Text>,
post_ids: List<Uuid>,
books_by_genre: Map<Text, Frozen<List<Text>>>,
}
Now we get additional queries:
impl User {
const PUSH_BOOKS_BY_GENRE_QUERY: &'static str = "UPDATE users SET books_by_genre = books_by_genre + ? WHERE id = ?";
const PULL_BOOKS_BY_GENRE_QUERY: &'static str = "UPDATE users SET books_by_genre = books_by_genre - ? WHERE id = ?";
}
And methods:
user.push_books_by_genre(map: HashMap<K, V>).execute(&session).await;
user.pull_books_by_genre(map: HashMap<K, V>).execute(&session).await;
Published by GoranBrkuljan 7 months ago
Clone
is not added by default to UDTs anymore
Introduce custom delete macro 908df58e8b88fca1f42d807b91cde8265fd69d97. Now if we have:
#[charybdis_model(
table_name = posts,
partition_keys = [category_id],
clustering_keys = [date, title],
global_secondary_indexes = []
)]
pub struct Post {..}
we can build & execute custom delete query:
delete_post!("date = ? AND category_id in ?", (date, category_vec)).execute(&session).await?
Batch append statement functions are not async
anymore and we can use method chaining to execute it:
let batch = User::batch()
.consistency(Consistency::One)
.retry_policy(Some(Arc::new(DefaultRetryPolicy::new())))
.append_update(&user_1)
.append_update(&user_2)
.execute(data.db_session())
.await?;
or
let batch = User::batch()
.consistency(Consistency::One)
.retry_policy(Some(Arc::new(DefaultRetryPolicy::new())))
.chunked_inserts(&session, users, 100)
.await?;
Published by GoranBrkuljan 7 months ago
insert_if_not_exist
to model batch https://github.com/nodecosmos/charybdis/pull/12
Published by GoranBrkuljan 7 months ago
Introduce find
, find_first
& maybe_find_first
native functions for local_secondary_indexes, so now we have all of the following:
use scylla::CachingSession;
use charybdis::errors::CharybdisError;
use charybdis::macros::charybdis_model;
use charybdis::stream::CharybdisModelStream;
use charybdis::types::{Date, Text, Uuid};
#[charybdis_model(
table_name = posts,
partition_keys = [date],
clustering_keys = [category_id, title],
local_secondary_indexes = [title]
)]
pub struct Post {
pub date: Date,
pub category_id: Uuid,
pub title: Text,
}
impl Post {
async fn find_various(db_session: &CachingSession) -> Result<(), CharybdisError> {
let date = Date::default();
let category_id = Uuid::new_v4();
let title = Text::default();
let posts: CharybdisModelStream<Post> = Post::find_by_date(date).execute(db_session).await?;
let posts: CharybdisModelStream<Post> = Post::find_by_date_and_category_id(date, category_id).execute(db_session).await?;
let posts: Post = Post::find_by_date_and_category_id_and_title(date, category_id, title.clone()).execute(db_session).await?;
let post: Post = Post::find_first_by_date(date).execute(db_session).await?;
let post: Post = Post::find_first_by_date_and_category_id(date, category_id).execute(db_session).await?;
let post: Option<Post> = Post::maybe_find_first_by_date(date).execute(db_session).await?;
let post: Option<Post> = Post::maybe_find_first_by_date_and_category_id(date, category_id).execute(db_session).await?;
let post: Option<Post> = Post::maybe_find_first_by_date_and_category_id_and_title(date, category_id, title.clone()).execute(db_session).await?;
// find by local secondary index
let posts: CharybdisModelStream<Post> = Post::find_by_date_and_title(date, title.clone()).execute(db_session).await?;
let post: Post = Post::find_first_by_date_and_title(date, title.clone()).execute(db_session).await?;
let post: Option<Post> = Post::maybe_find_first_by_date_and_title(date, title.clone()).execute(db_session).await?;
Ok(())
}
}
Refactor charybdis-macros to utilize traits
Published by GoranBrkuljan 7 months ago
find_first
& maybe_find_first
native functions for up to 3 primary keys https://github.com/nodecosmos/charybdis/pull/10
#[charybdis_model(
table_name = posts,
partition_keys = [date],
clustering_keys = [categogry_id, title],
global_secondary_indexes = []
)]
pub struct Post {...}
// Now we have
post.find_first_by_date(date).execute(db_session).await -> Result<Post, CharybdisError>
post.maybe_find_first_by_date(date).execute(db_session).await -> Result<Option<Post>, CharybdisError>
post.find_first_by_date_and_category_id(date, category_id).execute(db_session).await -> Result<Post, CharybdisError>
post.maybe_find_first_by_date_and_category_id(date, category_id).execute(db_session).await -> Result<Option<Post>, CharybdisError>
post.find_first_by_date_and_category_id_and_title(date, category_id, title).execute(db_session) -> Result<Post, CharybdisError>
post.maybe_find_first_by_date_and_category_id_and_title(date, category_id, title).execute(db_session) -> Result<Option<Post>, CharybdisError>