generated from alecodes/base-template
Compare commits
1 commit
b93f037017
...
0980c9b4d2
| Author | SHA1 | Date | |
|---|---|---|---|
| 0980c9b4d2 |
3 changed files with 31 additions and 77 deletions
|
|
@ -30,9 +30,6 @@ enum Commands {
|
|||
Discover {
|
||||
/// Schema to discover, it defaults to `public` in postures.
|
||||
schema: Option<String>,
|
||||
|
||||
#[arg(short = 'o', long)]
|
||||
output: Option<String>,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
@ -51,9 +48,7 @@ async fn main() -> Result<()> {
|
|||
// matches just as you would the top level cmd
|
||||
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
|
||||
}
|
||||
Commands::Discover { schema } => sql::discover_scheme(url, schema.to_owned()).await,
|
||||
};
|
||||
|
||||
if let Err(err) = result {
|
||||
|
|
|
|||
24
src/sql.rs
24
src/sql.rs
|
|
@ -1,7 +1,3 @@
|
|||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
use clap::ValueEnum;
|
||||
use sea_schema::postgres::discovery::SchemaDiscovery;
|
||||
use sqlx::PgPool;
|
||||
|
|
@ -9,7 +5,7 @@ use url::Url;
|
|||
|
||||
use crate::error::{Error, Result};
|
||||
|
||||
use self::schema::{DataModel, Schema};
|
||||
use self::schema::SchemaDefinition;
|
||||
|
||||
mod postgres;
|
||||
mod schema;
|
||||
|
|
@ -47,11 +43,7 @@ pub async fn handle_query(url: String, query: &String) -> Result<()> {
|
|||
return Ok(());
|
||||
}
|
||||
|
||||
pub async fn discover_scheme(
|
||||
url: String,
|
||||
schema: Option<String>,
|
||||
output: Option<String>,
|
||||
) -> Result<()> {
|
||||
pub async fn discover_scheme(url: String, schema: Option<String>) -> Result<()> {
|
||||
let (_, db_name) = get_connector(&url).await?;
|
||||
|
||||
let schema_discovery = match db_name.as_str() {
|
||||
|
|
@ -70,17 +62,9 @@ pub async fn discover_scheme(
|
|||
|
||||
let schema = schema_discovery.discover().await?;
|
||||
|
||||
let mut data_model = DataModel::new();
|
||||
data_model
|
||||
.schemas
|
||||
.insert(schema.schema.to_owned(), Schema::from(schema));
|
||||
let schema_definition = SchemaDefinition::from(schema);
|
||||
|
||||
let mut buffer: Box<dyn io::Write> = match output {
|
||||
Some(path) => Box::new(File::create(Path::new(&path))?),
|
||||
None => Box::new(io::stdout()),
|
||||
};
|
||||
|
||||
data_model.write(&mut buffer)?;
|
||||
println!("{}", schema_definition);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,62 +2,40 @@ use heck::ToTitleCase;
|
|||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use std::io::Write;
|
||||
use toml_edit::visit_mut::VisitMut;
|
||||
use toml_edit::visit_mut::{visit_table_like_kv_mut, VisitMut};
|
||||
use toml_edit::{DocumentMut, Item, KeyMut, Table as TomlTable, Value};
|
||||
|
||||
use sea_schema::postgres::def as sea_schema_def;
|
||||
|
||||
use crate::error;
|
||||
use sea_schema::postgres::def::{ColumnInfo, ColumnType, References, Schema, TableDef};
|
||||
|
||||
struct InlineTableFix;
|
||||
|
||||
// the toml serializer doesn't generate inline tables by default
|
||||
impl VisitMut for InlineTableFix {
|
||||
fn visit_table_like_kv_mut(
|
||||
&mut self,
|
||||
mut key: toml_edit::KeyMut<'_>,
|
||||
node: &mut toml_edit::Item,
|
||||
) {
|
||||
// add the keys of the tables that needs to be inline here
|
||||
fn visit_table_like_kv_mut(&mut self, mut key: KeyMut<'_>, node: &mut Item) {
|
||||
if ["reference", "type"].contains(&key.get()) {
|
||||
if let toml_edit::Item::Table(table) = node {
|
||||
// Turn the table into an inline table.
|
||||
if let Item::Table(table) = node {
|
||||
// Turn the table into an inline table.
|
||||
let table = std::mem::replace(table, toml_edit::Table::new());
|
||||
let table = std::mem::replace(table, TomlTable::new());
|
||||
let inline_table = table.into_inline_table();
|
||||
key.fmt();
|
||||
*node = toml_edit::Item::Value(toml_edit::Value::InlineTable(inline_table));
|
||||
*node = Item::Value(Value::InlineTable(inline_table));
|
||||
}
|
||||
}
|
||||
|
||||
toml_edit::visit_mut::visit_table_like_kv_mut(self, key, node);
|
||||
visit_table_like_kv_mut(self, key, node);
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct DataModel {
|
||||
#[serde(flatten)]
|
||||
pub schemas: HashMap<String, Schema>,
|
||||
pub struct SchemaDefinition {
|
||||
/// Name of the schema, and table associated
|
||||
pub tables: HashMap<String, Table>,
|
||||
}
|
||||
|
||||
impl DataModel {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
schemas: HashMap::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl DataModel {
|
||||
pub fn write<T: Write>(&self, buffer: &mut T) -> error::Result<()> {
|
||||
buffer.write_all(self.to_string().as_bytes())?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for DataModel {
|
||||
impl fmt::Display for SchemaDefinition {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
let toml = toml::to_string_pretty(self).map_err(|_| fmt::Error)?;
|
||||
let mut document: toml_edit::DocumentMut = toml.parse().map_err(|_| fmt::Error)?;
|
||||
let mut document: DocumentMut = toml.parse().map_err(|_| fmt::Error)?;
|
||||
|
||||
let mut visitor = InlineTableFix;
|
||||
visitor.visit_document_mut(&mut document);
|
||||
|
|
@ -66,14 +44,8 @@ impl fmt::Display for DataModel {
|
|||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Schema {
|
||||
#[serde(flatten)]
|
||||
pub tables: HashMap<String, Table>,
|
||||
}
|
||||
|
||||
impl From<sea_schema_def::Schema> for Schema {
|
||||
fn from(schema: sea_schema_def::Schema) -> Self {
|
||||
impl From<Schema> for SchemaDefinition {
|
||||
fn from(schema: Schema) -> Self {
|
||||
let mut tables: HashMap<String, Table> = HashMap::new();
|
||||
|
||||
for table in schema.tables {
|
||||
|
|
@ -86,14 +58,17 @@ impl From<sea_schema_def::Schema> for Schema {
|
|||
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct Table {
|
||||
/// real name of the table
|
||||
name: String,
|
||||
/// Default is capitalized name
|
||||
display_name: Option<String>,
|
||||
columns: Vec<Column>,
|
||||
}
|
||||
|
||||
impl From<sea_schema_def::TableDef> for Table {
|
||||
fn from(table: sea_schema_def::TableDef) -> Self {
|
||||
impl From<TableDef> for Table {
|
||||
fn from(table: TableDef) -> Self {
|
||||
Self {
|
||||
name: table.info.name.to_owned(),
|
||||
display_name: Some(table.info.name.to_owned().to_title_case()),
|
||||
columns: table
|
||||
.columns
|
||||
|
|
@ -121,14 +96,14 @@ impl From<sea_schema_def::TableDef> for Table {
|
|||
pub struct Column {
|
||||
name: String,
|
||||
#[serde(rename = "type")]
|
||||
col_type: sea_schema_def::ColumnType,
|
||||
col_type: ColumnType,
|
||||
default: Option<String>,
|
||||
not_null: bool,
|
||||
reference: Option<ColumnReference>,
|
||||
}
|
||||
|
||||
impl From<sea_schema_def::ColumnInfo> for Column {
|
||||
fn from(col: sea_schema_def::ColumnInfo) -> Self {
|
||||
impl From<ColumnInfo> for Column {
|
||||
fn from(col: ColumnInfo) -> Self {
|
||||
Self {
|
||||
name: col.name,
|
||||
col_type: col.col_type,
|
||||
|
|
@ -146,8 +121,8 @@ pub struct ColumnReference {
|
|||
label: Option<String>,
|
||||
}
|
||||
|
||||
impl From<sea_schema_def::References> for ColumnReference {
|
||||
fn from(reference: sea_schema_def::References) -> Self {
|
||||
impl From<References> for ColumnReference {
|
||||
fn from(reference: References) -> Self {
|
||||
Self {
|
||||
table: reference.table,
|
||||
identity: reference.foreign_columns[0].to_owned(),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue