use crate::Error;
use rusqlite::{Connection, params};
use serde_json::Value;
use std::fs;
pub trait Serializer {
fn serialize(&self, data: &Value) -> Result<Vec<u8>, Error>;
fn extension(&self) -> &str;
fn serialize_bundle(
&self,
endpoints: &serde_json::Map<String, Value>,
) -> Result<Vec<u8>, Error> {
self.serialize(&Value::Object(endpoints.clone()))
}
}
pub struct JSONSerializer {
pub minify: bool,
}
impl Serializer for JSONSerializer {
fn serialize(&self, d: &Value) -> Result<Vec<u8>, Error> {
if self.minify {
serde_json::to_vec(d).map_err(|e| e.into())
} else {
serde_json::to_vec_pretty(d).map_err(|e| e.into())
}
}
fn extension(&self) -> &str {
"json"
}
}
pub struct TypescriptSerializer {
pub minify: bool,
}
impl Serializer for TypescriptSerializer {
fn serialize(&self, d: &Value) -> Result<Vec<u8>, Error> {
let json = if self.minify {
serde_json::to_string(d)?
} else {
serde_json::to_string_pretty(d)?
};
Ok(format!("export const data = {};", json).into_bytes())
}
fn extension(&self) -> &str {
"ts"
}
}
pub struct SqliteSerializer;
impl Serializer for SqliteSerializer {
fn serialize(&self, d: &Value) -> Result<Vec<u8>, Error> {
self.build_db(|conn| self.populate_db(conn, d))
}
fn extension(&self) -> &str {
"db"
}
fn serialize_bundle(
&self,
endpoints: &serde_json::Map<String, Value>,
) -> Result<Vec<u8>, Error> {
self.build_db(|conn| {
conn.execute(
"CREATE TABLE endpoints (path TEXT PRIMARY KEY, value TEXT)",
[],
)?;
for (path, value) in endpoints {
conn.execute(
"INSERT INTO endpoints (path, value) VALUES (?1, ?2)",
params![path, value.to_string()],
)?;
}
Ok(())
})
}
}
impl SqliteSerializer {
fn build_db<F>(&self, populate: F) -> Result<Vec<u8>, Error>
where
F: FnOnce(&Connection) -> Result<(), Error>,
{
let tmp = tempfile::NamedTempFile::new()?;
let conn = Connection::open(tmp.path())?;
populate(&conn)?;
fs::read(tmp.path()).map_err(|e| e.into())
}
fn populate_db(&self, conn: &Connection, d: &Value) -> Result<(), Error> {
conn.execute("CREATE TABLE data (id INTEGER PRIMARY KEY, value TEXT)", [])?;
match d.as_array() {
Some(arr) => {
for (i, val) in arr.iter().enumerate() {
conn.execute(
"INSERT INTO data (id, value) VALUES (?1, ?2)",
params![i as i64, val.to_string()],
)?;
}
}
None => {
conn.execute(
"INSERT INTO data (id, value) VALUES (?1, ?2)",
params![0i64, d.to_string()],
)?;
}
}
Ok(())
}
}