mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: filter with cell data
This commit is contained in:
parent
1f7f0b5880
commit
35491b22ac
@ -7,7 +7,7 @@ import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/block_entities.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-grid/dart_notification.pb.dart';
|
||||
|
||||
typedef GridBlockUpdateNotifierValue = Either<List<GridRowsChangeset>, FlowyError>;
|
||||
typedef GridBlockUpdateNotifierValue = Either<List<GridBlockChangeset>, FlowyError>;
|
||||
|
||||
class GridBlockListener {
|
||||
final String blockId;
|
||||
@ -33,7 +33,7 @@ class GridBlockListener {
|
||||
switch (ty) {
|
||||
case GridNotification.DidUpdateGridBlock:
|
||||
result.fold(
|
||||
(payload) => _rowsUpdateNotifier?.value = left([GridRowsChangeset.fromBuffer(payload)]),
|
||||
(payload) => _rowsUpdateNotifier?.value = left([GridBlockChangeset.fromBuffer(payload)]),
|
||||
(error) => _rowsUpdateNotifier?.value = right(error),
|
||||
);
|
||||
break;
|
||||
|
@ -57,17 +57,19 @@ class GridRowCacheService {
|
||||
_deleteRows(changeset.deletedRows);
|
||||
_insertRows(changeset.insertedRows);
|
||||
_updateRows(changeset.updatedRows);
|
||||
_hideRows(changeset.hideRows);
|
||||
_showRows(changeset.visibleRows);
|
||||
}
|
||||
}
|
||||
|
||||
void _deleteRows(List<GridRowId> deletedRows) {
|
||||
void _deleteRows(List<String> deletedRows) {
|
||||
if (deletedRows.isEmpty) {
|
||||
return;
|
||||
}
|
||||
|
||||
final List<GridRow> newRows = [];
|
||||
final DeletedIndexs deletedIndex = [];
|
||||
final Map<String, GridRowId> deletedRowByRowId = {for (var e in deletedRows) e.rowId: e};
|
||||
final Map<String, String> deletedRowByRowId = {for (var rowId in deletedRows) rowId: rowId};
|
||||
|
||||
_rows.asMap().forEach((index, row) {
|
||||
if (deletedRowByRowId[row.rowId] == null) {
|
||||
@ -80,7 +82,7 @@ class GridRowCacheService {
|
||||
_notifier.receive(GridRowChangeReason.delete(deletedIndex));
|
||||
}
|
||||
|
||||
void _insertRows(List<IndexRow> insertRows) {
|
||||
void _insertRows(List<InsertedRow> insertRows) {
|
||||
if (insertRows.isEmpty) {
|
||||
return;
|
||||
}
|
||||
@ -93,7 +95,7 @@ class GridRowCacheService {
|
||||
rowId: insertRow.rowId,
|
||||
);
|
||||
insertIndexs.add(insertIndex);
|
||||
newRows.insert(insertRow.index, (buildGridRow(insertRow.rowId, insertIndex.row.height)));
|
||||
newRows.insert(insertRow.index, (buildGridRow(insertRow.rowId, insertRow.height.toDouble())));
|
||||
}
|
||||
|
||||
_notifier.receive(GridRowChangeReason.insert(insertIndexs));
|
||||
@ -121,6 +123,10 @@ class GridRowCacheService {
|
||||
_notifier.receive(GridRowChangeReason.update(updatedIndexs));
|
||||
}
|
||||
|
||||
void _hideRows(List<String> hideRows) {}
|
||||
|
||||
void _showRows(List<String> visibleRows) {}
|
||||
|
||||
void onRowsChanged(
|
||||
void Function(GridRowChangeReason) onRowChanged,
|
||||
) {
|
||||
|
@ -1,4 +1,3 @@
|
||||
use crate::entities::GridRowId;
|
||||
use flowy_derive::ProtoBuf;
|
||||
use flowy_error::ErrorCode;
|
||||
use flowy_grid_data_model::parser::NotEmptyStr;
|
||||
@ -11,11 +10,11 @@ pub struct GridBlock {
|
||||
pub id: String,
|
||||
|
||||
#[pb(index = 2)]
|
||||
pub row_infos: Vec<BlockRowInfo>,
|
||||
pub row_infos: Vec<RowInfo>,
|
||||
}
|
||||
|
||||
impl GridBlock {
|
||||
pub fn new(block_id: &str, row_orders: Vec<BlockRowInfo>) -> Self {
|
||||
pub fn new(block_id: &str, row_orders: Vec<RowInfo>) -> Self {
|
||||
Self {
|
||||
id: block_id.to_owned(),
|
||||
row_infos: row_orders,
|
||||
@ -24,7 +23,7 @@ impl GridBlock {
|
||||
}
|
||||
|
||||
#[derive(Debug, Default, Clone, ProtoBuf)]
|
||||
pub struct BlockRowInfo {
|
||||
pub struct RowInfo {
|
||||
#[pb(index = 1)]
|
||||
pub block_id: String,
|
||||
|
||||
@ -35,7 +34,7 @@ pub struct BlockRowInfo {
|
||||
pub height: i32,
|
||||
}
|
||||
|
||||
impl BlockRowInfo {
|
||||
impl RowInfo {
|
||||
pub fn row_id(&self) -> &str {
|
||||
&self.row_id
|
||||
}
|
||||
@ -45,7 +44,7 @@ impl BlockRowInfo {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&RowRevision> for BlockRowInfo {
|
||||
impl std::convert::From<&RowRevision> for RowInfo {
|
||||
fn from(rev: &RowRevision) -> Self {
|
||||
Self {
|
||||
block_id: rev.block_id.clone(),
|
||||
@ -55,7 +54,7 @@ impl std::convert::From<&RowRevision> for BlockRowInfo {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<&Arc<RowRevision>> for BlockRowInfo {
|
||||
impl std::convert::From<&Arc<RowRevision>> for RowInfo {
|
||||
fn from(rev: &Arc<RowRevision>) -> Self {
|
||||
Self {
|
||||
block_id: rev.block_id.clone(),
|
||||
@ -140,8 +139,8 @@ impl UpdatedRow {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::From<BlockRowInfo> for InsertedRow {
|
||||
fn from(row_info: BlockRowInfo) -> Self {
|
||||
impl std::convert::From<RowInfo> for InsertedRow {
|
||||
fn from(row_info: RowInfo) -> Self {
|
||||
Self {
|
||||
row_id: row_info.row_id,
|
||||
block_id: row_info.block_id,
|
||||
@ -153,7 +152,7 @@ impl std::convert::From<BlockRowInfo> for InsertedRow {
|
||||
|
||||
impl std::convert::From<&RowRevision> for InsertedRow {
|
||||
fn from(row: &RowRevision) -> Self {
|
||||
let row_order = BlockRowInfo::from(row);
|
||||
let row_order = RowInfo::from(row);
|
||||
Self::from(row_order)
|
||||
}
|
||||
}
|
||||
@ -167,36 +166,39 @@ pub struct GridBlockChangeset {
|
||||
pub inserted_rows: Vec<InsertedRow>,
|
||||
|
||||
#[pb(index = 3)]
|
||||
pub deleted_rows: Vec<GridRowId>,
|
||||
pub deleted_rows: Vec<String>,
|
||||
|
||||
#[pb(index = 4)]
|
||||
pub updated_rows: Vec<UpdatedRow>,
|
||||
|
||||
#[pb(index = 5)]
|
||||
pub visible_rows: Vec<String>,
|
||||
|
||||
#[pb(index = 6)]
|
||||
pub hide_rows: Vec<String>,
|
||||
}
|
||||
impl GridBlockChangeset {
|
||||
pub fn insert(block_id: &str, inserted_rows: Vec<InsertedRow>) -> Self {
|
||||
Self {
|
||||
block_id: block_id.to_owned(),
|
||||
inserted_rows,
|
||||
deleted_rows: vec![],
|
||||
updated_rows: vec![],
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete(block_id: &str, deleted_rows: Vec<GridRowId>) -> Self {
|
||||
pub fn delete(block_id: &str, deleted_rows: Vec<String>) -> Self {
|
||||
Self {
|
||||
block_id: block_id.to_owned(),
|
||||
inserted_rows: vec![],
|
||||
deleted_rows,
|
||||
updated_rows: vec![],
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(block_id: &str, updated_rows: Vec<UpdatedRow>) -> Self {
|
||||
Self {
|
||||
block_id: block_id.to_owned(),
|
||||
inserted_rows: vec![],
|
||||
deleted_rows: vec![],
|
||||
updated_rows,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::dart_notification::{send_dart_notification, GridNotification};
|
||||
use crate::entities::{BlockRowInfo, CellChangeset, GridBlockChangeset, GridRowId, InsertedRow, Row, UpdatedRow};
|
||||
use crate::entities::{CellChangeset, GridBlockChangeset, InsertedRow, Row, RowInfo, UpdatedRow};
|
||||
use crate::manager::GridUser;
|
||||
use crate::services::block_revision_editor::GridBlockRevisionEditor;
|
||||
use crate::services::persistence::block_index::BlockIndexCache;
|
||||
@ -137,14 +137,8 @@ impl GridBlockManager {
|
||||
None => {}
|
||||
Some(row_info) => {
|
||||
let _ = editor.delete_rows(vec![Cow::Borrowed(&row_id)]).await?;
|
||||
|
||||
let row_identifier = GridRowId {
|
||||
grid_id: self.grid_id.clone(),
|
||||
block_id: row_info.block_id,
|
||||
row_id: row_info.row_id,
|
||||
};
|
||||
let _ = self
|
||||
.notify_did_update_block(&block_id, GridBlockChangeset::delete(&block_id, vec![row_identifier]))
|
||||
.notify_did_update_block(&block_id, GridBlockChangeset::delete(&block_id, vec![row_info.row_id]))
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
@ -154,7 +148,7 @@ impl GridBlockManager {
|
||||
|
||||
pub(crate) async fn delete_rows(
|
||||
&self,
|
||||
row_orders: Vec<BlockRowInfo>,
|
||||
row_orders: Vec<RowInfo>,
|
||||
) -> FlowyResult<Vec<GridBlockMetaRevisionChangeset>> {
|
||||
let mut changesets = vec![];
|
||||
for grid_block in block_from_row_orders(row_orders) {
|
||||
@ -186,16 +180,11 @@ impl GridBlockManager {
|
||||
height: row_rev.height,
|
||||
};
|
||||
|
||||
let deleted_row = GridRowId {
|
||||
grid_id: self.grid_id.clone(),
|
||||
block_id: row_rev.block_id.clone(),
|
||||
row_id: row_rev.id.clone(),
|
||||
};
|
||||
let notified_changeset = GridBlockChangeset {
|
||||
block_id: editor.block_id.clone(),
|
||||
inserted_rows: vec![insert_row],
|
||||
deleted_rows: vec![deleted_row],
|
||||
updated_rows: vec![],
|
||||
deleted_rows: vec![row_rev.id.clone()],
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
let _ = self
|
||||
@ -228,7 +217,7 @@ impl GridBlockManager {
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult<Vec<BlockRowInfo>> {
|
||||
pub async fn get_row_orders(&self, block_id: &str) -> FlowyResult<Vec<RowInfo>> {
|
||||
let editor = self.get_editor(block_id).await?;
|
||||
editor.get_row_infos::<&str>(None).await
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::entities::BlockRowInfo;
|
||||
use crate::entities::RowInfo;
|
||||
use bytes::Bytes;
|
||||
use flowy_error::{FlowyError, FlowyResult};
|
||||
use flowy_grid_data_model::revision::{CellRevision, GridBlockRevision, RowMetaChangeset, RowRevision};
|
||||
@ -123,12 +123,12 @@ impl GridBlockRevisionEditor {
|
||||
Ok(cell_revs)
|
||||
}
|
||||
|
||||
pub async fn get_row_info(&self, row_id: &str) -> FlowyResult<Option<BlockRowInfo>> {
|
||||
pub async fn get_row_info(&self, row_id: &str) -> FlowyResult<Option<RowInfo>> {
|
||||
let row_ids = Some(vec![Cow::Borrowed(row_id)]);
|
||||
Ok(self.get_row_infos(row_ids).await?.pop())
|
||||
}
|
||||
|
||||
pub async fn get_row_infos<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> FlowyResult<Vec<BlockRowInfo>>
|
||||
pub async fn get_row_infos<T>(&self, row_ids: Option<Vec<Cow<'_, T>>>) -> FlowyResult<Vec<RowInfo>>
|
||||
where
|
||||
T: AsRef<str> + ToOwned + ?Sized,
|
||||
{
|
||||
@ -138,8 +138,8 @@ impl GridBlockRevisionEditor {
|
||||
.await
|
||||
.get_row_revs(row_ids)?
|
||||
.iter()
|
||||
.map(BlockRowInfo::from)
|
||||
.collect::<Vec<BlockRowInfo>>();
|
||||
.map(RowInfo::from)
|
||||
.collect::<Vec<RowInfo>>();
|
||||
Ok(row_infos)
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,10 @@ impl CellDataOperation<String, GridCheckboxFilter> for CheckboxTypeOption {
|
||||
Ok(DecodedCellData::default())
|
||||
}
|
||||
|
||||
fn apply_filter(&self, _filter: GridCheckboxFilter) -> bool {
|
||||
fn apply_filter<T>(&self, encoded_data: T, _filter: &GridCheckboxFilter) -> bool
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -137,8 +137,10 @@ impl CellDataOperation<String, GridDateFilter> for DateTypeOption {
|
||||
let date = self.today_desc_from_timestamp(timestamp);
|
||||
DecodedCellData::try_from_bytes(date)
|
||||
}
|
||||
|
||||
fn apply_filter(&self, _filter: GridDateFilter) -> bool {
|
||||
fn apply_filter<T>(&self, encoded_data: T, _filter: &GridDateFilter) -> bool
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -178,8 +178,10 @@ impl CellDataOperation<String, GridNumberFilter> for NumberTypeOption {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_filter(&self, _filter: GridNumberFilter) -> bool {
|
||||
fn apply_filter<T>(&self, encoded_data: T, _filter: &GridNumberFilter) -> bool
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -123,7 +123,10 @@ impl CellDataOperation<String, GridSelectOptionFilter> for SingleSelectTypeOptio
|
||||
DecodedCellData::try_from_bytes(cell_data)
|
||||
}
|
||||
|
||||
fn apply_filter(&self, _filter: GridSelectOptionFilter) -> bool {
|
||||
fn apply_filter<T>(&self, encoded_data: T, _filter: &GridSelectOptionFilter) -> bool
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
@ -225,7 +228,10 @@ impl CellDataOperation<String, GridSelectOptionFilter> for MultiSelectTypeOption
|
||||
DecodedCellData::try_from_bytes(cell_data)
|
||||
}
|
||||
|
||||
fn apply_filter(&self, _filter: GridSelectOptionFilter) -> bool {
|
||||
fn apply_filter<T>(&self, encoded_data: T, _filter: &GridSelectOptionFilter) -> bool
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -52,7 +52,10 @@ impl CellDataOperation<String, GridTextFilter> for RichTextTypeOption {
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_filter(&self, _filter: GridTextFilter) -> bool {
|
||||
fn apply_filter<T>(&self, encoded_data: T, _filter: &GridTextFilter) -> bool
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
@ -50,7 +50,7 @@ impl CellDataOperation<EncodedCellData<URLCellData>, GridTextFilter> for URLType
|
||||
DecodedCellData::try_from_bytes(cell_data)
|
||||
}
|
||||
|
||||
fn apply_filter(&self, _filter: GridTextFilter) -> bool {
|
||||
fn apply_filter(&self, _filter: &GridTextFilter) -> bool {
|
||||
todo!()
|
||||
}
|
||||
|
||||
|
163
frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs
Normal file
163
frontend/rust-lib/flowy-grid/src/services/filter/filter_cache.rs
Normal file
@ -0,0 +1,163 @@
|
||||
use crate::entities::{
|
||||
FieldType, GridBlockChangeset, GridCheckboxFilter, GridDateFilter, GridNumberFilter, GridRowId,
|
||||
GridSelectOptionFilter, GridTextFilter, InsertedRow,
|
||||
};
|
||||
|
||||
use dashmap::DashMap;
|
||||
|
||||
use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
|
||||
use flowy_sync::client_grid::GridRevisionPad;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct FilterResultCache {
|
||||
// key: row id
|
||||
inner: DashMap<String, FilterResult>,
|
||||
}
|
||||
|
||||
impl FilterResultCache {
|
||||
pub fn new() -> Arc<Self> {
|
||||
let this = Self::default();
|
||||
Arc::new(this)
|
||||
}
|
||||
}
|
||||
|
||||
impl std::ops::Deref for FilterResultCache {
|
||||
type Target = DashMap<String, FilterResult>;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct FilterResult {
|
||||
pub(crate) row_id: String,
|
||||
pub(crate) row_index: i32,
|
||||
pub(crate) cell_by_field_id: HashMap<String, bool>,
|
||||
}
|
||||
|
||||
impl FilterResult {
|
||||
pub(crate) fn new(index: i32, row_rev: &RowRevision) -> Self {
|
||||
Self {
|
||||
row_index: index,
|
||||
row_id: row_rev.id.clone(),
|
||||
cell_by_field_id: row_rev.cells.iter().map(|(k, _)| (k.clone(), true)).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn update_cell(&mut self, cell_id: &str, exist: bool) {
|
||||
self.cell_by_field_id.insert(cell_id.to_owned(), exist);
|
||||
}
|
||||
|
||||
pub(crate) fn is_visible(&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct FilterCache {
|
||||
pub(crate) text_filter: DashMap<FilterId, GridTextFilter>,
|
||||
pub(crate) url_filter: DashMap<FilterId, GridTextFilter>,
|
||||
pub(crate) number_filter: DashMap<FilterId, GridNumberFilter>,
|
||||
pub(crate) date_filter: DashMap<FilterId, GridDateFilter>,
|
||||
pub(crate) select_option_filter: DashMap<FilterId, GridSelectOptionFilter>,
|
||||
pub(crate) checkbox_filter: DashMap<FilterId, GridCheckboxFilter>,
|
||||
}
|
||||
|
||||
impl FilterCache {
|
||||
pub(crate) async fn from_grid_pad(grid_pad: &Arc<RwLock<GridRevisionPad>>) -> Arc<Self> {
|
||||
let this = Arc::new(Self::default());
|
||||
let _ = reload_filter_cache(this.clone(), None, grid_pad).await;
|
||||
this
|
||||
}
|
||||
|
||||
pub(crate) fn remove(&self, filter_id: &FilterId) {
|
||||
let _ = match filter_id.field_type {
|
||||
FieldType::RichText => {
|
||||
let _ = self.text_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::Number => {
|
||||
let _ = self.number_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::DateTime => {
|
||||
let _ = self.date_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::SingleSelect => {
|
||||
let _ = self.select_option_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::MultiSelect => {
|
||||
let _ = self.select_option_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::Checkbox => {
|
||||
let _ = self.checkbox_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::URL => {
|
||||
let _ = self.url_filter.remove(filter_id);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn reload_filter_cache(
|
||||
cache: Arc<FilterCache>,
|
||||
field_ids: Option<Vec<String>>,
|
||||
grid_pad: &Arc<RwLock<GridRevisionPad>>,
|
||||
) {
|
||||
let grid_pad = grid_pad.read().await;
|
||||
let filters_revs = grid_pad.get_filters(None, field_ids).unwrap_or_default();
|
||||
|
||||
for filter_rev in filters_revs {
|
||||
match grid_pad.get_field_rev(&filter_rev.field_id) {
|
||||
None => {}
|
||||
Some((_, field_rev)) => {
|
||||
let filter_id = FilterId::from(field_rev);
|
||||
let field_type: FieldType = field_rev.field_type_rev.into();
|
||||
match &field_type {
|
||||
FieldType::RichText => {
|
||||
let _ = cache.text_filter.insert(filter_id, GridTextFilter::from(filter_rev));
|
||||
}
|
||||
FieldType::Number => {
|
||||
let _ = cache
|
||||
.number_filter
|
||||
.insert(filter_id, GridNumberFilter::from(filter_rev));
|
||||
}
|
||||
FieldType::DateTime => {
|
||||
let _ = cache.date_filter.insert(filter_id, GridDateFilter::from(filter_rev));
|
||||
}
|
||||
FieldType::SingleSelect | FieldType::MultiSelect => {
|
||||
let _ = cache
|
||||
.select_option_filter
|
||||
.insert(filter_id, GridSelectOptionFilter::from(filter_rev));
|
||||
}
|
||||
FieldType::Checkbox => {
|
||||
let _ = cache
|
||||
.checkbox_filter
|
||||
.insert(filter_id, GridCheckboxFilter::from(filter_rev));
|
||||
}
|
||||
FieldType::URL => {
|
||||
let _ = cache.url_filter.insert(filter_id, GridTextFilter::from(filter_rev));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Hash, Eq, PartialEq)]
|
||||
pub(crate) struct FilterId {
|
||||
pub(crate) field_id: String,
|
||||
pub(crate) field_type: FieldType,
|
||||
}
|
||||
|
||||
impl std::convert::From<&Arc<FieldRevision>> for FilterId {
|
||||
fn from(rev: &Arc<FieldRevision>) -> Self {
|
||||
Self {
|
||||
field_id: rev.id.clone(),
|
||||
field_type: rev.field_type_rev.into(),
|
||||
}
|
||||
}
|
||||
}
|
@ -1,16 +1,20 @@
|
||||
use crate::dart_notification::{send_dart_notification, GridNotification};
|
||||
use crate::entities::{
|
||||
FieldType, GridBlockChangeset, GridCheckboxFilter, GridDateFilter, GridNumberFilter, GridRowId,
|
||||
GridSelectOptionFilter, GridTextFilter, InsertedRow,
|
||||
};
|
||||
use crate::entities::{FieldType, GridBlockChangeset, GridTextFilter};
|
||||
use crate::services::block_manager::GridBlockManager;
|
||||
use crate::services::field::RichTextTypeOption;
|
||||
use crate::services::filter::filter_cache::{
|
||||
reload_filter_cache, FilterCache, FilterId, FilterResult, FilterResultCache,
|
||||
};
|
||||
use crate::services::grid_editor_task::GridServiceTaskScheduler;
|
||||
use crate::services::row::GridBlockSnapshot;
|
||||
use crate::services::row::{CellDataOperation, GridBlockSnapshot};
|
||||
use crate::services::tasks::{FilterTaskContext, Task, TaskContent};
|
||||
use dashmap::mapref::one::{Ref, RefMut};
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_grid_data_model::revision::{CellRevision, FieldId, FieldRevision, RowRevision};
|
||||
use flowy_sync::client_grid::GridRevisionPad;
|
||||
use flowy_sync::entities::grid::GridSettingChangesetParams;
|
||||
use rayon::prelude::*;
|
||||
use std::borrow::Cow;
|
||||
use std::collections::HashMap;
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::RwLock;
|
||||
@ -21,8 +25,8 @@ pub(crate) struct GridFilterService {
|
||||
scheduler: Arc<dyn GridServiceTaskScheduler>,
|
||||
grid_pad: Arc<RwLock<GridRevisionPad>>,
|
||||
block_manager: Arc<GridBlockManager>,
|
||||
filter_cache: Arc<RwLock<FilterCache>>,
|
||||
filter_result_cache: Arc<RwLock<FilterResultCache>>,
|
||||
filter_cache: Arc<FilterCache>,
|
||||
filter_result_cache: Arc<FilterResultCache>,
|
||||
}
|
||||
impl GridFilterService {
|
||||
pub async fn new<S: GridServiceTaskScheduler>(
|
||||
@ -31,13 +35,14 @@ impl GridFilterService {
|
||||
scheduler: S,
|
||||
) -> Self {
|
||||
let grid_id = grid_pad.read().await.grid_id();
|
||||
let filter_cache = Arc::new(RwLock::new(FilterCache::from_grid_pad(&grid_pad).await));
|
||||
let filter_result_cache = Arc::new(RwLock::new(FilterResultCache::default()));
|
||||
let scheduler = Arc::new(scheduler);
|
||||
let filter_cache = FilterCache::from_grid_pad(&grid_pad).await;
|
||||
let filter_result_cache = FilterResultCache::new();
|
||||
Self {
|
||||
grid_id,
|
||||
grid_pad,
|
||||
block_manager,
|
||||
scheduler: Arc::new(scheduler),
|
||||
scheduler,
|
||||
filter_cache,
|
||||
filter_result_cache,
|
||||
}
|
||||
@ -55,37 +60,31 @@ impl GridFilterService {
|
||||
|
||||
let mut changesets = vec![];
|
||||
for (index, block) in task_context.blocks.into_iter().enumerate() {
|
||||
let mut inserted_rows = vec![];
|
||||
let mut deleted_rows = vec![];
|
||||
block.row_revs.iter().for_each(|row_rev| {
|
||||
let result = filter_row(
|
||||
index,
|
||||
row_rev,
|
||||
&self.filter_cache,
|
||||
&self.filter_result_cache,
|
||||
&field_revs,
|
||||
);
|
||||
let results = block
|
||||
.row_revs
|
||||
.par_iter()
|
||||
.map(|row_rev| {
|
||||
let filter_result_cache = self.filter_result_cache.clone();
|
||||
let filter_cache = self.filter_cache.clone();
|
||||
filter_row(index, row_rev, filter_cache, filter_result_cache, &field_revs)
|
||||
})
|
||||
.collect::<Vec<FilterResult>>();
|
||||
|
||||
let mut visible_rows = vec![];
|
||||
let mut hide_rows = vec![];
|
||||
for result in results {
|
||||
if result.is_visible() {
|
||||
inserted_rows.push(InsertedRow {
|
||||
row_id: Default::default(),
|
||||
block_id: Default::default(),
|
||||
height: 1,
|
||||
index: Some(result.row_index),
|
||||
});
|
||||
visible_rows.push(result.row_id);
|
||||
} else {
|
||||
deleted_rows.push(GridRowId {
|
||||
grid_id: self.grid_id.clone(),
|
||||
block_id: block.block_id.clone(),
|
||||
row_id: result.row_id,
|
||||
});
|
||||
hide_rows.push(result.row_id);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
let changeset = GridBlockChangeset {
|
||||
block_id: block.block_id,
|
||||
inserted_rows,
|
||||
deleted_rows,
|
||||
updated_rows: vec![],
|
||||
hide_rows,
|
||||
visible_rows,
|
||||
..Default::default()
|
||||
};
|
||||
changesets.push(changeset);
|
||||
}
|
||||
@ -99,13 +98,13 @@ impl GridFilterService {
|
||||
}
|
||||
|
||||
if let Some(filter_id) = &changeset.insert_filter {
|
||||
let mut cache = self.filter_cache.write().await;
|
||||
let field_ids = Some(vec![filter_id.field_id.clone()]);
|
||||
reload_filter_cache(&mut cache, field_ids, &self.grid_pad).await;
|
||||
reload_filter_cache(self.filter_cache.clone(), field_ids, &self.grid_pad).await;
|
||||
todo!()
|
||||
}
|
||||
|
||||
if let Some(filter_id) = &changeset.delete_filter {
|
||||
self.filter_cache.write().await.remove(filter_id);
|
||||
self.filter_cache.remove(filter_id);
|
||||
}
|
||||
|
||||
if let Ok(blocks) = self.block_manager.get_block_snapshots(None).await {
|
||||
@ -138,15 +137,58 @@ impl GridFilterService {
|
||||
fn filter_row(
|
||||
index: usize,
|
||||
row_rev: &Arc<RowRevision>,
|
||||
_filter_cache: &Arc<RwLock<FilterCache>>,
|
||||
_filter_result_cache: &Arc<RwLock<FilterResultCache>>,
|
||||
_field_revs: &HashMap<FieldId, Arc<FieldRevision>>,
|
||||
filter_cache: Arc<FilterCache>,
|
||||
filter_result_cache: Arc<FilterResultCache>,
|
||||
field_revs: &HashMap<FieldId, Arc<FieldRevision>>,
|
||||
) -> FilterResult {
|
||||
let filter_result = FilterResult::new(index as i32, row_rev);
|
||||
row_rev.cells.iter().for_each(|(_k, cell_rev)| {
|
||||
let _cell_rev: &CellRevision = cell_rev;
|
||||
});
|
||||
filter_result
|
||||
match filter_result_cache.get_mut(&row_rev.id) {
|
||||
None => {
|
||||
let mut filter_result = FilterResult::new(index as i32, row_rev);
|
||||
for (field_id, cell_rev) in row_rev.cells.iter() {
|
||||
let _ = update_filter_result(field_revs, &mut filter_result, &filter_cache, field_id, cell_rev);
|
||||
}
|
||||
filter_result_cache.insert(row_rev.id.clone(), filter_result);
|
||||
}
|
||||
Some(mut result) => {
|
||||
for (field_id, cell_rev) in row_rev.cells.iter() {
|
||||
let _ = update_filter_result(field_revs, result.value_mut(), &filter_cache, field_id, cell_rev);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
todo!()
|
||||
}
|
||||
|
||||
fn update_filter_result(
|
||||
field_revs: &HashMap<FieldId, Arc<FieldRevision>>,
|
||||
filter_result: &mut FilterResult,
|
||||
filter_cache: &Arc<FilterCache>,
|
||||
field_id: &str,
|
||||
cell_rev: &CellRevision,
|
||||
) -> Option<()> {
|
||||
let field_rev = field_revs.get(field_id)?;
|
||||
let field_type = FieldType::from(field_rev.field_type_rev);
|
||||
let filter_id = FilterId {
|
||||
field_id: field_id.to_owned(),
|
||||
field_type,
|
||||
};
|
||||
match &filter_id.field_type {
|
||||
FieldType::RichText => match filter_cache.text_filter.get(&filter_id) {
|
||||
None => {}
|
||||
Some(filter) => {
|
||||
// let v = field_rev
|
||||
// .get_type_option_entry::<RichTextTypeOption, _>(&filter_id.field_type)?
|
||||
// .apply_filter(cell_rev, &filter);
|
||||
}
|
||||
},
|
||||
FieldType::Number => {}
|
||||
FieldType::DateTime => {}
|
||||
FieldType::SingleSelect => {}
|
||||
FieldType::MultiSelect => {}
|
||||
FieldType::Checkbox => {}
|
||||
FieldType::URL => {}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub struct GridFilterChangeset {
|
||||
@ -177,145 +219,3 @@ impl std::convert::From<&GridSettingChangesetParams> for GridFilterChangeset {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct FilterResultCache {
|
||||
#[allow(dead_code)]
|
||||
rows: HashMap<String, FilterResult>,
|
||||
}
|
||||
|
||||
impl FilterResultCache {
|
||||
#[allow(dead_code)]
|
||||
fn insert(&mut self, row_id: &str, result: FilterResult) {
|
||||
self.rows.insert(row_id.to_owned(), result);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct FilterResult {
|
||||
row_id: String,
|
||||
row_index: i32,
|
||||
cell_by_field_id: HashMap<String, bool>,
|
||||
}
|
||||
|
||||
impl FilterResult {
|
||||
fn new(index: i32, row_rev: &RowRevision) -> Self {
|
||||
Self {
|
||||
row_index: index,
|
||||
row_id: row_rev.id.clone(),
|
||||
cell_by_field_id: row_rev.cells.iter().map(|(k, _)| (k.clone(), true)).collect(),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn update_cell(&mut self, cell_id: &str, exist: bool) {
|
||||
self.cell_by_field_id.insert(cell_id.to_owned(), exist);
|
||||
}
|
||||
|
||||
fn is_visible(&self) -> bool {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
struct FilterCache {
|
||||
text_filter: HashMap<FilterId, GridTextFilter>,
|
||||
url_filter: HashMap<FilterId, GridTextFilter>,
|
||||
number_filter: HashMap<FilterId, GridNumberFilter>,
|
||||
date_filter: HashMap<FilterId, GridDateFilter>,
|
||||
select_option_filter: HashMap<FilterId, GridSelectOptionFilter>,
|
||||
checkbox_filter: HashMap<FilterId, GridCheckboxFilter>,
|
||||
}
|
||||
|
||||
impl FilterCache {
|
||||
async fn from_grid_pad(grid_pad: &Arc<RwLock<GridRevisionPad>>) -> Self {
|
||||
let mut this = Self::default();
|
||||
let _ = reload_filter_cache(&mut this, None, grid_pad).await;
|
||||
this
|
||||
}
|
||||
|
||||
fn remove(&mut self, filter_id: &FilterId) {
|
||||
let _ = match filter_id.field_type {
|
||||
FieldType::RichText => {
|
||||
let _ = self.text_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::Number => {
|
||||
let _ = self.number_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::DateTime => {
|
||||
let _ = self.date_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::SingleSelect => {
|
||||
let _ = self.select_option_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::MultiSelect => {
|
||||
let _ = self.select_option_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::Checkbox => {
|
||||
let _ = self.checkbox_filter.remove(filter_id);
|
||||
}
|
||||
FieldType::URL => {
|
||||
let _ = self.url_filter.remove(filter_id);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
async fn reload_filter_cache(
|
||||
cache: &mut FilterCache,
|
||||
field_ids: Option<Vec<String>>,
|
||||
grid_pad: &Arc<RwLock<GridRevisionPad>>,
|
||||
) {
|
||||
let grid_pad = grid_pad.read().await;
|
||||
let filters_revs = grid_pad.get_filters(None, field_ids).unwrap_or_default();
|
||||
|
||||
for filter_rev in filters_revs {
|
||||
match grid_pad.get_field_rev(&filter_rev.field_id) {
|
||||
None => {}
|
||||
Some((_, field_rev)) => {
|
||||
let filter_id = FilterId::from(field_rev);
|
||||
let field_type: FieldType = field_rev.field_type_rev.into();
|
||||
match &field_type {
|
||||
FieldType::RichText => {
|
||||
let _ = cache.text_filter.insert(filter_id, GridTextFilter::from(filter_rev));
|
||||
}
|
||||
FieldType::Number => {
|
||||
let _ = cache
|
||||
.number_filter
|
||||
.insert(filter_id, GridNumberFilter::from(filter_rev));
|
||||
}
|
||||
FieldType::DateTime => {
|
||||
let _ = cache.date_filter.insert(filter_id, GridDateFilter::from(filter_rev));
|
||||
}
|
||||
FieldType::SingleSelect | FieldType::MultiSelect => {
|
||||
let _ = cache
|
||||
.select_option_filter
|
||||
.insert(filter_id, GridSelectOptionFilter::from(filter_rev));
|
||||
}
|
||||
FieldType::Checkbox => {
|
||||
let _ = cache
|
||||
.checkbox_filter
|
||||
.insert(filter_id, GridCheckboxFilter::from(filter_rev));
|
||||
}
|
||||
FieldType::URL => {
|
||||
let _ = cache.url_filter.insert(filter_id, GridTextFilter::from(filter_rev));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Hash, Eq, PartialEq)]
|
||||
struct FilterId {
|
||||
field_id: String,
|
||||
field_type: FieldType,
|
||||
}
|
||||
|
||||
impl std::convert::From<&Arc<FieldRevision>> for FilterId {
|
||||
fn from(rev: &Arc<FieldRevision>) -> Self {
|
||||
Self {
|
||||
field_id: rev.id.clone(),
|
||||
field_type: rev.field_type_rev.into(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,4 @@
|
||||
mod filter_cache;
|
||||
mod filter_service;
|
||||
|
||||
pub(crate) use filter_service::*;
|
||||
|
@ -265,14 +265,14 @@ impl GridRevisionEditor {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn create_row(&self, start_row_id: Option<String>) -> FlowyResult<BlockRowInfo> {
|
||||
pub async fn create_row(&self, start_row_id: Option<String>) -> FlowyResult<RowInfo> {
|
||||
let field_revs = self.grid_pad.read().await.get_field_revs(None)?;
|
||||
let block_id = self.block_id().await?;
|
||||
|
||||
// insert empty row below the row whose id is upper_row_id
|
||||
let row_rev_ctx = CreateRowRevisionBuilder::new(&field_revs).build();
|
||||
let row_rev = make_row_rev_from_context(&block_id, row_rev_ctx);
|
||||
let row_order = BlockRowInfo::from(&row_rev);
|
||||
let row_order = RowInfo::from(&row_rev);
|
||||
|
||||
// insert the row
|
||||
let row_count = self.block_manager.create_row(&block_id, row_rev, start_row_id).await?;
|
||||
@ -283,13 +283,13 @@ impl GridRevisionEditor {
|
||||
Ok(row_order)
|
||||
}
|
||||
|
||||
pub async fn insert_rows(&self, contexts: Vec<CreateRowRevisionPayload>) -> FlowyResult<Vec<BlockRowInfo>> {
|
||||
pub async fn insert_rows(&self, contexts: Vec<CreateRowRevisionPayload>) -> FlowyResult<Vec<RowInfo>> {
|
||||
let block_id = self.block_id().await?;
|
||||
let mut rows_by_block_id: HashMap<String, Vec<RowRevision>> = HashMap::new();
|
||||
let mut row_orders = vec![];
|
||||
for ctx in contexts {
|
||||
let row_rev = make_row_rev_from_context(&block_id, ctx);
|
||||
row_orders.push(BlockRowInfo::from(&row_rev));
|
||||
row_orders.push(RowInfo::from(&row_rev));
|
||||
rows_by_block_id
|
||||
.entry(block_id.clone())
|
||||
.or_insert_with(Vec::new)
|
||||
@ -421,7 +421,7 @@ impl GridRevisionEditor {
|
||||
Ok(block_meta_revs)
|
||||
}
|
||||
|
||||
pub async fn delete_rows(&self, row_orders: Vec<BlockRowInfo>) -> FlowyResult<()> {
|
||||
pub async fn delete_rows(&self, row_orders: Vec<RowInfo>) -> FlowyResult<()> {
|
||||
let changesets = self.block_manager.delete_rows(row_orders).await?;
|
||||
for changeset in changesets {
|
||||
let _ = self.update_block(changeset).await?;
|
||||
|
@ -17,7 +17,9 @@ pub trait CellDataOperation<D, F> {
|
||||
where
|
||||
T: Into<D>;
|
||||
|
||||
fn apply_filter(&self, filter: F) -> bool;
|
||||
fn apply_filter<T>(&self, encoded_data: T, filter: &F) -> bool
|
||||
where
|
||||
T: Into<D>;
|
||||
|
||||
fn apply_changeset<C: Into<CellContentChangeset>>(
|
||||
&self,
|
||||
@ -73,6 +75,13 @@ impl std::convert::TryInto<TypeOptionCellData> for String {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::convert::TryFrom<&CellRevision> for TypeOptionCellData {
|
||||
type Error = FlowyError;
|
||||
|
||||
fn try_from(value: &CellRevision) -> Result<Self, Self::Error> {
|
||||
Self::from_str(&value.data)
|
||||
}
|
||||
}
|
||||
impl TypeOptionCellData {
|
||||
pub fn new<T: ToString>(data: T, field_type: FieldType) -> Self {
|
||||
TypeOptionCellData {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use crate::entities::{BlockRowInfo, GridBlock, RepeatedGridBlock, Row};
|
||||
use crate::entities::{GridBlock, RepeatedGridBlock, Row, RowInfo};
|
||||
use flowy_error::FlowyResult;
|
||||
use flowy_grid_data_model::revision::{FieldRevision, RowRevision};
|
||||
use std::collections::HashMap;
|
||||
@ -9,7 +9,7 @@ pub struct GridBlockSnapshot {
|
||||
pub row_revs: Vec<Arc<RowRevision>>,
|
||||
}
|
||||
|
||||
pub(crate) fn block_from_row_orders(row_orders: Vec<BlockRowInfo>) -> Vec<GridBlock> {
|
||||
pub(crate) fn block_from_row_orders(row_orders: Vec<RowInfo>) -> Vec<GridBlock> {
|
||||
let mut map: HashMap<String, GridBlock> = HashMap::new();
|
||||
row_orders.into_iter().for_each(|row_info| {
|
||||
// Memory Optimization: escape clone block_id
|
||||
@ -35,8 +35,8 @@ pub(crate) fn block_from_row_orders(row_orders: Vec<BlockRowInfo>) -> Vec<GridBl
|
||||
// Some((field_id, cell))
|
||||
// }
|
||||
|
||||
pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc<RowRevision>]) -> Vec<BlockRowInfo> {
|
||||
row_revs.iter().map(BlockRowInfo::from).collect::<Vec<_>>()
|
||||
pub(crate) fn make_row_orders_from_row_revs(row_revs: &[Arc<RowRevision>]) -> Vec<RowInfo> {
|
||||
row_revs.iter().map(RowInfo::from).collect::<Vec<_>>()
|
||||
}
|
||||
|
||||
pub(crate) fn make_row_from_row_rev(fields: &[Arc<FieldRevision>], row_rev: Arc<RowRevision>) -> Option<Row> {
|
||||
|
@ -137,9 +137,9 @@ async fn grid_row_add_date_cell_test() {
|
||||
}
|
||||
let context = builder.build();
|
||||
let date_field = date_field.unwrap();
|
||||
let cell_data = context.cell_by_field_id.get(&date_field.id).unwrap().clone();
|
||||
let cell_rev = context.cell_by_field_id.get(&date_field.id).unwrap().clone();
|
||||
assert_eq!(
|
||||
decode_cell_data(cell_data.data.clone(), &date_field)
|
||||
decode_cell_data(cell_rev, &date_field)
|
||||
.parse::<DateCellData>()
|
||||
.unwrap()
|
||||
.date,
|
||||
|
@ -99,7 +99,7 @@ pub struct GridEditorTest {
|
||||
pub row_revs: Vec<Arc<RowRevision>>,
|
||||
pub field_count: usize,
|
||||
|
||||
pub row_order_by_row_id: HashMap<String, BlockRowInfo>,
|
||||
pub row_order_by_row_id: HashMap<String, RowInfo>,
|
||||
}
|
||||
|
||||
impl GridEditorTest {
|
||||
@ -220,7 +220,7 @@ impl GridEditorTest {
|
||||
let row_orders = row_ids
|
||||
.into_iter()
|
||||
.map(|row_id| self.row_order_by_row_id.get(&row_id).unwrap().clone())
|
||||
.collect::<Vec<BlockRowInfo>>();
|
||||
.collect::<Vec<RowInfo>>();
|
||||
|
||||
self.editor.delete_rows(row_orders).await.unwrap();
|
||||
self.row_revs = self.get_row_revs().await;
|
||||
|
Loading…
Reference in New Issue
Block a user