From 371a3e49ffe52c2684030f4d3cb669a3aac2b3ca Mon Sep 17 00:00:00 2001 From: Jake Swenson Date: Sat, 15 May 2021 10:01:03 -0700 Subject: adding basic property filters --- src/lib.rs | 41 +++++++++++++++++++++++++++++++++++-- src/models.rs | 20 ++++++++++++++---- src/models/search.rs | 58 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+), 6 deletions(-) (limited to 'src') diff --git a/src/lib.rs b/src/lib.rs index 19d79ee..3636ab7 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,6 +11,23 @@ const NOTION_API_VERSION: &'static str = "2021-05-13"; // todo: replace with proper snafu error pub type NotionApiClientError = Box; +trait Identifiable { + // There should only be one way to identify an object + type Type; + fn id(&self) -> &Self::Type; +} + +impl Identifiable for &U +where + U: Identifiable, +{ + type Type = T; + + fn id(&self) -> &Self::Type { + self.id() + } +} + struct NotionApi { client: Client, } @@ -63,16 +80,36 @@ impl NotionApi { .await?) } - pub async fn get_database>( + pub async fn get_database>( &self, database_id: T, ) -> Result> { Ok(NotionApi::make_json_request(self.client.get(format!( "https://api.notion.com/v1/databases/{}", - database_id.as_ref().id() + database_id.id().id() ))) .await?) } + + pub async fn query_database( + &self, + database: D, + query: T, + ) -> Result, NotionApiClientError> + where + T: Into, + D: Identifiable, + { + Ok(NotionApi::make_json_request( + self.client + .post(&format!( + "https://api.notion.com/v1/databases/{database_id}/query", + database_id = database.id() + )) + .json(&query.into()), + ) + .await?) + } } #[cfg(test)] diff --git a/src/models.rs b/src/models.rs index 4500cc0..bb1ba42 100644 --- a/src/models.rs +++ b/src/models.rs @@ -8,8 +8,10 @@ use crate::models::text::RichText; use serde::{Deserialize, Serialize}; use std::collections::HashMap; +use crate::Identifiable; pub use chrono::{DateTime, Utc}; pub use serde_json::value::Number; +use std::fmt::{Display, Formatter}; #[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Copy, Clone)] #[serde(rename_all = "lowercase")] @@ -29,12 +31,20 @@ impl DatabaseId { } } -impl AsRef for DatabaseId { - fn as_ref(&self) -> &Self { +impl Identifiable for DatabaseId { + type Type = DatabaseId; + + fn id(&self) -> &Self::Type { self } } +impl Display for DatabaseId { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + /// Represents a Notion Database /// See https://developers.notion.com/reference/database #[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)] @@ -57,8 +67,10 @@ pub struct Database { properties: HashMap, } -impl AsRef for Database { - fn as_ref(&self) -> &DatabaseId { +impl Identifiable for Database { + type Type = DatabaseId; + + fn id(&self) -> &Self::Type { &self.id } } diff --git a/src/models/search.rs b/src/models/search.rs index ee0bb51..09a74b4 100644 --- a/src/models/search.rs +++ b/src/models/search.rs @@ -51,6 +51,42 @@ pub struct SearchRequest { paging: Option, } +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)] +#[serde(rename_all = "snake_case")] +pub enum TextCondition { + Equals(String), + DoesNotEqual(String), + Contains(String), + DoesNotContain(String), + StartsWith(String), + EndsWith(String), + IsEmpty, + IsNotEmpty, +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)] +#[serde(rename_all = "lowercase")] +pub enum PropertyCondition { + Text(TextCondition), +} + +#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)] +pub struct FilterCondition { + property: String, + #[serde(flatten)] + condition: PropertyCondition, +} + +#[derive(Serialize, Debug, Eq, PartialEq, Default)] +pub struct DatabaseQuery { + #[serde(skip_serializing_if = "Option::is_none")] + sorts: Option, + #[serde(skip_serializing_if = "Option::is_none")] + filter: Option, + #[serde(flatten)] + paging: Option, +} + #[derive(Debug, Eq, PartialEq)] pub enum NotionSearch { Query(String), @@ -88,3 +124,25 @@ impl From for SearchRequest { } } } + +#[cfg(test)] +mod tests { + mod text_filters { + use crate::models::search::PropertyCondition::Text; + use crate::models::search::{FilterCondition, PropertyCondition, TextCondition}; + + #[test] + fn text_property_equals() -> Result<(), Box> { + let json = serde_json::to_string(&FilterCondition { + property: "Name".to_string(), + condition: Text(TextCondition::Equals("Test".to_string())), + })?; + assert_eq!( + dbg!(json), + r#"{"property":"Name","text":{"equals":"Test"}}"# + ); + + Ok(()) + } + } +} -- cgit v1.2.3