Skip to content
1 change: 0 additions & 1 deletion codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand Down
7 changes: 7 additions & 0 deletions codegen/src/name_generator.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
3 changes: 2 additions & 1 deletion codegen/src/persist_table/generator/space_file/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
types_phantom: std::marker::PhantomData,
};

#wt_ident(
Expand Down
59 changes: 57 additions & 2 deletions codegen/src/worktable/generator/index.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use crate::name_generator::WorktableNameGenerator;
use crate::worktable::generator::Generator;

use proc_macro2::{Literal, TokenStream};
use proc_macro2::{Ident, Literal, Span, TokenStream};
use quote::quote;

impl Generator {
Expand Down Expand Up @@ -51,14 +51,17 @@ impl Generator {
let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string());
let row_type_ident = name_generator.get_row_type_ident();
let index_type_ident = name_generator.get_index_type_ident();
let avt_type_ident = name_generator.get_available_type_ident();

let save_row_fn = self.gen_save_row_index_fn();
let delete_row_fn = self.gen_delete_row_index_fn();
let process_difference_fn = self.gen_process_difference_index_fn();

quote! {
impl TableSecondaryIndex<#row_type_ident> for #index_type_ident {
impl TableSecondaryIndex<#row_type_ident, #avt_type_ident> for #index_type_ident {
#save_row_fn
#delete_row_fn
#process_difference_fn
}
}
}
Expand Down Expand Up @@ -128,6 +131,58 @@ impl Generator {
}
}
}

/// Generates `process_difference` function of `TableIndex` trait for index. It updates `Link` for all secondary indexes.
/// Uses HashMap<&str, Difference<AvaialableTypes>> 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();

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! {
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);
}
}
}
} else {
quote! {}
};

match_arm
});

quote! {
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(())
}
}
}
}

// TODO: tests...
1 change: 1 addition & 0 deletions codegen/src/worktable/generator/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ mod queries;
mod row;
mod table;
//mod table_old;
//mod table_index;
mod wrapper;

use proc_macro2::Ident;
Expand Down
38 changes: 38 additions & 0 deletions codegen/src/worktable/generator/queries/type.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,46 @@
use proc_macro2::{Ident, Span, TokenStream};
use quote::quote;

use crate::name_generator::WorktableNameGenerator;
use crate::worktable::generator::Generator;

impl Generator {
pub fn gen_available_types_def(&mut self) -> syn::Result<TokenStream> {
let name_generator = WorktableNameGenerator::from_table_name(self.name.to_string());
let avt_type_ident = name_generator.get_available_type_ident();

let rows: Vec<_> = self
.columns
.indexes
.iter()
.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();

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<TokenStream> {
if let Some(queries) = &self.queries {
let query_defs = queries
Expand Down Expand Up @@ -31,6 +68,7 @@ impl Generator {
.collect::<Result<Vec<_>, _>>()?;

Ok::<_, syn::Error>(quote! {

#[derive(rkyv::Archive, Debug, rkyv::Deserialize, Clone, rkyv::Serialize)]
#[repr(C)]
pub struct #ident {
Expand Down
74 changes: 73 additions & 1 deletion codegen/src/worktable/generator/queries/update.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use proc_macro2::Literal;
use std::collections::HashMap;

use crate::name_generator::WorktableNameGenerator;
Expand Down Expand Up @@ -100,6 +101,22 @@ impl Generator {
.values()
.find(|idx| idx.field.to_string() == op.by.to_string());

let indexes_columns: Option<Vec<_>> = {
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 {
let index_name = &index.name;
Expand All @@ -114,7 +131,12 @@ impl Generator {
if self.columns.primary_keys.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!()
}
Expand All @@ -135,6 +157,7 @@ impl Generator {
snake_case_name: String,
name: &Ident,
idents: &Vec<Ident>,
idx_idents: Option<&Vec<Ident>>,
) -> TokenStream {
let pk_ident = &self.pk.as_ref().unwrap().ident;
let method_ident = Ident::new(
Expand All @@ -160,6 +183,10 @@ impl Generator {
format!("verify_{snake_case_name}_lock").as_str(),
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| {
Expand All @@ -169,20 +196,65 @@ impl Generator {
})
.collect::<Vec<_>>();

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

let diff = Difference {
old: old.clone(),
new: new.clone(),
};

diffs.insert(#diff_key, diff);
}
})
.collect::<Vec<_>>()
});

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();
#(#diff)*
}
} else {
quote! {}
};

let process_diff_ident = if let Some(_) = diff {
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> {
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());

#diff_container_ident

let mut bytes = rkyv::to_bytes::<rkyv::rancor::Error>(&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 = self.0
.pk_map
.get(&by)
.map(|v| v.get().value)
.ok_or(WorkTableError::NotFound)?;

#process_diff_ident

let id = self.0.data.with_ref(link, |archived| {
archived.#check_ident()
}).map_err(WorkTableError::PagesError)?;
Expand Down
3 changes: 3 additions & 0 deletions codegen/src/worktable/generator/table/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ impl Generator {
let primary_key_type = name_generator.get_primary_key_type_ident();
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! {
Expand All @@ -81,6 +82,7 @@ impl Generator {
WorkTable<
#row_type,
#primary_key_type,
#avt_type_ident,
#index_type,
<#primary_key_type as TablePrimaryKey>::Generator,
#inner_const_name
Expand All @@ -95,6 +97,7 @@ impl Generator {
WorkTable<
#row_type,
#primary_key_type,
#avt_type_ident,
#index_type
>
#persist_type_part
Expand Down
2 changes: 2 additions & 0 deletions codegen/src/worktable/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
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()?;
Expand All @@ -61,6 +62,7 @@ pub fn expand(input: TokenStream) -> syn::Result<TokenStream> {
Ok(TokenStream::from(quote! {
#pk_def
#row_def
#query_available_def
#wrapper_def
#index_def
#table_def
Expand Down
Loading
Loading