mithril_persistence/sqlite/
projection.rs1use super::SourceAlias;
2
3pub struct ProjectionField {
18 pub name: String,
20
21 pub definition: String,
23
24 pub output_type: String,
26}
27
28impl ProjectionField {
29 pub fn new(name: &str, definition: &str, output_type: &str) -> Self {
31 Self {
32 name: name.to_string(),
33 definition: definition.to_string(),
34 output_type: output_type.to_string(),
35 }
36 }
37}
38
39pub struct Projection {
43 fields: Vec<ProjectionField>,
44}
45
46impl Projection {
47 pub fn new(fields: Vec<ProjectionField>) -> Self {
49 Self { fields }
50 }
51
52 pub fn from(fields: &[(&str, &str, &str)]) -> Self {
54 let field_defs: Vec<ProjectionField> = fields
55 .iter()
56 .map(|(name, definition, sql_type)| ProjectionField::new(name, definition, sql_type))
57 .collect();
58
59 Self::new(field_defs)
60 }
61
62 pub fn add_field(&mut self, field_name: &str, definition: &str, output_type: &str) {
66 self.fields.push(ProjectionField {
67 name: field_name.to_string(),
68 definition: definition.to_string(),
69 output_type: output_type.to_string(),
70 })
71 }
72
73 pub fn get_fields(&self) -> &Vec<ProjectionField> {
75 &self.fields
76 }
77
78 pub fn expand(&self, aliases: SourceAlias) -> String {
80 let mut fields: String = self
81 .get_fields()
82 .iter()
83 .map(|field| format!("{} as {}", field.definition, field.name))
84 .collect::<Vec<String>>()
85 .join(", ");
86
87 for (alias, source) in aliases.get_iterator() {
88 fields = fields.replace(alias, source);
89 }
90
91 fields
92 }
93}
94
95impl Default for Projection {
96 fn default() -> Self {
97 Self::new(Vec::new())
98 }
99}
100
101#[cfg(test)]
102mod tests {
103 use super::*;
104
105 #[test]
106 fn simple_projection() {
107 let mut projection = Projection::default();
108 projection.add_field("test_id", "{:test:}.test_id", "integer");
109 projection.add_field("name", "{:test:}.name", "text");
110 projection.add_field("created_at", "{:test:}.created_at", "timestamp");
111 projection.add_field("thing_count", "count({:thing:}.*)", "integer");
112
113 let aliases = SourceAlias::new(&[("{:test:}", "pika"), ("{:thing:}", "thing_alias")]);
114
115 assert_eq!(
116 "pika.test_id as test_id, pika.name as name, pika.created_at as created_at, count(thing_alias.*) as thing_count".to_string(),
117 projection.expand(aliases)
118 )
119 }
120
121 #[test]
122 fn list_constructor() {
123 let projection = Projection::from(&[
124 ("something_id", "{:test:}.something_id", "integer"),
125 ("name", "{:test:}.name", "text"),
126 ("created_at", "{:test:}.created_at", "timestamp"),
127 ]);
128
129 let aliases = SourceAlias::new(&[("{:test:}", "test")]);
130
131 assert_eq!(
132 "test.something_id as something_id, test.name as name, test.created_at as created_at",
133 projection.expand(aliases)
134 );
135 }
136}