Browse Source

chore: add date filter tests

appflowy 2 năm trước cách đây
mục cha
commit
c80fa5da78

+ 12 - 55
frontend/rust-lib/flowy-grid/src/entities/filter_entities/date_filter.rs

@@ -1,5 +1,3 @@
-use crate::entities::parser::NotEmptyStr;
-use crate::entities::FieldType;
 use flowy_derive::{ProtoBuf, ProtoBuf_Enum};
 use flowy_error::ErrorCode;
 use grid_rev_model::FilterRevision;
@@ -17,68 +15,25 @@ pub struct DateFilterPB {
 
     #[pb(index = 3, one_of)]
     pub end: Option<i64>,
-}
-
-#[derive(ProtoBuf, Default, Clone, Debug)]
-pub struct CreateGridDateFilterPayload {
-    #[pb(index = 1)]
-    pub field_id: String,
-
-    #[pb(index = 2)]
-    pub field_type: FieldType,
-
-    #[pb(index = 3)]
-    pub condition: DateFilterCondition,
 
     #[pb(index = 4, one_of)]
-    pub start: Option<i64>,
-
-    #[pb(index = 5, one_of)]
-    pub end: Option<i64>,
+    pub timestamp: Option<i64>,
 }
 
-pub struct CreateGridDateFilterParams {
-    pub field_id: String,
-
-    pub field_type: FieldType,
-
-    pub condition: DateFilterCondition,
-
+#[derive(Deserialize, Serialize, Default, Clone, Debug)]
+pub struct DateFilterContent {
     pub start: Option<i64>,
-
     pub end: Option<i64>,
+    pub timestamp: Option<i64>,
 }
 
-impl TryInto<CreateGridDateFilterParams> for CreateGridDateFilterPayload {
-    type Error = ErrorCode;
-
-    fn try_into(self) -> Result<CreateGridDateFilterParams, Self::Error> {
-        let field_id = NotEmptyStr::parse(self.field_id)
-            .map_err(|_| ErrorCode::FieldIdIsEmpty)?
-            .0;
-        Ok(CreateGridDateFilterParams {
-            field_id,
-            condition: self.condition,
-            start: self.start,
-            field_type: self.field_type,
-            end: self.end,
-        })
-    }
-}
-
-#[derive(Serialize, Deserialize, Default)]
-struct DateRange {
-    start: Option<i64>,
-    end: Option<i64>,
-}
-
-impl ToString for DateRange {
+impl ToString for DateFilterContent {
     fn to_string(&self) -> String {
-        serde_json::to_string(self).unwrap_or_else(|_| "".to_string())
+        serde_json::to_string(self).unwrap()
     }
 }
 
-impl FromStr for DateRange {
+impl FromStr for DateFilterContent {
     type Err = serde_json::Error;
 
     fn from_str(s: &str) -> Result<Self, Self::Err> {
@@ -96,6 +51,7 @@ pub enum DateFilterCondition {
     DateOnOrAfter = 4,
     DateWithIn = 5,
     DateIsEmpty = 6,
+    DateIsNotEmpty = 7,
 }
 
 impl std::convert::From<DateFilterCondition> for u32 {
@@ -133,9 +89,10 @@ impl std::convert::From<Arc<FilterRevision>> for DateFilterPB {
             ..Default::default()
         };
 
-        if let Ok(range) = DateRange::from_str(&rev.content) {
-            filter.start = range.start;
-            filter.end = range.end;
+        if let Ok(content) = DateFilterContent::from_str(&rev.content) {
+            filter.start = content.start;
+            filter.end = content.end;
+            filter.timestamp = content.timestamp;
         };
 
         filter

+ 86 - 31
frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_filter.rs

@@ -1,30 +1,60 @@
 use crate::entities::{DateFilterCondition, DateFilterPB};
 use crate::services::cell::{AnyCellData, CellData, CellFilterOperation};
 use crate::services::field::{DateTimestamp, DateTypeOptionPB};
+use chrono::NaiveDateTime;
 use flowy_error::FlowyResult;
 
 impl DateFilterPB {
-    pub fn is_visible<T: Into<i64>>(&self, cell_timestamp: T) -> bool {
-        if self.start.is_none() {
-            return false;
-        }
-        let cell_timestamp = cell_timestamp.into();
-        let start_timestamp = *self.start.as_ref().unwrap();
-        // We assume that the cell_timestamp doesn't contain hours, just day.
-        match self.condition {
-            DateFilterCondition::DateIs => cell_timestamp == start_timestamp,
-            DateFilterCondition::DateBefore => cell_timestamp < start_timestamp,
-            DateFilterCondition::DateAfter => cell_timestamp > start_timestamp,
-            DateFilterCondition::DateOnOrBefore => cell_timestamp <= start_timestamp,
-            DateFilterCondition::DateOnOrAfter => cell_timestamp >= start_timestamp,
-            DateFilterCondition::DateWithIn => {
-                if let Some(end_timestamp) = self.end.as_ref() {
-                    cell_timestamp >= start_timestamp && cell_timestamp <= *end_timestamp
-                } else {
-                    false
+    pub fn is_visible<T: Into<Option<i64>>>(&self, cell_timestamp: T) -> bool {
+        match cell_timestamp.into() {
+            None => DateFilterCondition::DateIsEmpty == self.condition,
+            Some(timestamp) => {
+                match self.condition {
+                    DateFilterCondition::DateIsNotEmpty => {
+                        return true;
+                    }
+                    DateFilterCondition::DateIsEmpty => {
+                        return false;
+                    }
+                    _ => {}
+                }
+
+                let cell_time = NaiveDateTime::from_timestamp(timestamp, 0);
+                let cell_date = cell_time.date();
+                match self.timestamp {
+                    None => {
+                        if self.start.is_none() {
+                            return true;
+                        }
+
+                        if self.end.is_none() {
+                            return true;
+                        }
+
+                        let start_time = NaiveDateTime::from_timestamp(*self.start.as_ref().unwrap(), 0);
+                        let start_date = start_time.date();
+
+                        let end_time = NaiveDateTime::from_timestamp(*self.end.as_ref().unwrap(), 0);
+                        let end_date = end_time.date();
+
+                        cell_date >= start_date && cell_date <= end_date
+                    }
+                    Some(timestamp) => {
+                        let expected_timestamp = NaiveDateTime::from_timestamp(timestamp, 0);
+                        let expected_date = expected_timestamp.date();
+
+                        // We assume that the cell_timestamp doesn't contain hours, just day.
+                        match self.condition {
+                            DateFilterCondition::DateIs => cell_date == expected_date,
+                            DateFilterCondition::DateBefore => cell_date < expected_date,
+                            DateFilterCondition::DateAfter => cell_date > expected_date,
+                            DateFilterCondition::DateOnOrBefore => cell_date <= expected_date,
+                            DateFilterCondition::DateOnOrAfter => cell_date >= expected_date,
+                            _ => true,
+                        }
+                    }
                 }
             }
-            DateFilterCondition::DateIsEmpty => cell_timestamp == 0_i64,
         }
     }
 }
@@ -49,11 +79,12 @@ mod tests {
     fn date_filter_is_test() {
         let filter = DateFilterPB {
             condition: DateFilterCondition::DateIs,
-            start: Some(123),
+            timestamp: Some(1668387885),
             end: None,
+            start: None,
         };
 
-        for (val, visible) in vec![(123, true), (12, false)] {
+        for (val, visible) in vec![(1668387885, true), (1647251762, false)] {
             assert_eq!(filter.is_visible(val as i64), visible);
         }
     }
@@ -61,23 +92,26 @@ mod tests {
     fn date_filter_before_test() {
         let filter = DateFilterPB {
             condition: DateFilterCondition::DateBefore,
-            start: Some(123),
+            timestamp: Some(1668387885),
+            start: None,
             end: None,
         };
 
-        for (val, visible) in vec![(123, false), (122, true)] {
-            assert_eq!(filter.is_visible(val as i64), visible);
+        for (val, visible, msg) in vec![(1668387884, false, "1"), (1647251762, true, "2")] {
+            assert_eq!(filter.is_visible(val as i64), visible, "{}", msg);
         }
     }
+
     #[test]
     fn date_filter_before_or_on_test() {
         let filter = DateFilterPB {
             condition: DateFilterCondition::DateOnOrBefore,
-            start: Some(123),
+            timestamp: Some(1668387885),
+            start: None,
             end: None,
         };
 
-        for (val, visible) in vec![(123, true), (122, true)] {
+        for (val, visible) in vec![(1668387884, true), (1668387885, true)] {
             assert_eq!(filter.is_visible(val as i64), visible);
         }
     }
@@ -85,24 +119,45 @@ mod tests {
     fn date_filter_after_test() {
         let filter = DateFilterPB {
             condition: DateFilterCondition::DateAfter,
-            start: Some(123),
+            timestamp: Some(1668387885),
+            start: None,
             end: None,
         };
 
-        for (val, visible) in vec![(1234, true), (122, false), (0, false)] {
+        for (val, visible) in vec![(1668387888, false), (1668531885, true), (0, false)] {
             assert_eq!(filter.is_visible(val as i64), visible);
         }
     }
+
     #[test]
     fn date_filter_within_test() {
         let filter = DateFilterPB {
             condition: DateFilterCondition::DateWithIn,
-            start: Some(123),
-            end: Some(130),
+            start: Some(1668272685), // 11/13
+            end: Some(1668618285),   // 11/17
+            timestamp: None,
         };
 
-        for (val, visible) in vec![(123, true), (130, true), (132, false)] {
+        for (val, visible, _msg) in vec![
+            (1668272685, true, "11/13"),
+            (1668359085, true, "11/14"),
+            (1668704685, false, "11/18"),
+        ] {
             assert_eq!(filter.is_visible(val as i64), visible);
         }
     }
+
+    #[test]
+    fn date_filter_is_empty_test() {
+        let filter = DateFilterPB {
+            condition: DateFilterCondition::DateIsEmpty,
+            start: None,
+            end: None,
+            timestamp: None,
+        };
+
+        for (val, visible) in vec![(None, true), (Some(123), false)] {
+            assert_eq!(filter.is_visible(val), visible);
+        }
+    }
 }

+ 2 - 2
frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option.rs

@@ -32,8 +32,8 @@ impl DateTypeOptionPB {
         Self::default()
     }
 
-    fn today_desc_from_timestamp<T: AsRef<i64>>(&self, timestamp: T) -> DateCellDataPB {
-        let timestamp = *timestamp.as_ref();
+    fn today_desc_from_timestamp<T: Into<i64>>(&self, timestamp: T) -> DateCellDataPB {
+        let timestamp = timestamp.into();
         let native = chrono::NaiveDateTime::from_timestamp(timestamp, 0);
         if native.timestamp() == 0 {
             return DateCellDataPB::default();

+ 7 - 6
frontend/rust-lib/flowy-grid/src/services/field/type_options/date_type_option/date_type_option_entities.rs

@@ -68,14 +68,15 @@ impl ToString for DateCellChangeset {
     }
 }
 
-pub struct DateTimestamp(i64);
-impl AsRef<i64> for DateTimestamp {
-    fn as_ref(&self) -> &i64 {
-        &self.0
+pub struct DateTimestamp(Option<i64>);
+
+impl std::convert::From<DateTimestamp> for i64 {
+    fn from(timestamp: DateTimestamp) -> Self {
+        timestamp.0.unwrap_or(0)
     }
 }
 
-impl std::convert::From<DateTimestamp> for i64 {
+impl std::convert::From<DateTimestamp> for Option<i64> {
     fn from(timestamp: DateTimestamp) -> Self {
         timestamp.0
     }
@@ -86,7 +87,7 @@ impl FromCellString for DateTimestamp {
     where
         Self: Sized,
     {
-        let num = s.parse::<i64>().unwrap_or(0);
+        let num = s.parse::<i64>().ok();
         Ok(DateTimestamp(num))
     }
 }

+ 1 - 0
frontend/rust-lib/flowy-grid/tests/grid/block_test/util.rs

@@ -41,6 +41,7 @@ impl<'a> GridRowTestBuilder<'a> {
         let value = serde_json::to_string(&DateCellChangeset {
             date: Some(data.to_string()),
             time: None,
+            is_utc: true,
         })
         .unwrap();
         let date_field = self.field_rev_with_type(&FieldType::DateTime);

+ 1 - 1
frontend/rust-lib/flowy-grid/tests/grid/cell_test/script.rs

@@ -29,7 +29,7 @@ impl GridCellTest {
 
         match script {
             CellScript::UpdateCell { changeset, is_err } => {
-                let result = self.editor.update_cell(changeset).await;
+                let result = self.editor.update_cell_with_changeset(changeset).await;
                 if is_err {
                     assert!(result.is_err())
                 } else {

+ 1 - 0
frontend/rust-lib/flowy-grid/tests/grid/field_test/util.rs

@@ -58,6 +58,7 @@ pub fn make_date_cell_string(s: &str) -> String {
     serde_json::to_string(&DateCellChangeset {
         date: Some(s.to_string()),
         time: None,
+        is_utc: true,
     })
     .unwrap()
 }

+ 64 - 3
frontend/rust-lib/flowy-grid/tests/grid/filter_test/date_filter_test.rs

@@ -3,15 +3,76 @@ use crate::grid::filter_test::script::GridFilterTest;
 use flowy_grid::entities::DateFilterCondition;
 
 #[tokio::test]
-#[should_panic]
-async fn grid_filter_date_is_check_test() {
+async fn grid_filter_date_is_test() {
     let mut test = GridFilterTest::new().await;
     let scripts = vec![
         CreateDateFilter {
             condition: DateFilterCondition::DateIs,
-            content: "1647251762".to_string(),
+            start: None,
+            end: None,
+            timestamp: Some(1647251762),
+        },
+        AssertNumberOfRows { expected: 3 },
+    ];
+    test.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+async fn grid_filter_date_after_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateDateFilter {
+            condition: DateFilterCondition::DateAfter,
+            start: None,
+            end: None,
+            timestamp: Some(1647251762),
+        },
+        AssertNumberOfRows { expected: 2 },
+    ];
+    test.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+async fn grid_filter_date_on_or_after_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateDateFilter {
+            condition: DateFilterCondition::DateOnOrAfter,
+            start: None,
+            end: None,
+            timestamp: Some(1668359085),
         },
         AssertNumberOfRows { expected: 2 },
     ];
     test.run_scripts(scripts).await;
 }
+
+#[tokio::test]
+async fn grid_filter_date_on_or_before_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateDateFilter {
+            condition: DateFilterCondition::DateOnOrBefore,
+            start: None,
+            end: None,
+            timestamp: Some(1668359085),
+        },
+        AssertNumberOfRows { expected: 4 },
+    ];
+    test.run_scripts(scripts).await;
+}
+
+#[tokio::test]
+async fn grid_filter_date_within_test() {
+    let mut test = GridFilterTest::new().await;
+    let scripts = vec![
+        CreateDateFilter {
+            condition: DateFilterCondition::DateWithIn,
+            start: Some(1647251762),
+            end: Some(1668704685),
+            timestamp: None,
+        },
+        AssertNumberOfRows { expected: 5 },
+    ];
+    test.run_scripts(scripts).await;
+}

+ 11 - 4
frontend/rust-lib/flowy-grid/tests/grid/filter_test/script.rs

@@ -4,7 +4,7 @@
 #![allow(unused_imports)]
 
 use futures::TryFutureExt;
-use flowy_grid::entities::{CreateFilterParams, CreateFilterPayloadPB, DeleteFilterParams, GridLayout, GridSettingChangesetParams, GridSettingPB, RowPB, TextFilterCondition, FieldType, NumberFilterCondition, CheckboxFilterCondition, DateFilterCondition};
+use flowy_grid::entities::{CreateFilterParams, CreateFilterPayloadPB, DeleteFilterParams, GridLayout, GridSettingChangesetParams, GridSettingPB, RowPB, TextFilterCondition, FieldType, NumberFilterCondition, CheckboxFilterCondition, DateFilterCondition, DateFilterContent};
 use flowy_grid::services::setting::GridSettingChangesetBuilder;
 use grid_rev_model::{FieldRevision, FieldTypeRevision};
 use flowy_grid::services::filter::FilterType;
@@ -27,7 +27,9 @@ pub enum FilterScript {
     },
     CreateDateFilter{
         condition: DateFilterCondition,
-        content: String,
+        start: Option<i64>,
+        end: Option<i64>,
+        timestamp: Option<i64>,
     },
     AssertFilterCount {
         count: i32,
@@ -91,10 +93,16 @@ impl GridFilterTest {
                     CreateFilterPayloadPB::new(field_rev, condition, "".to_string());
                 self.insert_filter(payload).await;
             }
-            FilterScript::CreateDateFilter { condition, content} => {
+            FilterScript::CreateDateFilter { condition, start, end, timestamp} => {
                 let field_rev = self.get_field_rev(FieldType::DateTime);
+                let content = DateFilterContent {
+                    start,
+                    end,
+                    timestamp,
+                }.to_string();
                 let payload =
                     CreateFilterPayloadPB::new(field_rev, condition, content);
+
                 self.insert_filter(payload).await;
             }
             FilterScript::AssertFilterCount { count } => {
@@ -125,7 +133,6 @@ impl GridFilterTest {
     }
 
     async fn insert_filter(&self, payload: CreateFilterPayloadPB) {
-
         let params: CreateFilterParams = payload.try_into().unwrap();
         let _ = self.editor.create_filter(params).await.unwrap();
     }

+ 2 - 2
frontend/rust-lib/flowy-grid/tests/grid/grid_editor.rs

@@ -236,7 +236,7 @@ fn make_test_grid() -> BuildGridContext {
                     match field_type {
                         FieldType::RichText => row_builder.insert_text_cell("DA"),
                         FieldType::Number => row_builder.insert_number_cell("4"),
-                        FieldType::DateTime => row_builder.insert_date_cell("1647251762"),
+                        FieldType::DateTime => row_builder.insert_date_cell("1668704685"),
                         FieldType::SingleSelect => {
                             row_builder.insert_single_select_cell(|mut options| options.remove(1))
                         }
@@ -250,7 +250,7 @@ fn make_test_grid() -> BuildGridContext {
                     match field_type {
                         FieldType::RichText => row_builder.insert_text_cell("AE"),
                         FieldType::Number => row_builder.insert_number_cell(""),
-                        FieldType::DateTime => row_builder.insert_date_cell("1647251762"),
+                        FieldType::DateTime => row_builder.insert_date_cell("1668359085"),
                         FieldType::SingleSelect => {
                             row_builder.insert_single_select_cell(|mut options| options.remove(2))
                         }