object_store_opendal/lib.rs
1// Licensed to the Apache Software Foundation (ASF) under one
2// or more contributor license agreements. See the NOTICE file
3// distributed with this work for additional information
4// regarding copyright ownership. The ASF licenses this file
5// to you under the Apache License, Version 2.0 (the
6// "License"); you may not use this file except in compliance
7// with the License. You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing,
12// software distributed under the License is distributed on an
13// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14// KIND, either express or implied. See the License for the
15// specific language governing permissions and limitations
16// under the License.
17
18//! object_store_opendal is an object store implementation using opendal.
19//!
20//! This crate can help you to access 30 more storage services with the same object_store API.
21//!
22//! ```no_run
23//! use std::sync::Arc;
24//!
25//! use bytes::Bytes;
26//! use object_store::path::Path;
27//! use object_store::ObjectStore;
28//! use object_store::ObjectStoreExt;
29//! use object_store_opendal::OpendalStore;
30//! use opendal::services::S3;
31//! use opendal::{Builder, Operator};
32//!
33//! #[tokio::main]
34//! async fn main() {
35//! let builder = S3::default()
36//! .access_key_id("my_access_key")
37//! .secret_access_key("my_secret_key")
38//! .endpoint("my_endpoint")
39//! .region("my_region");
40//!
41//! // Create a new operator
42//! let operator = Operator::new(builder).unwrap().finish();
43//!
44//! // Create a new object store
45//! let object_store = Arc::new(OpendalStore::new(operator));
46//!
47//! let path = Path::from("data/nested/test.txt");
48//! let bytes = Bytes::from_static(b"hello, world! I am nested.");
49//!
50//! object_store.put(&path, bytes.clone().into()).await.unwrap();
51//!
52//! let content = object_store
53//! .get(&path)
54//! .await
55//! .unwrap()
56//! .bytes()
57//! .await
58//! .unwrap();
59//!
60//! assert_eq!(content, bytes);
61//! }
62//! ```
63
64mod store;
65pub use store::OpendalStore;
66
67mod utils;
68
69#[cfg(feature = "services-s3")]
70mod amazon_s3;
71
72mod service;
73
74pub use service::{ObjectStoreBuilder, ObjectStoreService};
75
76// Make sure `send_wrapper` works as expected
77#[cfg(all(feature = "send_wrapper", test))]
78mod assert_send {
79 use object_store::{ObjectStore, ObjectStoreExt, PutPayload};
80 use opendal::Operator;
81
82 #[allow(dead_code)]
83 fn assert_send<T: Send>(_: T) {}
84
85 #[allow(dead_code)]
86 fn assertion() {
87 let op = Operator::new(opendal::services::Memory::default())
88 .unwrap()
89 .finish();
90 let store = super::OpendalStore::new(op);
91 assert_send(store.put(&"test".into(), PutPayload::new()));
92 assert_send(store.get(&"test".into()));
93 assert_send(store.get_range(&"test".into(), 0..1));
94 assert_send(store.head(&"test".into()));
95 assert_send(store.delete(&"test".into()));
96 assert_send(store.list(None));
97 assert_send(store.list_with_offset(None, &"test".into()));
98 assert_send(store.list_with_delimiter(None));
99 }
100}
101
102fn timestamp_to_datetime(ts: opendal::raw::Timestamp) -> Option<chrono::DateTime<chrono::Utc>> {
103 let jiff_ts = ts.into_inner();
104 chrono::DateTime::<chrono::Utc>::from_timestamp(
105 jiff_ts.as_second(),
106 jiff_ts.subsec_nanosecond() as u32,
107 )
108}
109
110fn datetime_to_timestamp(dt: chrono::DateTime<chrono::Utc>) -> Option<opendal::raw::Timestamp> {
111 opendal::raw::Timestamp::new(dt.timestamp(), dt.timestamp_subsec_nanos() as i32).ok()
112}