-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathadapter.rs
153 lines (135 loc) · 4.98 KB
/
adapter.rs
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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
/**
* -----------------------------------------------------------------------------
* ADAPTER PATTERN
*
* To execute, please run: cargo run --bin adapter
* To run tests, please run: cargo test --bin adapter
* -----------------------------------------------------------------------------
*
* An adapter pattern is a structural design pattern which allows objects with
* incompatible interfaces or traits to work together.
*
* An adapter works as a wrapper or an interpreter which allows to convert one
* type of information to another so that the information can be passed to
* another object. This process includes transformation of information.
*
* The main components of adapter pattern are as follows:
*
* 1. Target Interface : It is an interface where interaction needs to be done.
* 2. Adaptee : It is a data structure which is incompatible with the
* existing target interface.
* 3. Adapter : It creates the compatibility layer between the target
* interface and adaptee.
* 4. Client : It is the part of the code that uses adaptee to perform tasks
* that are incompatible with target interface.
*
* Adapter pattern is useful when creating plugins, parsers, media converters,
* media players, etc.
*
* The example below shows an adapter that integrates with an existing ORM to
* generate database queries directly from the json data.
*
**/
mod my_orm {
pub(crate) trait QueryTrait {
fn db_query(table_name: &str) -> Self;
fn select(&mut self, columns: Vec<&str>) -> &mut Self;
fn filter(&mut self, condition: &str) -> &mut Self;
}
#[derive(Default, Clone)]
pub(crate) struct Query {
table: String,
columns: Vec<String>,
filters: Vec<String>,
}
impl Query {
fn build_condition(&self) -> String {
if self.filters.len() > 0 {
return format!(" WHERE {}", self.filters.join(" AND "));
}
return String::new();
}
pub(crate) fn evaluate(&self) -> String {
let mut raw_query = String::from("SELECT ");
let len = self.columns.len();
if len == 0 {
raw_query.push_str("*")
} else {
raw_query.push_str(self.columns.join(", ").as_str())
}
raw_query.push_str(format!(" FROM {}", self.table).as_str());
raw_query.push_str(self.build_condition().as_str());
raw_query.push(';');
raw_query
}
}
impl QueryTrait for Query {
fn db_query(table_name: &str) -> Self {
let mut q = Query::default();
q.table = table_name.trim().to_string();
q.to_owned()
}
fn select(&mut self, columns: Vec<&str>) -> &mut Self {
self.columns = columns.iter().map(|f| f.trim().to_string()).collect();
self
}
fn filter(&mut self, condition: &str) -> &mut Self {
self.filters.push(condition.trim().to_string());
self
}
}
}
mod json_adapter {
use super::my_orm::{Query, QueryTrait};
use serde::Deserialize;
// adapter for json data
pub(crate) trait QueryUtilTrait {
fn get_query_from_json(json_string: &str) -> Result<String, String>;
}
#[derive(Deserialize)]
pub(crate) struct QueryAdapter {
_select: Vec<String>,
_from: String,
_where: Vec<String>,
}
impl QueryUtilTrait for QueryAdapter {
fn get_query_from_json(json_string: &str) -> Result<String, String> {
let query_adapter = serde_json::from_str::<QueryAdapter>(json_string);
match query_adapter {
Ok(adapter) => {
let mut q = Query::db_query(adapter._from.as_str());
q.select(adapter._select.iter().map(|v| v.as_str()).collect());
for condition in adapter._where {
q.filter(&condition);
}
Ok(q.evaluate())
}
Err(err) => {
println!("{}", err);
Err("Invalid Json Structure".to_string())
}
}
}
}
}
use json_adapter::{QueryAdapter, QueryUtilTrait};
use my_orm::{Query, QueryTrait};
fn main() {
// using query without adapter
let query1 = Query::db_query("person")
.select(vec!["id", "name"])
.filter("id > 5")
.filter("id < 10")
.evaluate();
let query2 = Query::db_query("table_name").filter("id > 5").evaluate();
println!("Raw query 1 is:\t{}", query1);
println!("Raw query 2 is:\t{}", query2);
// using query with adapter
let query_result = QueryAdapter::get_query_from_json(
r#"{"_select": ["id", "name"],"_from": "Employee","_where": ["id>5", "id<10"]}"#,
);
match query_result {
Ok(query) => println!("Raw query using adapter:\t{}", query),
Err(message) => println!("[Error]:\t{}", message),
}
}