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}