object_store/client/
s3.rs

1// or more contributor license agreements.  See the NOTICE file
2// distributed with this work for additional information
3// regarding copyright ownership.  The ASF licenses this file
4// to you under the Apache License, Version 2.0 (the
5// "License"); you may not use this file except in compliance
6// with the License.  You may obtain a copy of the License at
7//
8//   http://www.apache.org/licenses/LICENSE-2.0
9//
10// Unless required by applicable law or agreed to in writing,
11// software distributed under the License is distributed on an
12// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
13// KIND, either express or implied.  See the License for the
14// specific language governing permissions and limitations
15// under the License.
16
17//! The list and multipart API used by both GCS and S3
18
19use crate::multipart::PartId;
20use crate::path::Path;
21use crate::{ListResult, ObjectMeta, Result};
22use chrono::{DateTime, Utc};
23use serde::{Deserialize, Serialize};
24
25#[derive(Debug, Deserialize)]
26#[serde(rename_all = "PascalCase")]
27pub struct ListResponse {
28    #[serde(default)]
29    pub contents: Vec<ListContents>,
30    #[serde(default)]
31    pub common_prefixes: Vec<ListPrefix>,
32    #[serde(default)]
33    pub next_continuation_token: Option<String>,
34}
35
36impl TryFrom<ListResponse> for ListResult {
37    type Error = crate::Error;
38
39    fn try_from(value: ListResponse) -> Result<Self> {
40        let common_prefixes = value
41            .common_prefixes
42            .into_iter()
43            .map(|x| Ok(Path::parse(x.prefix)?))
44            .collect::<Result<_>>()?;
45
46        let objects = value
47            .contents
48            .into_iter()
49            .map(TryFrom::try_from)
50            .collect::<Result<_>>()?;
51
52        Ok(Self {
53            common_prefixes,
54            objects,
55        })
56    }
57}
58
59#[derive(Debug, Deserialize)]
60#[serde(rename_all = "PascalCase")]
61pub struct ListPrefix {
62    pub prefix: String,
63}
64
65#[derive(Debug, Deserialize)]
66#[serde(rename_all = "PascalCase")]
67pub struct ListContents {
68    pub key: String,
69    pub size: usize,
70    pub last_modified: DateTime<Utc>,
71    #[serde(rename = "ETag")]
72    pub e_tag: Option<String>,
73}
74
75impl TryFrom<ListContents> for ObjectMeta {
76    type Error = crate::Error;
77
78    fn try_from(value: ListContents) -> Result<Self> {
79        Ok(Self {
80            location: Path::parse(value.key)?,
81            last_modified: value.last_modified,
82            size: value.size,
83            e_tag: value.e_tag,
84            version: None,
85        })
86    }
87}
88
89#[derive(Debug, Deserialize)]
90#[serde(rename_all = "PascalCase")]
91pub struct InitiateMultipartUploadResult {
92    pub upload_id: String,
93}
94
95#[derive(Debug, Serialize)]
96#[serde(rename_all = "PascalCase")]
97pub struct CompleteMultipartUpload {
98    pub part: Vec<MultipartPart>,
99}
100
101impl From<Vec<PartId>> for CompleteMultipartUpload {
102    fn from(value: Vec<PartId>) -> Self {
103        let part = value
104            .into_iter()
105            .enumerate()
106            .map(|(part_number, part)| MultipartPart {
107                e_tag: part.content_id,
108                part_number: part_number + 1,
109            })
110            .collect();
111        Self { part }
112    }
113}
114
115#[derive(Debug, Serialize)]
116pub struct MultipartPart {
117    #[serde(rename = "ETag")]
118    pub e_tag: String,
119    #[serde(rename = "PartNumber")]
120    pub part_number: usize,
121}
122
123#[derive(Debug, Deserialize)]
124#[serde(rename_all = "PascalCase")]
125pub struct CompleteMultipartUploadResult {
126    #[serde(rename = "ETag")]
127    pub e_tag: String,
128}