aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/lib.rs70
-rw-r--r--src/models.rs222
-rw-r--r--src/models/search.rs89
3 files changed, 381 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..7a65f31
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,70 @@
+use crate::models::{Database, ListResponse};
+use std::collections::HashMap;
+use crate::models::search::SearchRequest;
+
+mod models;
+
+struct NotionApi {
+ token: String
+}
+
+impl NotionApi {
+ /// This method is apparently deprecated
+ pub async fn list_databases(&self) -> Result<ListResponse<Database>, Box<dyn std::error::Error>> {
+ let client = reqwest::ClientBuilder::new().build()?;
+ let json = client.get("https://api.notion.com/v1/databases")
+ .bearer_auth(self.token.clone())
+ .send()
+ .await?
+ .text().await?;
+ dbg!(&json);
+ let result = serde_json::from_str(&json)?;
+
+ Ok(result)
+ }
+
+
+ pub async fn search<T: Into<SearchRequest>>(&self, query: T) -> Result<ListResponse<Database>, Box<dyn std::error::Error>> {
+ let client = reqwest::ClientBuilder::new().build()?;
+ let json = client.post("https://api.notion.com/v1/search")
+ .bearer_auth(self.token.clone())
+ .json(&query.into())
+ .send()
+ .await?
+ .text().await?;
+
+ dbg!(serde_json::from_str::<serde_json::Value>(&json)?);
+ let result = serde_json::from_str(&json)?;
+
+ Ok(result)
+ }
+}
+
+#[cfg(test)]
+mod tests {
+ use crate::NotionApi;
+ use crate::models::search::{NotionSearch, FilterValue, FilterProperty};
+ const TEST_TOKEN: &'static str = include_str!(".api_token");
+
+ #[tokio::test]
+ async fn list_databases() -> Result<(), Box<dyn std::error::Error>> {
+ let api = NotionApi {
+ token: TEST_TOKEN.to_string()
+ };
+
+ dbg!(api.list_databases().await?);
+
+ Ok(())
+ }
+
+ #[tokio::test]
+ async fn search() -> Result<(), Box<dyn std::error::Error>> {
+ let api = NotionApi {
+ token: TEST_TOKEN.to_string()
+ };
+
+ dbg!(api.search(NotionSearch::Filter {value: FilterValue::Database, property: FilterProperty::Object}).await?);
+
+ Ok(())
+ }
+}
diff --git a/src/models.rs b/src/models.rs
new file mode 100644
index 0000000..c11c97b
--- /dev/null
+++ b/src/models.rs
@@ -0,0 +1,222 @@
+pub mod search;
+
+use serde::{Serialize, Deserialize};
+use chrono::{DateTime, Utc};
+use std::collections::HashMap;
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[serde(rename_all = "lowercase")]
+enum ObjectType {
+ Database,
+ List,
+}
+
+/// A zero-cost wrapper type around a Database ID
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[serde(transparent)]
+pub struct DatabaseId(String);
+
+/// Represents a Notion Database
+/// See https://developers.notion.com/reference/database
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
+pub struct Database {
+ /// Always "database"
+ object: ObjectType,
+ /// Unique identifier for the database.
+ id: DatabaseId,
+ /// Date and time when this database was created.
+ created_time: DateTime<Utc>,
+ /// Date and time when this database was updated.
+ last_edited_time: DateTime<Utc>,
+ /// Name of the database as it appears in Notion.
+ title: Vec<RichText>,
+ /// Schema of properties for the database as they appear in Notion.
+ //
+ // key string
+ // The name of the property as it appears in Notion.
+ //
+ // value object
+ // A Property object.
+ properties: HashMap<String, PropertyConfiguration>,
+}
+
+#[derive(Serialize, Deserialize, Eq, PartialEq, Debug)]
+pub struct ListResponse<T> {
+ object: ObjectType,
+ results: Vec<T>,
+ next_cursor: Option<String>,
+ has_more: bool,
+}
+
+#[derive(Serialize, Deserialize, Eq, PartialEq, Ord, PartialOrd, Hash, Debug)]
+#[serde(transparent)]
+struct PropertyId(String);
+
+/// How the number is displayed in Notion.
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
+#[serde(tag = "type")]
+#[serde(rename_all = "snake_case")]
+enum NumberFormat {
+ Number,
+ NumberWithCommas,
+ Percent,
+ Dollar,
+ Euro,
+ Pound,
+ Yen,
+ Ruble,
+ Rupee,
+ Won,
+ Yuan,
+}
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)]
+#[serde(transparent)]
+pub struct SelectOptionId(String);
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
+#[serde(rename_all = "lowercase")]
+pub enum Color {
+ Default,
+ Gray,
+ Brown,
+ Orange,
+ Yellow,
+ Green,
+ Blue,
+ Purple,
+ Pink,
+ Red,
+}
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
+pub struct SelectOption {
+ name: String,
+ id: SelectOptionId,
+ color: Color,
+}
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
+pub struct Select {
+ /// Sorted list of options available for this property.
+ options: Vec<SelectOption>,
+}
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
+#[serde(tag = "type")]
+#[serde(rename_all = "snake_case")]
+pub enum PropertyConfiguration {
+ /// Represents the special Title property required on every database.
+ /// See https://developers.notion.com/reference/database#title-configuration
+ Title {
+ id: PropertyId,
+ },
+ /// Represents a Text property
+ /// https://developers.notion.com/reference/database#text-configuration
+ #[serde(rename = "rich_text")]
+ Text {
+ id: PropertyId,
+ },
+ /// Represents a Number Property
+ /// See https://developers.notion.com/reference/database#number-configuration
+ Number {
+ id: PropertyId,
+ /// How the number is displayed in Notion.
+ format: NumberFormat,
+ },
+ /// Represents a Select Property
+ /// See https://developers.notion.com/reference/database#select-configuration
+ Select {
+ id: PropertyId,
+ select: Select,
+ },
+ /// Represents a Date Property
+ /// See https://developers.notion.com/reference/database#date-configuration
+ Date {
+ id: PropertyId
+ },
+ /// Represents a File Property
+ /// See https://developers.notion.com/reference/database#date-configuration
+ File {
+ id: PropertyId
+ },
+}
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
+#[serde(rename_all = "snake_case")]
+pub enum TextColor {
+ Default,
+ Gray,
+ Brown,
+ Orange,
+ Yellow,
+ Green,
+ Blue,
+ Purple,
+ Pink,
+ Red,
+ GrayBackground,
+ BrownBackground,
+ OrangeBackground,
+ YellowBackground,
+ GreenBackground,
+ BlueBackground,
+ PurpleBackground,
+ PinkBackground,
+ RedBackground,
+}
+
+/// Rich text annotations
+/// See https://developers.notion.com/reference/rich-text#annotations
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
+struct Annotations {
+ bold: bool,
+ code: bool,
+ color: TextColor,
+ italic: bool,
+ strikethrough: bool,
+ underline: bool,
+}
+
+/// Properties common on all rich text objects
+/// See https://developers.notion.com/reference/rich-text#all-rich-text
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
+struct RichTextCommon {
+ plain_text: String,
+ href: Option<String>,
+ annotations: Annotations,
+}
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
+pub struct Link {
+ url: String
+}
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
+pub struct Text {
+ content: String,
+ link: Option<String>,
+}
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
+#[serde(tag = "type")]
+#[serde(rename_all = "snake_case")]
+pub enum RichText {
+ /// See https://developers.notion.com/reference/rich-text#text-objects
+ Text {
+ #[serde(flatten)]
+ rich_text: RichTextCommon,
+ text: Text,
+ },
+ /// See https://developers.notion.com/reference/rich-text#mention-objects
+ Mention {
+ #[serde(flatten)]
+ rich_text: RichTextCommon,
+ },
+ /// See https://developers.notion.com/reference/rich-text#equation-objects
+ Equation {
+ #[serde(flatten)]
+ rich_text: RichTextCommon,
+
+ },
+}
diff --git a/src/models/search.rs b/src/models/search.rs
new file mode 100644
index 0000000..cc0cdf4
--- /dev/null
+++ b/src/models/search.rs
@@ -0,0 +1,89 @@
+use serde::{Deserialize, Serialize};
+use chrono::{DateTime, Utc};
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Hash, Copy, Clone)]
+#[serde(rename_all = "snake_case")]
+pub enum SortDirection {
+ Ascending,
+ Descending
+}
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Hash, Copy, Clone)]
+#[serde(rename_all = "snake_case")]
+pub enum SortTimestamp {
+ LastEditedTime,
+}
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Hash, Copy, Clone)]
+#[serde(rename_all = "snake_case")]
+pub enum FilterValue {
+ Page,
+ Database
+}
+
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Hash, Copy, Clone)]
+#[serde(rename_all = "snake_case")]
+pub enum FilterProperty {
+ Object
+}
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
+pub struct Sort {
+ direction: SortDirection,
+ timestamp: SortTimestamp
+}
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Clone)]
+pub struct Filter {
+ value: FilterValue,
+ property: FilterProperty
+}
+
+#[derive(Serialize, Deserialize, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Clone)]
+#[serde(transparent)]
+pub struct PagingCursor(String);
+
+#[derive(Serialize, Debug, Eq, PartialEq, Default)]
+pub struct SearchRequest {
+ #[serde(skip_serializing_if = "Option::is_none")]
+ query: Option<String>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ sort: Option<Sort>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ filter: Option<Filter>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ start_cursor: Option<PagingCursor>,
+ #[serde(skip_serializing_if = "Option::is_none")]
+ page_size: Option<u8>
+}
+
+#[derive(Debug, Eq, PartialEq)]
+pub enum NotionSearch {
+ Query(String),
+ Sort{
+ direction: SortDirection,
+ timestamp: SortTimestamp
+ },
+ Filter {
+ value: FilterValue,
+ property: FilterProperty
+ }
+}
+
+impl From<NotionSearch> for SearchRequest {
+ fn from(search: NotionSearch) -> Self {
+ match search {
+ NotionSearch::Query(query) => SearchRequest { query: Some(query), ..Default::default() },
+ NotionSearch::Sort { direction, timestamp } => SearchRequest { sort: Some(Sort {
+ direction, timestamp
+ }), ..Default::default()},
+ NotionSearch::Filter { value, property } => SearchRequest {
+ filter: Some(Filter {
+ value, property
+ }),
+ ..Default::default()
+ }
+ }
+ }
+}