tugraph/
types.rs

1// Copyright 2023 antkiller
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7//     http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15use std::{
16    fmt::{Debug, Display},
17    ops::Deref,
18};
19
20use chrono::Datelike;
21
22use crate::{
23    ffi,
24    raw::{RawDate, RawDateTime, RawEdgeUid},
25};
26
27/// `EdgeUid` is the primary key, or key for short, of Edge element.
28#[derive(Clone, Copy, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
29pub struct EdgeUid {
30    /// The key of source vertex.
31    pub src: i64,
32    /// The label id of the label of the Edge.
33    pub lid: u16,
34    /// The temporal id, which can be used as rank key. For example, transfer time.
35    pub tid: i64,
36    /// The key of destination vertex.
37    pub dst: i64,
38    /// The id of edge which aims to distinguish when src, lid, tid, dst are all same.
39    pub eid: i64,
40}
41
42impl EdgeUid {
43    pub(crate) fn from_raw(raw: &RawEdgeUid) -> Self {
44        unsafe {
45            let (src, lid, tid, dst, eid) = (
46                ffi::lgraph_api_edge_euid_get_src(raw.as_ptr_mut()),
47                ffi::lgraph_api_edge_euid_get_lid(raw.as_ptr_mut()),
48                ffi::lgraph_api_edge_euid_get_tid(raw.as_ptr_mut()),
49                ffi::lgraph_api_edge_euid_get_dst(raw.as_ptr_mut()),
50                ffi::lgraph_api_edge_euid_get_eid(raw.as_ptr_mut()),
51            );
52
53            EdgeUid {
54                src,
55                lid,
56                tid,
57                dst,
58                eid,
59            }
60        }
61    }
62
63    pub(crate) fn as_raw(&self) -> RawEdgeUid {
64        unsafe {
65            let ptr =
66                ffi::lgraph_api_create_edge_euid(self.src, self.dst, self.lid, self.tid, self.eid);
67            RawEdgeUid::from_ptr(ptr)
68        }
69    }
70}
71
72impl Display for EdgeUid {
73    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
74        write!(f, "{:?}", self)
75    }
76}
77
78/// `AccessLevel` is a type that represents all possible priorities of database.
79#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
80pub enum AccessLevel {
81    /// Neither can read nor write
82    #[default]
83    None = ffi::lgraph_api_access_level_none as isize,
84    /// Read only
85    Read = ffi::lgraph_api_access_level_read as isize,
86    /// Read write
87    Write = ffi::lgraph_api_access_level_write as isize,
88    /// Read write and all administrate operations
89    Full = ffi::lgraph_api_access_level_full as isize,
90}
91
92impl TryFrom<u32> for AccessLevel {
93    type Error = crate::Error;
94    fn try_from(value: u32) -> Result<Self, Self::Error> {
95        match value {
96            ffi::lgraph_api_access_level_none => Ok(Self::None),
97            ffi::lgraph_api_access_level_read => Ok(Self::Read),
98            ffi::lgraph_api_access_level_write => Ok(Self::Write),
99            ffi::lgraph_api_access_level_full => Ok(Self::Full),
100            _ => Err(crate::Error::new("Invalid parameter.".to_string())),
101        }
102    }
103}
104
105impl Display for AccessLevel {
106    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107        write!(f, "{:?}", self)
108    }
109}
110
111/// ISO 8601 calendar date without timezone.
112///
113/// See the [`crate::field::FieldData`] for details
114#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
115#[repr(transparent)]
116pub struct Date {
117    inner: chrono::NaiveDate,
118}
119
120impl Deref for Date {
121    type Target = chrono::NaiveDate;
122    fn deref(&self) -> &Self::Target {
123        &self.inner
124    }
125}
126
127impl AsRef<chrono::NaiveDate> for Date {
128    fn as_ref(&self) -> &chrono::NaiveDate {
129        &self.inner
130    }
131}
132
133impl Date {
134    pub fn from_native(native: chrono::NaiveDate) -> Self {
135        Date { inner: native }
136    }
137
138    pub(crate) fn from_raw_date(raw: &RawDate) -> Self {
139        Date {
140            inner: chrono::NaiveDate::from_num_days_from_ce_opt(raw.days_since_epoch()).unwrap(),
141        }
142    }
143
144    pub(crate) fn as_raw_date(&self) -> RawDate {
145        RawDate::from_days(self.num_days_from_ce())
146    }
147}
148
149impl Debug for Date {
150    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
151        write!(f, "{:?}", self.inner)
152    }
153}
154
155impl Display for Date {
156    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
157        write!(f, "{:?}", self)
158    }
159}
160
161/// ISO 8601 combined date and time without timezone.
162#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Hash, Default)]
163#[repr(transparent)]
164pub struct DateTime {
165    inner: chrono::NaiveDateTime,
166}
167
168impl Deref for DateTime {
169    type Target = chrono::NaiveDateTime;
170    fn deref(&self) -> &Self::Target {
171        &self.inner
172    }
173}
174
175impl AsRef<chrono::NaiveDateTime> for DateTime {
176    fn as_ref(&self) -> &chrono::NaiveDateTime {
177        &self.inner
178    }
179}
180
181impl DateTime {
182    /// Create from a [`chrono::NaiveDateTime`]. Actually DateTime is implemented in term of that.
183    ///
184    /// # Examples
185    ///
186    /// ```
187    /// use chrono::{NaiveDate, Datelike, Timelike, Weekday};
188    /// use tugraph::types::DateTime;
189    ///
190    /// let native = NaiveDate::from_ymd_opt(2016, 7, 8).unwrap().and_hms_opt(9, 10, 11).unwrap();
191    /// let dt = DateTime::from_native(native);
192    /// // Since DataTime implement Deref<Target = chrono::NaiveDateTime> trait,
193    /// // you can use methods from NaiveDateTime
194    /// assert_eq!(dt.weekday(), Weekday::Fri);
195    /// assert_eq!(dt.num_seconds_from_midnight(), 33011);
196    pub fn from_native(native: chrono::NaiveDateTime) -> Self {
197        DateTime { inner: native }
198    }
199
200    /// Create from the number of non-leap seconds
201    /// since the midnight UTC on January 1, 1970 (aka "UNIX timestamp")
202    ///
203    /// # Exmaples
204    ///
205    /// ```
206    /// use tugraph::types::DateTime;
207    /// use std::i64;
208    ///
209    /// let from_timestamp_opt = DateTime::from_timestamp_opt;
210    ///
211    /// assert!(from_timestamp_opt(0).is_some());
212    /// assert!(from_timestamp_opt(1000_000_000).is_some());
213    /// assert!(from_timestamp_opt(i64::MAX).is_none());
214    /// ```
215    pub fn from_timestamp_opt(secs: i64) -> Option<Self> {
216        chrono::NaiveDateTime::from_timestamp_opt(secs, 0).map(Self::from_native)
217    }
218
219    pub(crate) fn from_raw_datetime(raw: &RawDateTime) -> Self {
220        DateTime {
221            inner: chrono::NaiveDateTime::from_timestamp_opt(raw.seconds_since_epoch(), 0).unwrap(),
222        }
223    }
224
225    pub(crate) fn as_raw_datetime(&self) -> RawDateTime {
226        RawDateTime::from_seconds_since_epoch(self.timestamp())
227    }
228}
229
230impl Debug for DateTime {
231    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
232        write!(f, "{:?}", self.inner)
233    }
234}
235
236impl Display for DateTime {
237    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
238        write!(f, "{:?}", self)
239    }
240}
241
242#[cfg(test)]
243mod tests {
244    use super::{AccessLevel, Date, DateTime, EdgeUid};
245    use chrono::Datelike;
246
247    #[test]
248    fn test_edge_uid() {
249        let euid = EdgeUid {
250            src: 1,
251            lid: 1,
252            tid: 1,
253            dst: 1,
254            eid: 1,
255        };
256        let raw_euid = euid.as_raw();
257        assert_eq!(raw_euid.src(), 1);
258        assert_eq!(raw_euid.lid(), 1);
259        assert_eq!(raw_euid.tid(), 1);
260        assert_eq!(raw_euid.dst(), 1);
261        assert_eq!(raw_euid.eid(), 1);
262    }
263
264    #[test]
265    fn test_access_level() {
266        let none: AccessLevel = libtugraph_sys::lgraph_api_access_level_none
267            .try_into()
268            .expect("faield to convert access_level_none");
269        assert!(matches!(none, AccessLevel::None));
270        let read: AccessLevel = libtugraph_sys::lgraph_api_access_level_read
271            .try_into()
272            .expect("faield to convert access_level_read");
273        assert!(matches!(read, AccessLevel::Read));
274        let write: AccessLevel = libtugraph_sys::lgraph_api_access_level_write
275            .try_into()
276            .expect("faield to convert access_level_write");
277        assert!(matches!(write, AccessLevel::Write));
278        let full: AccessLevel = libtugraph_sys::lgraph_api_access_level_full
279            .try_into()
280            .expect("faield to convert access_level_full");
281        assert!(matches!(full, AccessLevel::Full));
282        let invalid: Result<AccessLevel, _> = 4_u32.try_into();
283        assert!(invalid.is_err());
284    }
285
286    #[test]
287    fn test_date() {
288        let date = Date::from_native(chrono::NaiveDate::from_num_days_from_ce_opt(10000).unwrap());
289        let raw_date = date.as_raw_date();
290        assert_eq!(raw_date.days_since_epoch(), date.num_days_from_ce());
291    }
292
293    #[test]
294    fn test_datetime() {
295        let datetime = DateTime::from_native(
296            chrono::NaiveDateTime::from_timestamp_opt(1_000_000_000, 0).unwrap(),
297        );
298        let raw_datetime = datetime.as_raw_datetime();
299        assert_eq!(raw_datetime.seconds_since_epoch(), datetime.timestamp());
300    }
301}