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
use crate::sql::{DBObject, TypeWriter};
use crate::type_writers::Postgresql;
use crate::util::*;
use std::error::Error;
use std::fs::File;
use std::io::prelude::*;

type BxTypeWriter = Box<dyn TypeWriter>;
type Objects = Vec<Box<dyn DBObject>>;

/// DML processor and SQL generator
///
/// Collects DBObject's and creates SQL sql_statements using the supplied
///  TypeWriter or Postgresql if none is provided
pub struct Processor<'a> {
    objs: Vec<Box<&'a dyn DBObject>>,
    type_writer:BxTypeWriter,
}

impl <'a> Processor<'a> {
    /// Create a new Processor optionally specifying a TypeWriter to use
    pub fn new(type_writer:Option<BxTypeWriter>) -> Self {
        let type_writer = if let Some(tr) = type_writer {
            tr
        } else {
            Box::new(Postgresql{})
        };
        Processor {
            objs: Vec::new(),
            type_writer,
        }
    }
    /// Create a new Processor optionally specifying a TypeWriter to use
    pub fn new_with_objects(objects:&'a Objects, type_writer:Option<BxTypeWriter>) -> Self {
        let mut me = Processor::new(type_writer);
        for obj in objects.iter() {
            me.objs.push(Box::new(obj.as_ref()))
        }
        me
    }
    /// Add a DB object
    pub fn add(&mut self, object:&'a dyn DBObject) -> &Self {
        self.objs.push(Box::new(object));
        self
    }
    /// Get the list of serialized SQL sql_statements
    pub fn sql_statements(&self) -> Vec<String> {
        let mut out = Vec::new();
        for obj in &self.objs {
            out.push(obj.to_sql(self.type_writer.as_ref()))
        }
        out
    }
    /// Get a String with all of the SQL statments
    pub fn join_sql_statements(&self) -> String {
        self.sql_statements().join("\n")
    }
    /// Write objects to a YAML file
    pub fn serialize_to_yaml_file(&self, file_name:&str) -> Result<(), Box<dyn Error>> {
        Ok(write_yaml_to_file(file_name, &self.objs)?)
    }
    /// Write generated SQL to file
    pub fn write_to_sql_file(&self, file_name:&str) -> Result<(), Box<dyn Error>> {
        let sqls = self.join_sql_statements();
        let mut fh = File::create(file_name)?;
        Ok(fh.write_all(&sqls.as_bytes())?)
    }
    /// Get number of objects present
    pub fn objects(&self) -> &Vec<Box<&'a dyn DBObject>> {
        &self.objs
    }
}


/// DML yaml loader
///
/// Loads DBObject's from a .yaml file and permits accesing them
/// Used for giving scope to Processor
pub struct Loader {
    objs: Objects,
}

impl Loader {
    /// Create Loader from YAML in a String
    pub fn new(data:&str) -> Result<Self, Box<dyn Error>> {
        Ok(Loader {
            objs: read_yaml_from_string(data).expect(format!("To load objects from string '{data}'").as_str())
        })
    }
    /// Create Loader reading from a YAML file
    pub fn new_from_file(file_name:&str) -> Result<Self, Box<dyn Error>> {
        Ok(Loader {
            objs: read_yaml_from_file(file_name).expect(format!("To load objects from '{file_name}'").as_str())
        })
    }
    pub fn objects(&self) -> &Objects {
        &self.objs
    }
}