xapi_rs/db/
mod.rs

1// SPDX-License-Identifier: GPL-3.0-or-later
2
3#![warn(missing_docs)]
4#![doc = include_str!("../../doc/DB_README.md")]
5
6pub mod activity;
7pub mod activity_profile;
8pub(crate) mod actor;
9pub mod agent_profile;
10pub(crate) mod attachment;
11pub(crate) mod context;
12pub(crate) mod filter;
13mod mockdb;
14pub(crate) mod result;
15pub(crate) mod schema;
16pub mod state;
17pub mod statement;
18pub(crate) mod sub_statement;
19pub(crate) mod user;
20pub mod verb;
21pub(crate) use mockdb::*;
22
23use serde::{Deserialize, Serialize};
24use sqlx::FromRow;
25
26/// Structure to use when SQL is RETURNING a row ID.
27#[derive(Debug, FromRow)]
28struct RowID(i32);
29
30/// Structure to use when SQL computes an aggregate.
31#[derive(Debug, FromRow)]
32struct Count(i64);
33
34/// Structure used when computing SQL Aggregates suitable for use by a client's
35/// pagination mechanism.
36#[derive(Debug, Deserialize, FromRow, Serialize)]
37pub struct Aggregates {
38    min: i32,
39    max: i32,
40    count: i64,
41}
42
43impl Aggregates {
44    /// Current value of the `min` field.
45    pub fn min(&self) -> i32 {
46        self.min
47    }
48
49    /// Current value of the `max` field.
50    pub fn max(&self) -> i32 {
51        self.max
52    }
53
54    /// Current value of the `count` field.
55    pub fn count(&self) -> i64 {
56        self.count
57    }
58}
59
60/// Macro for logging and handling errors with a custom return value to use
61/// when the database raises a `RowNotFound` error.
62#[macro_export]
63macro_rules! handle_db_error {
64    ( $err: expr, $not_found_val: expr, $( $arg: expr),* ) => {
65        match $err {
66            sqlx::Error::RowNotFound => Ok($not_found_val),
67            x => {
68                let __msg = format!($($arg),*);
69                tracing::error!("{}: {:?}", __msg, x);
70                Err(MyError::DB(x))
71            }
72        }
73    };
74}
75
76/// Macro for logging and wrapping database errors before returning them as
77/// ours.
78#[macro_export]
79macro_rules! emit_db_error {
80    ( $err: expr, $( $arg: expr),* ) => {{
81        let __msg = format!($($arg),*);
82        tracing::error!("{}: {:?}", __msg, $err);
83        Err(MyError::DB($err))
84    }};
85}
86
87#[cfg(test)]
88mod tests {
89    use serde_json::{Map, Value};
90
91    #[test]
92    fn test_serde_json_map() {
93        let s1 = r#"{ "key1": 1, "key2": "value2", "key3": { "subkey1": "subvalue1" } }"#;
94        let s2 = r#"{"key2":"value2","key1":1,"key3":{"subkey1":"subvalue1"}}"#;
95
96        let obj1: Map<String, Value> = serde_json::from_str(s1).unwrap();
97        let obj2: Map<String, Value> = serde_json::from_str(s2).unwrap();
98
99        // serde_json uses a BTree when deserializing a Map.  this should guarantee
100        // the keys are sorted.
101        assert_eq!(obj1, obj2);
102        // or by virtue of PartialEq...
103        assert!(obj1 == obj2)
104    }
105}