Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions crates/controller/src/block_schema_manager/ctx.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
use logisheets_base::id_fetcher::{IdFetcherTrait, SheetIdFetcherByIdxTrait};

pub trait BlockSchemaCtx: IdFetcherTrait + SheetIdFetcherByIdxTrait {}
115 changes: 115 additions & 0 deletions crates/controller/src/block_schema_manager/executor.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
use logisheets_base::errors::BasicError;

use crate::{
block_schema_manager::{
ctx::BlockSchemaCtx,
manager::SchemaManager,
schema::{ColSchema, RandomSchema, RowSchema, Schema, SchemaTrait},
},
edit_action::EditPayload,
Error,
};

pub struct BlockSchemaExecutor {
pub manager: SchemaManager,
}

impl BlockSchemaExecutor {
pub fn new(manager: SchemaManager) -> Self {
Self { manager }
}

pub fn execute<C: BlockSchemaCtx>(
self,
ctx: &mut C,
payload: EditPayload,
) -> Result<(Self, bool), Error> {
match payload {
EditPayload::BindFormSchema(p) => {
let mut manager = self.manager;
let sheet_id = ctx
.fetch_sheet_id_by_index(p.sheet_idx)
.map_err(|l| BasicError::SheetIdxExceed(l))?;
let block_id = p.block_id;
let mut fields = Vec::new();
for (i, (field, render_id)) in p
.fields
.into_iter()
.zip(p.render_ids.into_iter())
.enumerate()
{
let idx = i + p.field_from;
let id = if p.row {
ctx.fetch_block_cell_id(&sheet_id, &block_id, idx, 0)?.row
} else {
ctx.fetch_block_cell_id(&sheet_id, &block_id, 0, idx)?.col
};
fields.push((field, (id, render_id)));
}
let mut keys = Vec::new();

for (j, k) in p.keys.into_iter().enumerate() {
let idx = j + p.key_from;
let id = if p.row {
ctx.fetch_block_cell_id(&sheet_id, &block_id, idx, 0)?.row
} else {
ctx.fetch_block_cell_id(&sheet_id, &block_id, 0, idx)?.col
};
keys.push((k, id));
}
let schema = if p.row {
Schema::RowSchema(RowSchema {
fields,
keys,
name: p.ref_name.clone(),
})
} else {
Schema::ColSchema(ColSchema {
fields,
keys,
name: p.ref_name.clone(),
})
};
let old_schema = manager.schemas.get(&(sheet_id, block_id));
if old_schema.is_some() {
manager.refs.remove(&old_schema.unwrap().get_ref_name());
}
manager.schemas.insert((sheet_id, block_id), schema);
manager.refs.insert(p.ref_name, (sheet_id, block_id));
Ok((Self { manager }, true))
}
EditPayload::BindRandomSchema(p) => {
let mut manager = self.manager;
let sheet_id = ctx
.fetch_sheet_id_by_index(p.sheet_idx)
.map_err(|l| BasicError::SheetIdxExceed(l))?;
let block_id = p.block_id;
let mut key_field = Vec::new();
for unit in p.units {
let r = unit.row;
let c = unit.col;
let cell_id = ctx.fetch_block_cell_id(&sheet_id, &block_id, r, c)?;
key_field.push((
unit.key,
unit.field,
cell_id.row,
cell_id.col,
unit.render_id,
));
}
let schema = Schema::RandomSchema(RandomSchema {
key_field,
name: p.ref_name.clone(),
});
let old_schema = manager.schemas.get(&(sheet_id, block_id));
if old_schema.is_some() {
manager.refs.remove(&old_schema.unwrap().get_ref_name());
}
manager.schemas.insert((sheet_id, block_id), schema);
manager.refs.insert(p.ref_name, (sheet_id, block_id));
Ok((Self { manager }, true))
}
_ => Ok((self, false)),
}
}
}
45 changes: 45 additions & 0 deletions crates/controller/src/block_schema_manager/manager.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
use imbl::HashMap;
use logisheets_base::{BlockCellId, BlockId, ColId, RowId, SheetId};

use crate::block_schema_manager::schema::{Field, Key, RenderId, Schema, SchemaTrait};

#[derive(Debug, Clone, Default)]
pub struct SchemaManager {
pub schemas: HashMap<(SheetId, BlockId), Schema>,
pub refs: HashMap<String, (SheetId, BlockId)>,
}

impl SchemaManager {
pub fn new() -> Self {
SchemaManager {
schemas: HashMap::new(),
refs: HashMap::new(),
}
}

pub fn resolve_by_ref_name(
&self,
name: &str,
key: &Key,
field: &Field,
) -> Option<(RowId, ColId)> {
let (sheet_id, block_id) = self.refs.get(name)?;
self.resolve_by_block_id(sheet_id, block_id, key, field)
}

pub fn resolve_by_block_id(
&self,
sheet_id: &SheetId,
block_id: &BlockId,
key: &Key,
field: &Field,
) -> Option<(RowId, ColId)> {
let schema = self.schemas.get(&(*sheet_id, *block_id))?;
schema.resolve(key, field)
}

pub fn get_render_id(&self, sheet_id: &SheetId, cell_id: &BlockCellId) -> Option<RenderId> {
let schema = self.schemas.get(&(*sheet_id, cell_id.block_id))?;
schema.get_render_id(cell_id.row, cell_id.col)
}
}
6 changes: 6 additions & 0 deletions crates/controller/src/block_schema_manager/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
pub mod ctx;
pub mod executor;
mod manager;
pub mod schema;

pub use manager::SchemaManager;
134 changes: 134 additions & 0 deletions crates/controller/src/block_schema_manager/schema.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
use logisheets_base::{ColId, RowId};

pub type RowSchema = FormSchema<ColId, RowId, true>;
pub type ColSchema = FormSchema<RowId, ColId, false>;
pub type RenderId = String;

#[derive(Debug, Clone)]
pub struct FormSchema<F, K, const IS_ROW: bool> {
pub fields: Vec<(Field, (F, RenderId))>,
pub keys: Vec<(Key, K)>,
pub name: String,
}

pub type Field = String;
pub type Key = String;

#[derive(Debug, Clone)]
pub struct RandomSchema {
pub key_field: Vec<(Key, Field, RowId, ColId, RenderId)>,
pub name: String,
}

#[derive(Debug, Clone)]
pub enum Schema {
RowSchema(RowSchema),
ColSchema(ColSchema),
RandomSchema(RandomSchema),
}

impl SchemaTrait for Schema {
fn resolve(&self, key: &Key, field: &Field) -> Option<(RowId, ColId)> {
match self {
Schema::RowSchema(schema) => schema.resolve(key, field),
Schema::ColSchema(schema) => schema.resolve(key, field),
Schema::RandomSchema(schema) => schema.resolve(key, field),
}
}

fn get_render_id(&self, row: RowId, col: ColId) -> Option<RenderId> {
match self {
Schema::RowSchema(schema) => schema.get_render_id(row, col),
Schema::ColSchema(schema) => schema.get_render_id(row, col),
Schema::RandomSchema(schema) => schema.get_render_id(row, col),
}
}

fn get_ref_name(&self) -> String {
match self {
Schema::RowSchema(schema) => schema.get_ref_name(),
Schema::ColSchema(schema) => schema.get_ref_name(),
Schema::RandomSchema(schema) => schema.get_ref_name(),
}
}
}

pub trait SchemaTrait {
fn resolve(&self, key: &Key, field: &Field) -> Option<(RowId, ColId)>;
fn get_render_id(&self, row: RowId, col: ColId) -> Option<RenderId>;
fn get_ref_name(&self) -> String;
}

impl SchemaTrait for RowSchema {
fn resolve(&self, key: &Key, field: &Field) -> Option<(RowId, ColId)> {
let k = self
.keys
.iter()
.find(|(k, _)| k == key)
.map(|(_, id)| *id)?;
let f = self
.fields
.iter()
.find(|(f, _)| f == field)
.map(|(_, id)| id.0)?;
Some((k, f))
}

fn get_render_id(&self, _row: RowId, col: ColId) -> Option<RenderId> {
self.fields
.iter()
.find(|(_, (f, _))| f == &col)
.map(|(_, (_, id))| id.clone())
}

fn get_ref_name(&self) -> String {
self.name.clone()
}
}

impl SchemaTrait for ColSchema {
fn resolve(&self, key: &Key, field: &Field) -> Option<(RowId, ColId)> {
let k = self
.keys
.iter()
.find(|(k, _)| k == key)
.map(|(_, id)| *id)?;
let f = self
.fields
.iter()
.find(|(f, _)| f == field)
.map(|(_, id)| id.0)?;
Some((f, k))
}

fn get_render_id(&self, row: RowId, _col: ColId) -> Option<RenderId> {
self.fields
.iter()
.find(|(_, (f, _))| f == &row)
.map(|(_, (_, id))| id.clone())
}

fn get_ref_name(&self) -> String {
self.name.clone()
}
}

impl SchemaTrait for RandomSchema {
fn resolve(&self, key: &Key, field: &Field) -> Option<(RowId, ColId)> {
self.key_field
.iter()
.find(|(k, f, _, _, _)| k == key && f == field)
.map(|(_, _, r, c, _)| (*r, *c))
}

fn get_render_id(&self, row: RowId, col: ColId) -> Option<RenderId> {
self.key_field
.iter()
.find(|(_, _, r, c, _)| r == &row && c == &col)
.map(|(_, _, _, _, id)| id.clone())
}

fn get_ref_name(&self) -> String {
self.name.clone()
}
}
82 changes: 82 additions & 0 deletions crates/controller/src/connectors/block_schema_connector.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
use logisheets_base::{
errors::BasicError,
id_fetcher::{IdFetcherTrait, SheetIdFetcherByIdxTrait},
BlockCellId, BlockId, CellId, ColId, ExtBookId, FuncId, NameId, NormalCellId, RowId, SheetId,
TextId,
};

use crate::{
block_schema_manager::ctx::BlockSchemaCtx, id_manager::SheetIdManager, navigator::Navigator,
workbook::sheet_info_manager::SheetInfoManager,
};

pub struct BlockSchemaConnector<'a> {
pub id_navigator: &'a Navigator,
pub sheet_info_manager: &'a mut SheetInfoManager,
pub sheet_id_manager: &'a mut SheetIdManager,
}

type Result<T> = std::result::Result<T, BasicError>;

impl<'a> IdFetcherTrait for BlockSchemaConnector<'a> {
fn fetch_row_id(&self, sheet_id: &SheetId, row_idx: usize) -> Result<RowId> {
self.id_navigator.fetch_row_id(sheet_id, row_idx)
}

fn fetch_col_id(&self, sheet_id: &SheetId, col_idx: usize) -> Result<ColId> {
self.id_navigator.fetch_col_id(sheet_id, col_idx)
}

fn fetch_cell_id(&self, sheet_id: &SheetId, row_idx: usize, col_idx: usize) -> Result<CellId> {
self.id_navigator.fetch_cell_id(sheet_id, row_idx, col_idx)
}

fn fetch_sheet_id(&mut self, sheet_name: &str) -> SheetId {
self.sheet_id_manager.get_or_register_id(sheet_name)
}

fn fetch_name_id(&mut self, _workbook: &Option<&str>, _name: &str) -> NameId {
unreachable!()
}

fn fetch_ext_book_id(&mut self, _book: &str) -> ExtBookId {
unreachable!()
}

fn fetch_text_id(&mut self, _text: &str) -> TextId {
unreachable!()
}

fn fetch_func_id(&mut self, _func_name: &str) -> FuncId {
unreachable!()
}

fn fetch_norm_cell_id(
&self,
sheet_id: &SheetId,
row_idx: usize,
col_idx: usize,
) -> Result<NormalCellId> {
self.id_navigator
.fetch_norm_cell_id(sheet_id, row_idx, col_idx)
}

fn fetch_block_cell_id(
&self,
sheet_id: &SheetId,
block_id: &BlockId,
row: usize,
col: usize,
) -> Result<BlockCellId> {
self.id_navigator
.fetch_block_cell_id(sheet_id, block_id, row, col)
}
}

impl<'a> SheetIdFetcherByIdxTrait for BlockSchemaConnector<'a> {
fn fetch_sheet_id_by_index(&self, idx: usize) -> std::result::Result<SheetId, usize> {
self.sheet_info_manager.pos.get(idx).copied().ok_or(idx)
}
}

impl<'a> BlockSchemaCtx for BlockSchemaConnector<'a> {}
Loading