aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGravatar Jake Swenson <jake@jakeswenson.com> 2021-05-15 10:01:03 -0700
committerGravatar Jake Swenson <jake@jakeswenson.com> 2021-05-15 10:01:03 -0700
commit371a3e49ffe52c2684030f4d3cb669a3aac2b3ca (patch)
tree8d624c21a3faf2cf437a89b1102d7be25fa28fea /src
parentd18843ab949e803e25c48f514b4e25244477c731 (diff)
downloadnotion-371a3e49ffe52c2684030f4d3cb669a3aac2b3ca.tar.gz
notion-371a3e49ffe52c2684030f4d3cb669a3aac2b3ca.tar.zst
notion-371a3e49ffe52c2684030f4d3cb669a3aac2b3ca.zip
adding basic property filters
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs41
-rw-r--r--src/models.rs20
-rw-r--r--src/models/search.rs58
3 files changed, 113 insertions, 6 deletions
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<dyn std::error::Error>;
+trait Identifiable {
+ // There should only be one way to identify an object
+ type Type;
+ fn id(&self) -> &Self::Type;
+}
+
+impl<T, U> Identifiable for &U
+where
+ U: Identifiable<Type = T>,
+{
+ 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<T: AsRef<DatabaseId>>(
+ pub async fn get_database<T: Identifiable<Type = DatabaseId>>(
&self,
database_id: T,
) -> Result<Database, Box<dyn std::error::Error>> {
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<D, T>(
+ &self,
+ database: D,
+ query: T,
+ ) -> Result<ListResponse<Database>, NotionApiClientError>
+ where
+ T: Into<SearchRequest>,
+ D: Identifiable<Type = DatabaseId>,
+ {
+ 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<DatabaseId> 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<String, PropertyConfiguration>,
}
-impl AsRef<DatabaseId> 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<Paging>,
}
+#[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<Sort>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ filter: Option<FilterCondition>,
+ #[serde(flatten)]
+ paging: Option<Paging>,
+}
+
#[derive(Debug, Eq, PartialEq)]
pub enum NotionSearch {
Query(String),
@@ -88,3 +124,25 @@ impl From<NotionSearch> 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<dyn std::error::Error>> {
+ 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(())
+ }
+ }
+}