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 BxObject<'a> = &'a Box<&'a dyn DBObject>;
type Objects = Vec<Box<dyn DBObject>>;
pub struct Processor<'a> {
objs: Vec<Box<&'a dyn DBObject>>,
type_writer:BxTypeWriter,
}
impl <'a> Processor<'a> {
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,
}
}
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
}
pub fn add(&mut self, object:&'a dyn DBObject) -> &Self {
self.objs.push(Box::new(object));
self
}
fn add_to_toplevel(&self, obj:&mut BxObject, out:&mut Vec<String>, delayed:&mut Vec<&Box<&dyn DBObject>>) {
let sql;
if delayed.is_empty() {
sql = obj.to_sql(self.type_writer.as_ref())
} else {
sql = obj.top_level_to_sql(self.type_writer.as_ref(), &delayed);
delayed.clear()
};
if ! sql.is_empty() {
out.push(sql);
}
}
pub fn sql_statements(&self) -> Vec<String> {
let mut out = Vec::new();
let mut delayed = Vec::new();
let mut top : Option<BxObject> = None;
for obj in &self.objs {
if ! obj.is_top_level() {
delayed.push(obj)
} else {
if let Some(mut tl) = top {
self.add_to_toplevel(&mut tl, &mut out, &mut delayed);
}
top = Some(obj)
}
}
if let Some(mut tl) = top {
self.add_to_toplevel(&mut tl, &mut out, &mut delayed)
}
out
}
pub fn join_sql_statements(&self) -> String {
self.sql_statements().join("\n")
}
pub fn serialize_to_yaml_file(&self, file_name:&str) -> Result<(), Box<dyn Error>> {
Ok(write_yaml_to_file(file_name, &self.objs)?)
}
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())?)
}
pub fn objects(&self) -> &Vec<Box<&'a dyn DBObject>> {
&self.objs
}
}
pub struct Loader {
objs: Objects,
}
impl Loader {
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())
})
}
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
}
}