Compare commits
No commits in common. "main" and "feat-switch-to-surf-instead-of-reqwest" have entirely different histories.
main
...
feat-switc
5 changed files with 36 additions and 266 deletions
0
.gitignore
vendored
Executable file → Normal file
0
.gitignore
vendored
Executable file → Normal file
3
Cargo.toml
Executable file → Normal file
3
Cargo.toml
Executable file → Normal file
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "notion-client"
|
name = "notion-client"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2024"
|
edition = "2021"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
[features]
|
[features]
|
||||||
|
|
@ -20,4 +20,3 @@ regex = "1.7.1"
|
||||||
serde = { version = "^1.0", features = ["derive"], default-features = false }
|
serde = { version = "^1.0", features = ["derive"], default-features = false }
|
||||||
serde_json = { version = "^1.0", features = ["raw_value"], default-features = false }
|
serde_json = { version = "^1.0", features = ["raw_value"], default-features = false }
|
||||||
surf = { version = "2.3.2", default-features = false }
|
surf = { version = "2.3.2", default-features = false }
|
||||||
uuid = "1.16.0"
|
|
||||||
|
|
|
||||||
0
LICENSE
Executable file → Normal file
0
LICENSE
Executable file → Normal file
0
README.md
Executable file → Normal file
0
README.md
Executable file → Normal file
299
src/lib.rs
Executable file → Normal file
299
src/lib.rs
Executable file → Normal file
|
|
@ -1,12 +1,12 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use chrono::{DateTime, Utc};
|
use chrono::{DateTime, NaiveTime, Utc};
|
||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use regex::Regex;
|
use regex::Regex;
|
||||||
use serde::de::Error as SerdeError;
|
use serde::de::Error as SerdeError;
|
||||||
use serde::{Deserialize, Deserializer, Serialize};
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
use serde_json::Value;
|
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
use serde_json::Value;
|
||||||
use surf::http::StatusCode;
|
use surf::http::StatusCode;
|
||||||
|
|
||||||
use futures_core::future::BoxFuture;
|
use futures_core::future::BoxFuture;
|
||||||
|
|
@ -276,7 +276,6 @@ pub struct Databases<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Databases<'_> {
|
impl Databases<'_> {
|
||||||
// FIXME: This call can have Databases mixed in with the Page's, needs an intermediary
|
|
||||||
pub async fn query<'a>(
|
pub async fn query<'a>(
|
||||||
&self,
|
&self,
|
||||||
options: DatabaseQueryOptions<'a>,
|
options: DatabaseQueryOptions<'a>,
|
||||||
|
|
@ -389,7 +388,9 @@ pub struct Users<'a> {
|
||||||
|
|
||||||
impl Users<'_> {
|
impl Users<'_> {
|
||||||
pub async fn get(&self) -> Result<QueryResponse<User>> {
|
pub async fn get(&self) -> Result<QueryResponse<User>> {
|
||||||
let request = self.http_client.get("https://api.notion.com/v1/users");
|
let url = "https://api.notion.com/v1/users".to_owned();
|
||||||
|
|
||||||
|
let request = self.http_client.get(&url);
|
||||||
|
|
||||||
let mut response = (self.request_handler)(request).await?;
|
let mut response = (self.request_handler)(request).await?;
|
||||||
|
|
||||||
|
|
@ -701,7 +702,7 @@ pub struct ChildDatabase {
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
pub struct User {
|
pub struct User {
|
||||||
pub id: uuid::Uuid,
|
pub id: String,
|
||||||
pub name: Option<String>,
|
pub name: Option<String>,
|
||||||
pub person: Option<Person>,
|
pub person: Option<Person>,
|
||||||
pub avatar_url: Option<String>,
|
pub avatar_url: Option<String>,
|
||||||
|
|
@ -802,7 +803,7 @@ pub enum DatabaseProperty {
|
||||||
Relation {
|
Relation {
|
||||||
id: String,
|
id: String,
|
||||||
name: String,
|
name: String,
|
||||||
relation: DatabaseRelation,
|
// relation: Relation,
|
||||||
},
|
},
|
||||||
RichText {
|
RichText {
|
||||||
id: String,
|
id: String,
|
||||||
|
|
@ -811,11 +812,7 @@ pub enum DatabaseProperty {
|
||||||
Rollup {
|
Rollup {
|
||||||
id: String,
|
id: String,
|
||||||
name: String,
|
name: String,
|
||||||
function: RollupFunction,
|
// TODO: Implement Rollup
|
||||||
relation_property_id: String,
|
|
||||||
relation_property_name: String,
|
|
||||||
rollup_property_id: String,
|
|
||||||
rollup_property_name: String,
|
|
||||||
},
|
},
|
||||||
Select {
|
Select {
|
||||||
id: String,
|
id: String,
|
||||||
|
|
@ -825,8 +822,7 @@ pub enum DatabaseProperty {
|
||||||
Status {
|
Status {
|
||||||
id: String,
|
id: String,
|
||||||
name: String,
|
name: String,
|
||||||
// TODO: add "groups"
|
// TODO: Implement Status
|
||||||
options: DatabaseSelectOptions,
|
|
||||||
},
|
},
|
||||||
Title {
|
Title {
|
||||||
id: String,
|
id: String,
|
||||||
|
|
@ -845,7 +841,7 @@ pub enum DatabaseProperty {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl DatabaseProperty {
|
impl DatabaseProperty {
|
||||||
pub fn id(&self) -> Option<&str> {
|
pub fn id(&self) -> Option<String> {
|
||||||
use DatabaseProperty::*;
|
use DatabaseProperty::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -868,13 +864,13 @@ impl DatabaseProperty {
|
||||||
| Status { id, .. }
|
| Status { id, .. }
|
||||||
| Title { id, .. }
|
| Title { id, .. }
|
||||||
| Button { id, .. }
|
| Button { id, .. }
|
||||||
| Url { id, .. } => Some(id),
|
| Url { id, .. } => Some(id.to_owned()),
|
||||||
|
|
||||||
Unsupported(..) => None,
|
Unsupported(..) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn name(&self) -> Option<&str> {
|
pub fn name(&self) -> Option<String> {
|
||||||
use DatabaseProperty::*;
|
use DatabaseProperty::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -897,7 +893,7 @@ impl DatabaseProperty {
|
||||||
| Status { name, .. }
|
| Status { name, .. }
|
||||||
| Button { name, .. }
|
| Button { name, .. }
|
||||||
| Title { name, .. }
|
| Title { name, .. }
|
||||||
| Url { name, .. } => Some(name),
|
| Url { name, .. } => Some(name.to_owned()),
|
||||||
|
|
||||||
Unsupported(..) => None,
|
Unsupported(..) => None,
|
||||||
}
|
}
|
||||||
|
|
@ -921,7 +917,7 @@ where
|
||||||
|
|
||||||
serde_json::from_value::<DatabaseProperty>(value.to_owned()).unwrap_or_else(|error| {
|
serde_json::from_value::<DatabaseProperty>(value.to_owned()).unwrap_or_else(|error| {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Could not parse DatabaseProperty value because of error, defaulting to DatabaseProperty::Unsupported:\n= ERROR:\n{error:?}\n= JSON:\n{:?}\n---",
|
"Could not parse value because of error, defaulting to DatabaseProperty::Unsupported:\n= ERROR:\n{error:?}\n= JSON:\n{:?}\n---",
|
||||||
serde_json::to_string_pretty(&value).expect("to pretty print the database property error")
|
serde_json::to_string_pretty(&value).expect("to pretty print the database property error")
|
||||||
);
|
);
|
||||||
DatabaseProperty::Unsupported(value.to_owned())
|
DatabaseProperty::Unsupported(value.to_owned())
|
||||||
|
|
@ -933,179 +929,16 @@ where
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
pub struct Number {
|
pub struct Number {
|
||||||
pub format: NumberFormat,
|
// TODO: Implement NumberFormat
|
||||||
}
|
// pub format: NumberFormat
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum NumberFormat {
|
|
||||||
ArgentinePeso,
|
|
||||||
Baht,
|
|
||||||
AustralianDollar,
|
|
||||||
CanadianDollar,
|
|
||||||
ChileanPeso,
|
|
||||||
ColombianPeso,
|
|
||||||
DanishKrone,
|
|
||||||
Dirham,
|
|
||||||
Dollar,
|
|
||||||
Euro,
|
|
||||||
Forint,
|
|
||||||
Franc,
|
|
||||||
HongKongDollar,
|
|
||||||
Koruna,
|
|
||||||
Krona,
|
|
||||||
Leu,
|
|
||||||
Lira,
|
|
||||||
MexicanPeso,
|
|
||||||
NewTaiwanDollar,
|
|
||||||
NewZealandDollar,
|
|
||||||
NorwegianKrone,
|
|
||||||
Number,
|
|
||||||
NumberWithCommas,
|
|
||||||
Percent,
|
|
||||||
PhilippinePeso,
|
|
||||||
Pound,
|
|
||||||
PeruvianSol,
|
|
||||||
Rand,
|
|
||||||
Real,
|
|
||||||
Ringgit,
|
|
||||||
Riyal,
|
|
||||||
Ruble,
|
|
||||||
Rupee,
|
|
||||||
Rupiah,
|
|
||||||
Shekel,
|
|
||||||
SingaporeDollar,
|
|
||||||
UruguayanPeso,
|
|
||||||
Yen,
|
|
||||||
Yuan,
|
|
||||||
Won,
|
|
||||||
Zloty,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
|
||||||
pub struct DatabaseRelation {
|
|
||||||
database_id: String,
|
|
||||||
synced_property_name: String,
|
|
||||||
synced_property_id: String,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
pub struct Relation {
|
pub struct Relation {
|
||||||
id: String,
|
// #[serde(alias = "database_id")]
|
||||||
}
|
// id: String,
|
||||||
|
// synced_property_name: String,
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
// synced_property_id: String,
|
||||||
#[serde(tag = "type")]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
// TODO: Implement all enums here
|
|
||||||
pub enum Rollup {
|
|
||||||
Array {
|
|
||||||
function: RollupFunction,
|
|
||||||
array: Vec<RollupProperty>,
|
|
||||||
},
|
|
||||||
Date,
|
|
||||||
Incomplete,
|
|
||||||
Number,
|
|
||||||
Unsupported,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum RollupFunction {
|
|
||||||
Average,
|
|
||||||
Checked,
|
|
||||||
CountPerGroup,
|
|
||||||
Count,
|
|
||||||
CountValues,
|
|
||||||
DateRange,
|
|
||||||
EarliestDate,
|
|
||||||
Empty,
|
|
||||||
LatestDate,
|
|
||||||
Max,
|
|
||||||
Median,
|
|
||||||
Min,
|
|
||||||
NotEmpty,
|
|
||||||
PercentChecked,
|
|
||||||
PercentEmpty,
|
|
||||||
PercentNotEmpty,
|
|
||||||
PercentPerGroup,
|
|
||||||
PercentUnchecked,
|
|
||||||
Range,
|
|
||||||
Unchecked,
|
|
||||||
Unique,
|
|
||||||
ShowOriginal,
|
|
||||||
ShowUnique,
|
|
||||||
Sum,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
|
||||||
#[serde(tag = "type")]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum RollupProperty {
|
|
||||||
Checkbox {
|
|
||||||
checkbox: bool,
|
|
||||||
},
|
|
||||||
CreatedBy {},
|
|
||||||
CreatedTime {
|
|
||||||
created_time: DateValue,
|
|
||||||
},
|
|
||||||
Date {
|
|
||||||
date: Option<Date>,
|
|
||||||
},
|
|
||||||
Email {
|
|
||||||
email: Option<String>,
|
|
||||||
},
|
|
||||||
Files {
|
|
||||||
files: Vec<File>,
|
|
||||||
},
|
|
||||||
Formula {
|
|
||||||
name: Option<String>,
|
|
||||||
formula: Formula,
|
|
||||||
},
|
|
||||||
LastEditedBy {
|
|
||||||
last_edited_by: User,
|
|
||||||
},
|
|
||||||
LastEditedTime {
|
|
||||||
last_edited_time: DateValue,
|
|
||||||
},
|
|
||||||
Select {
|
|
||||||
select: Option<SelectOption>,
|
|
||||||
},
|
|
||||||
MultiSelect {
|
|
||||||
multi_select: Vec<SelectOption>,
|
|
||||||
},
|
|
||||||
Number {
|
|
||||||
number: Option<f32>,
|
|
||||||
},
|
|
||||||
People {},
|
|
||||||
PhoneNumber {},
|
|
||||||
Relation {
|
|
||||||
relation: Vec<Relation>,
|
|
||||||
},
|
|
||||||
Rollup {
|
|
||||||
rollup: Rollup,
|
|
||||||
},
|
|
||||||
RichText {
|
|
||||||
rich_text: Vec<RichText>,
|
|
||||||
},
|
|
||||||
Status {
|
|
||||||
status: Option<SelectOption>,
|
|
||||||
},
|
|
||||||
Title {
|
|
||||||
title: Vec<RichText>,
|
|
||||||
},
|
|
||||||
Url {
|
|
||||||
url: Option<String>,
|
|
||||||
},
|
|
||||||
Verification {
|
|
||||||
state: VerificationState,
|
|
||||||
verified_by: Option<User>,
|
|
||||||
date: Option<Date>,
|
|
||||||
},
|
|
||||||
UniqueId {},
|
|
||||||
Button {},
|
|
||||||
|
|
||||||
Unsupported(Value),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Paginate all possible responses
|
// TODO: Paginate all possible responses
|
||||||
|
|
@ -1114,7 +947,6 @@ pub struct QueryResponse<T> {
|
||||||
pub has_more: Option<bool>,
|
pub has_more: Option<bool>,
|
||||||
pub next_cursor: Option<String>,
|
pub next_cursor: Option<String>,
|
||||||
pub results: Vec<T>,
|
pub results: Vec<T>,
|
||||||
// pub page_or_database: Value,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
|
|
@ -1134,7 +966,6 @@ pub struct Page {
|
||||||
pub properties: HashMap<String, Property>,
|
pub properties: HashMap<String, Property>,
|
||||||
|
|
||||||
pub archived: bool,
|
pub archived: bool,
|
||||||
pub in_trash: bool,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Page {
|
impl Page {
|
||||||
|
|
@ -1168,7 +999,6 @@ pub enum Property {
|
||||||
},
|
},
|
||||||
CreatedBy {
|
CreatedBy {
|
||||||
id: String,
|
id: String,
|
||||||
created_by: User,
|
|
||||||
},
|
},
|
||||||
CreatedTime {
|
CreatedTime {
|
||||||
id: String,
|
id: String,
|
||||||
|
|
@ -1193,8 +1023,7 @@ pub enum Property {
|
||||||
},
|
},
|
||||||
LastEditedBy {
|
LastEditedBy {
|
||||||
id: String,
|
id: String,
|
||||||
last_edited_by: User,
|
}, // TODO: Implement LastEditedBy
|
||||||
},
|
|
||||||
LastEditedTime {
|
LastEditedTime {
|
||||||
id: String,
|
id: String,
|
||||||
last_edited_time: DateValue,
|
last_edited_time: DateValue,
|
||||||
|
|
@ -1213,29 +1042,24 @@ pub enum Property {
|
||||||
},
|
},
|
||||||
People {
|
People {
|
||||||
id: String,
|
id: String,
|
||||||
people: Vec<User>,
|
|
||||||
},
|
},
|
||||||
PhoneNumber {
|
PhoneNumber {
|
||||||
id: String,
|
id: String,
|
||||||
phone_number: Option<String>,
|
|
||||||
},
|
},
|
||||||
Relation {
|
Relation {
|
||||||
id: String,
|
id: String,
|
||||||
has_more: bool,
|
// relation: Vec<Relation>,
|
||||||
relation: Vec<Relation>,
|
|
||||||
},
|
},
|
||||||
Rollup {
|
Rollup {
|
||||||
id: String,
|
id: String,
|
||||||
rollup: Rollup,
|
}, // TODO: Implement Rollup
|
||||||
},
|
|
||||||
RichText {
|
RichText {
|
||||||
id: String,
|
id: String,
|
||||||
rich_text: Vec<RichText>,
|
rich_text: Vec<RichText>,
|
||||||
},
|
},
|
||||||
Status {
|
Status {
|
||||||
id: String,
|
id: String,
|
||||||
status: Option<SelectOption>,
|
}, // TODO: Implement Status
|
||||||
},
|
|
||||||
Title {
|
Title {
|
||||||
id: String,
|
id: String,
|
||||||
title: Vec<RichText>,
|
title: Vec<RichText>,
|
||||||
|
|
@ -1245,12 +1069,10 @@ pub enum Property {
|
||||||
url: Option<String>,
|
url: Option<String>,
|
||||||
},
|
},
|
||||||
Verification {
|
Verification {
|
||||||
id: String,
|
id: String, // TODO: Implement
|
||||||
verification: Verification,
|
|
||||||
},
|
},
|
||||||
UniqueId {
|
UniqueId {
|
||||||
id: String,
|
id: String,
|
||||||
unique_id: UniqueId,
|
|
||||||
},
|
},
|
||||||
Button {
|
Button {
|
||||||
id: String,
|
id: String,
|
||||||
|
|
@ -1260,7 +1082,7 @@ pub enum Property {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Property {
|
impl Property {
|
||||||
pub fn id(&self) -> Option<&str> {
|
pub fn id(&self) -> Option<String> {
|
||||||
use Property::*;
|
use Property::*;
|
||||||
|
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -1286,7 +1108,7 @@ impl Property {
|
||||||
| Formula { id, .. }
|
| Formula { id, .. }
|
||||||
| Verification { id, .. }
|
| Verification { id, .. }
|
||||||
| Button { id, .. }
|
| Button { id, .. }
|
||||||
| UniqueId { id, .. } => Some(id),
|
| UniqueId { id, .. } => Some(id.to_owned()),
|
||||||
|
|
||||||
Unsupported(_) => None,
|
Unsupported(_) => None,
|
||||||
}
|
}
|
||||||
|
|
@ -1305,7 +1127,7 @@ where
|
||||||
.map_err(D::Error::custom)?
|
.map_err(D::Error::custom)?
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|(key, value)| {
|
.map(|(key, value)| {
|
||||||
if let Value::Object(object) = value {
|
if let Value::Object(ref mut object) = value {
|
||||||
// Notion sometimes sends an empty object when it means "null", so we gotta do it's homework
|
// Notion sometimes sends an empty object when it means "null", so we gotta do it's homework
|
||||||
for value in object.values_mut() {
|
for value in object.values_mut() {
|
||||||
if value == &mut json!({}) {
|
if value == &mut json!({}) {
|
||||||
|
|
@ -1361,7 +1183,7 @@ where
|
||||||
key.to_owned(),
|
key.to_owned(),
|
||||||
serde_json::from_value::<Property>(value.to_owned()).unwrap_or_else(|error| {
|
serde_json::from_value::<Property>(value.to_owned()).unwrap_or_else(|error| {
|
||||||
log::warn!(
|
log::warn!(
|
||||||
"Could not parse Property value because of error, defaulting to Property::Unsupported:\n= ERROR:\n{error:#?}\n= JSON:\n{}\n---",
|
"Could not parse value because of error, defaulting to Property::Unsupported:\n= ERROR:\n{error:#?}\n= JSON:\n{}\n---",
|
||||||
serde_json::to_string_pretty(&value).expect("to pretty print Property errors")
|
serde_json::to_string_pretty(&value).expect("to pretty print Property errors")
|
||||||
);
|
);
|
||||||
Property::Unsupported(value.to_owned())
|
Property::Unsupported(value.to_owned())
|
||||||
|
|
@ -1371,27 +1193,6 @@ where
|
||||||
.collect::<HashMap<String, Property>>())
|
.collect::<HashMap<String, Property>>())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
|
||||||
#[serde(rename_all = "snake_case")]
|
|
||||||
pub enum VerificationState {
|
|
||||||
Verified,
|
|
||||||
Unverified,
|
|
||||||
Expired,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
|
||||||
pub struct Verification {
|
|
||||||
state: VerificationState,
|
|
||||||
verified_by: Option<User>,
|
|
||||||
date: Option<Date>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
|
||||||
pub struct UniqueId {
|
|
||||||
number: i32,
|
|
||||||
prefix: Option<String>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
#[serde(tag = "type")]
|
#[serde(tag = "type")]
|
||||||
#[serde(rename_all = "snake_case")]
|
#[serde(rename_all = "snake_case")]
|
||||||
|
|
@ -1413,38 +1214,6 @@ pub enum Formula {
|
||||||
Unsupported,
|
Unsupported,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToString for Formula {
|
|
||||||
fn to_string(&self) -> String {
|
|
||||||
match self {
|
|
||||||
Formula::String {
|
|
||||||
string: Some(string),
|
|
||||||
..
|
|
||||||
} => string.to_owned(),
|
|
||||||
Formula::Number {
|
|
||||||
number: Some(number),
|
|
||||||
..
|
|
||||||
} => format!("{number}"),
|
|
||||||
Formula::Boolean {
|
|
||||||
boolean: Some(boolean),
|
|
||||||
..
|
|
||||||
} => format!("{boolean}"),
|
|
||||||
Formula::Date {
|
|
||||||
date: Some(date), ..
|
|
||||||
} => format!("{date}"),
|
|
||||||
|
|
||||||
Formula::Unsupported => {
|
|
||||||
log::warn!("User tried stringifying unsupported formula");
|
|
||||||
"Formula output unsupported".to_owned()
|
|
||||||
}
|
|
||||||
|
|
||||||
Formula::Number { number: None, .. }
|
|
||||||
| Formula::Date { date: None, .. }
|
|
||||||
| Formula::Boolean { boolean: None, .. }
|
|
||||||
| Formula::String { string: None, .. } => "".to_owned(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
pub struct PartialUser {
|
pub struct PartialUser {
|
||||||
pub id: String,
|
pub id: String,
|
||||||
|
|
@ -1555,7 +1324,7 @@ pub struct PartialBlock {
|
||||||
pub struct Date {
|
pub struct Date {
|
||||||
pub start: DateValue,
|
pub start: DateValue,
|
||||||
pub end: Option<DateValue>,
|
pub end: Option<DateValue>,
|
||||||
// TODO: Implement for updating with timezone in the future?
|
// TODO: Implement for setting
|
||||||
pub time_zone: Option<String>,
|
pub time_zone: Option<String>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1573,8 +1342,8 @@ impl std::fmt::Display for Date {
|
||||||
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
|
||||||
#[serde(try_from = "String", into = "String")]
|
#[serde(try_from = "String", into = "String")]
|
||||||
pub enum DateValue {
|
pub enum DateValue {
|
||||||
Date(DateTime<Utc>),
|
|
||||||
DateTime(DateTime<Utc>),
|
DateTime(DateTime<Utc>),
|
||||||
|
Date(chrono::NaiveDate),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TryFrom<String> for DateValue {
|
impl TryFrom<String> for DateValue {
|
||||||
|
|
@ -1583,7 +1352,9 @@ impl TryFrom<String> for DateValue {
|
||||||
fn try_from(string: String) -> Result<DateValue> {
|
fn try_from(string: String) -> Result<DateValue> {
|
||||||
// NOTE: is either ISO 8601 Date or assumed to be ISO 8601 DateTime
|
// NOTE: is either ISO 8601 Date or assumed to be ISO 8601 DateTime
|
||||||
let value = if ISO_8601_DATE.is_match(&string) {
|
let value = if ISO_8601_DATE.is_match(&string) {
|
||||||
DateValue::Date(DateTime::parse_from_rfc3339(&format!("{string}T00:00:00Z"))?.into())
|
DateValue::Date(
|
||||||
|
DateTime::parse_from_rfc3339(&format!("{string}T00:00:00Z"))?.date_naive(),
|
||||||
|
)
|
||||||
} else {
|
} else {
|
||||||
DateValue::DateTime(DateTime::parse_from_rfc3339(&string)?.with_timezone(&Utc))
|
DateValue::DateTime(DateTime::parse_from_rfc3339(&string)?.with_timezone(&Utc))
|
||||||
};
|
};
|
||||||
|
|
@ -1601,7 +1372,7 @@ impl From<DateValue> for String {
|
||||||
impl std::fmt::Display for DateValue {
|
impl std::fmt::Display for DateValue {
|
||||||
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
fn fmt(&self, formatter: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
let value = match self {
|
let value = match self {
|
||||||
DateValue::Date(date) => date.format("%Y-%m-%d").to_string(),
|
DateValue::Date(date) => date.and_time(NaiveTime::MIN).and_utc().to_rfc3339(),
|
||||||
DateValue::DateTime(date_time) => date_time.to_rfc3339(),
|
DateValue::DateTime(date_time) => date_time.to_rfc3339(),
|
||||||
};
|
};
|
||||||
Ok(write!(formatter, "{}", value)?)
|
Ok(write!(formatter, "{}", value)?)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue