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
use c3p0::{Model, Jpo};
use postgres::{Connection};

pub struct JpoPg {
    id_field_name: String,
    version_field_name: String,
    data_field_name: String,
    table_name: String,
    conn: Connection
}

impl JpoPg {
    pub fn new<D>(conn: Connection, table_name: &str) -> impl Jpo<D>
    where D: Clone + serde::ser::Serialize + serde::de::DeserializeOwned
    {
        JpoPg{
            conn,
            table_name: table_name.to_owned(),
            id_field_name: "id".to_owned(),
            version_field_name: "version".to_owned(),
            data_field_name: "data".to_owned(),
        }
    }

    pub fn new_custom<S: Into<String>, D>(conn: Connection, table_name: S, id_field_name: S,
    version_field_name: S,  data_field_name: S) -> impl Jpo<D>
        where D: Clone + serde::ser::Serialize + serde::de::DeserializeOwned
    {
        JpoPg{
            conn,
            table_name: table_name.into(),
            id_field_name: id_field_name.into(),
            version_field_name: version_field_name.into(),
            data_field_name: data_field_name.into(),
        }
    }
}

impl <DATA: Clone + serde::ser::Serialize + serde::de::DeserializeOwned> Jpo<DATA> for JpoPg {

    fn find_by_id(&self, id: i64) -> Option<Model<DATA>> {
        let query = format!("SELECT {}, {}, {} FROM {} WHERE {} = $1",
                            self.id_field_name,
                            self.version_field_name,
                            self.data_field_name,
                            self.table_name,
                            self.id_field_name,
        );
        let stmt = self.conn.prepare(&query).unwrap();
        let result = stmt.query(&[&id]).unwrap().iter().next().map(|row| {
            Model{
                id: Some(row.get(0)),
                version: row.get(1),
                data: serde_json::from_value::<DATA>(row.get(2)).unwrap()
            }
        });
        result
    }

    fn save(&self, obj: &Model<DATA>) -> Model<DATA> {
        let query = format!("INSERT INTO {} ({}, {}) VALUES ($1, $2) RETURNING {}",
            self.table_name,
            self.version_field_name,
            self.data_field_name,
            self.id_field_name
        );
        let stmt = self.conn.prepare(&query).unwrap();
        let json_data = serde_json::to_value(&obj.data).unwrap();
        let id: i64 = stmt.query(&[&obj.version, &json_data]).unwrap().iter().next().unwrap().get(0);

        let mut clone = obj.clone();
        clone.id = Some(id);
        clone
    }
}