feat: implements table, columns serialization
This commit is contained in:
107
Cargo.lock
generated
Normal file
107
Cargo.lock
generated
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 4
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "db_builder"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"serde",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "itoa"
|
||||||
|
version = "1.0.18"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "memchr"
|
||||||
|
version = "2.8.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proc-macro2"
|
||||||
|
version = "1.0.106"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||||
|
dependencies = [
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "quote"
|
||||||
|
version = "1.0.45"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
|
||||||
|
dependencies = [
|
||||||
|
"serde_core",
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_core"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad"
|
||||||
|
dependencies = [
|
||||||
|
"serde_derive",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_derive"
|
||||||
|
version = "1.0.228"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"syn",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "serde_json"
|
||||||
|
version = "1.0.149"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
|
||||||
|
dependencies = [
|
||||||
|
"itoa",
|
||||||
|
"memchr",
|
||||||
|
"serde",
|
||||||
|
"serde_core",
|
||||||
|
"zmij",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "syn"
|
||||||
|
version = "2.0.117"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||||
|
dependencies = [
|
||||||
|
"proc-macro2",
|
||||||
|
"quote",
|
||||||
|
"unicode-ident",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "unicode-ident"
|
||||||
|
version = "1.0.24"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "zmij"
|
||||||
|
version = "1.0.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa"
|
||||||
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
[package]
|
||||||
|
name = "db_builder"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
serde_json = "1.0.149"
|
||||||
|
serde = { version = "1.0.228", features = ["derive"] }
|
||||||
3
src/lib.rs
Normal file
3
src/lib.rs
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
mod mappings;
|
||||||
|
mod schemas;
|
||||||
|
mod query_builders;
|
||||||
66
src/mappings/mod.rs
Normal file
66
src/mappings/mod.rs
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
This module is used to make mapping between Rust and SQLite
|
||||||
|
*/
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Serialize, Default)]
|
||||||
|
pub enum SQLiteDatatypes {
|
||||||
|
Integer,
|
||||||
|
Real,
|
||||||
|
#[default]
|
||||||
|
Text,
|
||||||
|
Blob,
|
||||||
|
Null,
|
||||||
|
Numeric,
|
||||||
|
Any,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq, Clone, Copy, Deserialize, Default)]
|
||||||
|
pub enum SupportedTypes {
|
||||||
|
I32,
|
||||||
|
I64,
|
||||||
|
F64,
|
||||||
|
#[default]
|
||||||
|
String,
|
||||||
|
VecU8,
|
||||||
|
Bool,
|
||||||
|
Option,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SupportedTypes> for SQLiteDatatypes {
|
||||||
|
fn from(t: SupportedTypes) -> Self {
|
||||||
|
match t {
|
||||||
|
SupportedTypes::I32 | SupportedTypes::I64 | SupportedTypes::Bool => SQLiteDatatypes::Integer,
|
||||||
|
SupportedTypes::F64 => SQLiteDatatypes::Real,
|
||||||
|
SupportedTypes::String => SQLiteDatatypes::Text,
|
||||||
|
SupportedTypes::VecU8 => SQLiteDatatypes::Blob,
|
||||||
|
SupportedTypes::Option => SQLiteDatatypes::Any,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SQLiteDatatypes> for SupportedTypes {
|
||||||
|
fn from(t: SQLiteDatatypes) -> Self {
|
||||||
|
match t {
|
||||||
|
SQLiteDatatypes::Integer => SupportedTypes::I64,
|
||||||
|
SQLiteDatatypes::Real | SQLiteDatatypes::Numeric => SupportedTypes::F64,
|
||||||
|
SQLiteDatatypes::Text => SupportedTypes::String,
|
||||||
|
SQLiteDatatypes::Blob => SupportedTypes::VecU8,
|
||||||
|
SQLiteDatatypes::Null | SQLiteDatatypes::Any => SupportedTypes::Option,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<SQLiteDatatypes> for String {
|
||||||
|
fn from(t: SQLiteDatatypes) -> Self {
|
||||||
|
match t {
|
||||||
|
SQLiteDatatypes::Integer => String::from("INTEGER"),
|
||||||
|
SQLiteDatatypes::Real => String::from("REAL"),
|
||||||
|
SQLiteDatatypes::Text => String::from("TEXT"),
|
||||||
|
SQLiteDatatypes::Blob => String::from("BLOB"),
|
||||||
|
SQLiteDatatypes::Any => String::from("ANY"),
|
||||||
|
SQLiteDatatypes::Null => String::from("NULL"),
|
||||||
|
SQLiteDatatypes::Numeric => String::from("NUMERIC")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
109
src/query_builders/column_sql_serializer.rs
Normal file
109
src/query_builders/column_sql_serializer.rs
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
use crate::mappings::SQLiteDatatypes;
|
||||||
|
use crate::schemas::entities::Column;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct ColumnSqlSerializer {}
|
||||||
|
|
||||||
|
impl ColumnSqlSerializer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
ColumnSqlSerializer {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serialize(self, column: Column) -> Result<String, String> {
|
||||||
|
let mut query = String::from(column.name);
|
||||||
|
query.push(' ');
|
||||||
|
|
||||||
|
query += &*String::from(column.datatype);
|
||||||
|
query.push(' ');
|
||||||
|
|
||||||
|
if !column.nullable {
|
||||||
|
query += "NOT NULL " // Notice the space at the end
|
||||||
|
}
|
||||||
|
|
||||||
|
if column.unique {
|
||||||
|
query += "UNIQUE " // Notice the space at the end
|
||||||
|
}
|
||||||
|
|
||||||
|
if column.auto_increment {
|
||||||
|
query += "AUTO_INCREMENT " // Notice the space at the end
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(default) = column.default {
|
||||||
|
match column.datatype {
|
||||||
|
SQLiteDatatypes::Text | SQLiteDatatypes::Blob => {
|
||||||
|
query += &format!("DEFAULT '{}' ", default);
|
||||||
|
},
|
||||||
|
SQLiteDatatypes::Numeric | SQLiteDatatypes::Integer | SQLiteDatatypes::Real => {
|
||||||
|
query += &format!("DEFAULT {} ", default);
|
||||||
|
},
|
||||||
|
SQLiteDatatypes::Any | SQLiteDatatypes::Null => {
|
||||||
|
return Err("No default value can be set with Any and Null".to_string())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(check_constraint) = column.check_constraint {
|
||||||
|
query += &format!("CHECK {} ", check_constraint);
|
||||||
|
}
|
||||||
|
|
||||||
|
if column.primary_key {
|
||||||
|
query += "PRIMARY KEY ";
|
||||||
|
}
|
||||||
|
|
||||||
|
query.push(',');
|
||||||
|
Ok(query)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::super::super::schemas::builders::ColumnBuilder;
|
||||||
|
use crate::mappings::SQLiteDatatypes;
|
||||||
|
use crate::query_builders::column_sql_serializer::ColumnSqlSerializer;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_column_sql_serializer() {
|
||||||
|
let column = ColumnBuilder::new()
|
||||||
|
.with_name("id".to_string())
|
||||||
|
.with_datatype(SQLiteDatatypes::Integer)
|
||||||
|
.with_auto_increment()
|
||||||
|
.with_primary_key()
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let serializer = ColumnSqlSerializer::new();
|
||||||
|
let result = serializer.serialize(column).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result, "id INTEGER NOT NULL AUTO_INCREMENT PRIMARY KEY ,".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_column_sql_serializer_with_text_default() {
|
||||||
|
let column = ColumnBuilder::new()
|
||||||
|
.with_name("name".to_string())
|
||||||
|
.with_datatype(SQLiteDatatypes::Text)
|
||||||
|
.with_default("None".to_string())
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let serializer = ColumnSqlSerializer::new();
|
||||||
|
let result = serializer.serialize(column).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result, "name TEXT NOT NULL DEFAULT 'None' ,".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_column_sql_serializer_with_integer_default() {
|
||||||
|
let column = ColumnBuilder::new()
|
||||||
|
.with_name("age".to_string())
|
||||||
|
.with_datatype(SQLiteDatatypes::Integer)
|
||||||
|
.with_default("18".to_string())
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let serializer = ColumnSqlSerializer::new();
|
||||||
|
let result = serializer.serialize(column).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(result, "age INTEGER NOT NULL DEFAULT 18 ,".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
2
src/query_builders/mod.rs
Normal file
2
src/query_builders/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
|||||||
|
mod column_sql_serializer;
|
||||||
|
mod table_sql_serializer;
|
||||||
52
src/query_builders/table_sql_serializer.rs
Normal file
52
src/query_builders/table_sql_serializer.rs
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
use crate::query_builders::column_sql_serializer::ColumnSqlSerializer;
|
||||||
|
use crate::schemas::entities::Table;
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub struct TableSqlSerializer {}
|
||||||
|
|
||||||
|
impl TableSqlSerializer {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
TableSqlSerializer{}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serialize(self, table: Table) -> String {
|
||||||
|
let mut query = String::from("CREATE TABLE ");
|
||||||
|
query += &format!("{} (\n", table.name);
|
||||||
|
|
||||||
|
let column_serializer = ColumnSqlSerializer::new();
|
||||||
|
for column in table.columns {
|
||||||
|
query += &column_serializer.serialize(column).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
|
query += ");";
|
||||||
|
query
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::mappings::SQLiteDatatypes;
|
||||||
|
use crate::query_builders::table_sql_serializer::TableSqlSerializer;
|
||||||
|
use crate::schemas::builders::{ColumnBuilder, TableBuilder};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
pub fn test_table_sql_serializer() {
|
||||||
|
let column = ColumnBuilder::new()
|
||||||
|
.with_name("id".to_string())
|
||||||
|
.with_datatype(SQLiteDatatypes::Integer)
|
||||||
|
.with_auto_increment()
|
||||||
|
.build()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let table = TableBuilder::new()
|
||||||
|
.with_name("test".to_string())
|
||||||
|
.with_column(column)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
let serializer = TableSqlSerializer::new();
|
||||||
|
|
||||||
|
let result = serializer.serialize(table);
|
||||||
|
|
||||||
|
assert_eq!(result, "CREATE TABLE test (\nid INTEGER NOT NULL AUTO_INCREMENT ,);".to_string());
|
||||||
|
}
|
||||||
|
}
|
||||||
182
src/schemas/builders.rs
Normal file
182
src/schemas/builders.rs
Normal file
@@ -0,0 +1,182 @@
|
|||||||
|
use crate::mappings::SQLiteDatatypes;
|
||||||
|
use crate::schemas::entities::{Column, Table};
|
||||||
|
|
||||||
|
pub struct ColumnBuilder {
|
||||||
|
name: String,
|
||||||
|
datatype: SQLiteDatatypes,
|
||||||
|
nullable: bool,
|
||||||
|
default: Option<String>,
|
||||||
|
auto_increment: bool,
|
||||||
|
unique: bool,
|
||||||
|
check_constraint: Option<String>,
|
||||||
|
primary_key: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ColumnBuilder {
|
||||||
|
pub fn new() -> ColumnBuilder {
|
||||||
|
ColumnBuilder {
|
||||||
|
name: String::new(),
|
||||||
|
datatype: SQLiteDatatypes::Text,
|
||||||
|
nullable: false,
|
||||||
|
default: None,
|
||||||
|
auto_increment: false,
|
||||||
|
unique: false,
|
||||||
|
check_constraint: None,
|
||||||
|
primary_key: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_name(mut self, name: String) -> Self {
|
||||||
|
self.name = name;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_datatype(mut self, datatype: SQLiteDatatypes) -> Self {
|
||||||
|
self.datatype = datatype;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_nullable(mut self) -> Self {
|
||||||
|
self.nullable = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_default(mut self, default: String) -> Self {
|
||||||
|
self.default = Some(default);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_auto_increment(mut self) -> Self {
|
||||||
|
self.auto_increment = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_unique(mut self) -> Self {
|
||||||
|
self.unique = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_check_constraint(mut self, constraint: String) -> Self {
|
||||||
|
self.check_constraint = Some(constraint);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_primary_key(mut self) -> Self {
|
||||||
|
self.primary_key = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> Result<Column, String> {
|
||||||
|
if self.auto_increment && self.datatype != SQLiteDatatypes::Integer {
|
||||||
|
return Err("Cannot set AUTO_INCREMENT on non-INTEGER column".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Column::new(
|
||||||
|
self.name,
|
||||||
|
self.datatype,
|
||||||
|
self.nullable,
|
||||||
|
self.default,
|
||||||
|
self.auto_increment,
|
||||||
|
self.unique,
|
||||||
|
self.check_constraint,
|
||||||
|
self.primary_key,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TableBuilder {
|
||||||
|
name: String,
|
||||||
|
columns: Vec<Column>,
|
||||||
|
strict: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TableBuilder {
|
||||||
|
pub fn new() -> TableBuilder {
|
||||||
|
TableBuilder {
|
||||||
|
name: String::new(),
|
||||||
|
columns: Vec::new(),
|
||||||
|
strict: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_name(mut self, name: String) -> Self {
|
||||||
|
self.name = name;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_strict(mut self) -> Self {
|
||||||
|
self.strict = true;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_column(mut self, column: Column) -> Self {
|
||||||
|
self.columns.push(column);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn build(self) -> Table {
|
||||||
|
Table::new(self.name, self.columns, self.strict)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::mappings::SQLiteDatatypes;
|
||||||
|
use crate::schemas::builders::{ColumnBuilder, TableBuilder};
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_column_builder() {
|
||||||
|
let result = ColumnBuilder::new()
|
||||||
|
.with_name("name".to_string())
|
||||||
|
.with_datatype(SQLiteDatatypes::Text)
|
||||||
|
.with_nullable()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(column) => {
|
||||||
|
assert_eq!(column.name, String::from("name"));
|
||||||
|
assert_eq!(column.datatype, SQLiteDatatypes::Text);
|
||||||
|
assert_eq!(column.nullable, true);
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
assert!(false, "should not fail");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_column_builder_should_fail() {
|
||||||
|
let result = ColumnBuilder::new()
|
||||||
|
.with_name("name".to_string())
|
||||||
|
.with_datatype(SQLiteDatatypes::Blob)
|
||||||
|
.with_auto_increment()
|
||||||
|
.build();
|
||||||
|
|
||||||
|
match result {
|
||||||
|
Ok(_) => {
|
||||||
|
assert!(false, "Should not make auto increment with another type than integer")
|
||||||
|
},
|
||||||
|
Err(_) => {
|
||||||
|
assert!(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_table_builder() {
|
||||||
|
let column = ColumnBuilder::new()
|
||||||
|
.with_name("id".to_string())
|
||||||
|
.with_datatype(SQLiteDatatypes::Integer)
|
||||||
|
.with_auto_increment()
|
||||||
|
.build()
|
||||||
|
.expect("Failed to create id column");
|
||||||
|
|
||||||
|
let table = TableBuilder::new()
|
||||||
|
.with_name("my_table".to_string())
|
||||||
|
.with_column(column.clone())
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assert_eq!(table.name, String::from("my_table"));
|
||||||
|
assert_eq!(*table.columns.first().unwrap(), column);
|
||||||
|
}
|
||||||
|
}
|
||||||
46
src/schemas/entities.rs
Normal file
46
src/schemas/entities.rs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
use crate::mappings::SQLiteDatatypes;
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Default, Clone)]
|
||||||
|
pub struct Table {
|
||||||
|
pub name: String,
|
||||||
|
pub columns: Vec<Column>,
|
||||||
|
pub strict: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Deserialize, Serialize, Default, Clone, PartialEq)]
|
||||||
|
pub struct Column {
|
||||||
|
pub name: String,
|
||||||
|
pub datatype: SQLiteDatatypes,
|
||||||
|
pub nullable: bool,
|
||||||
|
pub default: Option<String>,
|
||||||
|
pub auto_increment: bool,
|
||||||
|
pub unique: bool,
|
||||||
|
pub check_constraint: Option<String>, // raw check constraint
|
||||||
|
pub primary_key: bool
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Table {
|
||||||
|
pub fn new(name: String, columns: Vec<Column>, strict: bool) -> Table {
|
||||||
|
Table {
|
||||||
|
name,
|
||||||
|
columns,
|
||||||
|
strict
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Column {
|
||||||
|
pub fn new(name: String, datatype: SQLiteDatatypes, nullable: bool, default: Option<String>, auto_increment: bool, unique: bool, check_constraint: Option<String>, primary_key: bool) -> Column {
|
||||||
|
Column {
|
||||||
|
name,
|
||||||
|
datatype,
|
||||||
|
nullable,
|
||||||
|
default,
|
||||||
|
auto_increment,
|
||||||
|
unique,
|
||||||
|
check_constraint,
|
||||||
|
primary_key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
4
src/schemas/mod.rs
Normal file
4
src/schemas/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
pub(crate) mod reader;
|
||||||
|
pub(crate) mod entities;
|
||||||
|
pub(crate) mod builders;
|
||||||
|
mod writer;
|
||||||
23
src/schemas/reader.rs
Normal file
23
src/schemas/reader.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
use std::fs;
|
||||||
|
use crate::schemas::entities::Table;
|
||||||
|
|
||||||
|
pub struct SchemaParsingFacade {}
|
||||||
|
|
||||||
|
impl SchemaParsingFacade {
|
||||||
|
pub fn new() -> SchemaParsingFacade {
|
||||||
|
SchemaParsingFacade{}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn parse(&self, path: String) -> Vec<Table> {
|
||||||
|
let json_schema = self.read_schema_file(path);
|
||||||
|
self.parse_schema_file(json_schema)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn read_schema_file(&self, path: String) -> String {
|
||||||
|
fs::read_to_string(path).expect("Error reading schema files")
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_schema_file(&self, json_schema: String) -> Vec<Table> {
|
||||||
|
serde_json::from_str(&json_schema).expect("Error parsing JSON schema")
|
||||||
|
}
|
||||||
|
}
|
||||||
32
src/schemas/writer.rs
Normal file
32
src/schemas/writer.rs
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
use std::io::Write;
|
||||||
|
use crate::schemas::entities::Table;
|
||||||
|
|
||||||
|
pub struct SchemaWriter {
|
||||||
|
tables: Vec<Table>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SchemaWriter {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
SchemaWriter{
|
||||||
|
tables: Vec::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn add_table(mut self, table: Table) -> Self {
|
||||||
|
self.tables.push(table);
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
// create_schemas create the schema as a JSON file. the name doesn't need to have the ".json"
|
||||||
|
pub fn create_schemas(self, schema_name: String) -> Result<(), String> {
|
||||||
|
let schema_file_path = format!("{}.json", schema_name);
|
||||||
|
|
||||||
|
let content_result = serde_json::to_string(self.tables.as_slice()).expect("Error serializing tables");
|
||||||
|
|
||||||
|
let mut schema_file = File::create(schema_file_path).expect("Failed to create schema file");
|
||||||
|
schema_file.write_all(content_result.as_bytes()).expect("Error writing in schema file");
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user