notionrs_schema/object/page/files.rs
1use serde::{Deserialize, Serialize};
2
3/// <https://developers.notion.com/reference/page-property-values#files>
4///
5/// - `$.['*'].id`: An underlying identifier for the property.
6/// `id` remains constant when the property name changes.
7/// - `$.['*'].type`: Always `"files"`
8/// - `$.['*'].files`: An array of objects containing information about
9/// the [files](https://developers.notion.com/reference/file-object).
10/// If the file does not exist, an empty array will be returned.
11///
12/// **Note**: The `['*']` part represents the column name you set when creating the database.
13///
14/// Example files page property value
15///
16/// ```json
17/// {
18/// "Files & media": {
19/// "id": "Q%7Dn%3E",
20/// "type": "files",
21/// "files": [
22/// {
23/// "name": "Project Alpha blueprint",
24/// "type": "file",
25/// "file": {
26/// "url": "https://prod-files-secure.s3.us-west-2.amazonaws.com/daa95f86-2d56-4e18-be3b-16d81b31dc0d",
27/// "expiry_time": "2024-04-04T10:45:54.308Z"
28/// }
29/// }
30/// ]
31/// }
32/// }
33/// ```
34#[derive(Debug, Deserialize, Serialize, Clone, PartialEq, Eq, Default, notionrs_macro::Setter)]
35pub struct PageFilesProperty {
36 /// An underlying identifier for the property.
37 /// `id` remains constant when the property name changes.
38 #[serde(skip_serializing_if = "Option::is_none")]
39 pub id: Option<String>,
40
41 /// An array of objects containing information
42 /// about the [files](https://developers.notion.com/reference/file-object).
43 ///
44 /// When creating, both the external path of the file and `name` are required.
45 pub files: Vec<crate::object::file::File>,
46}
47
48impl<T> From<T> for PageFilesProperty
49where
50 T: AsRef<str>,
51{
52 fn from(value: T) -> Self {
53 let file = crate::object::file::File::default()
54 .url(value.as_ref())
55 .name(value.as_ref());
56 Self::default().files(vec![file])
57 }
58}
59
60impl From<crate::object::file::File> for PageFilesProperty {
61 fn from(value: crate::object::file::File) -> Self {
62 Self::default().files(vec![value])
63 }
64}
65
66impl std::fmt::Display for PageFilesProperty {
67 /// display the files' names in a comma-separated list
68 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
69 write!(
70 f,
71 "{}",
72 self.files
73 .iter()
74 .map(|file| file.to_string())
75 .collect::<Vec<String>>()
76 .join(", ")
77 )
78 }
79}
80
81// # --------------------------------------------------------------------------------
82//
83// unit test
84//
85// # --------------------------------------------------------------------------------
86
87#[cfg(test)]
88mod unit_tests {
89
90 use super::*;
91
92 #[test]
93 fn deserialize_page_files_property() {
94 let json_data = r#"
95 {
96 "File": {
97 "id": "%3AlnV",
98 "type": "files",
99 "files": [
100 {
101 "name": "0208a.jpg",
102 "type": "file",
103 "file": {
104 "url": "https://prod-files-secure.s3.us-west-2.amazonaws.com",
105 "expiry_time": "2024-08-15T05:56:14.346Z"
106 }
107 },
108 {
109 "name": "Favicon.ico",
110 "type": "external",
111 "external": {
112 "url": "https://www.notion.so/images/favicon.ico"
113 }
114 }
115 ]
116 }
117 }
118 "#;
119
120 let file_map =
121 serde_json::from_str::<std::collections::HashMap<String, PageFilesProperty>>(json_data)
122 .unwrap();
123
124 let file = file_map.get("File").unwrap();
125
126 assert_eq!(file.id, Some("%3AlnV".to_string()));
127
128 for file in &file.files {
129 match &file {
130 crate::object::file::File::Uploaded(f) => {
131 assert_eq!(f.name, Some("0208a.jpg".to_string()));
132 assert_eq!(
133 f.file.url,
134 "https://prod-files-secure.s3.us-west-2.amazonaws.com"
135 );
136 assert_eq!(f.file.expiry_time, "2024-08-15T05:56:14.346Z");
137 }
138 crate::object::file::File::External(f) => {
139 assert_eq!(f.name, Some("Favicon.ico".to_string()));
140 assert_eq!(f.external.url, "https://www.notion.so/images/favicon.ico");
141 }
142 }
143 }
144 }
145}