From 6ac6c2c17866df88f06d1801b5a791cc09145591 Mon Sep 17 00:00:00 2001 From: aleidk Date: Mon, 27 Jan 2025 15:38:15 -0300 Subject: [PATCH 1/2] fix: create parent folders when creating schema file --- .justfile | 6 ++- example/schema.toml | 21 --------- examples/schema.toml | 110 +++++++++++++++++++++++++++++++++++++++++++ src/sql.rs | 9 +++- 4 files changed, 122 insertions(+), 24 deletions(-) delete mode 100644 example/schema.toml create mode 100644 examples/schema.toml diff --git a/.justfile b/.justfile index 691a92a..7e00533 100644 --- a/.justfile +++ b/.justfile @@ -1,5 +1,7 @@ set dotenv-load := true dev: - # cargo run --bin cli -- query "SELECT * FROM sources;" - cargo run --bin cli -- discover + cargo run --bin cli -- query "SELECT * FROM sources;" + +build-schema: + cargo run --bin cli -- discover -o examples/schema.toml diff --git a/example/schema.toml b/example/schema.toml deleted file mode 100644 index 2234a4e..0000000 --- a/example/schema.toml +++ /dev/null @@ -1,21 +0,0 @@ -[public] - -[public.entries] - -name = "entries" -display_name = "entries" -columns = [ - { name = "id", col_type = "Integer", default = false, not_null = true, reference = { table = "", identity = "", label = "" } }, -] - -[public.sources] - -name = "sources" -display_name = "Sources" - -[[public.sources.columns]] -name = "id" -col_type = "Integer" -default = false -not_null = true -reference = { table = "", identity = "", label = "" } diff --git a/examples/schema.toml b/examples/schema.toml new file mode 100644 index 0000000..859b151 --- /dev/null +++ b/examples/schema.toml @@ -0,0 +1,110 @@ +[public.entry_categories] +display_name = "Entry Categories" + +[[public.entry_categories.columns]] +name = "entry_id" +type = "Integer" +not_null = true +reference = { table = "entries", identity = "id", label = "Entry Id" } + +[[public.entry_categories.columns]] +name = "entry_date" +type = "Date" +not_null = true +reference = { table = "entries", identity = "id", label = "Entry Id" } + +[[public.entry_categories.columns]] +name = "category_id" +type = "Integer" +not_null = true +reference = { table = "categories", identity = "id", label = "Category Id" } + +[public.sources] +display_name = "Sources" + +[[public.sources.columns]] +name = "id" +type = "Integer" +default = "nextval('sources_id_seq'::regclass)" +not_null = true + +[[public.sources.columns]] +name = "name" +not_null = true +type = { Varchar = { length = 20 } } + +[[public.sources.columns]] +name = "uid" +not_null = true +type = { Varchar = { length = 8 } } + +[[public.sources.columns]] +name = "uri" +not_null = true +type = { Varchar = {} } + +[[public.sources.columns]] +name = "created_at" +default = "CURRENT_TIMESTAMP" +not_null = true +type = { TimestampWithTimeZone = { precision = 6 } } + +[[public.sources.columns]] +name = "updated_at" +not_null = false +type = { TimestampWithTimeZone = { precision = 6 } } + +[[public.sources.columns]] +name = "deleted_at" +not_null = false +type = { TimestampWithTimeZone = { precision = 6 } } + +[public.categories] +display_name = "Categories" + +[[public.categories.columns]] +name = "id" +type = "Integer" +default = "nextval('category_id_seq'::regclass)" +not_null = true + +[[public.categories.columns]] +name = "name" +not_null = true +type = { Varchar = { length = 20 } } + +[[public.categories.columns]] +name = "uid" +not_null = false +type = { Varchar = { length = 8 } } + +[public.entries] +display_name = "Entries" + +[[public.entries.columns]] +name = "id" +type = "Integer" +default = "nextval('entries_id_seq'::regclass)" +not_null = true + +[[public.entries.columns]] +name = "date" +type = "Date" +default = "CURRENT_TIMESTAMP" +not_null = true + +[[public.entries.columns]] +name = "source_id" +type = "Integer" +not_null = true +reference = { table = "sources", identity = "id", label = "Source Id" } + +[[public.entries.columns]] +name = "uid" +not_null = true +type = { Varchar = {} } + +[[public.entries.columns]] +name = "text" +type = "Text" +not_null = false diff --git a/src/sql.rs b/src/sql.rs index af8509f..bd52693 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -76,7 +76,14 @@ pub async fn discover_scheme( .insert(schema.schema.to_owned(), Schema::from(schema)); let mut buffer: Box = match output { - Some(path) => Box::new(File::create(Path::new(&path))?), + Some(path) => { + let path = Path::new(&path); + if let Some(parent) = path.parent() { + std::fs::create_dir_all(parent)?; + } + + Box::new(File::create(path)?) + } None => Box::new(io::stdout()), }; From fe5ae0de75983135aa9e9bc7f1cf0326f53ea612 Mon Sep 17 00:00:00 2001 From: aleidk Date: Mon, 27 Jan 2025 16:20:35 -0300 Subject: [PATCH 2/2] feat: allow to read a configuration file --- .justfile | 2 +- examples/schema.toml | 100 +++++++++++++++++++++---------------------- src/bin/cli/main.rs | 7 ++- src/error.rs | 3 ++ src/sql.rs | 12 +++--- src/sql/schema.rs | 24 ++++++++--- 6 files changed, 86 insertions(+), 62 deletions(-) diff --git a/.justfile b/.justfile index 7e00533..313e864 100644 --- a/.justfile +++ b/.justfile @@ -4,4 +4,4 @@ dev: cargo run --bin cli -- query "SELECT * FROM sources;" build-schema: - cargo run --bin cli -- discover -o examples/schema.toml + cargo run --bin cli -- discover -c examples/schema.toml -o examples/schema.toml diff --git a/examples/schema.toml b/examples/schema.toml index 859b151..3afa1e3 100644 --- a/examples/schema.toml +++ b/examples/schema.toml @@ -19,6 +19,56 @@ type = "Integer" not_null = true reference = { table = "categories", identity = "id", label = "Category Id" } +[public.entries] +display_name = "Entries" + +[[public.entries.columns]] +name = "id" +type = "Integer" +default = "nextval('entries_id_seq'::regclass)" +not_null = true + +[[public.entries.columns]] +name = "date" +type = "Date" +default = "CURRENT_TIMESTAMP" +not_null = true + +[[public.entries.columns]] +name = "source_id" +type = "Integer" +not_null = true +reference = { table = "sources", identity = "id", label = "Source Id" } + +[[public.entries.columns]] +name = "uid" +not_null = true +type = { Varchar = {} } + +[[public.entries.columns]] +name = "text" +type = "Text" +not_null = false + +[public.categories] +display_name = "Categories" + +[[public.categories.columns]] +name = "id" +type = "Integer" +default = "nextval('category_id_seq'::regclass)" +not_null = true + +[[public.categories.columns]] +name = "name" +not_null = true +type = { Varchar = { length = 20 } } + +[[public.categories.columns]] +name = "uid" +not_null = false +type = { Varchar = { length = 8 } } + [public.sources] display_name = "Sources" @@ -58,53 +108,3 @@ type = { TimestampWithTimeZone = { precision = 6 } } name = "deleted_at" not_null = false type = { TimestampWithTimeZone = { precision = 6 } } - -[public.categories] -display_name = "Categories" - -[[public.categories.columns]] -name = "id" -type = "Integer" -default = "nextval('category_id_seq'::regclass)" -not_null = true - -[[public.categories.columns]] -name = "name" -not_null = true -type = { Varchar = { length = 20 } } - -[[public.categories.columns]] -name = "uid" -not_null = false -type = { Varchar = { length = 8 } } - -[public.entries] -display_name = "Entries" - -[[public.entries.columns]] -name = "id" -type = "Integer" -default = "nextval('entries_id_seq'::regclass)" -not_null = true - -[[public.entries.columns]] -name = "date" -type = "Date" -default = "CURRENT_TIMESTAMP" -not_null = true - -[[public.entries.columns]] -name = "source_id" -type = "Integer" -not_null = true -reference = { table = "sources", identity = "id", label = "Source Id" } - -[[public.entries.columns]] -name = "uid" -not_null = true -type = { Varchar = {} } - -[[public.entries.columns]] -name = "text" -type = "Text" -not_null = false diff --git a/src/bin/cli/main.rs b/src/bin/cli/main.rs index 2f6ca5b..29c102c 100644 --- a/src/bin/cli/main.rs +++ b/src/bin/cli/main.rs @@ -1,6 +1,8 @@ #![allow(unused)] #![allow(dead_code)] +use std::path::PathBuf; + use clap::{Parser, Subcommand}; use simple_crud::error::Error; use simple_crud::error::Result; @@ -17,6 +19,9 @@ struct Cli { #[arg(short = 'u', long, global = true, env = "CLI_DB_URL")] db_url: Option, + + #[arg(short, long, global = true, env = "CLI_CONFIG")] + config_file: Option, } #[derive(Subcommand)] @@ -52,7 +57,7 @@ async fn main() -> Result<()> { let result = match &cli.command { Commands::Query { sql } => sql::handle_query(url, sql).await, Commands::Discover { schema, output } => { - sql::discover_scheme(url, schema.to_owned(), output.to_owned()).await + sql::discover_scheme(url, cli.config_file, schema.to_owned(), output.to_owned()).await } }; diff --git a/src/error.rs b/src/error.rs index c468be5..067e098 100644 --- a/src/error.rs +++ b/src/error.rs @@ -17,6 +17,9 @@ pub enum Error { #[error(transparent)] TomlEncoding(#[from] toml::ser::Error), + #[error(transparent)] + TomlDecodign(#[from] toml::de::Error), + #[error(transparent)] ParseError(#[from] url::ParseError), diff --git a/src/sql.rs b/src/sql.rs index bd52693..79e8819 100644 --- a/src/sql.rs +++ b/src/sql.rs @@ -1,6 +1,6 @@ use std::fs::File; use std::io; -use std::path::Path; +use std::path::{Path, PathBuf}; use clap::ValueEnum; use sea_schema::postgres::discovery::SchemaDiscovery; @@ -49,6 +49,7 @@ pub async fn handle_query(url: String, query: &String) -> Result<()> { pub async fn discover_scheme( url: String, + config_file: Option, schema: Option, output: Option, ) -> Result<()> { @@ -68,12 +69,13 @@ pub async fn discover_scheme( } }; + let mut data_model = DataModel::new(config_file)?; + + println!("{:?}", data_model); + let schema = schema_discovery.discover().await?; - let mut data_model = DataModel::new(); - data_model - .schemas - .insert(schema.schema.to_owned(), Schema::from(schema)); + data_model.insert_schema(schema.schema.to_owned(), Schema::from(schema)); let mut buffer: Box = match output { Some(path) => { diff --git a/src/sql/schema.rs b/src/sql/schema.rs index 10fc03c..b1c3ff4 100644 --- a/src/sql/schema.rs +++ b/src/sql/schema.rs @@ -2,12 +2,14 @@ use heck::ToTitleCase; use serde::{Deserialize, Serialize}; use std::collections::HashMap; use std::fmt; +use std::fs::read_to_string; use std::io::Write; +use std::path::PathBuf; use toml_edit::visit_mut::VisitMut; use sea_schema::postgres::def as sea_schema_def; -use crate::error; +use crate::error::{self, Result}; struct InlineTableFix; @@ -36,15 +38,27 @@ impl VisitMut for InlineTableFix { #[derive(Serialize, Deserialize, Debug)] pub struct DataModel { #[serde(flatten)] - pub schemas: HashMap, + schemas: HashMap, } impl DataModel { - pub fn new() -> Self { - Self { - schemas: HashMap::new(), + pub fn new(path: Option) -> Result { + match path { + Some(path) => { + let content = read_to_string(&path)?; + let data_model: Self = toml::from_str(&content)?; + + Ok(data_model) + } + None => Ok(Self { + schemas: HashMap::new(), + }), } } + + pub fn insert_schema(&mut self, name: String, schema: Schema) { + self.schemas.insert(name, schema); + } } impl DataModel {