From efedc5eebae100ee44eaf55d926e255486bf36e3 Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Mon, 27 Jan 2025 21:41:53 +0300 Subject: [PATCH 01/16] WIP index update --- .../src/worktable/generator/queries/update.rs | 38 ++++++++++++++++++- examples/src/main.rs | 28 +++++++++----- 2 files changed, 56 insertions(+), 10 deletions(-) diff --git a/codegen/src/worktable/generator/queries/update.rs b/codegen/src/worktable/generator/queries/update.rs index 4c15a78c..9398601e 100644 --- a/codegen/src/worktable/generator/queries/update.rs +++ b/codegen/src/worktable/generator/queries/update.rs @@ -95,6 +95,17 @@ impl Generator { .values() .find(|idx| idx.field.to_string() == op.by.to_string()); + let index_columns = self + .columns + .indexes + .values() + .filter(|idx| !idx.is_unique) + .find(|idx| { + op.columns + .iter() + .any(|col| col.to_string() == idx.field.to_string()) + }); + let idents = &op.columns; if let Some(index) = index { let index_name = &index.name; @@ -109,7 +120,11 @@ impl Generator { if self.columns.primary_keys.0.first().unwrap().to_string() == op.by.to_string() { - self.gen_pk_update(snake_case_name, name, idents) + if let Some(index) = index_columns { + self.gen_pk_update(snake_case_name, name, idents, Some(&index.name)) + } else { + self.gen_pk_update(snake_case_name, name, idents, None) + } } else { todo!() } @@ -130,6 +145,7 @@ impl Generator { snake_case_name: String, name: &Ident, idents: &Vec, + index_name: Option<&Ident>, ) -> TokenStream { let pk_ident = &self.pk.as_ref().unwrap().ident; let method_ident = Ident::new( @@ -164,6 +180,25 @@ impl Generator { }) .collect::>(); + let new_index_value = if let Some(index_name) = index_name { + idents + .iter() + .map(|i| { + quote! { + let _ = TableIndex::remove(&self.0.indexes.#index_name, &row.#i.to_string()); + if let Some(set) = TableIndex::peek(&self.0.indexes.#index_name, &row.#i.to_string()) { + set.insert(link).expect("`Link` should not be already in set"); + } else { + let set = LockFreeSet::new(); + set.insert(link).expect("`Link` should not be already in set"); + TableIndex::insert(&self.0.indexes.#index_name, row.#i.to_string(), std::sync::Arc::new(set)); + } + } + }).collect::>() + } else { + Vec::new() + }; + quote! { pub async fn #method_ident(&self, row: #query_ident, by: #pk_ident) -> core::result::Result<(), WorkTableError> { let op_id = self.0.lock_map.next_id(); @@ -177,6 +212,7 @@ impl Generator { let guard = Guard::new(); TableIndex::peek(&self.0.pk_map, &by).ok_or(WorkTableError::NotFound)? }; + #(#new_index_value)* let id = self.0.data.with_ref(link, |archived| { archived.#check_ident() }).map_err(WorkTableError::PagesError)?; diff --git a/examples/src/main.rs b/examples/src/main.rs index 97d46068..511f3275 100644 --- a/examples/src/main.rs +++ b/examples/src/main.rs @@ -20,6 +20,7 @@ fn main() { queries: { update: { ValByAttr(val) by attribute, + AttrById(attribute) by id, }, delete: { ByAttr() by attribute, @@ -74,14 +75,23 @@ fn main() { ); // Update all recrods val by attr TEST2 - let update_val = my_table.update_val_by_attr(ValByAttrQuery { val: 777 }, "TEST2".to_string()); - let _ = task::block_on(update_val); - - let select_updated = my_table.select_by_attribute("TEST2".to_string()); - println!( - "Select updated by Attribute TEST2: {:?}", - select_updated.unwrap().vals + //let update_val = my_table.update_val_by_attr(ValByAttrQuery { val: 777 }, "TEST2".to_string()); + //let _ = task::block_on(update_val); + // + //let select_updated = my_table.select_by_attribute("TEST2".to_string()); + //println!( + // "Select updated by Attribute TEST2: {:?}", + // select_updated.unwrap().vals + //); + + // Update attr by ID + let update_attr = my_table.update_attr_by_id( + AttrByIdQuery { + attribute: "TEST2".to_string(), + }, + MyPrimaryKey(3), ); + let _ = task::block_on(update_attr); // Update record attribute TEST2 -> TEST3 with id 1 let update_exchange = @@ -94,11 +104,11 @@ fn main() { select_all_after_update.execute() ); - let test_delete = my_table.delete_by_attr("TEST3".to_string()); + let test_delete = my_table.delete_by_attr("TEST2".to_string()); let _ = task::block_on(test_delete); println!( - "Select after deleted TEST3 {:?}", + "Select after deleted TEST2 {:?}", my_table.select_all().execute() ); } From 164b379623341bd682ec328733f8f08c49380605 Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Tue, 28 Jan 2025 14:42:25 +0300 Subject: [PATCH 02/16] WIP Index update --- .../src/worktable/generator/queries/update.rs | 50 ++++++++++-- examples/src/main.rs | 78 +++++++++++++------ 2 files changed, 97 insertions(+), 31 deletions(-) diff --git a/codegen/src/worktable/generator/queries/update.rs b/codegen/src/worktable/generator/queries/update.rs index 9398601e..25c4d48c 100644 --- a/codegen/src/worktable/generator/queries/update.rs +++ b/codegen/src/worktable/generator/queries/update.rs @@ -95,6 +95,8 @@ impl Generator { .values() .find(|idx| idx.field.to_string() == op.by.to_string()); + + let index_columns = self .columns .indexes @@ -107,6 +109,11 @@ impl Generator { }); let idents = &op.columns; + + let column_type = idents.iter().find_map(|ident| { + self.columns.columns_map + .get(ident) + }); if let Some(index) = index { let index_name = &index.name; @@ -121,9 +128,11 @@ impl Generator { == op.by.to_string() { if let Some(index) = index_columns { - self.gen_pk_update(snake_case_name, name, idents, Some(&index.name)) + self.gen_pk_update(snake_case_name, name, idents, Some(&index.name), column_type.unwrap(), + ) } else { - self.gen_pk_update(snake_case_name, name, idents, None) + self.gen_pk_update(snake_case_name, name, idents, None, column_type.unwrap(), + ) } } else { todo!() @@ -140,12 +149,14 @@ impl Generator { } } + fn gen_pk_update( &self, snake_case_name: String, name: &Ident, idents: &Vec, index_name: Option<&Ident>, + column_type: &TokenStream, ) -> TokenStream { let pk_ident = &self.pk.as_ref().unwrap().ident; let method_ident = Ident::new( @@ -171,11 +182,24 @@ impl Generator { format!("verify_{snake_case_name}_lock").as_str(), Span::mixed_site(), ); + + let postfix = if column_type.to_string() == "String" { + quote! { to_string() } + } else { + quote! { into() } + }; + let row_updates = idents .iter() .map(|i| { quote! { + + if let Some(set) = TableIndex::peek(&self.0.indexes.#index_name, &archived.inner.#i.#postfix) { + set.remove(&link); + } std::mem::swap(&mut archived.inner.#i, &mut row.#i); + + } }) .collect::>(); @@ -185,34 +209,42 @@ impl Generator { .iter() .map(|i| { quote! { - let _ = TableIndex::remove(&self.0.indexes.#index_name, &row.#i.to_string()); - if let Some(set) = TableIndex::peek(&self.0.indexes.#index_name, &row.#i.to_string()) { + + + if let Some(set) = TableIndex::peek(&self.0.indexes.#index_name, &row.#i.#postfix) { set.insert(link).expect("`Link` should not be already in set"); } else { let set = LockFreeSet::new(); set.insert(link).expect("`Link` should not be already in set"); - TableIndex::insert(&self.0.indexes.#index_name, row.#i.to_string(), std::sync::Arc::new(set)); + TableIndex::insert(&self.0.indexes.#index_name, row.#i.#postfix, std::sync::Arc::new(set)); } + + } }).collect::>() } else { Vec::new() }; - quote! { + let t = quote! { pub async fn #method_ident(&self, row: #query_ident, by: #pk_ident) -> core::result::Result<(), WorkTableError> { + println!("{:?}", row); let op_id = self.0.lock_map.next_id(); let lock = std::sync::Arc::new(Lock::new()); self.0.lock_map.insert(op_id.into(), lock.clone()); + let mut bytes = rkyv::to_bytes::(&row).map_err(|_| WorkTableError::SerializeError)?; let mut row = unsafe { rkyv::access_unchecked_mut::<<#query_ident as rkyv::Archive>::Archived>(&mut bytes[..]).unseal_unchecked() }; + let link = { let guard = Guard::new(); TableIndex::peek(&self.0.pk_map, &by).ok_or(WorkTableError::NotFound)? }; - #(#new_index_value)* + + #(#new_index_value)* + let id = self.0.data.with_ref(link, |archived| { archived.#check_ident() }).map_err(WorkTableError::PagesError)?; @@ -243,7 +275,9 @@ impl Generator { core::result::Result::Ok(()) } - } + }; + println!("{}", t.to_string()); + t } fn gen_non_unique_update( diff --git a/examples/src/main.rs b/examples/src/main.rs index 511f3275..43cc4f87 100644 --- a/examples/src/main.rs +++ b/examples/src/main.rs @@ -1,5 +1,3 @@ -use std::fmt::Debug; - use async_std::task; use worktable::prelude::*; use worktable::worktable; @@ -11,19 +9,22 @@ fn main() { columns: { id: u64 primary_key autoincrement, val: i64, - attribute: String, + attr: String, + attr2: i16, }, indexes: { - attribute_idx: attribute, - } + attr_idx: attr, + attr2_idx: attr2, + }, queries: { update: { - ValByAttr(val) by attribute, - AttrById(attribute) by id, + ValByAttr(val) by attr, + AttrById(attr) by id, + Attr2ById(attr2) by id, }, delete: { - ByAttr() by attribute, + ByAttr() by attr, ById() by id, } } @@ -35,25 +36,29 @@ fn main() { // WT rows (has prefix My because of table name) let row = MyRow { val: 1, - attribute: "TEST".to_string(), + attr: "TEST".to_string(), + attr2: 65, id: 0, }; let row1 = MyRow { val: 2, - attribute: "TEST2".to_string(), + attr: "TEST2".to_string(), + attr2: 65, id: 1, }; let row2 = MyRow { val: 1337, - attribute: "TEST2".to_string(), + attr: "TEST2".to_string(), + attr2: 65, id: 2, }; let row3 = MyRow { val: 555, - attribute: "TEST3".to_string(), + attr: "TEST3".to_string(), + attr2: 65, id: 3, }; @@ -68,31 +73,41 @@ fn main() { println!("Select All {:?}", select_all); // Select All records with attribute TEST2 - let select_by_attr = my_table.select_by_attribute("TEST2".to_string()); + let select_by_attr = my_table.select_by_attr("TEST2".to_string()); println!( "Select by Attribute TEST2: {:?}", select_by_attr.unwrap().vals ); // Update all recrods val by attr TEST2 - //let update_val = my_table.update_val_by_attr(ValByAttrQuery { val: 777 }, "TEST2".to_string()); - //let _ = task::block_on(update_val); - // - //let select_updated = my_table.select_by_attribute("TEST2".to_string()); - //println!( - // "Select updated by Attribute TEST2: {:?}", - // select_updated.unwrap().vals - //); + let update_val = my_table.update_val_by_attr(ValByAttrQuery { val: 777 }, "TEST2".to_string()); + let _ = task::block_on(update_val); + + let select_updated = my_table.select_by_attr("TEST2".to_string()); + println!( + "Select updated by Attribute TEST2: {:?}", + select_updated.unwrap().vals + ); // Update attr by ID + println!("update attr TEST3 -> TEST2"); let update_attr = my_table.update_attr_by_id( AttrByIdQuery { - attribute: "TEST2".to_string(), + attr: "TEST2".to_string(), }, MyPrimaryKey(3), ); let _ = task::block_on(update_attr); + println!("FINISH update attr TEST3 -> TEST2"); + + // Update attr2 by ID + println!("update attr2 67 -> 1337"); + let update_attr = my_table.update_attr_2_by_id(Attr2ByIdQuery { attr2: 1337 }, MyPrimaryKey(3)); + let _ = task::block_on(update_attr); + + println!("FINISH update attr2"); + // Update record attribute TEST2 -> TEST3 with id 1 let update_exchange = my_table.update_val_by_attr(ValByAttrQuery { val: 7777 }, "TEST2".to_string()); @@ -103,9 +118,26 @@ fn main() { "Select After Val Update by Attribute: {:?}", select_all_after_update.execute() ); - let test_delete = my_table.delete_by_attr("TEST2".to_string()); let _ = task::block_on(test_delete); + // + let select_by_attr = my_table.select_by_attr("TEST2".to_string()); + println!( + "Select by Attribute TEST2 after del: {:?}", + select_by_attr.unwrap().vals + ); + // + let select_by_attr = my_table.select_by_attr("TEST3".to_string()); + println!( + "Select by Attribute TEST3 after del: {:?}", + select_by_attr.unwrap().vals + ); + + let select_by_attr = my_table.select_by_attr2(65); + println!( + "Select by Attribute 65 after del: {:?}", + select_by_attr.unwrap().vals + ); println!( "Select after deleted TEST2 {:?}", From e54f3be87226f3f88a9957137205f84e062b08ad Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Fri, 31 Jan 2025 20:55:37 +0300 Subject: [PATCH 03/16] WIP --- codegen/src/worktable/generator/index.rs | 40 ++++++++++++++++- .../src/worktable/generator/queries/type.rs | 44 +++++++++++++++++++ .../src/worktable/generator/queries/update.rs | 18 ++++++-- codegen/src/worktable/mod.rs | 2 + codegen/src/worktable/model/column.rs | 13 ++++++ examples/src/main.rs | 15 +++++-- src/index/table_secondary_index.rs | 30 +++++++++++++ 7 files changed, 153 insertions(+), 9 deletions(-) diff --git a/codegen/src/worktable/generator/index.rs b/codegen/src/worktable/generator/index.rs index ee002d97..85b37f1d 100644 --- a/codegen/src/worktable/generator/index.rs +++ b/codegen/src/worktable/generator/index.rs @@ -56,13 +56,18 @@ impl Generator { let save_row_fn = self.gen_save_row_index_fn(); let delete_row_fn = self.gen_delete_row_index_fn(); + let process_differences_row_fn = self.gen_process_difference_index_fn(); - quote! { + let t = quote! { impl TableSecondaryIndex<#row_type_ident> for #index_type_ident { #save_row_fn #delete_row_fn + #process_differences_row_fn } - } + }; + println!("{}", t); + + t } /// Generates `save_row` function of `TableIndex` trait for index. It saves `Link` to all secondary indexes. Logic @@ -140,6 +145,37 @@ impl Generator { } } } + + fn gen_process_difference_index_fn(&self) -> TokenStream { + let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string()); + let row_type_ident = name_generator.get_row_type_ident(); + + let process_difference_rows = self + .columns + .indexes + .iter() + .map(|(_i, idx)| { + let _index_field_name = &idx.name; + //let difference_type_ident = + if idx.is_unique { + quote! { + todo()!; + } + } else { + quote! { + todo()!; + } + } + }) + .collect::>(); + + quote! { + fn process_difference(&self, row: #row_type_ident, link: Link, difference: HashMap<#row_type_ident, Difference >) -> core::result::Result<(), WorkTableError> { + #(#process_difference_rows)* + core::result::Result::Ok(()) + } + } + } } // TODO: tests... diff --git a/codegen/src/worktable/generator/queries/type.rs b/codegen/src/worktable/generator/queries/type.rs index 5505f982..88deb2b1 100644 --- a/codegen/src/worktable/generator/queries/type.rs +++ b/codegen/src/worktable/generator/queries/type.rs @@ -4,6 +4,49 @@ use quote::quote; use crate::worktable::generator::Generator; impl Generator { + pub fn gen_available_types_def(&mut self) -> syn::Result { + let rows: Vec<_> = self + .columns + .indexes + .iter() + .map(|(_i, idx)| self.columns.columns_map.get(&idx.field)) + .into_iter() + .map(|t| { + let type_upper = Ident::new( + &t.expect("REASON").to_string().to_uppercase(), + Span::mixed_site(), + ); + + Ok::<_, syn::Error>(quote! { + + #type_upper(#t), + }) + }) + .collect::, _>>()?; + + let type_ident = Ident::new(format!("AvailableTypes").as_str(), Span::mixed_site()); + let diff_ident = Ident::new(format!("Difference").as_str(), Span::mixed_site()); + + let defs = Ok::<_, syn::Error>(quote! { + #[derive(rkyv::Archive, Debug, rkyv::Deserialize, Clone, rkyv::Serialize)] + #[repr(C)] + pub enum #type_ident { + #(#rows)* + } + + #[derive(rkyv::Archive, Debug, rkyv::Deserialize, Clone, rkyv::Serialize)] + #[repr(C)] + pub struct #diff_ident { + old_value: #type_ident, + new_value: #type_ident, + } + }); + + let t = defs?; + println!("{}", t.to_string()); + Ok(t) + } + pub fn gen_result_types_def(&mut self) -> syn::Result { if let Some(queries) = &self.queries { let query_defs = queries @@ -31,6 +74,7 @@ impl Generator { .collect::, _>>()?; Ok::<_, syn::Error>(quote! { + #[derive(rkyv::Archive, Debug, rkyv::Deserialize, Clone, rkyv::Serialize)] #[repr(C)] pub struct #ident { diff --git a/codegen/src/worktable/generator/queries/update.rs b/codegen/src/worktable/generator/queries/update.rs index 25c4d48c..a804d56c 100644 --- a/codegen/src/worktable/generator/queries/update.rs +++ b/codegen/src/worktable/generator/queries/update.rs @@ -7,6 +7,8 @@ use convert_case::{Case, Casing}; use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; + + impl Generator { pub fn gen_query_update_impl(&mut self) -> syn::Result { let custom_updates = if let Some(q) = &self.queries { @@ -108,14 +110,14 @@ impl Generator { .any(|col| col.to_string() == idx.field.to_string()) }); - let idents = &op.columns; + let idents = &op.columns; let column_type = idents.iter().find_map(|ident| { self.columns.columns_map .get(ident) }); if let Some(index) = index { - let index_name = &index.name; + let index_name = &index. name; if index.is_unique { self.gen_unique_update(snake_case_name, name, index_name, idents) @@ -197,8 +199,9 @@ impl Generator { if let Some(set) = TableIndex::peek(&self.0.indexes.#index_name, &archived.inner.#i.#postfix) { set.remove(&link); } + + std::mem::swap(&mut archived.inner.#i, &mut row.#i); - } }) @@ -210,6 +213,13 @@ impl Generator { .map(|i| { quote! { + let diff = self.0.data.with_ref(link, |archived| { + Difference { + old_value: archived.inner.#i, + new_value: row.#i, + } + }); + if let Some(set) = TableIndex::peek(&self.0.indexes.#index_name, &row.#i.#postfix) { set.insert(link).expect("`Link` should not be already in set"); @@ -243,6 +253,8 @@ impl Generator { TableIndex::peek(&self.0.pk_map, &by).ok_or(WorkTableError::NotFound)? }; + + #(#new_index_value)* let id = self.0.data.with_ref(link, |archived| { diff --git a/codegen/src/worktable/mod.rs b/codegen/src/worktable/mod.rs index 21a7b752..2511ad21 100644 --- a/codegen/src/worktable/mod.rs +++ b/codegen/src/worktable/mod.rs @@ -53,6 +53,7 @@ pub fn expand(input: TokenStream) -> syn::Result { let index_def = generator.gen_index_def(); let table_def = generator.gen_table_def()?; let query_types_def = generator.gen_result_types_def()?; + let query_available_def = generator.gen_available_types_def()?; let query_locks_impls = generator.gen_query_locks_impl()?; let select_impls = generator.gen_query_select_impl()?; let update_impls = generator.gen_query_update_impl()?; @@ -65,6 +66,7 @@ pub fn expand(input: TokenStream) -> syn::Result { #index_def #table_def #query_types_def + #query_available_def #query_locks_impls #select_impls #update_impls diff --git a/codegen/src/worktable/model/column.rs b/codegen/src/worktable/model/column.rs index f1147ccc..0d11f387 100644 --- a/codegen/src/worktable/model/column.rs +++ b/codegen/src/worktable/model/column.rs @@ -24,6 +24,19 @@ pub struct Row { pub optional: bool, } +#[derive(Debug)] +pub enum AvailableType { + I16(i16), + U16(u16), + STRING(String), +} + +#[derive(Debug)] +pub struct Difference { + pub old_value: AvailableType, + pub new_value: AvailableType, +} + impl Columns { pub fn try_from_rows(rows: Vec, input: &TokenStream) -> syn::Result { let mut columns_map = HashMap::new(); diff --git a/examples/src/main.rs b/examples/src/main.rs index 43cc4f87..b7807da4 100644 --- a/examples/src/main.rs +++ b/examples/src/main.rs @@ -22,6 +22,7 @@ fn main() { ValByAttr(val) by attr, AttrById(attr) by id, Attr2ById(attr2) by id, + AllAttrById(attr, attr2) by id, }, delete: { ByAttr() by attr, @@ -79,6 +80,15 @@ fn main() { select_by_attr.unwrap().vals ); + let update_val = my_table.update_all_attr_by_id( + AllAttrByIdQuery { + attr: "TEST5".to_string(), + attr2: 1337, + }, + MyPrimaryKey(3), + ); + let _ = task::block_on(update_val); + // Update all recrods val by attr TEST2 let update_val = my_table.update_val_by_attr(ValByAttrQuery { val: 777 }, "TEST2".to_string()); let _ = task::block_on(update_val); @@ -139,8 +149,5 @@ fn main() { select_by_attr.unwrap().vals ); - println!( - "Select after deleted TEST2 {:?}", - my_table.select_all().execute() - ); + println!("Select ALL {:?}", my_table.select_all().execute()); } diff --git a/src/index/table_secondary_index.rs b/src/index/table_secondary_index.rs index a40279b0..31b7c9bf 100644 --- a/src/index/table_secondary_index.rs +++ b/src/index/table_secondary_index.rs @@ -1,11 +1,32 @@ use data_bucket::Link; +use std::collections::HashMap; use crate::WorkTableError; +#[derive(Debug)] +pub enum AvailableType { + I16(i16), + U16(u16), + STRING(String), +} + +#[derive(Debug)] +pub struct Difference { + pub old_value: AvailableType, + pub new_value: AvailableType, +} + pub trait TableSecondaryIndex { fn save_row(&self, row: Row, link: Link) -> Result<(), WorkTableError>; fn delete_row(&self, row: Row, link: Link) -> Result<(), WorkTableError>; + + fn process_difference( + &self, + row: Row, + link: Link, + differences: HashMap, + ) -> Result<(), WorkTableError>; } impl TableSecondaryIndex for () { @@ -16,4 +37,13 @@ impl TableSecondaryIndex for () { fn delete_row(&self, _: Row, _: Link) -> Result<(), WorkTableError> { Ok(()) } + + fn process_difference( + &self, + _: Row, + _: Link, + _: HashMap, + ) -> Result<(), WorkTableError> { + Ok(()) + } } From fb846f5e310940ae49c44a9a053c67d6d2b01093 Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Sun, 2 Feb 2025 11:27:42 +0300 Subject: [PATCH 04/16] WIp --- codegen/src/lib.rs | 1 - .../src/worktable/generator/queries/type.rs | 6 ++ .../src/worktable/generator/queries/update.rs | 78 ++++++++----------- codegen/src/worktable/mod.rs | 8 +- codegen/src/worktable/model/column.rs | 6 +- examples/src/main.rs | 50 ++++++------ src/index/table_secondary_index.rs | 6 +- 7 files changed, 74 insertions(+), 81 deletions(-) diff --git a/codegen/src/lib.rs b/codegen/src/lib.rs index 3bdea326..c9725b65 100644 --- a/codegen/src/lib.rs +++ b/codegen/src/lib.rs @@ -4,7 +4,6 @@ mod persist_table; mod worktable; use proc_macro::TokenStream; - // TODO: Refactor this codegen stuff because it's now too strange. #[proc_macro] diff --git a/codegen/src/worktable/generator/queries/type.rs b/codegen/src/worktable/generator/queries/type.rs index 88deb2b1..371f623f 100644 --- a/codegen/src/worktable/generator/queries/type.rs +++ b/codegen/src/worktable/generator/queries/type.rs @@ -34,6 +34,12 @@ impl Generator { #(#rows)* } + impl From for #type_ident { + fn from(s: rkyv::string::ArchivedString) -> Self { + #type_ident::STRING(s.to_string()) + } + } + #[derive(rkyv::Archive, Debug, rkyv::Deserialize, Clone, rkyv::Serialize)] #[repr(C)] pub struct #diff_ident { diff --git a/codegen/src/worktable/generator/queries/update.rs b/codegen/src/worktable/generator/queries/update.rs index a804d56c..92f84a99 100644 --- a/codegen/src/worktable/generator/queries/update.rs +++ b/codegen/src/worktable/generator/queries/update.rs @@ -7,8 +7,6 @@ use convert_case::{Case, Casing}; use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; - - impl Generator { pub fn gen_query_update_impl(&mut self) -> syn::Result { let custom_updates = if let Some(q) = &self.queries { @@ -97,8 +95,6 @@ impl Generator { .values() .find(|idx| idx.field.to_string() == op.by.to_string()); - - let index_columns = self .columns .indexes @@ -110,14 +106,13 @@ impl Generator { .any(|col| col.to_string() == idx.field.to_string()) }); - let idents = &op.columns; + let idents = &op.columns; - let column_type = idents.iter().find_map(|ident| { - self.columns.columns_map - .get(ident) - }); + let column_type = idents + .iter() + .find_map(|ident| self.columns.columns_map.get(ident)); if let Some(index) = index { - let index_name = &index. name; + let index_name = &index.name; if index.is_unique { self.gen_unique_update(snake_case_name, name, index_name, idents) @@ -130,11 +125,21 @@ impl Generator { == op.by.to_string() { if let Some(index) = index_columns { - self.gen_pk_update(snake_case_name, name, idents, Some(&index.name), column_type.unwrap(), - ) + self.gen_pk_update( + snake_case_name, + name, + idents, + Some(&index.name), + column_type.unwrap(), + ) } else { - self.gen_pk_update(snake_case_name, name, idents, None, column_type.unwrap(), - ) + self.gen_pk_update( + snake_case_name, + name, + idents, + None, + column_type.unwrap(), + ) } } else { todo!() @@ -151,7 +156,6 @@ impl Generator { } } - fn gen_pk_update( &self, snake_case_name: String, @@ -185,21 +189,10 @@ impl Generator { Span::mixed_site(), ); - let postfix = if column_type.to_string() == "String" { - quote! { to_string() } - } else { - quote! { into() } - }; - let row_updates = idents .iter() .map(|i| { quote! { - - if let Some(set) = TableIndex::peek(&self.0.indexes.#index_name, &archived.inner.#i.#postfix) { - set.remove(&link); - } - std::mem::swap(&mut archived.inner.#i, &mut row.#i); @@ -207,31 +200,22 @@ impl Generator { }) .collect::>(); - let new_index_value = if let Some(index_name) = index_name { + let new_index_value = if let Some(_index_name) = index_name { idents .iter() .map(|i| { quote! { - - let diff = self.0.data.with_ref(link, |archived| { - Difference { - old_value: archived.inner.#i, - new_value: row.#i, - } - }); - - - if let Some(set) = TableIndex::peek(&self.0.indexes.#index_name, &row.#i.#postfix) { - set.insert(link).expect("`Link` should not be already in set"); - } else { - let set = LockFreeSet::new(); - set.insert(link).expect("`Link` should not be already in set"); - TableIndex::insert(&self.0.indexes.#index_name, row.#i.#postfix, std::sync::Arc::new(set)); - } - - + // let value = archived.inner.#i.as_ref(); + + let diff = self.0.data.with_ref(link, |archived| { + Difference { + old_value: archived.inner.#i.into(), + new_value: row.#i.clone().into(), + } + }); } - }).collect::>() + }) + .collect::>() } else { Vec::new() }; @@ -253,7 +237,7 @@ impl Generator { TableIndex::peek(&self.0.pk_map, &by).ok_or(WorkTableError::NotFound)? }; - + #(#new_index_value)* diff --git a/codegen/src/worktable/mod.rs b/codegen/src/worktable/mod.rs index 2511ad21..71c3c185 100644 --- a/codegen/src/worktable/mod.rs +++ b/codegen/src/worktable/mod.rs @@ -59,7 +59,7 @@ pub fn expand(input: TokenStream) -> syn::Result { let update_impls = generator.gen_query_update_impl()?; let delete_impls = generator.gen_query_delete_impl()?; - Ok(TokenStream::from(quote! { + let t = TokenStream::from(quote! { #pk_def #row_def #wrapper_def @@ -71,7 +71,11 @@ pub fn expand(input: TokenStream) -> syn::Result { #select_impls #update_impls #delete_impls - })) + }); + + println!("MAIN {}", t.to_string()); + + Ok(t) } #[cfg(test)] diff --git a/codegen/src/worktable/model/column.rs b/codegen/src/worktable/model/column.rs index 0d11f387..65bd307b 100644 --- a/codegen/src/worktable/model/column.rs +++ b/codegen/src/worktable/model/column.rs @@ -25,7 +25,7 @@ pub struct Row { } #[derive(Debug)] -pub enum AvailableType { +pub enum AvailableTypes { I16(i16), U16(u16), STRING(String), @@ -33,8 +33,8 @@ pub enum AvailableType { #[derive(Debug)] pub struct Difference { - pub old_value: AvailableType, - pub new_value: AvailableType, + pub old_value: AvailableTypes, + pub new_value: AvailableTypes, } impl Columns { diff --git a/examples/src/main.rs b/examples/src/main.rs index b7807da4..ae38a967 100644 --- a/examples/src/main.rs +++ b/examples/src/main.rs @@ -1,4 +1,5 @@ use async_std::task; +use std::collections::HashMap; use worktable::prelude::*; use worktable::worktable; @@ -20,9 +21,9 @@ fn main() { queries: { update: { ValByAttr(val) by attr, - AttrById(attr) by id, - Attr2ById(attr2) by id, - AllAttrById(attr, attr2) by id, + // AttrById(attr) by id, + // Attr2ById(attr2) by id, + AllAttrById(attr, attr2) by id, }, delete: { ByAttr() by attr, @@ -80,14 +81,14 @@ fn main() { select_by_attr.unwrap().vals ); - let update_val = my_table.update_all_attr_by_id( - AllAttrByIdQuery { - attr: "TEST5".to_string(), - attr2: 1337, - }, - MyPrimaryKey(3), - ); - let _ = task::block_on(update_val); + //let update_val = my_table.update_all_attr_by_id( + // AllAttrByIdQuery { + // attr: "TEST5".to_string(), + // attr2: 1337, + // }, + // MyPrimaryKey(3), + //); + //let _ = task::block_on(update_val); // Update all recrods val by attr TEST2 let update_val = my_table.update_val_by_attr(ValByAttrQuery { val: 777 }, "TEST2".to_string()); @@ -101,20 +102,19 @@ fn main() { // Update attr by ID println!("update attr TEST3 -> TEST2"); - let update_attr = my_table.update_attr_by_id( - AttrByIdQuery { - attr: "TEST2".to_string(), - }, - MyPrimaryKey(3), - ); - let _ = task::block_on(update_attr); + // let update_attr = my_table.update_attr_by_id( + // attr: "TEST2".to_string(), + // }, + // MyPrimaryKey(3), + //); + // let _ = task::block_on(update_attr); println!("FINISH update attr TEST3 -> TEST2"); // Update attr2 by ID println!("update attr2 67 -> 1337"); - let update_attr = my_table.update_attr_2_by_id(Attr2ByIdQuery { attr2: 1337 }, MyPrimaryKey(3)); - let _ = task::block_on(update_attr); + // let update_attr = my_table.update_attr_2_by_id(Attr2ByIdQuery { attr2: 1337 }, MyPrimaryKey(3)); + // let _ = task::block_on(update_attr); println!("FINISH update attr2"); @@ -143,11 +143,11 @@ fn main() { select_by_attr.unwrap().vals ); - let select_by_attr = my_table.select_by_attr2(65); - println!( - "Select by Attribute 65 after del: {:?}", - select_by_attr.unwrap().vals - ); + //let select_by_attr = my_table.select_by_attr2(65); + // println!( + // "Select by Attribute 65 after del: {:?}", + // select_by_attr.unwrap().vals + // ); println!("Select ALL {:?}", my_table.select_all().execute()); } diff --git a/src/index/table_secondary_index.rs b/src/index/table_secondary_index.rs index 31b7c9bf..027137ce 100644 --- a/src/index/table_secondary_index.rs +++ b/src/index/table_secondary_index.rs @@ -4,7 +4,7 @@ use std::collections::HashMap; use crate::WorkTableError; #[derive(Debug)] -pub enum AvailableType { +pub enum AvailableTypes { I16(i16), U16(u16), STRING(String), @@ -12,8 +12,8 @@ pub enum AvailableType { #[derive(Debug)] pub struct Difference { - pub old_value: AvailableType, - pub new_value: AvailableType, + pub old_value: AvailableTypes, + pub new_value: AvailableTypes, } pub trait TableSecondaryIndex { From fb9d8ac00b51cf7492d3ed99afd1f019fdd57065 Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Mon, 3 Feb 2025 02:35:19 +0300 Subject: [PATCH 05/16] WIP --- codegen/src/worktable/generator/index.rs | 17 ++++++---- .../src/worktable/generator/queries/type.rs | 18 +++++----- .../src/worktable/generator/queries/update.rs | 8 ++--- .../src/worktable/generator/table/impls.rs | 20 +++++++---- .../worktable/generator/table/index_fns.rs | 6 ++-- codegen/src/worktable/generator/table/mod.rs | 2 ++ codegen/src/worktable/mod.rs | 4 +-- codegen/src/worktable/model/column.rs | 13 -------- examples/src/main.rs | 10 +++--- src/index/mod.rs | 2 +- src/index/table_secondary_index.rs | 24 +++++++------- src/lib.rs | 2 +- src/table/mod.rs | 33 ++++++++++++++++--- 13 files changed, 94 insertions(+), 65 deletions(-) diff --git a/codegen/src/worktable/generator/index.rs b/codegen/src/worktable/generator/index.rs index 85b37f1d..3f777b2e 100644 --- a/codegen/src/worktable/generator/index.rs +++ b/codegen/src/worktable/generator/index.rs @@ -10,11 +10,14 @@ impl Generator { let type_def = self.gen_type_def(); let impl_def = self.gen_impl_def(); - quote! { + let t = quote! { #type_def #impl_def - } + }; + + println!("index gen {}", t); + t } /// Generates table's secondary index struct definition. It has fields with index names and types varying on index @@ -40,12 +43,14 @@ impl Generator { }) .collect::>(); - quote! { + let t = quote! { #[derive(Debug, Default, PersistIndex)] pub struct #ident { #(#index_rows),* } - } + }; + println!("{}", t); + t } /// Generates implementation of `TableIndex` trait for index. @@ -59,7 +64,7 @@ impl Generator { let process_differences_row_fn = self.gen_process_difference_index_fn(); let t = quote! { - impl TableSecondaryIndex<#row_type_ident> for #index_type_ident { + impl TableSecondaryIndex<#row_type_ident, AvailableTypes> for #index_type_ident { #save_row_fn #delete_row_fn #process_differences_row_fn @@ -170,7 +175,7 @@ impl Generator { .collect::>(); quote! { - fn process_difference(&self, row: #row_type_ident, link: Link, difference: HashMap<#row_type_ident, Difference >) -> core::result::Result<(), WorkTableError> { + fn process_difference(&self, row: #row_type_ident, link: Link, difference: HashMap<&str, Difference >) -> core::result::Result<(), WorkTableError> { #(#process_difference_rows)* core::result::Result::Ok(()) } diff --git a/codegen/src/worktable/generator/queries/type.rs b/codegen/src/worktable/generator/queries/type.rs index 371f623f..bef4b491 100644 --- a/codegen/src/worktable/generator/queries/type.rs +++ b/codegen/src/worktable/generator/queries/type.rs @@ -25,7 +25,6 @@ impl Generator { .collect::, _>>()?; let type_ident = Ident::new(format!("AvailableTypes").as_str(), Span::mixed_site()); - let diff_ident = Ident::new(format!("Difference").as_str(), Span::mixed_site()); let defs = Ok::<_, syn::Error>(quote! { #[derive(rkyv::Archive, Debug, rkyv::Deserialize, Clone, rkyv::Serialize)] @@ -34,22 +33,25 @@ impl Generator { #(#rows)* } + impl Default for #type_ident { + fn default() -> Self { + + #type_ident::STRING(String::default()) + + } + } + impl From for #type_ident { fn from(s: rkyv::string::ArchivedString) -> Self { #type_ident::STRING(s.to_string()) } } - #[derive(rkyv::Archive, Debug, rkyv::Deserialize, Clone, rkyv::Serialize)] - #[repr(C)] - pub struct #diff_ident { - old_value: #type_ident, - new_value: #type_ident, - } + }); let t = defs?; - println!("{}", t.to_string()); + // println!("{}", t.to_string()); Ok(t) } diff --git a/codegen/src/worktable/generator/queries/update.rs b/codegen/src/worktable/generator/queries/update.rs index 92f84a99..e3e9f2ba 100644 --- a/codegen/src/worktable/generator/queries/update.rs +++ b/codegen/src/worktable/generator/queries/update.rs @@ -162,7 +162,7 @@ impl Generator { name: &Ident, idents: &Vec, index_name: Option<&Ident>, - column_type: &TokenStream, + _column_type: &TokenStream, ) -> TokenStream { let pk_ident = &self.pk.as_ref().unwrap().ident; let method_ident = Ident::new( @@ -200,7 +200,7 @@ impl Generator { }) .collect::>(); - let new_index_value = if let Some(_index_name) = index_name { + let _new_index_value = if let Some(_index_name) = index_name { idents .iter() .map(|i| { @@ -210,7 +210,7 @@ impl Generator { let diff = self.0.data.with_ref(link, |archived| { Difference { old_value: archived.inner.#i.into(), - new_value: row.#i.clone().into(), + new_value: row.#i.into(), } }); } @@ -239,7 +239,7 @@ impl Generator { - #(#new_index_value)* + // #(#new_index_value)* let id = self.0.data.with_ref(link, |archived| { archived.#check_ident() diff --git a/codegen/src/worktable/generator/table/impls.rs b/codegen/src/worktable/generator/table/impls.rs index 6314eaed..23bf5612 100644 --- a/codegen/src/worktable/generator/table/impls.rs +++ b/codegen/src/worktable/generator/table/impls.rs @@ -19,7 +19,7 @@ impl Generator { let iter_with_fn = self.gen_table_iter_with_fn(); let iter_with_async_fn = self.gen_table_iter_with_async_fn(); - quote! { + let t = quote! { impl #ident { #new_fn #name_fn @@ -30,7 +30,10 @@ impl Generator { #iter_with_fn #iter_with_async_fn } - } + }; + + // println!("TAABLE {}", t.to_string()); + t } fn gen_table_new_fn(&self) -> TokenStream { @@ -38,13 +41,15 @@ impl Generator { let table_name = name_generator.get_work_table_literal_name(); if self.is_persist { - quote! { + let t = quote! { pub fn new(manager: std::sync::Arc) -> Self { let mut inner = WorkTable::default(); inner.table_name = #table_name; Self(inner, manager) } - } + }; + println!("NEW {}", t.to_string()); + t } else { quote! {} } @@ -75,11 +80,14 @@ impl Generator { let row_type = name_generator.get_row_type_ident(); let primary_key_type = name_generator.get_primary_key_type_ident(); - quote! { + let t = quote! { pub fn insert(&self, row: #row_type) -> core::result::Result<#primary_key_type, WorkTableError> { self.0.insert(row) } - } + }; + + println!("INSERTT {}", t.to_string()); + t } fn gen_table_upsert_fn(&self) -> TokenStream { let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string()); diff --git a/codegen/src/worktable/generator/table/index_fns.rs b/codegen/src/worktable/generator/table/index_fns.rs index 78b8058b..d3e283d5 100644 --- a/codegen/src/worktable/generator/table/index_fns.rs +++ b/codegen/src/worktable/generator/table/index_fns.rs @@ -71,7 +71,7 @@ impl Generator { let fn_name = Ident::new(format!("select_by_{i}").as_str(), Span::mixed_site()); let field_ident = &idx.name; - Ok(quote! { + let t = quote! { pub fn #fn_name(&self, by: #type_) -> core::result::Result, WorkTableError> { let rows = { TableIndex::peek(&self.0.indexes.#field_ident, &by) @@ -85,6 +85,8 @@ impl Generator { .collect::, _>>()?; core::result::Result::Ok(SelectResult::<#row_ident, Self>::new(rows)) } - }) + }; + println!("Index --> {}", t.to_string()); + Ok(t) } } diff --git a/codegen/src/worktable/generator/table/mod.rs b/codegen/src/worktable/generator/table/mod.rs index 24e4dd33..2384475f 100644 --- a/codegen/src/worktable/generator/table/mod.rs +++ b/codegen/src/worktable/generator/table/mod.rs @@ -83,6 +83,7 @@ impl Generator { #row_type, #primary_key_type, #primary_index_type<#primary_key_type, Link>, + AvailableTypes, #index_type, <#primary_key_type as TablePrimaryKey>::Generator, #inner_const_name @@ -98,6 +99,7 @@ impl Generator { #row_type, #primary_key_type, #primary_index_type<#primary_key_type, Link>, + AvailableTypes, #index_type > #persist_type_part diff --git a/codegen/src/worktable/mod.rs b/codegen/src/worktable/mod.rs index 71c3c185..c9ca0536 100644 --- a/codegen/src/worktable/mod.rs +++ b/codegen/src/worktable/mod.rs @@ -62,18 +62,18 @@ pub fn expand(input: TokenStream) -> syn::Result { let t = TokenStream::from(quote! { #pk_def #row_def + #query_available_def #wrapper_def #index_def #table_def #query_types_def - #query_available_def #query_locks_impls #select_impls #update_impls #delete_impls }); - println!("MAIN {}", t.to_string()); + // println!("MAIN {}", t.to_string()); Ok(t) } diff --git a/codegen/src/worktable/model/column.rs b/codegen/src/worktable/model/column.rs index 65bd307b..f1147ccc 100644 --- a/codegen/src/worktable/model/column.rs +++ b/codegen/src/worktable/model/column.rs @@ -24,19 +24,6 @@ pub struct Row { pub optional: bool, } -#[derive(Debug)] -pub enum AvailableTypes { - I16(i16), - U16(u16), - STRING(String), -} - -#[derive(Debug)] -pub struct Difference { - pub old_value: AvailableTypes, - pub new_value: AvailableTypes, -} - impl Columns { pub fn try_from_rows(rows: Vec, input: &TokenStream) -> syn::Result { let mut columns_map = HashMap::new(); diff --git a/examples/src/main.rs b/examples/src/main.rs index ae38a967..4931261a 100644 --- a/examples/src/main.rs +++ b/examples/src/main.rs @@ -16,7 +16,7 @@ fn main() { }, indexes: { attr_idx: attr, - attr2_idx: attr2, + //attr2_idx: attr2, }, queries: { update: { @@ -65,10 +65,10 @@ fn main() { }; // insert - let _ = my_table.insert(row); - let _ = my_table.insert(row1); - let _ = my_table.insert(row2); - let _ = my_table.insert(row3); + let _ = my_table.upsert(row); + //let _ = my_table.insert(row1); + //let _ = my_table.insert(row2); + //let _ = my_table.insert(row3); // Select ALL records from WT let select_all = my_table.select_all().execute(); diff --git a/src/index/mod.rs b/src/index/mod.rs index 6e133d80..792d48be 100644 --- a/src/index/mod.rs +++ b/src/index/mod.rs @@ -9,7 +9,7 @@ mod table_index; mod table_secondary_index; pub use table_index::{IndexSet, LockFreeMap, LockedHashMap, TableIndex}; -pub use table_secondary_index::TableSecondaryIndex; +pub use table_secondary_index::{Difference, TableSecondaryIndex}; pub enum IndexType<'a, T> { Unique(&'a TreeIndex), diff --git a/src/index/table_secondary_index.rs b/src/index/table_secondary_index.rs index 027137ce..d64c00c5 100644 --- a/src/index/table_secondary_index.rs +++ b/src/index/table_secondary_index.rs @@ -1,22 +1,19 @@ use data_bucket::Link; use std::collections::HashMap; +use std::fmt::Debug; use crate::WorkTableError; #[derive(Debug)] -pub enum AvailableTypes { - I16(i16), - U16(u16), - STRING(String), -} - -#[derive(Debug)] -pub struct Difference { +pub struct Difference { pub old_value: AvailableTypes, pub new_value: AvailableTypes, } -pub trait TableSecondaryIndex { +pub trait TableSecondaryIndex +where + AvailableTypes: 'static, +{ fn save_row(&self, row: Row, link: Link) -> Result<(), WorkTableError>; fn delete_row(&self, row: Row, link: Link) -> Result<(), WorkTableError>; @@ -25,11 +22,14 @@ pub trait TableSecondaryIndex { &self, row: Row, link: Link, - differences: HashMap, + differences: HashMap<&str, Difference>, ) -> Result<(), WorkTableError>; } -impl TableSecondaryIndex for () { +impl TableSecondaryIndex for () +where + AvailableTypes: 'static, +{ fn save_row(&self, _: Row, _: Link) -> Result<(), WorkTableError> { Ok(()) } @@ -42,7 +42,7 @@ impl TableSecondaryIndex for () { &self, _: Row, _: Link, - _: HashMap, + _: HashMap<&str, Difference>, ) -> Result<(), WorkTableError> { Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 5731633e..ea0422e8 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -27,7 +27,7 @@ pub mod prelude { Order, SelectQueryBuilder, SelectQueryExecutor, SelectResult, SelectResultExecutor, }; pub use crate::{ - lock::Lock, IndexSet, LockFreeMap, LockedHashMap, TableIndex, TableRow, + lock::Lock, Difference, IndexSet, LockFreeMap, LockedHashMap, TableIndex, TableRow, TableSecondaryIndex, WorkTable, WorkTableError, }; pub use data_bucket::{ diff --git a/src/table/mod.rs b/src/table/mod.rs index e492b87d..e064fc5d 100644 --- a/src/table/mod.rs +++ b/src/table/mod.rs @@ -22,6 +22,7 @@ pub struct WorkTable< Row, PrimaryKey, IndexType, + AvailableTypes, SecondaryIndexes = (), PkGen = ::Generator, const DATA_LENGTH: usize = INNER_PAGE_SIZE, @@ -43,14 +44,25 @@ pub struct WorkTable< pub table_name: &'static str, pub pk_phantom: PhantomData, + + pub available_types_phantom: PhantomData, } // Manual implementations to avoid unneeded trait bounds. -impl Default - for WorkTable +impl< + Row, + PrimaryKey, + IndexType, + AvailableTypes, + SecondaryIndexes, + PkGen, + const DATA_LENGTH: usize, + > Default + for WorkTable where PrimaryKey: Clone + Ord + TablePrimaryKey, SecondaryIndexes: Default, + AvailableTypes: Default, IndexType: Default + TableIndex, PkGen: Default, Row: StorableRow, @@ -65,18 +77,28 @@ where lock_map: LockMap::new(), table_name: "", pk_phantom: PhantomData, + available_types_phantom: PhantomData, } } } -impl - WorkTable +impl< + Row, + PrimaryKey, + IndexType, + AvailableTypes, + SecondaryIndexes, + PkGen, + const DATA_LENGTH: usize, + > WorkTable where Row: TableRow, PrimaryKey: Clone + Ord + TablePrimaryKey, IndexType: TableIndex, Row: StorableRow, ::WrappedRow: RowWrapper, + AvailableTypes: 'static, + SecondaryIndexes: TableSecondaryIndex, { pub fn get_next_pk(&self) -> PrimaryKey where @@ -119,7 +141,8 @@ where Strategy, Share>, rkyv::rancor::Error>, >, PrimaryKey: Clone, - SecondaryIndexes: TableSecondaryIndex, + AvailableTypes: 'static, + SecondaryIndexes: TableSecondaryIndex, { let pk = row.get_primary_key().clone(); let link = self From ec2b2b8ca1d5860caf660d2c4637de02d745973a Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Mon, 3 Feb 2025 02:41:00 +0300 Subject: [PATCH 06/16] WIP --- examples/src/main.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/src/main.rs b/examples/src/main.rs index 4931261a..ce92f3dc 100644 --- a/examples/src/main.rs +++ b/examples/src/main.rs @@ -16,7 +16,7 @@ fn main() { }, indexes: { attr_idx: attr, - //attr2_idx: attr2, + attr2_idx: attr2, }, queries: { update: { @@ -66,9 +66,9 @@ fn main() { // insert let _ = my_table.upsert(row); - //let _ = my_table.insert(row1); - //let _ = my_table.insert(row2); - //let _ = my_table.insert(row3); + let _ = my_table.insert(row1); + let _ = my_table.insert(row2); + let _ = my_table.insert(row3); // Select ALL records from WT let select_all = my_table.select_all().execute(); From e85d7cd576e7063f620ffbee33eca364a506195d Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Tue, 4 Feb 2025 12:38:09 +0300 Subject: [PATCH 07/16] WIP --- examples/src/main.rs | 151 +++++++++++++++++++++++-------------------- 1 file changed, 80 insertions(+), 71 deletions(-) diff --git a/examples/src/main.rs b/examples/src/main.rs index ce92f3dc..93675c5c 100644 --- a/examples/src/main.rs +++ b/examples/src/main.rs @@ -11,18 +11,18 @@ fn main() { id: u64 primary_key autoincrement, val: i64, attr: String, - attr2: i16, + attr2: u64, }, indexes: { - attr_idx: attr, - attr2_idx: attr2, + attr_idx: attr2, + attr2_idx: attr, }, queries: { update: { ValByAttr(val) by attr, // AttrById(attr) by id, - // Attr2ById(attr2) by id, + // Attr2ById(attr2) by id, AllAttrById(attr, attr2) by id, }, delete: { @@ -37,49 +37,49 @@ fn main() { // WT rows (has prefix My because of table name) let row = MyRow { - val: 1, + val: 777, attr: "TEST".to_string(), - attr2: 65, + attr2: 345, id: 0, }; - let row1 = MyRow { - val: 2, - attr: "TEST2".to_string(), - attr2: 65, - id: 1, - }; - - let row2 = MyRow { - val: 1337, - attr: "TEST2".to_string(), - attr2: 65, - id: 2, - }; - - let row3 = MyRow { - val: 555, - attr: "TEST3".to_string(), - attr2: 65, - id: 3, - }; + // let row1 = MyRow { + // val: 2, + // attr: "TEST2".to_string(), + // attr2: "EST".to_string(), + // id: 1, + // }; + // + // let row2 = MyRow { + // val: 1337, + // attr: "TEST2".to_string(), + // attr2: "EST".to_string(), + // id: 2, + // }; + // + // let row3 = MyRow { + // val: 555, + // attr: "TEST3".to_string(), + // attr2: "EST".to_string(), + // id: 3, + // }; // insert - let _ = my_table.upsert(row); - let _ = my_table.insert(row1); - let _ = my_table.insert(row2); - let _ = my_table.insert(row3); + let _ = my_table.insert(row); + //let _ = my_table.insert(row1); + //let _ = my_table.insert(row2); + //let _ = my_table.insert(row3); // Select ALL records from WT let select_all = my_table.select_all().execute(); println!("Select All {:?}", select_all); // Select All records with attribute TEST2 - let select_by_attr = my_table.select_by_attr("TEST2".to_string()); - println!( - "Select by Attribute TEST2: {:?}", - select_by_attr.unwrap().vals - ); + //let select_by_attr = my_table.select_by_attr("TEST2".to_string()); + //println!( + // "Select by Attribute TEST2: {:?}", + // select_by_attr.unwrap().vals + //); //let update_val = my_table.update_all_attr_by_id( // AllAttrByIdQuery { @@ -91,17 +91,17 @@ fn main() { //let _ = task::block_on(update_val); // Update all recrods val by attr TEST2 - let update_val = my_table.update_val_by_attr(ValByAttrQuery { val: 777 }, "TEST2".to_string()); - let _ = task::block_on(update_val); - - let select_updated = my_table.select_by_attr("TEST2".to_string()); - println!( - "Select updated by Attribute TEST2: {:?}", - select_updated.unwrap().vals - ); + // let update_val = my_table.update_val_by_attr(ValByAttrQuery { val: 777 }, "TEST2".to_string()); + // let _ = task::block_on(update_val); + // + // let select_updated = my_table.select_by_attr("TEST2".to_string()); + // println!( + // "Select updated by Attribute TEST2: {:?}", + // select_updated.unwrap().vals + // ); // Update attr by ID - println!("update attr TEST3 -> TEST2"); + //println!("update attr TEST3 -> TEST2"); // let update_attr = my_table.update_attr_by_id( // attr: "TEST2".to_string(), // }, @@ -109,45 +109,54 @@ fn main() { //); // let _ = task::block_on(update_attr); - println!("FINISH update attr TEST3 -> TEST2"); + // println!("FINISH update attr TEST3 -> TEST2"); // Update attr2 by ID - println!("update attr2 67 -> 1337"); + // println!("update attr2 67 -> 1337"); // let update_attr = my_table.update_attr_2_by_id(Attr2ByIdQuery { attr2: 1337 }, MyPrimaryKey(3)); // let _ = task::block_on(update_attr); - println!("FINISH update attr2"); + //println!("FINISH update attr2"); // Update record attribute TEST2 -> TEST3 with id 1 - let update_exchange = - my_table.update_val_by_attr(ValByAttrQuery { val: 7777 }, "TEST2".to_string()); - let _ = task::block_on(update_exchange); - - let select_all_after_update = my_table.select_all(); - println!( - "Select After Val Update by Attribute: {:?}", - select_all_after_update.execute() - ); - let test_delete = my_table.delete_by_attr("TEST2".to_string()); - let _ = task::block_on(test_delete); + //let update_exchange = + // my_table.update_val_by_attr(ValByAttrQuery { val: 7777 }, "TEST2".to_string()); + //let _ = task::block_on(update_exchange); // - let select_by_attr = my_table.select_by_attr("TEST2".to_string()); - println!( - "Select by Attribute TEST2 after del: {:?}", - select_by_attr.unwrap().vals + // let select_all_after_update = my_table.select_all(); + // println!( + // "Select After Val Update by Attribute: {:?}", + // select_all_after_update.execute() + // ); + // let test_delete = my_table.delete_by_attr("TEST2".to_string()); + // let _ = task::block_on(test_delete); + // // + // let select_by_attr = my_table.select_by_attr("TEST2".to_string()); + // println!( + // "Select by Attribute TEST2 after del: {:?}", + // select_by_attr.unwrap().vals + // ); + // // + // let select_by_attr = my_table.select_by_attr("TEST3".to_string()); + // println!( + // "Select by Attribute TEST3 after del: {:?}", + // select_by_attr.unwrap().vals + // ); + + let all_update = my_table.update_all_attr_by_id( + AllAttrByIdQuery { + attr: "OK".to_string(), + attr2: 1337, + }, + MyPrimaryKey(0), ); - // - let select_by_attr = my_table.select_by_attr("TEST3".to_string()); + let _ = task::block_on(all_update); + + let select_by_attr = my_table.select_by_attr("TEST".to_string()); println!( - "Select by Attribute TEST3 after del: {:?}", + "Select by Attribute TEST after del: {:?}", select_by_attr.unwrap().vals ); - //let select_by_attr = my_table.select_by_attr2(65); - // println!( - // "Select by Attribute 65 after del: {:?}", - // select_by_attr.unwrap().vals - // ); - println!("Select ALL {:?}", my_table.select_all().execute()); } From 47ea45ab4c04d7b0d4a6387c16ca3430769893b2 Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Tue, 4 Feb 2025 12:38:22 +0300 Subject: [PATCH 08/16] WIP --- codegen/src/worktable/generator/index.rs | 56 +++++++++--- .../src/worktable/generator/queries/locks.rs | 6 +- .../src/worktable/generator/queries/type.rs | 30 ++++--- .../src/worktable/generator/queries/update.rs | 87 +++++++------------ src/index/table_secondary_index.rs | 6 +- tests/worktable/index.rs | 29 +++++++ 6 files changed, 124 insertions(+), 90 deletions(-) create mode 100644 tests/worktable/index.rs diff --git a/codegen/src/worktable/generator/index.rs b/codegen/src/worktable/generator/index.rs index 3f777b2e..73378058 100644 --- a/codegen/src/worktable/generator/index.rs +++ b/codegen/src/worktable/generator/index.rs @@ -108,12 +108,14 @@ impl Generator { }) .collect::>(); - quote! { + let t = quote! { fn save_row(&self, row: #row_type_ident, link: Link) -> core::result::Result<(), WorkTableError> { #(#save_rows)* core::result::Result::Ok(()) } - } + }; + println!("SAVE_RoOWS {}", t.to_string()); + t } /// Generates `delete_row` function of `TableIndex` trait for index. It removes `Link` from all secondary indexes. @@ -143,12 +145,14 @@ impl Generator { }) .collect::>(); - quote! { + let t = quote! { fn delete_row(&self, row: #row_type_ident, link: Link) -> core::result::Result<(), WorkTableError> { #(#delete_rows)* core::result::Result::Ok(()) } - } + }; + println!("deelete {}", t.to_string()); + t } fn gen_process_difference_index_fn(&self) -> TokenStream { @@ -159,27 +163,53 @@ impl Generator { .columns .indexes .iter() - .map(|(_i, idx)| { - let _index_field_name = &idx.name; - //let difference_type_ident = + .map(|(i, idx)| { + let index_field_name = &idx.name; + if idx.is_unique { quote! { - todo()!; + + println!("Should be implemented"); + } } else { quote! { - todo()!; - } + + let diff = difference.get(stringify!(#i)).expect("Ok"); + + println!("AA{:?}", stringify!(#row_type_ident.#i)); + + println!("DIFF PROCESA {:?}", diff); + // let old: #row_type_ident.#i = diff.into(); + // + // println!("ROOW {:?}, Diff {:?}", row_type_ident, old); + // + // if let Some(set) = TableIndex::peek(&self.#index_field_name, &diff.old) { + // set.remove(&link); + // } + // + // if let Some(set) = TableIndex::peek(&self.#index_field_name, &diff.new) { + // set.insert(link).expect("is ok"); + // } else { + // let set = LockFreeSet::new(); + // set.insert(link).expect("`Link` should not be already in set"); + // TableIndex::insert(&self.#index_field_name, &diff.new, std::sync::Arc::new(set)) + // .map_err(|_| WorkTableError::AlreadyExists)?; + // } + } } }) .collect::>(); - quote! { - fn process_difference(&self, row: #row_type_ident, link: Link, difference: HashMap<&str, Difference >) -> core::result::Result<(), WorkTableError> { + let t = quote! { + fn process_difference(&self, link: Link, difference: HashMap<&str, Difference>) -> core::result::Result<(), WorkTableError> { #(#process_difference_rows)* core::result::Result::Ok(()) } - } + }; + + println!("PROCESS_DIIF {}", t.to_string()); + t } } diff --git a/codegen/src/worktable/generator/queries/locks.rs b/codegen/src/worktable/generator/queries/locks.rs index fd0ac853..d6dcca2c 100644 --- a/codegen/src/worktable/generator/queries/locks.rs +++ b/codegen/src/worktable/generator/queries/locks.rs @@ -128,11 +128,13 @@ impl Generator { }) .collect::>(); - Ok(quote! { + let t = quote! { impl #archived_wrapper { #(#fns)* } - }) + }; + println!("Wrapper {}", t.to_string()); + Ok(t) } else { Ok(quote! {}) } diff --git a/codegen/src/worktable/generator/queries/type.rs b/codegen/src/worktable/generator/queries/type.rs index bef4b491..fd13d2c0 100644 --- a/codegen/src/worktable/generator/queries/type.rs +++ b/codegen/src/worktable/generator/queries/type.rs @@ -1,5 +1,6 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; +use std::collections::HashSet; use crate::worktable::generator::Generator; @@ -11,15 +12,17 @@ impl Generator { .iter() .map(|(_i, idx)| self.columns.columns_map.get(&idx.field)) .into_iter() + .filter_map(|t| t) + .map(|s| s.to_string()) + .collect::>() + .into_iter() .map(|t| { - let type_upper = Ident::new( - &t.expect("REASON").to_string().to_uppercase(), - Span::mixed_site(), - ); + let type_ = Ident::new(&t.to_string(), Span::mixed_site()); + let type_upper = Ident::new(&t.to_string().to_uppercase(), Span::mixed_site()); Ok::<_, syn::Error>(quote! { - - #type_upper(#t), + #[from] + #type_upper(#type_), }) }) .collect::, _>>()?; @@ -28,7 +31,7 @@ impl Generator { let defs = Ok::<_, syn::Error>(quote! { #[derive(rkyv::Archive, Debug, rkyv::Deserialize, Clone, rkyv::Serialize)] - #[repr(C)] + #[derive(From, PartialEq)] pub enum #type_ident { #(#rows)* } @@ -41,17 +44,18 @@ impl Generator { } } - impl From for #type_ident { - fn from(s: rkyv::string::ArchivedString) -> Self { - #type_ident::STRING(s.to_string()) - } - } + //impl From for #type_ident { + // fn from(s: rkyv::string::ArchivedString) -> Self { + // #type_ident::STRING(s.to_string()) + // } + // } + }); let t = defs?; - // println!("{}", t.to_string()); + println!("AvT {}", t.to_string()); Ok(t) } diff --git a/codegen/src/worktable/generator/queries/update.rs b/codegen/src/worktable/generator/queries/update.rs index e3e9f2ba..325b94be 100644 --- a/codegen/src/worktable/generator/queries/update.rs +++ b/codegen/src/worktable/generator/queries/update.rs @@ -95,22 +95,8 @@ impl Generator { .values() .find(|idx| idx.field.to_string() == op.by.to_string()); - let index_columns = self - .columns - .indexes - .values() - .filter(|idx| !idx.is_unique) - .find(|idx| { - op.columns - .iter() - .any(|col| col.to_string() == idx.field.to_string()) - }); - let idents = &op.columns; - let column_type = idents - .iter() - .find_map(|ident| self.columns.columns_map.get(ident)); if let Some(index) = index { let index_name = &index.name; @@ -124,23 +110,7 @@ impl Generator { if self.columns.primary_keys.0.first().unwrap().to_string() == op.by.to_string() { - if let Some(index) = index_columns { - self.gen_pk_update( - snake_case_name, - name, - idents, - Some(&index.name), - column_type.unwrap(), - ) - } else { - self.gen_pk_update( - snake_case_name, - name, - idents, - None, - column_type.unwrap(), - ) - } + self.gen_pk_update(snake_case_name, name, idents) } else { todo!() } @@ -161,8 +131,6 @@ impl Generator { snake_case_name: String, name: &Ident, idents: &Vec, - index_name: Option<&Ident>, - _column_type: &TokenStream, ) -> TokenStream { let pk_ident = &self.pk.as_ref().unwrap().ident; let method_ident = Ident::new( @@ -193,41 +161,46 @@ impl Generator { .iter() .map(|i| { quote! { - std::mem::swap(&mut archived.inner.#i, &mut row.#i); - } }) .collect::>(); - let _new_index_value = if let Some(_index_name) = index_name { - idents - .iter() - .map(|i| { - quote! { - // let value = archived.inner.#i.as_ref(); - - let diff = self.0.data.with_ref(link, |archived| { - Difference { - old_value: archived.inner.#i.into(), - new_value: row.#i.into(), - } - }); - } - }) - .collect::>() - } else { - Vec::new() - }; + let diff = idents + .iter() + .map(|i| { + quote! { + + let old: AvailableTypes = row_old.#i.into(); + let new: AvailableTypes = row_new.#i.into(); + + let diff = Difference { + old: old.clone(), + new: new.clone(), + }; + + diffs.insert(stringify!(#i), diff); + } + }) + .collect::>(); let t = quote! { pub async fn #method_ident(&self, row: #query_ident, by: #pk_ident) -> core::result::Result<(), WorkTableError> { - println!("{:?}", row); + println!("Row {:?}", row); let op_id = self.0.lock_map.next_id(); let lock = std::sync::Arc::new(Lock::new()); self.0.lock_map.insert(op_id.into(), lock.clone()); + let row_old = self.select(by.clone()).unwrap(); + let row_new = row.clone(); + let mut diffs: HashMap<&str, Difference> = HashMap::new(); + + #(#diff)* + + println!("diffs {:?}",diffs ); + + let mut bytes = rkyv::to_bytes::(&row).map_err(|_| WorkTableError::SerializeError)?; let mut row = unsafe { rkyv::access_unchecked_mut::<<#query_ident as rkyv::Archive>::Archived>(&mut bytes[..]).unseal_unchecked() }; @@ -237,9 +210,7 @@ impl Generator { TableIndex::peek(&self.0.pk_map, &by).ok_or(WorkTableError::NotFound)? }; - - - // #(#new_index_value)* + self.0.indexes.process_difference(link, diffs)?; let id = self.0.data.with_ref(link, |archived| { archived.#check_ident() diff --git a/src/index/table_secondary_index.rs b/src/index/table_secondary_index.rs index d64c00c5..7e81ff56 100644 --- a/src/index/table_secondary_index.rs +++ b/src/index/table_secondary_index.rs @@ -6,8 +6,8 @@ use crate::WorkTableError; #[derive(Debug)] pub struct Difference { - pub old_value: AvailableTypes, - pub new_value: AvailableTypes, + pub old: AvailableTypes, + pub new: AvailableTypes, } pub trait TableSecondaryIndex @@ -20,7 +20,6 @@ where fn process_difference( &self, - row: Row, link: Link, differences: HashMap<&str, Difference>, ) -> Result<(), WorkTableError>; @@ -40,7 +39,6 @@ where fn process_difference( &self, - _: Row, _: Link, _: HashMap<&str, Difference>, ) -> Result<(), WorkTableError> { diff --git a/tests/worktable/index.rs b/tests/worktable/index.rs new file mode 100644 index 00000000..4c4dca42 --- /dev/null +++ b/tests/worktable/index.rs @@ -0,0 +1,29 @@ + +use std::collections::HashMap; +use worktable::prelude::*; +use worktable::worktable; + +fn main() { + worktable!( + name: Test, + columns: { + id: u64 primary_key autoincrement, + val: i64, + attr: String, + }, + indexes: { + attr_idx: attr2, + attr2_idx: attr, + }, + queries: { + update: { + ValByAttr(val) by attr, + // AttrById(attr) by id, + // Attr2ById(attr2) by id, + AllAttrById(attr, attr2) by id, + }, + delete: { + ById() by id, + } + } + ); From a0cf5b96a32a356d8959599cb2aac0692f1ba3da Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Fri, 7 Feb 2025 06:03:20 +0300 Subject: [PATCH 09/16] WIP --- codegen/src/worktable/generator/index.rs | 126 +++++++++--------- .../src/worktable/generator/queries/locks.rs | 6 +- .../src/worktable/generator/queries/type.rs | 16 +-- .../src/worktable/generator/queries/update.rs | 14 +- .../src/worktable/generator/table/impls.rs | 20 +-- .../worktable/generator/table/index_fns.rs | 6 +- examples/src/main.rs | 79 ++++++----- 7 files changed, 125 insertions(+), 142 deletions(-) diff --git a/codegen/src/worktable/generator/index.rs b/codegen/src/worktable/generator/index.rs index 73378058..57ef9165 100644 --- a/codegen/src/worktable/generator/index.rs +++ b/codegen/src/worktable/generator/index.rs @@ -2,6 +2,8 @@ use crate::name_generator::WorktableNameGenerator; use crate::worktable::generator::Generator; use proc_macro2::TokenStream; +use proc_macro2::{Ident, Span}; + use quote::quote; impl Generator { @@ -10,14 +12,11 @@ impl Generator { let type_def = self.gen_type_def(); let impl_def = self.gen_impl_def(); - let t = quote! { + quote! { #type_def #impl_def - }; - - println!("index gen {}", t); - t + } } /// Generates table's secondary index struct definition. It has fields with index names and types varying on index @@ -43,14 +42,12 @@ impl Generator { }) .collect::>(); - let t = quote! { + quote! { #[derive(Debug, Default, PersistIndex)] pub struct #ident { #(#index_rows),* } - }; - println!("{}", t); - t + } } /// Generates implementation of `TableIndex` trait for index. @@ -63,16 +60,13 @@ impl Generator { let delete_row_fn = self.gen_delete_row_index_fn(); let process_differences_row_fn = self.gen_process_difference_index_fn(); - let t = quote! { + quote! { impl TableSecondaryIndex<#row_type_ident, AvailableTypes> for #index_type_ident { #save_row_fn #delete_row_fn #process_differences_row_fn } - }; - println!("{}", t); - - t + } } /// Generates `save_row` function of `TableIndex` trait for index. It saves `Link` to all secondary indexes. Logic @@ -108,14 +102,12 @@ impl Generator { }) .collect::>(); - let t = quote! { + quote! { fn save_row(&self, row: #row_type_ident, link: Link) -> core::result::Result<(), WorkTableError> { #(#save_rows)* core::result::Result::Ok(()) } - }; - println!("SAVE_RoOWS {}", t.to_string()); - t + } } /// Generates `delete_row` function of `TableIndex` trait for index. It removes `Link` from all secondary indexes. @@ -145,71 +137,83 @@ impl Generator { }) .collect::>(); - let t = quote! { + quote! { fn delete_row(&self, row: #row_type_ident, link: Link) -> core::result::Result<(), WorkTableError> { #(#delete_rows)* core::result::Result::Ok(()) } - }; - println!("deelete {}", t.to_string()); - t + } } fn gen_process_difference_index_fn(&self) -> TokenStream { - let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string()); - let row_type_ident = name_generator.get_row_type_ident(); - + let process_difference_rows = self .columns .indexes .iter() .map(|(i, idx)| { let index_field_name = &idx.name; + let diff_key = Ident::new(&format!("{}", i), Span::mixed_site()); + + let match_arms: Vec<_> = self + .columns + .columns_map + .get(&idx.field) + .map(|t| { + let type_str = t.to_string(); + let variant_ident = + Ident::new(&type_str.to_uppercase(), Span::mixed_site()); + + let value_expr = if type_str == "String" { + quote! { new.to_string() } + } else { + quote! { *new } + }; + + quote! { + if let Some(diff) = difference.get(stringify!(#diff_key)) { + match &diff.old { + AvailableTypes::#variant_ident(old) => { + if let Some(set) = TableIndex::peek(&self.#index_field_name, old) { + set.remove(&link); + } + } + _ => {} + } + + match &diff.new { + AvailableTypes::#variant_ident(new) => { + let key_new = #value_expr; + + if let Some(set) = TableIndex::peek(&self.#index_field_name, new) { + set.insert(link).expect("is ok"); + } else { + let set = LockFreeSet::new(); + set.insert(link).expect("`Link` should not be already in set"); + TableIndex::insert(&self.#index_field_name, key_new, std::sync::Arc::new(set)) + .map_err(|_| WorkTableError::AlreadyExists)?; + } + } + _ => {} + } + } + } + }) + .into_iter() + .collect(); - if idx.is_unique { - quote! { - - println!("Should be implemented"); - - } - } else { - quote! { - - let diff = difference.get(stringify!(#i)).expect("Ok"); - - println!("AA{:?}", stringify!(#row_type_ident.#i)); - - println!("DIFF PROCESA {:?}", diff); - // let old: #row_type_ident.#i = diff.into(); - // - // println!("ROOW {:?}, Diff {:?}", row_type_ident, old); - // - // if let Some(set) = TableIndex::peek(&self.#index_field_name, &diff.old) { - // set.remove(&link); - // } - // - // if let Some(set) = TableIndex::peek(&self.#index_field_name, &diff.new) { - // set.insert(link).expect("is ok"); - // } else { - // let set = LockFreeSet::new(); - // set.insert(link).expect("`Link` should not be already in set"); - // TableIndex::insert(&self.#index_field_name, &diff.new, std::sync::Arc::new(set)) - // .map_err(|_| WorkTableError::AlreadyExists)?; - // } - } + quote! { + #(#match_arms)* } }) .collect::>(); - let t = quote! { + quote! { fn process_difference(&self, link: Link, difference: HashMap<&str, Difference>) -> core::result::Result<(), WorkTableError> { #(#process_difference_rows)* core::result::Result::Ok(()) } - }; - - println!("PROCESS_DIIF {}", t.to_string()); - t + } } } diff --git a/codegen/src/worktable/generator/queries/locks.rs b/codegen/src/worktable/generator/queries/locks.rs index d6dcca2c..fd0ac853 100644 --- a/codegen/src/worktable/generator/queries/locks.rs +++ b/codegen/src/worktable/generator/queries/locks.rs @@ -128,13 +128,11 @@ impl Generator { }) .collect::>(); - let t = quote! { + Ok(quote! { impl #archived_wrapper { #(#fns)* } - }; - println!("Wrapper {}", t.to_string()); - Ok(t) + }) } else { Ok(quote! {}) } diff --git a/codegen/src/worktable/generator/queries/type.rs b/codegen/src/worktable/generator/queries/type.rs index fd13d2c0..3ecdce54 100644 --- a/codegen/src/worktable/generator/queries/type.rs +++ b/codegen/src/worktable/generator/queries/type.rs @@ -30,7 +30,7 @@ impl Generator { let type_ident = Ident::new(format!("AvailableTypes").as_str(), Span::mixed_site()); let defs = Ok::<_, syn::Error>(quote! { - #[derive(rkyv::Archive, Debug, rkyv::Deserialize, Clone, rkyv::Serialize)] + #[derive(rkyv::Archive, Debug, derive_more::Display, rkyv::Deserialize, Clone, rkyv::Serialize)] #[derive(From, PartialEq)] pub enum #type_ident { #(#rows)* @@ -43,20 +43,8 @@ impl Generator { } } - - //impl From for #type_ident { - // fn from(s: rkyv::string::ArchivedString) -> Self { - // #type_ident::STRING(s.to_string()) - // } - // } - - - }); - - let t = defs?; - println!("AvT {}", t.to_string()); - Ok(t) + defs } pub fn gen_result_types_def(&mut self) -> syn::Result { diff --git a/codegen/src/worktable/generator/queries/update.rs b/codegen/src/worktable/generator/queries/update.rs index 325b94be..29f48094 100644 --- a/codegen/src/worktable/generator/queries/update.rs +++ b/codegen/src/worktable/generator/queries/update.rs @@ -171,7 +171,7 @@ impl Generator { .map(|i| { quote! { - let old: AvailableTypes = row_old.#i.into(); + let old: AvailableTypes = row_old.clone().#i.into(); let new: AvailableTypes = row_new.#i.into(); let diff = Difference { @@ -184,9 +184,8 @@ impl Generator { }) .collect::>(); - let t = quote! { + quote! { pub async fn #method_ident(&self, row: #query_ident, by: #pk_ident) -> core::result::Result<(), WorkTableError> { - println!("Row {:?}", row); let op_id = self.0.lock_map.next_id(); let lock = std::sync::Arc::new(Lock::new()); @@ -198,10 +197,6 @@ impl Generator { #(#diff)* - println!("diffs {:?}",diffs ); - - - let mut bytes = rkyv::to_bytes::(&row).map_err(|_| WorkTableError::SerializeError)?; let mut row = unsafe { rkyv::access_unchecked_mut::<<#query_ident as rkyv::Archive>::Archived>(&mut bytes[..]).unseal_unchecked() }; @@ -210,6 +205,7 @@ impl Generator { TableIndex::peek(&self.0.pk_map, &by).ok_or(WorkTableError::NotFound)? }; + self.0.indexes.process_difference(link, diffs)?; let id = self.0.data.with_ref(link, |archived| { @@ -242,9 +238,7 @@ impl Generator { core::result::Result::Ok(()) } - }; - println!("{}", t.to_string()); - t + } } fn gen_non_unique_update( diff --git a/codegen/src/worktable/generator/table/impls.rs b/codegen/src/worktable/generator/table/impls.rs index 23bf5612..6314eaed 100644 --- a/codegen/src/worktable/generator/table/impls.rs +++ b/codegen/src/worktable/generator/table/impls.rs @@ -19,7 +19,7 @@ impl Generator { let iter_with_fn = self.gen_table_iter_with_fn(); let iter_with_async_fn = self.gen_table_iter_with_async_fn(); - let t = quote! { + quote! { impl #ident { #new_fn #name_fn @@ -30,10 +30,7 @@ impl Generator { #iter_with_fn #iter_with_async_fn } - }; - - // println!("TAABLE {}", t.to_string()); - t + } } fn gen_table_new_fn(&self) -> TokenStream { @@ -41,15 +38,13 @@ impl Generator { let table_name = name_generator.get_work_table_literal_name(); if self.is_persist { - let t = quote! { + quote! { pub fn new(manager: std::sync::Arc) -> Self { let mut inner = WorkTable::default(); inner.table_name = #table_name; Self(inner, manager) } - }; - println!("NEW {}", t.to_string()); - t + } } else { quote! {} } @@ -80,14 +75,11 @@ impl Generator { let row_type = name_generator.get_row_type_ident(); let primary_key_type = name_generator.get_primary_key_type_ident(); - let t = quote! { + quote! { pub fn insert(&self, row: #row_type) -> core::result::Result<#primary_key_type, WorkTableError> { self.0.insert(row) } - }; - - println!("INSERTT {}", t.to_string()); - t + } } fn gen_table_upsert_fn(&self) -> TokenStream { let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string()); diff --git a/codegen/src/worktable/generator/table/index_fns.rs b/codegen/src/worktable/generator/table/index_fns.rs index d3e283d5..78b8058b 100644 --- a/codegen/src/worktable/generator/table/index_fns.rs +++ b/codegen/src/worktable/generator/table/index_fns.rs @@ -71,7 +71,7 @@ impl Generator { let fn_name = Ident::new(format!("select_by_{i}").as_str(), Span::mixed_site()); let field_ident = &idx.name; - let t = quote! { + Ok(quote! { pub fn #fn_name(&self, by: #type_) -> core::result::Result, WorkTableError> { let rows = { TableIndex::peek(&self.0.indexes.#field_ident, &by) @@ -85,8 +85,6 @@ impl Generator { .collect::, _>>()?; core::result::Result::Ok(SelectResult::<#row_ident, Self>::new(rows)) } - }; - println!("Index --> {}", t.to_string()); - Ok(t) + }) } } diff --git a/examples/src/main.rs b/examples/src/main.rs index 93675c5c..b8935168 100644 --- a/examples/src/main.rs +++ b/examples/src/main.rs @@ -11,17 +11,17 @@ fn main() { id: u64 primary_key autoincrement, val: i64, attr: String, - attr2: u64, + attr2: i16, }, indexes: { - attr_idx: attr2, - attr2_idx: attr, + idx1: attr, + idx2: attr2, }, queries: { update: { ValByAttr(val) by attr, - // AttrById(attr) by id, + // AttrById(attr) by id, // Attr2ById(attr2) by id, AllAttrById(attr, attr2) by id, }, @@ -43,32 +43,32 @@ fn main() { id: 0, }; - // let row1 = MyRow { - // val: 2, - // attr: "TEST2".to_string(), - // attr2: "EST".to_string(), - // id: 1, - // }; - // - // let row2 = MyRow { - // val: 1337, - // attr: "TEST2".to_string(), - // attr2: "EST".to_string(), - // id: 2, - // }; - // - // let row3 = MyRow { - // val: 555, - // attr: "TEST3".to_string(), - // attr2: "EST".to_string(), - // id: 3, - // }; + let row1 = MyRow { + val: 2, + attr: "TEST2".to_string(), + attr2: 123, + id: 1, + }; + + let row2 = MyRow { + val: 1337, + attr: "TEST2".to_string(), + attr2: 345, + id: 2, + }; + + let row3 = MyRow { + val: 555, + attr: "TEST3".to_string(), + attr2: 123, + id: 3, + }; // insert let _ = my_table.insert(row); - //let _ = my_table.insert(row1); - //let _ = my_table.insert(row2); - //let _ = my_table.insert(row3); + let _ = my_table.insert(row1); + let _ = my_table.insert(row2); + let _ = my_table.insert(row3); // Select ALL records from WT let select_all = my_table.select_all().execute(); @@ -128,8 +128,8 @@ fn main() { // "Select After Val Update by Attribute: {:?}", // select_all_after_update.execute() // ); - // let test_delete = my_table.delete_by_attr("TEST2".to_string()); - // let _ = task::block_on(test_delete); + let test_delete = my_table.delete_by_attr("TEST2".to_string()); + let _ = task::block_on(test_delete); // // // let select_by_attr = my_table.select_by_attr("TEST2".to_string()); // println!( @@ -145,18 +145,27 @@ fn main() { let all_update = my_table.update_all_attr_by_id( AllAttrByIdQuery { - attr: "OK".to_string(), + attr: "test".to_string(), attr2: 1337, }, MyPrimaryKey(0), ); let _ = task::block_on(all_update); - let select_by_attr = my_table.select_by_attr("TEST".to_string()); + // let select_by_attr = my_table.select_by_attr("test".to_string()); + // println!( + // "Select by Attribute 222 after del: {:?}", + // select_by_attr.unwrap().vals + // ); + // + println!("Select ALL {:?}", my_table.select_all().execute()); + + let select_by_attr = my_table.select_by_attr("test".to_string()); + println!("Select by Attribute OK: {:?}", select_by_attr.unwrap().vals); + + let select_by_attr2 = my_table.select_by_attr2(1337); println!( - "Select by Attribute TEST after del: {:?}", - select_by_attr.unwrap().vals + "Select by Attribute 1337: {:?}", + select_by_attr2.unwrap().vals ); - - println!("Select ALL {:?}", my_table.select_all().execute()); } From 79d74c8bfce175317d8ce50f966f51c078289b49 Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Sat, 8 Feb 2025 02:03:32 +0300 Subject: [PATCH 10/16] WIP --- codegen/src/name_generator.rs | 7 ++ codegen/src/worktable/generator/index.rs | 11 +- .../src/worktable/generator/queries/type.rs | 49 ++++++-- .../src/worktable/generator/queries/update.rs | 79 ++++++++++--- codegen/src/worktable/generator/table/mod.rs | 5 +- codegen/src/worktable/mod.rs | 10 +- examples/src/main.rs | 105 +++++++++--------- tests/worktable/index.rs | 90 +++++++++++---- tests/worktable/mod.rs | 1 + 9 files changed, 244 insertions(+), 113 deletions(-) diff --git a/codegen/src/name_generator.rs b/codegen/src/name_generator.rs index 61c642d8..cdc3fe96 100644 --- a/codegen/src/name_generator.rs +++ b/codegen/src/name_generator.rs @@ -29,6 +29,13 @@ impl WorktableNameGenerator { Ident::new(format!("{}Row", self.name).as_str(), Span::mixed_site()) } + pub fn get_available_type_ident(&self) -> Ident { + Ident::new( + format!("{}AvaiableTypes", self.name).as_str(), + Span::mixed_site(), + ) + } + pub fn get_work_table_ident(&self) -> Ident { Ident::new( format!("{}WorkTable", self.name).as_str(), diff --git a/codegen/src/worktable/generator/index.rs b/codegen/src/worktable/generator/index.rs index 57ef9165..b630c405 100644 --- a/codegen/src/worktable/generator/index.rs +++ b/codegen/src/worktable/generator/index.rs @@ -59,9 +59,10 @@ impl Generator { let save_row_fn = self.gen_save_row_index_fn(); let delete_row_fn = self.gen_delete_row_index_fn(); let process_differences_row_fn = self.gen_process_difference_index_fn(); + let avt_type_ident = name_generator.get_available_type_ident(); quote! { - impl TableSecondaryIndex<#row_type_ident, AvailableTypes> for #index_type_ident { + impl TableSecondaryIndex<#row_type_ident, #avt_type_ident> for #index_type_ident { #save_row_fn #delete_row_fn #process_differences_row_fn @@ -146,6 +147,8 @@ impl Generator { } fn gen_process_difference_index_fn(&self) -> TokenStream { + let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string()); + let avt_type_ident = name_generator.get_available_type_ident(); let process_difference_rows = self .columns @@ -173,7 +176,7 @@ impl Generator { quote! { if let Some(diff) = difference.get(stringify!(#diff_key)) { match &diff.old { - AvailableTypes::#variant_ident(old) => { + #avt_type_ident::#variant_ident(old) => { if let Some(set) = TableIndex::peek(&self.#index_field_name, old) { set.remove(&link); } @@ -182,7 +185,7 @@ impl Generator { } match &diff.new { - AvailableTypes::#variant_ident(new) => { + #avt_type_ident::#variant_ident(new) => { let key_new = #value_expr; if let Some(set) = TableIndex::peek(&self.#index_field_name, new) { @@ -209,7 +212,7 @@ impl Generator { .collect::>(); quote! { - fn process_difference(&self, link: Link, difference: HashMap<&str, Difference>) -> core::result::Result<(), WorkTableError> { + fn process_difference(&self, link: Link, difference: HashMap<&str, Difference<#avt_type_ident>>) -> core::result::Result<(), WorkTableError> { #(#process_difference_rows)* core::result::Result::Ok(()) } diff --git a/codegen/src/worktable/generator/queries/type.rs b/codegen/src/worktable/generator/queries/type.rs index 3ecdce54..9954d6df 100644 --- a/codegen/src/worktable/generator/queries/type.rs +++ b/codegen/src/worktable/generator/queries/type.rs @@ -2,11 +2,15 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; use std::collections::HashSet; +use crate::name_generator::WorktableNameGenerator; use crate::worktable::generator::Generator; impl Generator { pub fn gen_available_types_def(&mut self) -> syn::Result { - let rows: Vec<_> = self + let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string()); + let avt_type_ident = name_generator.get_available_type_ident(); + + let types: Vec<_> = self .columns .indexes .iter() @@ -18,33 +22,56 @@ impl Generator { .into_iter() .map(|t| { let type_ = Ident::new(&t.to_string(), Span::mixed_site()); - let type_upper = Ident::new(&t.to_string().to_uppercase(), Span::mixed_site()); + Ok::<_, syn::Error>(quote! { + #type_ + }) + }) + .collect::, _>>()?; + let types = if types.is_empty() { + vec![quote! {String}] + } else { + types + }; + + let rows = types + .iter() + .map(|t| { + let type_upper = Ident::new(&t.to_string().to_uppercase(), Span::mixed_site()); Ok::<_, syn::Error>(quote! { #[from] - #type_upper(#type_), + #type_upper(#t) }) }) .collect::, _>>()?; - let type_ident = Ident::new(format!("AvailableTypes").as_str(), Span::mixed_site()); + let default_variant = if types.iter().any(|r| r.to_string().contains("String")) { + quote! { #avt_type_ident::STRING(String::default()) } + } else if let Some(first_variant) = types.first() { + let type_upper = Ident::new( + &first_variant.to_string().to_uppercase(), + Span::mixed_site(), + ); + quote! { #avt_type_ident::#type_upper(Default::default()) } + } else { + quote! {} + }; - let defs = Ok::<_, syn::Error>(quote! { + Ok::<_, syn::Error>(quote! { #[derive(rkyv::Archive, Debug, derive_more::Display, rkyv::Deserialize, Clone, rkyv::Serialize)] #[derive(From, PartialEq)] - pub enum #type_ident { - #(#rows)* + pub enum #avt_type_ident { + #(#rows),* } - impl Default for #type_ident { + impl Default for #avt_type_ident { fn default() -> Self { - #type_ident::STRING(String::default()) + #default_variant } } - }); - defs + }) } pub fn gen_result_types_def(&mut self) -> syn::Result { diff --git a/codegen/src/worktable/generator/queries/update.rs b/codegen/src/worktable/generator/queries/update.rs index 29f48094..525740ee 100644 --- a/codegen/src/worktable/generator/queries/update.rs +++ b/codegen/src/worktable/generator/queries/update.rs @@ -95,6 +95,22 @@ impl Generator { .values() .find(|idx| idx.field.to_string() == op.by.to_string()); + let indexes_columns: Option> = { + let columns: Vec<_> = self + .columns + .indexes + .values() + .filter(|idx| op.columns.contains(&idx.field)) + .map(|idx| idx.field.clone()) + .collect(); + + if columns.is_empty() { + None + } else { + Some(columns) + } + }; + let idents = &op.columns; if let Some(index) = index { @@ -110,7 +126,12 @@ impl Generator { if self.columns.primary_keys.0.first().unwrap().to_string() == op.by.to_string() { - self.gen_pk_update(snake_case_name, name, idents) + self.gen_pk_update( + snake_case_name, + name, + idents, + indexes_columns.as_ref(), + ) } else { todo!() } @@ -131,6 +152,7 @@ impl Generator { snake_case_name: String, name: &Ident, idents: &Vec, + idx_idents: Option<&Vec>, ) -> TokenStream { let pk_ident = &self.pk.as_ref().unwrap().ident; let method_ident = Ident::new( @@ -157,6 +179,9 @@ impl Generator { Span::mixed_site(), ); + let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string()); + let avt_type_ident = name_generator.get_available_type_ident(); + let row_updates = idents .iter() .map(|i| { @@ -166,23 +191,42 @@ impl Generator { }) .collect::>(); - let diff = idents - .iter() - .map(|i| { - quote! { + let diff = if let Some(columns) = idx_idents { + idents + .iter() + .filter(|i| columns.contains(i)) + .map(|i| { + quote! { - let old: AvailableTypes = row_old.clone().#i.into(); - let new: AvailableTypes = row_new.#i.into(); + let old: #avt_type_ident = row_old.clone().#i.into(); + let new: #avt_type_ident = row_new.#i.into(); - let diff = Difference { - old: old.clone(), - new: new.clone(), - }; + let diff = Difference { + old: old.clone(), + new: new.clone(), + }; - diffs.insert(stringify!(#i), diff); - } - }) - .collect::>(); + diffs.insert(stringify!(#i), diff); + } + }) + .collect::>() + } else { + vec![] + }; + + let diff_container_ident = if !diff.is_empty() { + quote! {let mut diffs: HashMap<&str, Difference<#avt_type_ident>> = HashMap::new();} + } else { + quote! {} + }; + + let process_diff_ident = if !diff.is_empty() { + quote! { + self.0.indexes.process_difference(link, diffs)?; + } + } else { + quote! {} + }; quote! { pub async fn #method_ident(&self, row: #query_ident, by: #pk_ident) -> core::result::Result<(), WorkTableError> { @@ -193,8 +237,8 @@ impl Generator { let row_old = self.select(by.clone()).unwrap(); let row_new = row.clone(); - let mut diffs: HashMap<&str, Difference> = HashMap::new(); + #diff_container_ident #(#diff)* let mut bytes = rkyv::to_bytes::(&row).map_err(|_| WorkTableError::SerializeError)?; @@ -205,8 +249,7 @@ impl Generator { TableIndex::peek(&self.0.pk_map, &by).ok_or(WorkTableError::NotFound)? }; - - self.0.indexes.process_difference(link, diffs)?; + #process_diff_ident let id = self.0.data.with_ref(link, |archived| { archived.#check_ident() diff --git a/codegen/src/worktable/generator/table/mod.rs b/codegen/src/worktable/generator/table/mod.rs index 2384475f..17f0c99b 100644 --- a/codegen/src/worktable/generator/table/mod.rs +++ b/codegen/src/worktable/generator/table/mod.rs @@ -57,6 +57,7 @@ impl Generator { let primary_index_type = &self.columns.primary_keys.1; let index_type = name_generator.get_index_type_ident(); let inner_const_name = name_generator.get_page_inner_size_const_ident(); + let avt_type_ident = name_generator.get_available_type_ident(); let derive = if self.is_persist { quote! { @@ -83,7 +84,7 @@ impl Generator { #row_type, #primary_key_type, #primary_index_type<#primary_key_type, Link>, - AvailableTypes, + #avt_type_ident, #index_type, <#primary_key_type as TablePrimaryKey>::Generator, #inner_const_name @@ -99,7 +100,7 @@ impl Generator { #row_type, #primary_key_type, #primary_index_type<#primary_key_type, Link>, - AvailableTypes, + #avt_type_ident, #index_type > #persist_type_part diff --git a/codegen/src/worktable/mod.rs b/codegen/src/worktable/mod.rs index c9ca0536..344932b5 100644 --- a/codegen/src/worktable/mod.rs +++ b/codegen/src/worktable/mod.rs @@ -59,7 +59,9 @@ pub fn expand(input: TokenStream) -> syn::Result { let update_impls = generator.gen_query_update_impl()?; let delete_impls = generator.gen_query_delete_impl()?; - let t = TokenStream::from(quote! { + println!("{}", query_available_def.to_string()); + + Ok(TokenStream::from(quote! { #pk_def #row_def #query_available_def @@ -71,11 +73,7 @@ pub fn expand(input: TokenStream) -> syn::Result { #select_impls #update_impls #delete_impls - }); - - // println!("MAIN {}", t.to_string()); - - Ok(t) + })) } #[cfg(test)] diff --git a/examples/src/main.rs b/examples/src/main.rs index b8935168..4ea2ff87 100644 --- a/examples/src/main.rs +++ b/examples/src/main.rs @@ -10,6 +10,7 @@ fn main() { columns: { id: u64 primary_key autoincrement, val: i64, + test: u8 optional, attr: String, attr2: i16, @@ -20,13 +21,14 @@ fn main() { }, queries: { update: { - ValByAttr(val) by attr, + ValById(val) by id, // AttrById(attr) by id, // Attr2ById(attr2) by id, - AllAttrById(attr, attr2) by id, + // AllAttrById(attr, attr2) by id, + // UpdateOptionalById(test) by id, }, delete: { - ByAttr() by attr, + // ByAttr() by attr, ById() by id, } } @@ -40,35 +42,36 @@ fn main() { val: 777, attr: "TEST".to_string(), attr2: 345, + test: Some(1), id: 0, }; - let row1 = MyRow { - val: 2, - attr: "TEST2".to_string(), - attr2: 123, - id: 1, - }; - - let row2 = MyRow { - val: 1337, - attr: "TEST2".to_string(), - attr2: 345, - id: 2, - }; - - let row3 = MyRow { - val: 555, - attr: "TEST3".to_string(), - attr2: 123, - id: 3, - }; + //let row1 = MyRow { + // val: 2, + // attr: "TEST2".to_string(), + // attr2: 123, + // id: 1, + //}; + // + //let row2 = MyRow { + // val: 1337, + // attr: "TEST2".to_string(), + // attr2: 345, + // id: 2, + //}; + // + //let row3 = MyRow { + // val: 555, + // attr: "TEST3".to_string(), + // attr2: 123, + // id: 3, + //}; // insert let _ = my_table.insert(row); - let _ = my_table.insert(row1); - let _ = my_table.insert(row2); - let _ = my_table.insert(row3); + // let _ = my_table.insert(row1); + // let _ = my_table.insert(row2); + // let _ = my_table.insert(row3); // Select ALL records from WT let select_all = my_table.select_all().execute(); @@ -128,8 +131,8 @@ fn main() { // "Select After Val Update by Attribute: {:?}", // select_all_after_update.execute() // ); - let test_delete = my_table.delete_by_attr("TEST2".to_string()); - let _ = task::block_on(test_delete); + // let test_delete = my_table.delete_by_attr("TEST2".to_string()); + //let _ = task::block_on(test_delete); // // // let select_by_attr = my_table.select_by_attr("TEST2".to_string()); // println!( @@ -143,29 +146,31 @@ fn main() { // select_by_attr.unwrap().vals // ); - let all_update = my_table.update_all_attr_by_id( - AllAttrByIdQuery { - attr: "test".to_string(), - attr2: 1337, - }, - MyPrimaryKey(0), - ); - let _ = task::block_on(all_update); + //let all_update = my_table.update_all_attr_by_id( + // AllAttrByIdQuery { + // attr: "test".to_string(), + // attr2: 1337, + // }, + // MyPrimaryKey(0), + //); + //let _ = task::block_on(all_update); - // let select_by_attr = my_table.select_by_attr("test".to_string()); - // println!( - // "Select by Attribute 222 after del: {:?}", - // select_by_attr.unwrap().vals - // ); - // - println!("Select ALL {:?}", my_table.select_all().execute()); + // let select_by_attr = my_table.select_by_attr("test".to_string()); + // println!( + // "Select by Attribute 222 after del: {:?}", + // select_by_attr.unwrap().vals + // ); + // println!("Select ALL {:?}", my_table.select_all().execute()); - let select_by_attr = my_table.select_by_attr("test".to_string()); - println!("Select by Attribute OK: {:?}", select_by_attr.unwrap().vals); + //let select_by_attr = my_table.select_by_attr("test".to_string()); + //println!( + // "Select by Attribute test: {:?}", + // select_by_attr.unwrap().vals + //); - let select_by_attr2 = my_table.select_by_attr2(1337); - println!( - "Select by Attribute 1337: {:?}", - select_by_attr2.unwrap().vals - ); + //let select_by_attr2 = my_table.select_by_attr2(1337); + //println!( + // "Select by Attribute 1337: {:?}", + // select_by_attr2.unwrap().vals + //); } diff --git a/tests/worktable/index.rs b/tests/worktable/index.rs index 4c4dca42..506b2ae1 100644 --- a/tests/worktable/index.rs +++ b/tests/worktable/index.rs @@ -1,29 +1,75 @@ - +use crate::worktable::index::WorkTableError::NotFound; use std::collections::HashMap; use worktable::prelude::*; use worktable::worktable; -fn main() { - worktable!( - name: Test, - columns: { - id: u64 primary_key autoincrement, - val: i64, - attr: String, - }, - indexes: { - attr_idx: attr2, - attr2_idx: attr, +worktable!( + name: Test, + columns: { + id: u64 primary_key autoincrement, + val: i64, + attr1: String, + attr2: i16, + }, + indexes: { + idx1: attr1, + idx2: attr2, + }, + queries: { + update: { + ValByAttr(val) by attr1, + AttrById(attr1) by id, + Attr2ById(attr2) by id, + AllAttrById(attr1, attr2) by id, }, - queries: { - update: { - ValByAttr(val) by attr, - // AttrById(attr) by id, - // Attr2ById(attr2) by id, - AllAttrById(attr, attr2) by id, - }, - delete: { - ById() by id, - } + delete: { + ById() by id, } + } +); + +#[tokio::test] +async fn update_index() { + let test_table = TestWorkTable::default(); + + let row = TestRow { + val: 1, + attr1: "TEST".to_string(), + attr2: 1000, + id: 0, + }; + let pk = test_table.insert(row.clone()).unwrap(); + let _all_update = test_table.update_all_attr_by_id( + AllAttrByIdQuery { + attr1: "TEST2".to_string(), + attr2: 1337, + }, + pk.clone(), ); + + let updated = test_table.select(pk).unwrap(); + assert_eq!(updated, row); + + let binding = test_table.select_by_attr2(1337).unwrap(); + let found = binding.vals.first().unwrap(); + assert_eq!(found, &updated); + + //let found = test_table + // .select_by_attr1("TEST2".to_string()) + // .unwrap() + // .vals + // .first() + // .unwrap(); + //assert_eq!(found, &updated); + // + //let not_found = test_table + // .select_by_attr2(1000) + // .unwrap() + // .vals + // .first() + // .unwrap(); + //assert_eq!(not_found, &updated); + + // let not_found = test_table.select_by_attr2(1000); + // assert_eq!(not_found, NotFound); +} diff --git a/tests/worktable/mod.rs b/tests/worktable/mod.rs index a982d05a..df37f676 100644 --- a/tests/worktable/mod.rs +++ b/tests/worktable/mod.rs @@ -2,6 +2,7 @@ mod array; mod base; mod config; mod custom_pk; +mod index; mod index_type; mod option; mod tuple_primary_key; From 12abfce487354b08059321dbf30d368ea34b212b Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Sat, 8 Feb 2025 02:24:01 +0300 Subject: [PATCH 11/16] WIP --- codegen/src/worktable/generator/index.rs | 2 +- .../src/worktable/generator/queries/update.rs | 2 +- examples/src/main.rs | 116 +++--------------- 3 files changed, 22 insertions(+), 98 deletions(-) diff --git a/codegen/src/worktable/generator/index.rs b/codegen/src/worktable/generator/index.rs index b630c405..e6217efc 100644 --- a/codegen/src/worktable/generator/index.rs +++ b/codegen/src/worktable/generator/index.rs @@ -212,7 +212,7 @@ impl Generator { .collect::>(); quote! { - fn process_difference(&self, link: Link, difference: HashMap<&str, Difference<#avt_type_ident>>) -> core::result::Result<(), WorkTableError> { + fn process_difference(&self, link: Link, difference: std::collections::HashMap<&str, Difference<#avt_type_ident>>) -> core::result::Result<(), WorkTableError> { #(#process_difference_rows)* core::result::Result::Ok(()) } diff --git a/codegen/src/worktable/generator/queries/update.rs b/codegen/src/worktable/generator/queries/update.rs index 525740ee..8bb8fdb3 100644 --- a/codegen/src/worktable/generator/queries/update.rs +++ b/codegen/src/worktable/generator/queries/update.rs @@ -215,7 +215,7 @@ impl Generator { }; let diff_container_ident = if !diff.is_empty() { - quote! {let mut diffs: HashMap<&str, Difference<#avt_type_ident>> = HashMap::new();} + quote! {let mut diffs: std::collections::HashMap<&str, Difference<#avt_type_ident>> = std::collections::HashMap::new();} } else { quote! {} }; diff --git a/examples/src/main.rs b/examples/src/main.rs index 4ea2ff87..569e9953 100644 --- a/examples/src/main.rs +++ b/examples/src/main.rs @@ -1,5 +1,4 @@ use async_std::task; -use std::collections::HashMap; use worktable::prelude::*; use worktable::worktable; @@ -24,7 +23,7 @@ fn main() { ValById(val) by id, // AttrById(attr) by id, // Attr2ById(attr2) by id, - // AllAttrById(attr, attr2) by id, + AllAttrById(attr, attr2) by id, // UpdateOptionalById(test) by id, }, delete: { @@ -77,100 +76,25 @@ fn main() { let select_all = my_table.select_all().execute(); println!("Select All {:?}", select_all); - // Select All records with attribute TEST2 - //let select_by_attr = my_table.select_by_attr("TEST2".to_string()); - //println!( - // "Select by Attribute TEST2: {:?}", - // select_by_attr.unwrap().vals - //); - - //let update_val = my_table.update_all_attr_by_id( - // AllAttrByIdQuery { - // attr: "TEST5".to_string(), - // attr2: 1337, - // }, - // MyPrimaryKey(3), - //); - //let _ = task::block_on(update_val); - - // Update all recrods val by attr TEST2 - // let update_val = my_table.update_val_by_attr(ValByAttrQuery { val: 777 }, "TEST2".to_string()); - // let _ = task::block_on(update_val); - // - // let select_updated = my_table.select_by_attr("TEST2".to_string()); - // println!( - // "Select updated by Attribute TEST2: {:?}", - // select_updated.unwrap().vals - // ); - - // Update attr by ID - //println!("update attr TEST3 -> TEST2"); - // let update_attr = my_table.update_attr_by_id( - // attr: "TEST2".to_string(), - // }, - // MyPrimaryKey(3), - //); - // let _ = task::block_on(update_attr); - - // println!("FINISH update attr TEST3 -> TEST2"); - - // Update attr2 by ID - // println!("update attr2 67 -> 1337"); - // let update_attr = my_table.update_attr_2_by_id(Attr2ByIdQuery { attr2: 1337 }, MyPrimaryKey(3)); - // let _ = task::block_on(update_attr); - - //println!("FINISH update attr2"); - - // Update record attribute TEST2 -> TEST3 with id 1 - //let update_exchange = - // my_table.update_val_by_attr(ValByAttrQuery { val: 7777 }, "TEST2".to_string()); - //let _ = task::block_on(update_exchange); - // - // let select_all_after_update = my_table.select_all(); - // println!( - // "Select After Val Update by Attribute: {:?}", - // select_all_after_update.execute() - // ); - // let test_delete = my_table.delete_by_attr("TEST2".to_string()); - //let _ = task::block_on(test_delete); - // // - // let select_by_attr = my_table.select_by_attr("TEST2".to_string()); - // println!( - // "Select by Attribute TEST2 after del: {:?}", - // select_by_attr.unwrap().vals - // ); - // // - // let select_by_attr = my_table.select_by_attr("TEST3".to_string()); - // println!( - // "Select by Attribute TEST3 after del: {:?}", - // select_by_attr.unwrap().vals - // ); - - //let all_update = my_table.update_all_attr_by_id( - // AllAttrByIdQuery { - // attr: "test".to_string(), - // attr2: 1337, - // }, - // MyPrimaryKey(0), - //); - //let _ = task::block_on(all_update); - - // let select_by_attr = my_table.select_by_attr("test".to_string()); - // println!( - // "Select by Attribute 222 after del: {:?}", - // select_by_attr.unwrap().vals - // ); - // println!("Select ALL {:?}", my_table.select_all().execute()); + // Select All records with attribute TEST + let select_by_attr = my_table.select_by_attr("TEST".to_string()); + println!( + "Select by Attribute TEST: {:?}", + select_by_attr.unwrap().vals + ); - //let select_by_attr = my_table.select_by_attr("test".to_string()); - //println!( - // "Select by Attribute test: {:?}", - // select_by_attr.unwrap().vals - //); + let update_val = my_table.update_all_attr_by_id( + AllAttrByIdQuery { + attr: "TEST5".to_string(), + attr2: 1337, + }, + MyPrimaryKey(0), + ); + let _ = task::block_on(update_val); - //let select_by_attr2 = my_table.select_by_attr2(1337); - //println!( - // "Select by Attribute 1337: {:?}", - // select_by_attr2.unwrap().vals - //); + let select_by_attr2 = my_table.select_by_attr2(1337); + println!( + "Select by Attribute 1337: {:?}", + select_by_attr2.unwrap().vals + ); } From 92d6167f7f1d45a58e1d142c86faabf9b42615c2 Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Mon, 10 Feb 2025 03:32:35 +0300 Subject: [PATCH 12/16] WIP megre --- codegen/src/worktable/generator/index.rs | 10 ++-- .../src/worktable/generator/queries/type.rs | 49 ++++--------------- .../src/worktable/generator/queries/update.rs | 4 +- codegen/src/worktable/mod.rs | 2 - examples/src/main.rs | 42 ++++++++-------- src/table/mod.rs | 7 ++- 6 files changed, 42 insertions(+), 72 deletions(-) diff --git a/codegen/src/worktable/generator/index.rs b/codegen/src/worktable/generator/index.rs index e6217efc..e14b3138 100644 --- a/codegen/src/worktable/generator/index.rs +++ b/codegen/src/worktable/generator/index.rs @@ -1,6 +1,7 @@ use crate::name_generator::WorktableNameGenerator; use crate::worktable::generator::Generator; +use proc_macro2::Literal; use proc_macro2::TokenStream; use proc_macro2::{Ident, Span}; @@ -60,7 +61,7 @@ impl Generator { let delete_row_fn = self.gen_delete_row_index_fn(); let process_differences_row_fn = self.gen_process_difference_index_fn(); let avt_type_ident = name_generator.get_available_type_ident(); - + quote! { impl TableSecondaryIndex<#row_type_ident, #avt_type_ident> for #index_type_ident { #save_row_fn @@ -156,7 +157,7 @@ impl Generator { .iter() .map(|(i, idx)| { let index_field_name = &idx.name; - let diff_key = Ident::new(&format!("{}", i), Span::mixed_site()); + let diff_key = Literal::string(i.to_string().as_str()); let match_arms: Vec<_> = self .columns @@ -164,8 +165,7 @@ impl Generator { .get(&idx.field) .map(|t| { let type_str = t.to_string(); - let variant_ident = - Ident::new(&type_str.to_uppercase(), Span::mixed_site()); + let variant_ident = Ident::new(&type_str.to_uppercase(), Span::mixed_site()); let value_expr = if type_str == "String" { quote! { new.to_string() } @@ -174,7 +174,7 @@ impl Generator { }; quote! { - if let Some(diff) = difference.get(stringify!(#diff_key)) { + if let Some(diff) = difference.get(#diff_key) { match &diff.old { #avt_type_ident::#variant_ident(old) => { if let Some(set) = TableIndex::peek(&self.#index_field_name, old) { diff --git a/codegen/src/worktable/generator/queries/type.rs b/codegen/src/worktable/generator/queries/type.rs index 9954d6df..765543dc 100644 --- a/codegen/src/worktable/generator/queries/type.rs +++ b/codegen/src/worktable/generator/queries/type.rs @@ -10,7 +10,13 @@ impl Generator { let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string()); let avt_type_ident = name_generator.get_available_type_ident(); - let types: Vec<_> = self + if self.columns.indexes.is_empty() { + return Ok(quote! { + type #avt_type_ident = (); + }); + } + + let rows: Vec<_> = self .columns .indexes .iter() @@ -22,54 +28,19 @@ impl Generator { .into_iter() .map(|t| { let type_ = Ident::new(&t.to_string(), Span::mixed_site()); - Ok::<_, syn::Error>(quote! { - #type_ - }) - }) - .collect::, _>>()?; - - let types = if types.is_empty() { - vec![quote! {String}] - } else { - types - }; - - let rows = types - .iter() - .map(|t| { let type_upper = Ident::new(&t.to_string().to_uppercase(), Span::mixed_site()); Ok::<_, syn::Error>(quote! { - #[from] - #type_upper(#t) + #[from] + #type_upper(#type_), }) }) .collect::, _>>()?; - let default_variant = if types.iter().any(|r| r.to_string().contains("String")) { - quote! { #avt_type_ident::STRING(String::default()) } - } else if let Some(first_variant) = types.first() { - let type_upper = Ident::new( - &first_variant.to_string().to_uppercase(), - Span::mixed_site(), - ); - quote! { #avt_type_ident::#type_upper(Default::default()) } - } else { - quote! {} - }; - Ok::<_, syn::Error>(quote! { #[derive(rkyv::Archive, Debug, derive_more::Display, rkyv::Deserialize, Clone, rkyv::Serialize)] #[derive(From, PartialEq)] pub enum #avt_type_ident { - #(#rows),* - } - - impl Default for #avt_type_ident { - fn default() -> Self { - - #default_variant - - } + #(#rows)* } }) } diff --git a/codegen/src/worktable/generator/queries/update.rs b/codegen/src/worktable/generator/queries/update.rs index 8bb8fdb3..ee247370 100644 --- a/codegen/src/worktable/generator/queries/update.rs +++ b/codegen/src/worktable/generator/queries/update.rs @@ -1,3 +1,4 @@ +use proc_macro2::Literal; use std::collections::HashMap; use crate::name_generator::WorktableNameGenerator; @@ -196,6 +197,7 @@ impl Generator { .iter() .filter(|i| columns.contains(i)) .map(|i| { + let diff_key = Literal::string(i.to_string().as_str()); quote! { let old: #avt_type_ident = row_old.clone().#i.into(); @@ -206,7 +208,7 @@ impl Generator { new: new.clone(), }; - diffs.insert(stringify!(#i), diff); + diffs.insert(#diff_key, diff); } }) .collect::>() diff --git a/codegen/src/worktable/mod.rs b/codegen/src/worktable/mod.rs index 344932b5..0f82964b 100644 --- a/codegen/src/worktable/mod.rs +++ b/codegen/src/worktable/mod.rs @@ -59,8 +59,6 @@ pub fn expand(input: TokenStream) -> syn::Result { let update_impls = generator.gen_query_update_impl()?; let delete_impls = generator.gen_query_delete_impl()?; - println!("{}", query_available_def.to_string()); - Ok(TokenStream::from(quote! { #pk_def #row_def diff --git a/examples/src/main.rs b/examples/src/main.rs index 569e9953..024e6a5d 100644 --- a/examples/src/main.rs +++ b/examples/src/main.rs @@ -24,7 +24,7 @@ fn main() { // AttrById(attr) by id, // Attr2ById(attr2) by id, AllAttrById(attr, attr2) by id, - // UpdateOptionalById(test) by id, + UpdateOptionalById(test) by id, }, delete: { // ByAttr() by attr, @@ -77,24 +77,24 @@ fn main() { println!("Select All {:?}", select_all); // Select All records with attribute TEST - let select_by_attr = my_table.select_by_attr("TEST".to_string()); - println!( - "Select by Attribute TEST: {:?}", - select_by_attr.unwrap().vals - ); - - let update_val = my_table.update_all_attr_by_id( - AllAttrByIdQuery { - attr: "TEST5".to_string(), - attr2: 1337, - }, - MyPrimaryKey(0), - ); - let _ = task::block_on(update_val); - - let select_by_attr2 = my_table.select_by_attr2(1337); - println!( - "Select by Attribute 1337: {:?}", - select_by_attr2.unwrap().vals - ); + // let select_by_attr = my_table.select_by_attr("TEST".to_string()); + // println!( + // "Select by Attribute TEST: {:?}", + // select_by_attr.unwrap().vals + // ); + // + // let update_val = my_table.update_all_attr_by_id( + // AllAttrByIdQuery { + // attr: "TEST5".to_string(), + // attr2: 1337, + // }, + // MyPrimaryKey(0), + // ); + // let _ = task::block_on(update_val); + // + // let select_by_attr2 = my_table.select_by_attr2(1337); + // println!( + // "Select by Attribute 1337: {:?}", + // select_by_attr2.unwrap().vals + // ); } diff --git a/src/table/mod.rs b/src/table/mod.rs index e064fc5d..a4c64b87 100644 --- a/src/table/mod.rs +++ b/src/table/mod.rs @@ -22,7 +22,7 @@ pub struct WorkTable< Row, PrimaryKey, IndexType, - AvailableTypes, + AvailableTypes = (), SecondaryIndexes = (), PkGen = ::Generator, const DATA_LENGTH: usize = INNER_PAGE_SIZE, @@ -45,7 +45,7 @@ pub struct WorkTable< pub pk_phantom: PhantomData, - pub available_types_phantom: PhantomData, + pub available_types: PhantomData, } // Manual implementations to avoid unneeded trait bounds. @@ -62,7 +62,6 @@ impl< where PrimaryKey: Clone + Ord + TablePrimaryKey, SecondaryIndexes: Default, - AvailableTypes: Default, IndexType: Default + TableIndex, PkGen: Default, Row: StorableRow, @@ -77,7 +76,7 @@ where lock_map: LockMap::new(), table_name: "", pk_phantom: PhantomData, - available_types_phantom: PhantomData, + available_types: PhantomData, } } } From 8499fe19d24e06c5fdd8f62b96a3650183dd6d52 Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Tue, 11 Feb 2025 12:28:54 +0300 Subject: [PATCH 13/16] Clean up --- codegen/src/worktable/generator/index.rs | 92 +++++++------------ .../src/worktable/generator/queries/update.rs | 21 ++--- examples/src/main.rs | 12 ++- src/index/table_secondary_index.rs | 4 - 4 files changed, 53 insertions(+), 76 deletions(-) diff --git a/codegen/src/worktable/generator/index.rs b/codegen/src/worktable/generator/index.rs index 8eabf5f0..18cb04a0 100644 --- a/codegen/src/worktable/generator/index.rs +++ b/codegen/src/worktable/generator/index.rs @@ -10,8 +10,6 @@ impl Generator { let type_def = self.gen_type_def(); let impl_def = self.gen_impl_def(); - println!("{}", self.gen_impl_def()); - quote! { #type_def #impl_def @@ -138,66 +136,46 @@ impl Generator { let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string()); let avt_type_ident = name_generator.get_available_type_ident(); - let process_difference_rows = self - .columns - .indexes - .iter() - .map(|(i, idx)| { - let index_field_name = &idx.name; - let diff_key = Literal::string(i.to_string().as_str()); - - let match_arms: Vec<_> = self - .columns - .columns_map - .get(&idx.field) - .map(|t| { - let type_str = t.to_string(); - let variant_ident = - Ident::new(&type_str.to_uppercase(), Span::mixed_site()); - - let new_value_expr = if type_str == "String" { - quote! { new.to_string() } - } else { - quote! { *new } - }; - - let old_value_expr = if type_str == "String" { - quote! { old.to_string() } - } else { - quote! { *old } - }; - - quote! { - if let Some(diff) = difference.get(#diff_key) { - match &diff.old { - #avt_type_ident::#variant_ident(old) => { - let key_old = #old_value_expr; - TableIndex::remove(&self.#index_field_name, key_old, link); - } - _ => {} - } - - match &diff.new { - #avt_type_ident::#variant_ident(new) => { - let key_new = #new_value_expr; - TableIndex::insert(&self.#index_field_name, key_new, link); - } - _ => {} - } - } - } - }) - .into_iter() - .collect(); + let process_difference_rows = self.columns.indexes.iter().map(|(i, idx)| { + let index_field_name = &idx.name; + let diff_key = Literal::string(i.to_string().as_str()); + + let match_arm = if let Some(t) = self.columns.columns_map.get(&idx.field) { + let type_str = t.to_string(); + let variant_ident = Ident::new(&type_str.to_uppercase(), Span::mixed_site()); + + let (new_value_expr, old_value_expr) = if type_str == "String" { + (quote! { new.to_string() }, quote! { old.to_string() }) + } else { + (quote! { *new }, quote! { *old }) + }; quote! { - #(#match_arms)* + if let Some(diff) = difference.get(#diff_key) { + if let #avt_type_ident::#variant_ident(old) = &diff.old { + let key_old = #old_value_expr; + TableIndex::remove(&self.#index_field_name, key_old, link); + } + + if let #avt_type_ident::#variant_ident(new) = &diff.new { + let key_new = #new_value_expr; + TableIndex::insert(&self.#index_field_name, key_new, link); + } + } } - }) - .collect::>(); + } else { + quote! {} + }; + + match_arm + }); quote! { - fn process_difference(&self, link: Link, difference: std::collections::HashMap<&str, Difference<#avt_type_ident>>) -> core::result::Result<(), WorkTableError> { + fn process_difference( + &self, + link: Link, + difference: std::collections::HashMap<&str, Difference<#avt_type_ident>> + ) -> core::result::Result<(), WorkTableError> { #(#process_difference_rows)* core::result::Result::Ok(()) } diff --git a/codegen/src/worktable/generator/queries/update.rs b/codegen/src/worktable/generator/queries/update.rs index 6e7dbc9f..cd03c309 100644 --- a/codegen/src/worktable/generator/queries/update.rs +++ b/codegen/src/worktable/generator/queries/update.rs @@ -195,14 +195,14 @@ impl Generator { } }) .collect::>(); - let diff = if let Some(columns) = idx_idents { + + let diff = idx_idents.map(|columns| { idents .iter() .filter(|i| columns.contains(i)) .map(|i| { let diff_key = Literal::string(i.to_string().as_str()); quote! { - let old: #avt_type_ident = row_old.clone().#i.into(); let new: #avt_type_ident = row_new.#i.into(); @@ -215,20 +215,20 @@ impl Generator { } }) .collect::>() - } else { - vec![] - }; + }); - let diff_container_ident = if !diff.is_empty() { + let diff_container_ident = if let Some(ref diff) = diff { quote! { - let row_old = self.select(by.clone()).unwrap(); - let row_new = row.clone(); - let mut diffs: std::collections::HashMap<&str, Difference<#avt_type_ident>> = std::collections::HashMap::new();} + let row_old = self.select(by.clone()).unwrap(); + let row_new = row.clone(); + let mut diffs: std::collections::HashMap<&str, Difference<#avt_type_ident>> = std::collections::HashMap::new(); + #(#diff)* + } } else { quote! {} }; - let process_diff_ident = if !diff.is_empty() { + let process_diff_ident = if let Some(_) = diff { quote! { self.0.indexes.process_difference(link, diffs)?; } @@ -244,7 +244,6 @@ impl Generator { self.0.lock_map.insert(op_id.into(), lock.clone()); #diff_container_ident - #(#diff)* let mut bytes = rkyv::to_bytes::(&row).map_err(|_| WorkTableError::SerializeError)?; let mut row = unsafe { rkyv::access_unchecked_mut::<<#query_ident as rkyv::Archive>::Archived>(&mut bytes[..]).unseal_unchecked() }; diff --git a/examples/src/main.rs b/examples/src/main.rs index a09dc0b9..49a63d6e 100644 --- a/examples/src/main.rs +++ b/examples/src/main.rs @@ -9,7 +9,7 @@ fn main() { columns: { id: u64 primary_key autoincrement, val: i64, - test: u8 optional, + test: u8, attr: String, attr2: i16, @@ -17,6 +17,7 @@ fn main() { indexes: { idx1: attr, idx2: attr2, + idx3: test, }, queries: { update: { @@ -41,7 +42,7 @@ fn main() { val: 777, attr: "TEST".to_string(), attr2: 345, - test: Some(1), + test: 1, id: 0, }; @@ -91,7 +92,7 @@ fn main() { MyPrimaryKey(0), ); let _ = task::block_on(update_val); - // + // // let select_by_attr2 = my_table.select_by_attr2(1337); println!( "Select by new Attribute 1337: {:?}", @@ -109,10 +110,13 @@ fn main() { "Select by new Attribute TEST5: {:?}", select_by_attr2.unwrap().vals ); - + // let select_by_attr2 = my_table.select_by_attr("TEST".to_string()); println!( "Select by old Attribute TEST: {:?}", select_by_attr2.unwrap().vals ); + + let select_all = my_table.select_all().execute(); + println!("Select All {:?}", select_all); } diff --git a/src/index/table_secondary_index.rs b/src/index/table_secondary_index.rs index 100f4c76..0f055662 100644 --- a/src/index/table_secondary_index.rs +++ b/src/index/table_secondary_index.rs @@ -23,12 +23,10 @@ where T: Eq + Hash + Clone + std::marker::Send + std::cmp::Ord, { fn insert(&self, value: T, link: Link) -> Option { - println!("Inserting into IndexMultiMap"); self.insert(value, link) } fn remove(&self, value: T, link: Link) -> Option<(T, Link)> { - println!("Removing from IndexMultiMap"); self.remove(&value, &link) } } @@ -38,12 +36,10 @@ where T: Eq + Hash + Clone + std::marker::Send + std::cmp::Ord, { fn insert(&self, value: T, link: Link) -> Option { - println!("Inserting into IndexMultiMap"); self.insert(value, link) } fn remove(&self, value: T, _link: Link) -> Option<(T, Link)> { - println!("Removing from IndexMultiMap"); self.remove(&value) } } From 82c61115a3b6e5ca85382d2532c26b66c0238c83 Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Tue, 11 Feb 2025 13:45:32 +0300 Subject: [PATCH 14/16] Tests for index update + cleanup --- .../persist_table/generator/space_file/mod.rs | 3 +- .../src/worktable/generator/queries/type.rs | 50 ++-- examples/src/main.rs | 91 ++------ tests/worktable/index.rs | 219 ++++++++++++++---- tests/worktable/mod.rs | 1 + 5 files changed, 224 insertions(+), 140 deletions(-) diff --git a/codegen/src/persist_table/generator/space_file/mod.rs b/codegen/src/persist_table/generator/space_file/mod.rs index 37e32d4a..a358203e 100644 --- a/codegen/src/persist_table/generator/space_file/mod.rs +++ b/codegen/src/persist_table/generator/space_file/mod.rs @@ -128,7 +128,8 @@ impl Generator { pk_gen: PrimaryKeyGeneratorState::from_state(self.info.inner.pk_gen_state), lock_map: LockMap::new(), table_name: "", - pk_phantom: std::marker::PhantomData + pk_phantom: std::marker::PhantomData, + available_types_phantom: std::marker::PhantomData, }; #wt_ident( diff --git a/codegen/src/worktable/generator/queries/type.rs b/codegen/src/worktable/generator/queries/type.rs index 765543dc..b50dc5ea 100644 --- a/codegen/src/worktable/generator/queries/type.rs +++ b/codegen/src/worktable/generator/queries/type.rs @@ -1,6 +1,5 @@ use proc_macro2::{Ident, Span, TokenStream}; use quote::quote; -use std::collections::HashSet; use crate::name_generator::WorktableNameGenerator; use crate::worktable::generator::Generator; @@ -10,39 +9,36 @@ impl Generator { let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string()); let avt_type_ident = name_generator.get_available_type_ident(); - if self.columns.indexes.is_empty() { - return Ok(quote! { - type #avt_type_ident = (); - }); - } - let rows: Vec<_> = self .columns .indexes .iter() - .map(|(_i, idx)| self.columns.columns_map.get(&idx.field)) - .into_iter() - .filter_map(|t| t) - .map(|s| s.to_string()) - .collect::>() - .into_iter() - .map(|t| { - let type_ = Ident::new(&t.to_string(), Span::mixed_site()); - let type_upper = Ident::new(&t.to_string().to_uppercase(), Span::mixed_site()); - Ok::<_, syn::Error>(quote! { - #[from] - #type_upper(#type_), + .filter_map(|(_, idx)| self.columns.columns_map.get(&idx.field)) + .map(|s| { + let type_ident = Ident::new(s.to_string().as_str(), Span::mixed_site()); + let type_upper = + Ident::new(&s.to_string().to_uppercase().as_str(), Span::mixed_site()); + Some(quote! { + #[from] + #type_upper(#type_ident), }) }) - .collect::, _>>()?; + .collect(); - Ok::<_, syn::Error>(quote! { - #[derive(rkyv::Archive, Debug, derive_more::Display, rkyv::Deserialize, Clone, rkyv::Serialize)] - #[derive(From, PartialEq)] - pub enum #avt_type_ident { - #(#rows)* - } - }) + if !rows.is_empty() { + Ok(quote! { + #[derive(rkyv::Archive, Debug, derive_more::Display, rkyv::Deserialize, Clone, rkyv::Serialize)] + #[derive(From, PartialEq)] + #[non_exhaustive] + pub enum #avt_type_ident { + #(#rows)* + } + }) + } else { + Ok(quote! { + type #avt_type_ident = (); + }) + } } pub fn gen_result_types_def(&mut self) -> syn::Result { diff --git a/examples/src/main.rs b/examples/src/main.rs index 49a63d6e..45854cad 100644 --- a/examples/src/main.rs +++ b/examples/src/main.rs @@ -1,4 +1,4 @@ -use async_std::task; +use futures::executor::block_on; use worktable::prelude::*; use worktable::worktable; @@ -17,18 +17,15 @@ fn main() { indexes: { idx1: attr, idx2: attr2, - idx3: test, }, queries: { update: { ValById(val) by id, - // AttrById(attr) by id, - // Attr2ById(attr2) by id, - AllAttrById(attr, attr2) by id, - UpdateOptionalById(test) by id, + AllAttrById(attr, attr2) by id, + UpdateOptionalById(test) by id, }, delete: { - // ByAttr() by attr, + ByAttr() by attr, ById() by id, } } @@ -40,83 +37,37 @@ fn main() { // WT rows (has prefix My because of table name) let row = MyRow { val: 777, - attr: "TEST".to_string(), + attr: "Attribute1".to_string(), attr2: 345, test: 1, id: 0, }; - //let row1 = MyRow { - // val: 2, - // attr: "TEST2".to_string(), - // attr2: 123, - // id: 1, - //}; - // - //let row2 = MyRow { - // val: 1337, - // attr: "TEST2".to_string(), - // attr2: 345, - // id: 2, - //}; - // - //let row3 = MyRow { - // val: 555, - // attr: "TEST3".to_string(), - // attr2: 123, - // id: 3, - //}; - // insert - let _ = my_table.insert(row); - // let _ = my_table.insert(row1); - // let _ = my_table.insert(row2); - // let _ = my_table.insert(row3); + let pk: MyPrimaryKey = my_table.insert(row).expect("primary key"); // Select ALL records from WT let select_all = my_table.select_all().execute(); println!("Select All {:?}", select_all); // Select All records with attribute TEST - // let select_by_attr = my_table.select_by_attr("TEST".to_string()); - // println!( - // "Select by Attribute TEST: {:?}", - // select_by_attr.unwrap().vals - // ); - // - let update_val = my_table.update_all_attr_by_id( - AllAttrByIdQuery { - attr: "TEST5".to_string(), - attr2: 1337, - }, - MyPrimaryKey(0), - ); - let _ = task::block_on(update_val); - // // - let select_by_attr2 = my_table.select_by_attr2(1337); - println!( - "Select by new Attribute 1337: {:?}", - select_by_attr2.unwrap().vals - ); + let select_all = my_table.select_all().execute(); + println!("Select All {:?}", select_all); - let select_by_attr2 = my_table.select_by_attr2(345); - println!( - "Select by old Attribute 345: {:?}", - select_by_attr2.unwrap().vals - ); + // Select by Idx + let select_by_attr = my_table.select_by_attr("Attribute1".to_string()); + println!("Select by idx {:?}", select_by_attr.unwrap().vals); - let select_by_attr2 = my_table.select_by_attr("TEST5".to_string()); - println!( - "Select by new Attribute TEST5: {:?}", - select_by_attr2.unwrap().vals - ); - // - let select_by_attr2 = my_table.select_by_attr("TEST".to_string()); - println!( - "Select by old Attribute TEST: {:?}", - select_by_attr2.unwrap().vals - ); + // Update Value query + let update = my_table.update_val_by_id(ValByIdQuery { val: 1337 }, pk.clone()); + let _ = block_on(update); let select_all = my_table.select_all().execute(); - println!("Select All {:?}", select_all); + println!("Select after update val {:?}", select_all); + + let delete = my_table.delete(pk); + let _ = block_on(delete); + + let select_all = my_table.select_all().execute(); + println!("Select after delete {:?}", select_all); } diff --git a/tests/worktable/index.rs b/tests/worktable/index.rs index 506b2ae1..eb8c34a5 100644 --- a/tests/worktable/index.rs +++ b/tests/worktable/index.rs @@ -1,10 +1,89 @@ -use crate::worktable::index::WorkTableError::NotFound; -use std::collections::HashMap; use worktable::prelude::*; use worktable::worktable; +// The test checks updates for 3 indecies at once worktable!( - name: Test, + name: Test3, + columns: { + id: u64 primary_key autoincrement, + val: i64, + attr1: String, + attr2: i16, + attr3: u64, + }, + indexes: { + idx1: attr1, + idx2: attr2, + idx3: attr3, + }, + queries: { + update: { + ThreeAttrById(attr1, attr2, attr3) by id, + }, + delete: { + ById() by id, + } + } +); + +#[tokio::test] +async fn update_3_idx() { + let test_table = Test3WorkTable::default(); + + let attr1_old = "TEST".to_string(); + let attr2_old = 1000; + let attr3_old = 65000; + + let row = Test3Row { + val: 1, + attr1: attr1_old.clone(), + attr2: attr2_old, + attr3: attr3_old, + id: 0, + }; + + let attr1_new = "1337".to_string(); + let attr2_new = 1337; + let attr3_new = 1337; + + let pk = test_table.insert(row.clone()).unwrap(); + let _ = test_table + .update_three_attr_by_id( + ThreeAttrByIdQuery { + attr1: attr1_new.clone(), + attr2: attr2_new, + attr3: attr3_new, + }, + pk.clone(), + ) + .await + .unwrap(); + + // Checks idx updated + let updated = test_table.select_by_attr1(attr1_new.clone()).unwrap(); + assert_eq!(updated.vals.first().unwrap().attr1, attr1_new); + + let updated = test_table.select_by_attr2(attr2_new).unwrap(); + assert_eq!(updated.vals.first().unwrap().attr2, attr2_new); + + let updated = test_table.select_by_attr3(attr3_new).unwrap(); + assert_eq!(updated.vals.first().unwrap().attr3, attr3_new); + + // Check old idx removed + let updated = test_table.select_by_attr1(attr1_old.clone()).unwrap(); + assert_eq!(updated.vals.first(), None); + + let updated = test_table.select_by_attr2(attr2_old.clone()).unwrap(); + assert_eq!(updated.vals.first(), None); + + let updated = test_table.select_by_attr3(attr3_old.clone()).unwrap(); + assert_eq!(updated.vals.first(), None); +} + +// The test checks updates for 2 indecies at once + +worktable!( + name: Test2, columns: { id: u64 primary_key autoincrement, val: i64, @@ -17,9 +96,6 @@ worktable!( }, queries: { update: { - ValByAttr(val) by attr1, - AttrById(attr1) by id, - Attr2ById(attr2) by id, AllAttrById(attr1, attr2) by id, }, delete: { @@ -29,47 +105,106 @@ worktable!( ); #[tokio::test] -async fn update_index() { +async fn update_2_idx() { + let test_table = Test2WorkTable::default(); + + let attr1_old = "TEST".to_string(); + let attr2_old = 1000; + + let row = Test2Row { + val: 1, + attr1: attr1_old.clone(), + attr2: attr2_old, + id: 0, + }; + + let attr1_new = "OK".to_string(); + let attr2_new = 1337; + + let pk = test_table.insert(row.clone()).unwrap(); + let _ = test_table + .update_all_attr_by_id( + AllAttrByIdQuery { + attr1: attr1_new.clone(), + attr2: attr2_new, + }, + pk.clone(), + ) + .await + .unwrap(); + + // Checks idx updated + let updated = test_table.select_by_attr1(attr1_new.clone()).unwrap(); + assert_eq!(updated.vals.first().unwrap().attr1, attr1_new); + + let updated = test_table.select_by_attr2(attr2_new).unwrap(); + assert_eq!(updated.vals.first().unwrap().attr2, attr2_new); + + // Check old idx removed + let updated = test_table.select_by_attr1(attr1_old.clone()).unwrap(); + assert_eq!(updated.vals.first(), None); + + let updated = test_table.select_by_attr2(attr2_old.clone()).unwrap(); + assert_eq!(updated.vals.first(), None); +} + +// The test checks updates for 1 index + +worktable!( + name: Test, + columns: { + id: u64 primary_key autoincrement, + val: i64, + attr1: String, + attr2: i16, + }, + indexes: { + idx1: attr1, + }, + queries: { + update: { + ValByAttr(val) by attr1, + Attr1ById(attr1) by id, + + }, + delete: { + ById() by id, + } + } +); + +#[tokio::test] +async fn update_1_idx() { let test_table = TestWorkTable::default(); + let attr1_old = "TEST".to_string(); + let attr2_old = 1000; + let row = TestRow { val: 1, - attr1: "TEST".to_string(), - attr2: 1000, + attr1: attr1_old.clone(), + attr2: attr2_old, id: 0, }; + + let attr1_new = "OK".to_string(); + let pk = test_table.insert(row.clone()).unwrap(); - let _all_update = test_table.update_all_attr_by_id( - AllAttrByIdQuery { - attr1: "TEST2".to_string(), - attr2: 1337, - }, - pk.clone(), - ); - - let updated = test_table.select(pk).unwrap(); - assert_eq!(updated, row); - - let binding = test_table.select_by_attr2(1337).unwrap(); - let found = binding.vals.first().unwrap(); - assert_eq!(found, &updated); - - //let found = test_table - // .select_by_attr1("TEST2".to_string()) - // .unwrap() - // .vals - // .first() - // .unwrap(); - //assert_eq!(found, &updated); - // - //let not_found = test_table - // .select_by_attr2(1000) - // .unwrap() - // .vals - // .first() - // .unwrap(); - //assert_eq!(not_found, &updated); - - // let not_found = test_table.select_by_attr2(1000); - // assert_eq!(not_found, NotFound); + let _ = test_table + .update_attr_1_by_id( + Attr1ByIdQuery { + attr1: attr1_new.clone(), + }, + pk.clone(), + ) + .await + .unwrap(); + + // Checks idx updated + let updated = test_table.select_by_attr1(attr1_new.clone()).unwrap(); + assert_eq!(updated.vals.first().unwrap().attr1, attr1_new); + + // Check old idx removed + let updated = test_table.select_by_attr1(attr1_old.clone()).unwrap(); + assert_eq!(updated.vals.first(), None); } diff --git a/tests/worktable/mod.rs b/tests/worktable/mod.rs index 3ef0f209..d144f4c8 100644 --- a/tests/worktable/mod.rs +++ b/tests/worktable/mod.rs @@ -2,6 +2,7 @@ mod array; mod base; mod config; mod custom_pk; +mod index; mod option; mod tuple_primary_key; mod uuid; From 6e2a1b98c9ed112ba37f73d16943791c1b991abc Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Wed, 12 Feb 2025 00:00:47 +0300 Subject: [PATCH 15/16] Clean up --- .../persist_table/generator/space_file/mod.rs | 2 +- codegen/src/worktable/generator/index.rs | 2 + src/index/mod.rs | 40 ++++++++++++++++- src/index/table_secondary_index.rs | 45 ++----------------- src/table/mod.rs | 4 +- 5 files changed, 47 insertions(+), 46 deletions(-) diff --git a/codegen/src/persist_table/generator/space_file/mod.rs b/codegen/src/persist_table/generator/space_file/mod.rs index a358203e..c4586d4a 100644 --- a/codegen/src/persist_table/generator/space_file/mod.rs +++ b/codegen/src/persist_table/generator/space_file/mod.rs @@ -129,7 +129,7 @@ impl Generator { lock_map: LockMap::new(), table_name: "", pk_phantom: std::marker::PhantomData, - available_types_phantom: std::marker::PhantomData, + types_phantom: std::marker::PhantomData, }; #wt_ident( diff --git a/codegen/src/worktable/generator/index.rs b/codegen/src/worktable/generator/index.rs index 18cb04a0..c0389a67 100644 --- a/codegen/src/worktable/generator/index.rs +++ b/codegen/src/worktable/generator/index.rs @@ -132,6 +132,8 @@ impl Generator { } } + /// Generates `process_difference` function of `TableIndex` trait for index. It updates `Link` for all secondary indexes. + /// Uses HashMap<&str, Difference> for storing all changes fn gen_process_difference_index_fn(&self) -> TokenStream { let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string()); let avt_type_ident = name_generator.get_available_type_ident(); diff --git a/src/index/mod.rs b/src/index/mod.rs index d6ea4539..e1d151a1 100644 --- a/src/index/mod.rs +++ b/src/index/mod.rs @@ -1,3 +1,4 @@ +use std::hash::Hash; use std::sync::Arc; use data_bucket::Link; @@ -9,9 +10,46 @@ mod table_secondary_index; pub use indexset::concurrent::map::BTreeMap as IndexMap; pub use indexset::concurrent::multimap::BTreeMultiMap as IndexMultiMap; -pub use table_secondary_index::{Difference, TableIndex, TableSecondaryIndex}; +pub use table_secondary_index::TableSecondaryIndex; pub enum IndexType<'a, T> { Unique(&'a TreeIndex), NonUnique(&'a TreeIndex>>), } + +#[derive(Debug)] +pub struct Difference { + pub old: AvailableTypes, + pub new: AvailableTypes, +} + +pub trait TableIndex { + fn insert(&self, value: T, link: Link) -> Option; + fn remove(&self, value: T, link: Link) -> Option<(T, Link)>; +} + +impl TableIndex for IndexMultiMap +where + T: Eq + Hash + Clone + std::marker::Send + std::cmp::Ord, +{ + fn insert(&self, value: T, link: Link) -> Option { + self.insert(value, link) + } + + fn remove(&self, value: T, link: Link) -> Option<(T, Link)> { + self.remove(&value, &link) + } +} + +impl TableIndex for IndexMap +where + T: Eq + Hash + Clone + std::marker::Send + std::cmp::Ord, +{ + fn insert(&self, value: T, link: Link) -> Option { + self.insert(value, link) + } + + fn remove(&self, value: T, _link: Link) -> Option<(T, Link)> { + self.remove(&value) + } +} diff --git a/src/index/table_secondary_index.rs b/src/index/table_secondary_index.rs index 0f055662..0e4f67a7 100644 --- a/src/index/table_secondary_index.rs +++ b/src/index/table_secondary_index.rs @@ -1,48 +1,9 @@ -use data_bucket::Link; -use indexset::concurrent::map::BTreeMap as IndexMap; -use indexset::concurrent::multimap::BTreeMultiMap as IndexMultiMap; use std::collections::HashMap; -use std::fmt::Debug; -use std::hash::Hash; - -use crate::WorkTableError; - -#[derive(Debug)] -pub struct Difference { - pub old: AvailableTypes, - pub new: AvailableTypes, -} - -pub trait TableIndex { - fn insert(&self, value: T, link: Link) -> Option; - fn remove(&self, value: T, link: Link) -> Option<(T, Link)>; -} - -impl TableIndex for IndexMultiMap -where - T: Eq + Hash + Clone + std::marker::Send + std::cmp::Ord, -{ - fn insert(&self, value: T, link: Link) -> Option { - self.insert(value, link) - } - fn remove(&self, value: T, link: Link) -> Option<(T, Link)> { - self.remove(&value, &link) - } -} - -impl TableIndex for IndexMap -where - T: Eq + Hash + Clone + std::marker::Send + std::cmp::Ord, -{ - fn insert(&self, value: T, link: Link) -> Option { - self.insert(value, link) - } +use data_bucket::Link; - fn remove(&self, value: T, _link: Link) -> Option<(T, Link)> { - self.remove(&value) - } -} +use crate::Difference; +use crate::WorkTableError; pub trait TableSecondaryIndex where diff --git a/src/table/mod.rs b/src/table/mod.rs index 02f48680..3075310a 100644 --- a/src/table/mod.rs +++ b/src/table/mod.rs @@ -45,7 +45,7 @@ pub struct WorkTable< pub pk_phantom: PhantomData, - pub available_types_phantom: PhantomData, + pub types_phantom: PhantomData, } // Manual implementations to avoid unneeded trait bounds. @@ -67,7 +67,7 @@ where lock_map: LockMap::new(), table_name: "", pk_phantom: PhantomData, - available_types_phantom: PhantomData, + types_phantom: PhantomData, } } } From 9664ff58dbe00edca13b0d6e4abeb334665aed49 Mon Sep 17 00:00:00 2001 From: Kira Sotnikov Date: Wed, 12 Feb 2025 03:11:57 +0300 Subject: [PATCH 16/16] fix clippy --- performance_measurement/src/profiler.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/performance_measurement/src/profiler.rs b/performance_measurement/src/profiler.rs index 7e4700e6..6c78532b 100644 --- a/performance_measurement/src/profiler.rs +++ b/performance_measurement/src/profiler.rs @@ -36,7 +36,7 @@ pub struct PerformanceProfiler; impl PerformanceProfiler { pub fn store_measurement(function_name: &'static str, duration: Duration) { - let mut global_performance_measurements = &GLOBAL_PERFORMANCE_MEASUREMENTS; + let global_performance_measurements = &GLOBAL_PERFORMANCE_MEASUREMENTS; let duration_ms = duration.as_nanos() as f64 / 1_000_000.0;