feat: implemented Unsupported types + more
This commit is contained in:
parent
57eb7c259e
commit
6f1cad9b89
191
src/lib.rs
191
src/lib.rs
|
@ -111,20 +111,18 @@ impl<'a> Client {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn search<'b>(self, options: SearchOptions<'b>) -> Result<QueryResponse<Page>> {
|
pub async fn search<'b, T: std::fmt::Debug + for<'de> serde::Deserialize<'de>>(self, options: SearchOptions<'b>) -> Result<QueryResponse<T>> {
|
||||||
let url = "https://api.notion.com/v1/search";
|
let response = self.http_client
|
||||||
|
.post("https://api.notion.com/v1/search")
|
||||||
let request = self.http_client
|
|
||||||
.post(url)
|
|
||||||
.json(&options)
|
.json(&options)
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
match request.error_for_status_ref() {
|
match response.error_for_status_ref() {
|
||||||
Ok(_) => Ok(request.json().await?),
|
Ok(_) => Ok(response.json().await?),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
println!("Error: {error:#?}");
|
println!("Error: {error:#?}");
|
||||||
println!("Body: {:#?}", request.json::<Value>().await?);
|
println!("Body: {:#?}", response.json::<Value>().await?);
|
||||||
Err(Error::Http(error))
|
Err(Error::Http(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -144,16 +142,16 @@ impl Pages {
|
||||||
pub async fn retrieve<'a>(self, options: PageOptions<'a>) -> Result<Page> {
|
pub async fn retrieve<'a>(self, options: PageOptions<'a>) -> Result<Page> {
|
||||||
let url = format!("https://api.notion.com/v1/pages/{page_id}", page_id = options.page_id);
|
let url = format!("https://api.notion.com/v1/pages/{page_id}", page_id = options.page_id);
|
||||||
|
|
||||||
let request = self.http_client
|
let response = self.http_client
|
||||||
.get(url)
|
.get(url)
|
||||||
.send()
|
.send()
|
||||||
.await?;
|
.await?;
|
||||||
|
|
||||||
match request.error_for_status_ref() {
|
match response.error_for_status_ref() {
|
||||||
Ok(_) => Ok(request.json().await?),
|
Ok(_) => Ok(response.json().await?),
|
||||||
Err(error) => {
|
Err(error) => {
|
||||||
println!("Error: {error:#?}");
|
println!("Error: {error:#?}");
|
||||||
println!("Body: {:#?}", request.json::<Value>().await?);
|
println!("Body: {:#?}", response.json::<Value>().await?);
|
||||||
Err(Error::Http(error))
|
Err(Error::Http(error))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -284,7 +282,7 @@ impl TryFrom<Value> for Block {
|
||||||
"column_list" => BlockType::ColumnList(parse("column_list", &data)?),
|
"column_list" => BlockType::ColumnList(parse("column_list", &data)?),
|
||||||
"column" => BlockType::Column(parse("column", &data)?),
|
"column" => BlockType::Column(parse("column", &data)?),
|
||||||
|
|
||||||
string => BlockType::Unsupported(string.to_string())
|
string => BlockType::Unsupported(string.to_string(), data)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
|
@ -313,7 +311,7 @@ pub enum BlockType {
|
||||||
PDF(PDF),
|
PDF(PDF),
|
||||||
ColumnList(ColumnList),
|
ColumnList(ColumnList),
|
||||||
Column(Column),
|
Column(Column),
|
||||||
Unsupported(String),
|
Unsupported(String, Value),
|
||||||
|
|
||||||
// TODO: Implement
|
// TODO: Implement
|
||||||
Toggle,
|
Toggle,
|
||||||
|
@ -545,7 +543,7 @@ pub struct Database {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
pub title: Vec<RichText>,
|
pub title: Vec<RichText>,
|
||||||
pub description: Vec<RichText>,
|
pub description: Vec<RichText>,
|
||||||
pub properties: Properties,
|
pub properties: DatabaseProperties,
|
||||||
pub url: String,
|
pub url: String,
|
||||||
|
|
||||||
pub parent: Parent,
|
pub parent: Parent,
|
||||||
|
@ -627,15 +625,44 @@ impl TryFrom<Value> for Properties {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub enum PropertyResponse {
|
#[serde(try_from = "Value")]
|
||||||
List(Vec<Property>),
|
pub struct DatabaseProperties {
|
||||||
PropertyItem(Box<Property>)
|
pub map: HashMap<String, DatabaseProperty>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl DatabaseProperties {
|
||||||
|
pub fn get(&self, key: &str) -> Option<DatabaseProperty> {
|
||||||
|
match self.map.get(key) {
|
||||||
|
Some(property) => Some(property.to_owned()),
|
||||||
|
None => None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn keys(&self) -> Vec<String> {
|
||||||
|
self.map.keys()
|
||||||
|
.map(|key| key.to_string())
|
||||||
|
.collect()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Value> for DatabaseProperties {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from(data: Value) -> Result<DatabaseProperties> {
|
||||||
|
let mut map = HashMap::new();
|
||||||
|
|
||||||
|
for key in data.as_object().unwrap().keys() {
|
||||||
|
map.insert(key.to_owned(), parse(key, &data)?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(DatabaseProperties { map })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
#[allow(unused)]
|
#[allow(unused)]
|
||||||
pub struct PartialProperty {
|
pub struct PartialProperty {
|
||||||
pub id: String,
|
pub id: String
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
@ -660,7 +687,39 @@ pub enum PropertyType {
|
||||||
CreatedBy,
|
CreatedBy,
|
||||||
LastEditedTime,
|
LastEditedTime,
|
||||||
LastEditedBy,
|
LastEditedBy,
|
||||||
Unknown
|
Empty,
|
||||||
|
Unsupported(String, Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
#[allow(unused)]
|
||||||
|
pub enum DatabasePropertyType {
|
||||||
|
RichText,
|
||||||
|
Number,
|
||||||
|
Select(Vec<SelectOption>),
|
||||||
|
MultiSelect(Vec<SelectOption>),
|
||||||
|
Date,
|
||||||
|
Formula(DatabaseFormula),
|
||||||
|
Relation,
|
||||||
|
Rollup,
|
||||||
|
Title,
|
||||||
|
People,
|
||||||
|
Files,
|
||||||
|
Checkbox,
|
||||||
|
Url,
|
||||||
|
Email,
|
||||||
|
PhoneNumber,
|
||||||
|
CreatedTime,
|
||||||
|
CreatedBy,
|
||||||
|
LastEditedTime,
|
||||||
|
LastEditedBy,
|
||||||
|
Empty,
|
||||||
|
Unsupported(String, Value)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
pub struct DatabaseFormula {
|
||||||
|
pub expression: String
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
@ -670,7 +729,7 @@ pub enum Formula {
|
||||||
Number(Option<i32>),
|
Number(Option<i32>),
|
||||||
Boolean(Option<bool>),
|
Boolean(Option<bool>),
|
||||||
Date(Option<Date>),
|
Date(Option<Date>),
|
||||||
Unknown
|
Unsupported(String, Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Value> for Formula {
|
impl TryFrom<Value> for Formula {
|
||||||
|
@ -683,7 +742,7 @@ impl TryFrom<Value> for Formula {
|
||||||
"number" => Formula::Number(parse("number", &data)?),
|
"number" => Formula::Number(parse("number", &data)?),
|
||||||
"boolean" => Formula::Boolean(parse("boolean", &data)?),
|
"boolean" => Formula::Boolean(parse("boolean", &data)?),
|
||||||
"date" => Formula::Date(parse("date", &data)?),
|
"date" => Formula::Date(parse("date", &data)?),
|
||||||
_ => Formula::Unknown
|
key => Formula::Unsupported(key.to_string(), data)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -738,7 +797,7 @@ pub enum RichText {
|
||||||
Text(Text, String),
|
Text(Text, String),
|
||||||
Mention(Mention, String),
|
Mention(Mention, String),
|
||||||
Equation(Equation, String),
|
Equation(Equation, String),
|
||||||
Unknown
|
Unsupported(String, Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Value> for RichText {
|
impl TryFrom<Value> for RichText {
|
||||||
|
@ -755,7 +814,7 @@ impl TryFrom<Value> for RichText {
|
||||||
"text" => RichText::Text(serde_json::from_value(data)?, plain_text),
|
"text" => RichText::Text(serde_json::from_value(data)?, plain_text),
|
||||||
"mention" => RichText::Mention(serde_json::from_value(data)?, plain_text),
|
"mention" => RichText::Mention(serde_json::from_value(data)?, plain_text),
|
||||||
"equation" => RichText::Equation(serde_json::from_value(data)?, plain_text),
|
"equation" => RichText::Equation(serde_json::from_value(data)?, plain_text),
|
||||||
_ => RichText::Unknown
|
key => RichText::Unsupported(key.to_string(), data)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -808,7 +867,7 @@ pub enum Mention {
|
||||||
Database(PartialDatabase),
|
Database(PartialDatabase),
|
||||||
Date(Date),
|
Date(Date),
|
||||||
LinkPreview(LinkPreview),
|
LinkPreview(LinkPreview),
|
||||||
Unknown
|
Unsupported(String, Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Value> for Mention {
|
impl TryFrom<Value> for Mention {
|
||||||
|
@ -822,10 +881,10 @@ impl TryFrom<Value> for Mention {
|
||||||
match parse::<String>("type", mention)?.as_str() {
|
match parse::<String>("type", mention)?.as_str() {
|
||||||
"user" => Mention::User(parse("user", mention)?),
|
"user" => Mention::User(parse("user", mention)?),
|
||||||
"page" => Mention::Page(parse("page", mention)?),
|
"page" => Mention::Page(parse("page", mention)?),
|
||||||
"date" => Mention::Date(parse("date", mention)?),
|
"date" => Mention::Date(parse("date", &mention)?),
|
||||||
"database" => Mention::Database(parse("database", mention)?),
|
"database" => Mention::Database(parse("database", mention)?),
|
||||||
"link_preview" => Mention::LinkPreview(parse("link_preview", mention)?),
|
"link_preview" => Mention::LinkPreview(parse("link_preview", mention)?),
|
||||||
_ => Mention::Unknown
|
key => Mention::Unsupported(key.to_string(), data)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -838,12 +897,12 @@ pub struct LinkPreview {
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct PartialPage {
|
pub struct PartialPage {
|
||||||
pub id: String,
|
pub id: String
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct PartialDatabase {
|
pub struct PartialDatabase {
|
||||||
pub id: String,
|
pub id: String
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
@ -854,9 +913,9 @@ pub struct PartialBlock {
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
pub struct Date {
|
pub struct Date {
|
||||||
pub start: DateValue,
|
pub start: DateValue,
|
||||||
pub end: Option<DateValue>
|
pub end: Option<DateValue>,
|
||||||
// TODO: Implement for setting
|
// TODO: Implement for setting
|
||||||
// pub time_zone: Option<String>
|
pub time_zone: Option<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl std::fmt::Display for Date {
|
impl std::fmt::Display for Date {
|
||||||
|
@ -982,6 +1041,10 @@ impl TryFrom<Value> for Property {
|
||||||
Ok(
|
Ok(
|
||||||
Property {
|
Property {
|
||||||
id: data.get("id").ok_or_else(|| Error::NoSuchProperty("id".to_string()))?.to_string(),
|
id: data.get("id").ok_or_else(|| Error::NoSuchProperty("id".to_string()))?.to_string(),
|
||||||
|
next_url: match data.get("next_url") {
|
||||||
|
Some(value) => Some(value.as_str().ok_or_else(|| Error::NoSuchProperty("next_url".to_string()))?.to_string()),
|
||||||
|
None => None
|
||||||
|
},
|
||||||
value: match parse::<String>("type", &data)?.as_str() {
|
value: match parse::<String>("type", &data)?.as_str() {
|
||||||
"title" => PropertyType::Title(parse("title", &data)?),
|
"title" => PropertyType::Title(parse("title", &data)?),
|
||||||
"rich_text" => PropertyType::RichText(parse("rich_text", &data)?),
|
"rich_text" => PropertyType::RichText(parse("rich_text", &data)?),
|
||||||
|
@ -990,17 +1053,59 @@ impl TryFrom<Value> for Property {
|
||||||
"select" => PropertyType::Select(parse("select", &data)?),
|
"select" => PropertyType::Select(parse("select", &data)?),
|
||||||
"formula" => PropertyType::Formula(parse("formula", &data)?),
|
"formula" => PropertyType::Formula(parse("formula", &data)?),
|
||||||
"checkbox" => PropertyType::Checkbox(parse("checkbox", &data)?),
|
"checkbox" => PropertyType::Checkbox(parse("checkbox", &data)?),
|
||||||
_ => PropertyType::Unknown
|
key => PropertyType::Unsupported(key.to_string(), data)
|
||||||
},
|
|
||||||
next_url: match data.get("next_url") {
|
|
||||||
Some(value) => Some(value.as_str().ok_or_else(|| Error::NoSuchProperty("next_url".to_string()))?.to_string()),
|
|
||||||
None => None
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
|
#[allow(unused)]
|
||||||
|
#[serde(try_from = "Value")]
|
||||||
|
// FIXME: Convert to enum / PropertyType
|
||||||
|
pub struct DatabaseProperty {
|
||||||
|
pub id: String,
|
||||||
|
pub next_url: Option<String>,
|
||||||
|
#[serde(rename(serialize = "type"))]
|
||||||
|
pub kind: DatabasePropertyType
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryFrom<Value> for DatabaseProperty {
|
||||||
|
type Error = Error;
|
||||||
|
|
||||||
|
fn try_from(data: Value) -> Result<DatabaseProperty> {
|
||||||
|
Ok(
|
||||||
|
DatabaseProperty {
|
||||||
|
id: data.get("id").ok_or_else(|| Error::NoSuchProperty("id".to_string()))?.to_string(),
|
||||||
|
next_url: match data.get("next_url") {
|
||||||
|
Some(value) => Some(value.as_str().ok_or_else(|| Error::NoSuchProperty("next_url".to_string()))?.to_string()),
|
||||||
|
None => None
|
||||||
|
},
|
||||||
|
kind: match parse::<String>("type", &data)?.as_str() {
|
||||||
|
"title" => DatabasePropertyType::Title,
|
||||||
|
"rich_text" => DatabasePropertyType::RichText,
|
||||||
|
"date" => DatabasePropertyType::Date,
|
||||||
|
"multi_select" => {
|
||||||
|
// FIXME: Remove unwrap
|
||||||
|
let options = parse::<Vec<SelectOption>>("options", &data.get("multi_select").unwrap())?;
|
||||||
|
DatabasePropertyType::MultiSelect(options)
|
||||||
|
},
|
||||||
|
"select" => {
|
||||||
|
// FIXME: Remove unwrap
|
||||||
|
let options = parse::<Vec<SelectOption>>("options", &data.get("select").unwrap())?;
|
||||||
|
DatabasePropertyType::Select(options)
|
||||||
|
},
|
||||||
|
"formula" => DatabasePropertyType::Formula(parse("formula", &data)?),
|
||||||
|
"checkbox" => DatabasePropertyType::Checkbox,
|
||||||
|
key => DatabasePropertyType::Unsupported(key.to_string(), data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone)]
|
#[derive(Debug, Serialize, Deserialize, Clone)]
|
||||||
#[serde(try_from = "Value")]
|
#[serde(try_from = "Value")]
|
||||||
pub enum Parent {
|
pub enum Parent {
|
||||||
|
@ -1008,7 +1113,7 @@ pub enum Parent {
|
||||||
Database(PartialDatabase),
|
Database(PartialDatabase),
|
||||||
Block(PartialBlock),
|
Block(PartialBlock),
|
||||||
Workspace(bool),
|
Workspace(bool),
|
||||||
Unknown
|
Unsupported(String, Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Value> for Parent {
|
impl TryFrom<Value> for Parent {
|
||||||
|
@ -1021,7 +1126,7 @@ impl TryFrom<Value> for Parent {
|
||||||
"database_id" => Parent::Database(PartialDatabase { id: parse(parse::<String>("type", &data)?.as_str(), &data)? }),
|
"database_id" => Parent::Database(PartialDatabase { id: parse(parse::<String>("type", &data)?.as_str(), &data)? }),
|
||||||
"block_id" => Parent::Block(PartialBlock { id: parse(parse::<String>("type", &data)?.as_str(), &data)? }),
|
"block_id" => Parent::Block(PartialBlock { id: parse(parse::<String>("type", &data)?.as_str(), &data)? }),
|
||||||
"workspace" => Parent::Workspace(parse("workspace", &data)?),
|
"workspace" => Parent::Workspace(parse("workspace", &data)?),
|
||||||
_ => Parent::Unknown
|
key => Parent::Unsupported(key.to_string(), data)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1033,7 +1138,7 @@ impl TryFrom<Value> for Parent {
|
||||||
pub enum File {
|
pub enum File {
|
||||||
Notion(String, DateValue),
|
Notion(String, DateValue),
|
||||||
External(String),
|
External(String),
|
||||||
Unknown
|
Unsupported(String, Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Value> for File {
|
impl TryFrom<Value> for File {
|
||||||
|
@ -1053,7 +1158,7 @@ impl TryFrom<Value> for File {
|
||||||
let external = data.get("external").ok_or_else(|| Error::NoSuchProperty("file".to_string()))?;
|
let external = data.get("external").ok_or_else(|| Error::NoSuchProperty("file".to_string()))?;
|
||||||
File::External(parse::<String>("url", external)?)
|
File::External(parse::<String>("url", external)?)
|
||||||
},
|
},
|
||||||
_ => File::Unknown
|
key => File::Unsupported(key.to_string(), data)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1064,7 +1169,7 @@ impl TryFrom<Value> for File {
|
||||||
pub enum Icon {
|
pub enum Icon {
|
||||||
File(File),
|
File(File),
|
||||||
Emoji(String),
|
Emoji(String),
|
||||||
Unknown
|
Unsupported(String, Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<Value> for Icon {
|
impl TryFrom<Value> for Icon {
|
||||||
|
@ -1075,7 +1180,7 @@ impl TryFrom<Value> for Icon {
|
||||||
match parse::<String>("type", &data)?.as_str() {
|
match parse::<String>("type", &data)?.as_str() {
|
||||||
"file" => Icon::File(serde_json::from_value::<File>(data)?),
|
"file" => Icon::File(serde_json::from_value::<File>(data)?),
|
||||||
"emoji" => Icon::Emoji(parse::<String>("emoji", &data)?),
|
"emoji" => Icon::Emoji(parse::<String>("emoji", &data)?),
|
||||||
_ => Icon::Unknown
|
key => Icon::Unsupported(key.to_string(), data)
|
||||||
}
|
}
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -1086,5 +1191,3 @@ impl std::fmt::Display for Error {
|
||||||
Ok(write!(formatter, "NotionError::{:?}", self)?)
|
Ok(write!(formatter, "NotionError::{:?}", self)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue