1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use serde::{Deserialize, Serialize};

/// Specifies the type of a `CompoundQuery`, defining how its `Query`s are combined.
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub enum QueryType {
    And,
    Or,
}

/// The root Query type, which can be either a `SingleQuery` or a `CompoundQuery`.
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub enum Query {
    Single(SingleQuery),
    Compound(CompoundQuery),
    GetById { id: String, collection: String },
    GetByIds { ids: Vec<String>, collection: String },
}

/// Represents a single query on a collection for a given use case.
///
/// This is the basic unit of querying in this system.
/// A `SingleQuery` operates on one collection and one use case.
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct SingleQuery {
    pub collection: String,
    pub usecase: String,
}

impl SingleQuery {
    /// Constructs a new `SingleQuery`.
    ///
    /// # Arguments
    ///
    /// * `collection` - A string specifying the collection to be queried.
    /// * `usecase` - A string specifying the use case for the query.
    ///
    /// # Returns
    ///
    /// Returns a `SingleQuery`.
    pub fn new(collection: String, usecase: String) -> Self {
        SingleQuery { collection, usecase }
    }
}

/// Represents a compound query composed of multiple `Query`s.
///
/// A `CompoundQuery` allows for complex query logic by combining multiple `Query`s
/// using a specified `QueryType` (e.g., And, Or).
#[derive(Debug, Serialize, Deserialize, PartialEq, Eq, Clone)]
pub struct CompoundQuery {
    pub query_type: QueryType,
    pub queries: Vec<Query>,
}

/// Builder for `SingleQuery`
#[derive(Debug, Default)]
pub struct SingleQueryBuilder {
    collection: String,
    usecase: String,
}

impl SingleQueryBuilder {
    pub fn with_collection(mut self, collection: String) -> Self {
        self.collection = collection;
        self
    }

    pub fn with_usecase(mut self, usecase: String) -> Self {
        self.usecase = usecase;
        self
    }

    pub fn build(self) -> SingleQuery {
        SingleQuery { collection: self.collection, usecase: self.usecase }
    }
}

impl CompoundQuery {
    /// Constructs a new `CompoundQuery`.
    ///
    /// # Arguments
    ///
    /// * `query_type` - A `QueryType` specifying how to combine the `queries`.
    /// * `queries` - A Vec of `Query`s to be combined.
    ///
    /// # Returns
    ///
    /// Returns a `CompoundQuery`.
    pub fn new(query_type: QueryType, queries: Vec<Query>) -> Self {
        CompoundQuery { query_type, queries }
    }
}

/// Builder for `CompoundQuery`
#[derive(Debug)]
pub struct CompoundQueryBuilder {
    query_type: QueryType,
    queries: Vec<Query>,
}

impl Default for CompoundQueryBuilder {
    fn default() -> Self {
        Self {
            query_type: QueryType::And,
            queries: Default::default(),
        }
    }
}

impl CompoundQueryBuilder {
    pub fn with_query_type(mut self, query_type: QueryType) -> Self {
        self.query_type = query_type;
        self
    }

    pub fn with_query(mut self, query: Query) -> Self {
        self.queries.push(query);
        self
    }

    pub fn build(self) -> CompoundQuery {
        CompoundQuery { query_type: self.query_type, queries: self.queries }
    }
}