Expand index trait to also include key type
Signed-off-by: Lee Smet <lee.smet@hotmail.com>
This commit is contained in:
parent
276cf3c8d8
commit
1343e61e0f
@ -77,11 +77,10 @@ fn main() {
|
|||||||
|
|
||||||
// Load all active users using the IsActive field index
|
// Load all active users using the IsActive field index
|
||||||
// TODO: expand Index type so it defines the type of the key
|
// TODO: expand Index type so it defines the type of the key
|
||||||
let key = true.to_string();
|
|
||||||
let active_users = db
|
let active_users = db
|
||||||
.collection::<User>()
|
.collection::<User>()
|
||||||
.expect("can open user collection")
|
.expect("can open user collection")
|
||||||
.get::<IsActive>(&key)
|
.get::<IsActive>(&true)
|
||||||
.expect("can load stored users");
|
.expect("can load stored users");
|
||||||
// We should have 2 active users
|
// We should have 2 active users
|
||||||
assert_eq!(active_users.len(), 2);
|
assert_eq!(active_users.len(), 2);
|
||||||
@ -96,15 +95,14 @@ fn main() {
|
|||||||
let active_users = db
|
let active_users = db
|
||||||
.collection::<User>()
|
.collection::<User>()
|
||||||
.expect("can open user collection")
|
.expect("can open user collection")
|
||||||
.get::<IsActive>(&key)
|
.get::<IsActive>(&true)
|
||||||
.expect("can load stored users");
|
.expect("can load stored users");
|
||||||
assert_eq!(active_users.len(), 1);
|
assert_eq!(active_users.len(), 1);
|
||||||
// And verify we still have 2 inactive users
|
// And verify we still have 2 inactive users
|
||||||
let key = false.to_string();
|
|
||||||
let inactive_users = db
|
let inactive_users = db
|
||||||
.collection::<User>()
|
.collection::<User>()
|
||||||
.expect("can open user collection")
|
.expect("can open user collection")
|
||||||
.get::<IsActive>(&key)
|
.get::<IsActive>(&false)
|
||||||
.expect("can load stored users");
|
.expect("can load stored users");
|
||||||
assert_eq!(inactive_users.len(), 2);
|
assert_eq!(inactive_users.len(), 2);
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ where
|
|||||||
type Error: std::fmt::Debug;
|
type Error: std::fmt::Debug;
|
||||||
|
|
||||||
/// Get all items where the given index field is equal to key.
|
/// Get all items where the given index field is equal to key.
|
||||||
fn get<I>(&self, key: K) -> Result<Vec<V>, Error<Self::Error>>
|
fn get<I>(&self, key: &I::Key) -> Result<Vec<V>, Error<Self::Error>>
|
||||||
where
|
where
|
||||||
I: Index<Model = V>;
|
I: Index<Model = V>;
|
||||||
|
|
||||||
@ -33,7 +33,7 @@ where
|
|||||||
fn set(&self, value: &V) -> Result<(), Error<Self::Error>>;
|
fn set(&self, value: &V) -> Result<(), Error<Self::Error>>;
|
||||||
|
|
||||||
/// Delete all items from the db with a given index.
|
/// Delete all items from the db with a given index.
|
||||||
fn delete<I>(&self, key: K) -> Result<(), Error<Self::Error>>
|
fn delete<I>(&self, key: &I::Key) -> Result<(), Error<Self::Error>>
|
||||||
where
|
where
|
||||||
I: Index<Model = V>;
|
I: Index<Model = V>;
|
||||||
|
|
||||||
@ -66,4 +66,3 @@ impl<E> From<bincode::error::EncodeError> for Error<E> {
|
|||||||
Error::Encode(value)
|
Error::Encode(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,12 +42,12 @@ where
|
|||||||
{
|
{
|
||||||
type Error = tst::Error;
|
type Error = tst::Error;
|
||||||
|
|
||||||
fn get<I>(&self, key: &str) -> Result<Vec<M>, super::Error<Self::Error>>
|
fn get<I>(&self, key: &I::Key) -> Result<Vec<M>, super::Error<Self::Error>>
|
||||||
where
|
where
|
||||||
I: Index<Model = M>,
|
I: Index<Model = M>,
|
||||||
{
|
{
|
||||||
let mut index_db = self.index.lock().expect("can lock index DB");
|
let mut index_db = self.index.lock().expect("can lock index DB");
|
||||||
let index_key = Self::index_key(M::db_prefix(), I::key(), key);
|
let index_key = Self::index_key(M::db_prefix(), I::key(), &key.to_string());
|
||||||
|
|
||||||
let Some(object_ids) = Self::get_tst_value::<HashSet<u32>>(&mut index_db, &index_key)?
|
let Some(object_ids) = Self::get_tst_value::<HashSet<u32>>(&mut index_db, &index_key)?
|
||||||
else {
|
else {
|
||||||
@ -140,12 +140,12 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete<I>(&self, key: &str) -> Result<(), super::Error<Self::Error>>
|
fn delete<I>(&self, key: &I::Key) -> Result<(), super::Error<Self::Error>>
|
||||||
where
|
where
|
||||||
I: Index<Model = M>,
|
I: Index<Model = M>,
|
||||||
{
|
{
|
||||||
let mut index_db = self.index.lock().expect("can lock index db");
|
let mut index_db = self.index.lock().expect("can lock index db");
|
||||||
let key = Self::index_key(M::db_prefix(), I::key(), key);
|
let key = Self::index_key(M::db_prefix(), I::key(), &key.to_string());
|
||||||
let raw_obj_ids = index_db.get(&key)?;
|
let raw_obj_ids = index_db.get(&key)?;
|
||||||
let (obj_ids, _): (HashSet<u32>, _) =
|
let (obj_ids, _): (HashSet<u32>, _) =
|
||||||
bincode::serde::decode_from_slice(&raw_obj_ids, BINCODE_CONFIG)?;
|
bincode::serde::decode_from_slice(&raw_obj_ids, BINCODE_CONFIG)?;
|
||||||
|
@ -6,7 +6,7 @@ use std::fmt::Debug;
|
|||||||
pub struct IndexKey {
|
pub struct IndexKey {
|
||||||
/// The name of the index key
|
/// The name of the index key
|
||||||
pub name: &'static str,
|
pub name: &'static str,
|
||||||
|
|
||||||
/// The value of the index key for a specific model instance
|
/// The value of the index key for a specific model instance
|
||||||
pub value: String,
|
pub value: String,
|
||||||
}
|
}
|
||||||
@ -25,13 +25,13 @@ impl IndexKeyBuilder {
|
|||||||
value: String::new(),
|
value: String::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the value for this index key
|
/// Set the value for this index key
|
||||||
pub fn value(mut self, value: impl ToString) -> Self {
|
pub fn value(mut self, value: impl ToString) -> Self {
|
||||||
self.value = value.to_string();
|
self.value = value.to_string();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build the IndexKey
|
/// Build the IndexKey
|
||||||
pub fn build(self) -> IndexKey {
|
pub fn build(self) -> IndexKey {
|
||||||
IndexKey {
|
IndexKey {
|
||||||
@ -42,10 +42,14 @@ impl IndexKeyBuilder {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Unified trait for all models
|
/// Unified trait for all models
|
||||||
pub trait Model: Debug + Clone + Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static {
|
pub trait Model:
|
||||||
|
Debug + Clone + Serialize + for<'de> Deserialize<'de> + Send + Sync + 'static
|
||||||
|
{
|
||||||
/// Get the database prefix for this model type
|
/// Get the database prefix for this model type
|
||||||
fn db_prefix() -> &'static str where Self: Sized;
|
fn db_prefix() -> &'static str
|
||||||
|
where
|
||||||
|
Self: Sized;
|
||||||
|
|
||||||
/// Returns a list of index keys for this model instance
|
/// Returns a list of index keys for this model instance
|
||||||
/// These keys will be used to create additional indexes in the TST
|
/// These keys will be used to create additional indexes in the TST
|
||||||
/// The default implementation returns an empty vector
|
/// The default implementation returns an empty vector
|
||||||
@ -53,21 +57,27 @@ pub trait Model: Debug + Clone + Serialize + for<'de> Deserialize<'de> + Send +
|
|||||||
fn db_keys(&self) -> Vec<IndexKey> {
|
fn db_keys(&self) -> Vec<IndexKey> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the unique ID for this model
|
/// Get the unique ID for this model
|
||||||
fn get_id(&self) -> u32;
|
fn get_id(&self) -> u32;
|
||||||
|
|
||||||
/// Get a mutable reference to the base_data field
|
/// Get a mutable reference to the base_data field
|
||||||
fn base_data_mut(&mut self) -> &mut BaseModelData;
|
fn base_data_mut(&mut self) -> &mut BaseModelData;
|
||||||
|
|
||||||
/// Set the ID for this model
|
/// Set the ID for this model
|
||||||
fn id(mut self, id: u32) -> Self where Self: Sized {
|
fn id(mut self, id: u32) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
self.base_data_mut().id = id;
|
self.base_data_mut().id = id;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build the model, updating the modified timestamp
|
/// Build the model, updating the modified timestamp
|
||||||
fn build(mut self) -> Self where Self: Sized {
|
fn build(mut self) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
self.base_data_mut().update_modified();
|
self.base_data_mut().update_modified();
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
@ -78,6 +88,8 @@ pub trait Index {
|
|||||||
/// The model for which this is an index in the database
|
/// The model for which this is an index in the database
|
||||||
type Model: Model;
|
type Model: Model;
|
||||||
|
|
||||||
|
type Key: ToString + ?Sized;
|
||||||
|
|
||||||
/// The key of this index
|
/// The key of this index
|
||||||
fn key() -> &'static str;
|
fn key() -> &'static str;
|
||||||
}
|
}
|
||||||
@ -87,13 +99,13 @@ pub trait Index {
|
|||||||
pub struct BaseModelData {
|
pub struct BaseModelData {
|
||||||
/// Unique incremental ID per circle
|
/// Unique incremental ID per circle
|
||||||
pub id: u32,
|
pub id: u32,
|
||||||
|
|
||||||
/// Unix epoch timestamp for creation time
|
/// Unix epoch timestamp for creation time
|
||||||
pub created_at: i64,
|
pub created_at: i64,
|
||||||
|
|
||||||
/// Unix epoch timestamp for last modification time
|
/// Unix epoch timestamp for last modification time
|
||||||
pub modified_at: i64,
|
pub modified_at: i64,
|
||||||
|
|
||||||
/// List of comment IDs referencing Comment objects
|
/// List of comment IDs referencing Comment objects
|
||||||
pub comments: Vec<u32>,
|
pub comments: Vec<u32>,
|
||||||
}
|
}
|
||||||
@ -109,24 +121,24 @@ impl BaseModelData {
|
|||||||
comments: Vec::new(),
|
comments: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new BaseModelDataBuilder
|
/// Create a new BaseModelDataBuilder
|
||||||
pub fn builder(id: u32) -> BaseModelDataBuilder {
|
pub fn builder(id: u32) -> BaseModelDataBuilder {
|
||||||
BaseModelDataBuilder::new(id)
|
BaseModelDataBuilder::new(id)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a comment to this model
|
/// Add a comment to this model
|
||||||
pub fn add_comment(&mut self, comment_id: u32) {
|
pub fn add_comment(&mut self, comment_id: u32) {
|
||||||
self.comments.push(comment_id);
|
self.comments.push(comment_id);
|
||||||
self.modified_at = chrono::Utc::now().timestamp();
|
self.modified_at = chrono::Utc::now().timestamp();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Remove a comment from this model
|
/// Remove a comment from this model
|
||||||
pub fn remove_comment(&mut self, comment_id: u32) {
|
pub fn remove_comment(&mut self, comment_id: u32) {
|
||||||
self.comments.retain(|&id| id != comment_id);
|
self.comments.retain(|&id| id != comment_id);
|
||||||
self.update_modified();
|
self.update_modified();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Update the modified timestamp
|
/// Update the modified timestamp
|
||||||
pub fn update_modified(&mut self) {
|
pub fn update_modified(&mut self) {
|
||||||
self.modified_at = chrono::Utc::now().timestamp();
|
self.modified_at = chrono::Utc::now().timestamp();
|
||||||
@ -151,31 +163,31 @@ impl BaseModelDataBuilder {
|
|||||||
comments: Vec::new(),
|
comments: Vec::new(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the created_at timestamp
|
/// Set the created_at timestamp
|
||||||
pub fn created_at(mut self, timestamp: i64) -> Self {
|
pub fn created_at(mut self, timestamp: i64) -> Self {
|
||||||
self.created_at = Some(timestamp);
|
self.created_at = Some(timestamp);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the modified_at timestamp
|
/// Set the modified_at timestamp
|
||||||
pub fn modified_at(mut self, timestamp: i64) -> Self {
|
pub fn modified_at(mut self, timestamp: i64) -> Self {
|
||||||
self.modified_at = Some(timestamp);
|
self.modified_at = Some(timestamp);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a comment ID
|
/// Add a comment ID
|
||||||
pub fn add_comment(mut self, comment_id: u32) -> Self {
|
pub fn add_comment(mut self, comment_id: u32) -> Self {
|
||||||
self.comments.push(comment_id);
|
self.comments.push(comment_id);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add multiple comment IDs
|
/// Add multiple comment IDs
|
||||||
pub fn add_comments(mut self, comment_ids: Vec<u32>) -> Self {
|
pub fn add_comments(mut self, comment_ids: Vec<u32>) -> Self {
|
||||||
self.comments.extend(comment_ids);
|
self.comments.extend(comment_ids);
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Build the BaseModelData
|
/// Build the BaseModelData
|
||||||
pub fn build(self) -> BaseModelData {
|
pub fn build(self) -> BaseModelData {
|
||||||
let now = chrono::Utc::now().timestamp();
|
let now = chrono::Utc::now().timestamp();
|
||||||
@ -197,14 +209,15 @@ macro_rules! impl_model {
|
|||||||
fn db_prefix() -> &'static str {
|
fn db_prefix() -> &'static str {
|
||||||
$prefix
|
$prefix
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_id(&self) -> u32 {
|
fn get_id(&self) -> u32 {
|
||||||
self.base_data.id
|
self.base_data.id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn base_data_mut(&mut self) -> &mut $crate::core::model::BaseModelData {
|
fn base_data_mut(&mut self) -> &mut $crate::core::model::BaseModelData {
|
||||||
&mut self.base_data
|
&mut self.base_data
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,21 +1,21 @@
|
|||||||
|
use crate::models::core::model::{BaseModelData, Index, IndexKey, Model};
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use crate::models::core::model::{Model, BaseModelData, IndexKey, Index};
|
|
||||||
|
|
||||||
/// Represents a user in the system
|
/// Represents a user in the system
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
/// Base model data
|
/// Base model data
|
||||||
pub base_data: BaseModelData,
|
pub base_data: BaseModelData,
|
||||||
|
|
||||||
/// User's username
|
/// User's username
|
||||||
pub username: String,
|
pub username: String,
|
||||||
|
|
||||||
/// User's email address
|
/// User's email address
|
||||||
pub email: String,
|
pub email: String,
|
||||||
|
|
||||||
/// User's full name
|
/// User's full name
|
||||||
pub full_name: String,
|
pub full_name: String,
|
||||||
|
|
||||||
/// Whether the user is active
|
/// Whether the user is active
|
||||||
pub is_active: bool,
|
pub is_active: bool,
|
||||||
}
|
}
|
||||||
@ -31,35 +31,35 @@ impl User {
|
|||||||
is_active: true,
|
is_active: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the username
|
/// Set the username
|
||||||
pub fn username(mut self, username: impl ToString) -> Self {
|
pub fn username(mut self, username: impl ToString) -> Self {
|
||||||
self.username = username.to_string();
|
self.username = username.to_string();
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the email
|
/// Set the email
|
||||||
pub fn email(mut self, email: impl ToString) -> Self {
|
pub fn email(mut self, email: impl ToString) -> Self {
|
||||||
self.email = email.to_string();
|
self.email = email.to_string();
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the full name
|
/// Set the full name
|
||||||
pub fn full_name(mut self, full_name: impl ToString) -> Self {
|
pub fn full_name(mut self, full_name: impl ToString) -> Self {
|
||||||
self.full_name = full_name.to_string();
|
self.full_name = full_name.to_string();
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set whether the user is active
|
/// Set whether the user is active
|
||||||
pub fn is_active(mut self, is_active: bool) -> Self {
|
pub fn is_active(mut self, is_active: bool) -> Self {
|
||||||
self.is_active = is_active;
|
self.is_active = is_active;
|
||||||
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add a comment ID
|
/// Add a comment ID
|
||||||
pub fn add_comment(mut self, comment_id: u32) -> Self {
|
pub fn add_comment(mut self, comment_id: u32) -> Self {
|
||||||
self.base_data.add_comment(comment_id);
|
self.base_data.add_comment(comment_id);
|
||||||
@ -70,7 +70,7 @@ impl User {
|
|||||||
pub fn deactivate(&mut self) {
|
pub fn deactivate(&mut self) {
|
||||||
self.is_active = false;
|
self.is_active = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Activate the user
|
/// Activate the user
|
||||||
pub fn activate(&mut self) {
|
pub fn activate(&mut self) {
|
||||||
self.is_active = true;
|
self.is_active = true;
|
||||||
@ -82,16 +82,16 @@ impl Model for User {
|
|||||||
fn db_prefix() -> &'static str {
|
fn db_prefix() -> &'static str {
|
||||||
"user"
|
"user"
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_id(&self) -> u32 {
|
fn get_id(&self) -> u32 {
|
||||||
self.base_data.id
|
self.base_data.id
|
||||||
}
|
}
|
||||||
|
|
||||||
//WHY?
|
//WHY?
|
||||||
fn base_data_mut(&mut self) -> &mut BaseModelData {
|
fn base_data_mut(&mut self) -> &mut BaseModelData {
|
||||||
&mut self.base_data
|
&mut self.base_data
|
||||||
}
|
}
|
||||||
|
|
||||||
fn db_keys(&self) -> Vec<IndexKey> {
|
fn db_keys(&self) -> Vec<IndexKey> {
|
||||||
vec![
|
vec![
|
||||||
IndexKey {
|
IndexKey {
|
||||||
@ -119,6 +119,8 @@ pub struct IsActive;
|
|||||||
impl Index for UserName {
|
impl Index for UserName {
|
||||||
type Model = User;
|
type Model = User;
|
||||||
|
|
||||||
|
type Key = str;
|
||||||
|
|
||||||
fn key() -> &'static str {
|
fn key() -> &'static str {
|
||||||
"username"
|
"username"
|
||||||
}
|
}
|
||||||
@ -127,6 +129,8 @@ impl Index for UserName {
|
|||||||
impl Index for Email {
|
impl Index for Email {
|
||||||
type Model = User;
|
type Model = User;
|
||||||
|
|
||||||
|
type Key = str;
|
||||||
|
|
||||||
fn key() -> &'static str {
|
fn key() -> &'static str {
|
||||||
"email"
|
"email"
|
||||||
}
|
}
|
||||||
@ -135,7 +139,10 @@ impl Index for Email {
|
|||||||
impl Index for IsActive {
|
impl Index for IsActive {
|
||||||
type Model = User;
|
type Model = User;
|
||||||
|
|
||||||
|
type Key = bool;
|
||||||
|
|
||||||
fn key() -> &'static str {
|
fn key() -> &'static str {
|
||||||
"is_active"
|
"is_active"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user