add generator picker
This commit is contained in:
parent
1fa7c7bbc8
commit
dc68f88f9d
3
Cargo.lock
generated
3
Cargo.lock
generated
@ -304,8 +304,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
|
|||||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
|
"js-sys",
|
||||||
"libc",
|
"libc",
|
||||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||||
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
@ -601,6 +603,7 @@ dependencies = [
|
|||||||
"base64",
|
"base64",
|
||||||
"chrono",
|
"chrono",
|
||||||
"fake",
|
"fake",
|
||||||
|
"getrandom",
|
||||||
"gloo",
|
"gloo",
|
||||||
"js-sys",
|
"js-sys",
|
||||||
"lazy-regex",
|
"lazy-regex",
|
||||||
|
@ -16,6 +16,7 @@ gloo = "0.8"
|
|||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
fake = "2.5"
|
fake = "2.5"
|
||||||
rand = "0.8"
|
rand = "0.8"
|
||||||
|
getrandom = { version = "0.2.8", features = ["js"] }
|
||||||
chrono = "0.4.23"
|
chrono = "0.4.23"
|
||||||
|
|
||||||
[dependencies.zip]
|
[dependencies.zip]
|
||||||
|
234
src/app.rs
234
src/app.rs
@ -1,3 +1,4 @@
|
|||||||
|
use std::cell::RefCell;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::collections::{HashMap, self};
|
use std::collections::{HashMap, self};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
@ -9,24 +10,32 @@ use web_sys::{DragEvent, Event, FileList, HtmlInputElement, MouseEvent};
|
|||||||
use yew::html::TargetCast;
|
use yew::html::TargetCast;
|
||||||
use yew::{html, Callback, Component, Context, Html};
|
use yew::{html, Callback, Component, Context, Html};
|
||||||
|
|
||||||
|
use crate::generate_sql::{SQLValueGuess, generate_table_guessess};
|
||||||
use crate::magicdraw_parser::{parse_project, SQLTableCollection, SQLTable};
|
use crate::magicdraw_parser::{parse_project, SQLTableCollection, SQLTable};
|
||||||
use crate::components::sql_column_info::SQLTableColumnInfo;
|
use crate::components::sql_column_info::SQLTableColumnInfo;
|
||||||
|
|
||||||
const COLLECTION_STORE_KEY: &str = "current_collection";
|
const COLLECTION_STORE_KEY: &str = "current_collection";
|
||||||
|
const DEFAULT_ROWS_PER_TABLE: u32 = 20;
|
||||||
|
|
||||||
pub enum Msg {
|
pub enum Msg {
|
||||||
Noop,
|
Noop,
|
||||||
Loaded(String, Vec<u8>),
|
Loaded(String, Vec<u8>),
|
||||||
UploadProject(File),
|
UploadProject(File),
|
||||||
UpdateCurrentProject(Option<SQLTableCollection>),
|
UpdateCurrentProject(Option<SQLTableCollection>),
|
||||||
|
UpdateGenarator(String, SQLValueGuess),
|
||||||
ShowNextTable,
|
ShowNextTable,
|
||||||
ShowPrevTable
|
ShowPrevTable,
|
||||||
|
AllGoodConfirmation,
|
||||||
|
GenerateSQL,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct App {
|
pub struct App {
|
||||||
active_readers: HashMap<String, FileReader>,
|
active_readers: HashMap<String, FileReader>,
|
||||||
current_collection: Option<Vec<Rc<SQLTable>>>,
|
current_collection: Option<Vec<Rc<SQLTable>>>,
|
||||||
currently_shown_table: usize
|
current_guessess: Vec<Rc<RefCell<HashMap<String, SQLValueGuess>>>>,
|
||||||
|
currently_shown_table: usize,
|
||||||
|
all_good_confirmed: bool,
|
||||||
|
generated_sql: Option<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Component for App {
|
impl Component for App {
|
||||||
@ -34,15 +43,24 @@ impl Component for App {
|
|||||||
type Properties = ();
|
type Properties = ();
|
||||||
|
|
||||||
fn create(_ctx: &Context<Self>) -> Self {
|
fn create(_ctx: &Context<Self>) -> Self {
|
||||||
|
let mut current_guessess = vec![];
|
||||||
let mut current_collection = None;
|
let mut current_collection = None;
|
||||||
if let Ok(collection) = LocalStorage::get::<SQLTableCollection>("current_collection") {
|
if let Ok(collection) = LocalStorage::get::<SQLTableCollection>("current_collection") {
|
||||||
|
for table in &collection.tables {
|
||||||
|
let guess = generate_table_guessess(table);
|
||||||
|
current_guessess.push(Rc::new(RefCell::new(guess)));
|
||||||
|
}
|
||||||
|
|
||||||
current_collection = Some(collection.tables.into_iter().map(Rc::new).collect());
|
current_collection = Some(collection.tables.into_iter().map(Rc::new).collect());
|
||||||
}
|
}
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
active_readers: HashMap::default(),
|
active_readers: HashMap::default(),
|
||||||
current_collection,
|
current_collection,
|
||||||
currently_shown_table: 0
|
currently_shown_table: 0,
|
||||||
|
all_good_confirmed: true, // TODO: make this false, by default
|
||||||
|
generated_sql: None,
|
||||||
|
current_guessess
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,6 +102,14 @@ impl Component for App {
|
|||||||
Msg::UpdateCurrentProject(collection) => {
|
Msg::UpdateCurrentProject(collection) => {
|
||||||
if let Some(collection) = collection {
|
if let Some(collection) = collection {
|
||||||
LocalStorage::set(COLLECTION_STORE_KEY, &collection).unwrap();
|
LocalStorage::set(COLLECTION_STORE_KEY, &collection).unwrap();
|
||||||
|
self.currently_shown_table = 0;
|
||||||
|
self.all_good_confirmed = false;
|
||||||
|
self.generated_sql = None;
|
||||||
|
self.current_guessess = vec![];
|
||||||
|
for table in &collection.tables {
|
||||||
|
let guess = generate_table_guessess(table);
|
||||||
|
self.current_guessess.push(Rc::new(RefCell::new(guess)));
|
||||||
|
}
|
||||||
self.current_collection = Some(collection.tables.into_iter().map(Rc::new).collect());
|
self.current_collection = Some(collection.tables.into_iter().map(Rc::new).collect());
|
||||||
} else {
|
} else {
|
||||||
LocalStorage::delete(COLLECTION_STORE_KEY);
|
LocalStorage::delete(COLLECTION_STORE_KEY);
|
||||||
@ -106,79 +132,36 @@ impl Component for App {
|
|||||||
}
|
}
|
||||||
false
|
false
|
||||||
},
|
},
|
||||||
|
Msg::AllGoodConfirmation => {
|
||||||
|
self.all_good_confirmed = true;
|
||||||
|
true
|
||||||
|
},
|
||||||
|
Msg::UpdateGenarator(column, generator) => {
|
||||||
|
console_dbg!(column, generator);
|
||||||
|
let mut guessess = self.current_guessess[self.currently_shown_table].borrow_mut();
|
||||||
|
let entry = guessess.get_mut(&column).unwrap();
|
||||||
|
*entry = generator;
|
||||||
|
true
|
||||||
|
},
|
||||||
|
Msg::GenerateSQL => {
|
||||||
|
false
|
||||||
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn view(&self, ctx: &Context<Self>) -> Html {
|
fn view(&self, ctx: &Context<Self>) -> Html {
|
||||||
let prevent_default_cb = Callback::from(|event: DragEvent| {
|
|
||||||
event.prevent_default();
|
|
||||||
});
|
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
<main class="flex-col 4rem center">
|
<main class="flex-col 4rem center">
|
||||||
<p class="text-3xl text-center">{ "🪄 MagicDraw SQL Data Generator" }</p>
|
<p class="text-3xl text-center">{ "🪄 MagicDraw SQL Data Generator" }</p>
|
||||||
<div>
|
{ self.show_step1(ctx) }
|
||||||
<p class="text-2xl mt-2rem pb-1rem">
|
if self.current_collection.is_some() {
|
||||||
<span>{ "1. Upload " }</span>
|
{ self.show_step2(ctx) }
|
||||||
<code class="bg-dark900 p-0.2rem rounded">{".mdzip"}</code>
|
if self.all_good_confirmed {
|
||||||
<span>{ " project" }</span>
|
{ self.show_step3(ctx) }
|
||||||
</p>
|
if self.generated_sql.is_some() {
|
||||||
<label for="file-upload">
|
{ self.show_step4(ctx) }
|
||||||
<div
|
}
|
||||||
class="flex flex-col rounded items-center p-3rem bg-dark800"
|
}
|
||||||
border="dotted dark100 0.2rem"
|
|
||||||
cursor="pointer"
|
|
||||||
ondrop={ctx.link().callback(|event: DragEvent| {
|
|
||||||
event.prevent_default();
|
|
||||||
let files = event.data_transfer().unwrap().files();
|
|
||||||
Self::upload_project(files)
|
|
||||||
})}
|
|
||||||
ondragover={&prevent_default_cb}
|
|
||||||
ondragenter={&prevent_default_cb}
|
|
||||||
>
|
|
||||||
<div class="i-mdi-file-upload-outline text-4rem"></div>
|
|
||||||
</div>
|
|
||||||
</label>
|
|
||||||
<input
|
|
||||||
id="file-upload"
|
|
||||||
type="file"
|
|
||||||
class = "hidden"
|
|
||||||
accept=".mdzip"
|
|
||||||
onchange={ctx.link().callback(move |e: Event| {
|
|
||||||
let input: HtmlInputElement = e.target_unchecked_into();
|
|
||||||
Self::upload_project(input.files())
|
|
||||||
})}
|
|
||||||
/>
|
|
||||||
<p class="text-amber300">{ "NOTE: This relies on the fact, that you have a .dll script configured" }</p>
|
|
||||||
</div>
|
|
||||||
if let Some(collection) = &self.current_collection {
|
|
||||||
<div>
|
|
||||||
<p class="text-2xl mt-2rem">{ "2. Make sure everything looks 👌" }</p>
|
|
||||||
<div class="mb-0.5rem gap-3 flex flex-row items-center">
|
|
||||||
<button
|
|
||||||
class="p-0.5rem btn-white"
|
|
||||||
onclick={ctx.link().callback(move |_: MouseEvent| {
|
|
||||||
Msg::ShowPrevTable
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{ "< Previous" }
|
|
||||||
</button>
|
|
||||||
<div> { self.currently_shown_table + 1 } { " / " } { collection.len() } </div>
|
|
||||||
<button
|
|
||||||
class="p-0.5rem btn-white"
|
|
||||||
onclick={ctx.link().callback(move |_: MouseEvent| {
|
|
||||||
Msg::ShowNextTable
|
|
||||||
})}
|
|
||||||
>
|
|
||||||
{ "Next >" }
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
{ Self::show_table(collection[self.currently_shown_table].clone()) }
|
|
||||||
<button class="display-block p-1rem mt-1rem btn-emerald">{ "All good?" }</button>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<p class="text-2xl mt-2rem">{ "3. Copy & Paste" }</p>
|
|
||||||
</div>
|
|
||||||
}
|
}
|
||||||
</main>
|
</main>
|
||||||
}
|
}
|
||||||
@ -186,10 +169,117 @@ impl Component for App {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl App {
|
impl App {
|
||||||
|
fn show_step1(&self, ctx: &Context<Self>) -> Html {
|
||||||
|
let prevent_default_cb = Callback::from(|event: DragEvent| {
|
||||||
|
event.prevent_default();
|
||||||
|
});
|
||||||
|
|
||||||
fn show_table(table: Rc<SQLTable>) -> Html {
|
html! {
|
||||||
html!{
|
<div>
|
||||||
<SQLTableColumnInfo table={table} />
|
<p class="text-2xl mt-2rem pb-1rem">
|
||||||
|
<span>{ "1. Upload " }</span>
|
||||||
|
<code class="bg-dark900 p-0.2rem rounded">{".mdzip"}</code>
|
||||||
|
<span>{ " project" }</span>
|
||||||
|
</p>
|
||||||
|
<label for="file-upload">
|
||||||
|
<div
|
||||||
|
class="flex flex-col rounded items-center p-3rem bg-dark800"
|
||||||
|
border="dotted dark100 0.2rem"
|
||||||
|
cursor="pointer"
|
||||||
|
ondrop={ctx.link().callback(|event: DragEvent| {
|
||||||
|
event.prevent_default();
|
||||||
|
let files = event.data_transfer().unwrap().files();
|
||||||
|
Self::upload_project(files)
|
||||||
|
})}
|
||||||
|
ondragover={&prevent_default_cb}
|
||||||
|
ondragenter={&prevent_default_cb}
|
||||||
|
>
|
||||||
|
<div class="i-mdi-file-upload-outline text-4rem"></div>
|
||||||
|
</div>
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="file-upload"
|
||||||
|
type="file"
|
||||||
|
class = "hidden"
|
||||||
|
accept=".mdzip"
|
||||||
|
onchange={ctx.link().callback(move |e: Event| {
|
||||||
|
let input: HtmlInputElement = e.target_unchecked_into();
|
||||||
|
Self::upload_project(input.files())
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<p class="text-amber300">{ "NOTE: This relies on the fact, that you have a .dll script configured" }</p>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_step2(&self, ctx: &Context<Self>) -> Html {
|
||||||
|
let collection = self.current_collection.as_ref().unwrap();
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<div>
|
||||||
|
<p class="text-2xl mt-2rem">{ "2. Make sure everything looks 👌" }</p>
|
||||||
|
<div class="mb-0.5rem gap-3 flex flex-row items-center">
|
||||||
|
<button
|
||||||
|
class="p-0.5rem btn-white"
|
||||||
|
onclick={ctx.link().callback(move |_: MouseEvent| { Msg::ShowPrevTable })}
|
||||||
|
>
|
||||||
|
{ "< Previous" }
|
||||||
|
</button>
|
||||||
|
<div> { self.currently_shown_table + 1 } { " / " } { collection.len() } </div>
|
||||||
|
<button
|
||||||
|
class="p-0.5rem btn-white"
|
||||||
|
onclick={ctx.link().callback(move |_: MouseEvent| { Msg::ShowNextTable })}
|
||||||
|
>
|
||||||
|
{ "Next >" }
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
<SQLTableColumnInfo
|
||||||
|
table={collection[self.currently_shown_table].clone()}
|
||||||
|
guessess={self.current_guessess[self.currently_shown_table].clone()}
|
||||||
|
onchange={ctx.link().callback(|(column_name, generator)| {
|
||||||
|
Msg::UpdateGenarator(column_name, generator)
|
||||||
|
})}
|
||||||
|
/>
|
||||||
|
<button
|
||||||
|
class="display-block p-1rem mt-1rem btn-emerald"
|
||||||
|
onclick={ctx.link().callback(move |_: MouseEvent| { Msg::AllGoodConfirmation })}
|
||||||
|
>{ "All good?" }</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_step3(&self, ctx: &Context<Self>) -> Html {
|
||||||
|
html! {
|
||||||
|
<div>
|
||||||
|
<p class="text-2xl mt-2rem">{ "3. Final settings" }</p>
|
||||||
|
<label for="gen-amount-input">
|
||||||
|
{ "Entries per table: " }
|
||||||
|
</label>
|
||||||
|
<input
|
||||||
|
id="gen-amount-input"
|
||||||
|
class="rounded items-center p-0.3rem bg-dark800 text-light100 w-5rem b-0"
|
||||||
|
value={DEFAULT_ROWS_PER_TABLE.to_string()}
|
||||||
|
type="number"
|
||||||
|
/>
|
||||||
|
|
||||||
|
<button
|
||||||
|
class="block mt-1rem p-1rem btn-emerald"
|
||||||
|
>
|
||||||
|
{ "Generate" }
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_step4(&self, ctx: &Context<Self>) -> Html {
|
||||||
|
let sql = self.generated_sql.as_ref().unwrap();
|
||||||
|
html! {
|
||||||
|
<div>
|
||||||
|
<p class="text-2xl mt-2rem">{ "4. Copy & Paste" }</p>
|
||||||
|
<code>
|
||||||
|
{ sql }
|
||||||
|
</code>
|
||||||
|
</div>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
191
src/components/generator_picker.rs
Normal file
191
src/components/generator_picker.rs
Normal file
@ -0,0 +1,191 @@
|
|||||||
|
use std::{collections::HashMap, str::FromStr};
|
||||||
|
|
||||||
|
use gloo::console::console_dbg;
|
||||||
|
use yew::{Html, html, Callback, TargetCast, AttrValue};
|
||||||
|
use web_sys::{Event, HtmlInputElement};
|
||||||
|
|
||||||
|
use crate::{generate_sql::{SQLValueGuess, SQLStringValueGuess, SQLBoolValueGuess, SQLTimeValueGuess, SQLIntValueGuess}, magicdraw_parser::{SQLColumn, SQLCheckConstraint}};
|
||||||
|
|
||||||
|
fn show_dropdown_picker(
|
||||||
|
selected: &str,
|
||||||
|
options: &[AttrValue],
|
||||||
|
onchange: Callback<String>
|
||||||
|
) -> Html {
|
||||||
|
html!{
|
||||||
|
<select onchange={Callback::from(move |e: Event| {
|
||||||
|
let value = e.target_unchecked_into::<HtmlInputElement>().value();
|
||||||
|
onchange.emit(value);
|
||||||
|
})}>
|
||||||
|
{
|
||||||
|
options.iter().map(|value| {
|
||||||
|
html! { <option selected={value.eq(&selected)} value={value.clone()}>{ value }</option> }
|
||||||
|
}).collect::<Html>()
|
||||||
|
}
|
||||||
|
</select>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_enum_dropdown<T: PartialEq + Clone + 'static>(
|
||||||
|
selected: &T,
|
||||||
|
options: HashMap<AttrValue, T>,
|
||||||
|
onchange: Callback<T>
|
||||||
|
) -> Html {
|
||||||
|
let keys = options.keys().map(AttrValue::clone).collect::<Vec<_>>();
|
||||||
|
let guess_str = options.iter().find(|(_, v)| v.eq(&selected)).unwrap().0.clone();
|
||||||
|
|
||||||
|
show_dropdown_picker(&guess_str, &keys, onchange.reform(move |value_str: String| {
|
||||||
|
options.get(value_str.as_str()).unwrap().clone()
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_range_picker<T: FromStr + ToString + Clone + 'static>(
|
||||||
|
min: T,
|
||||||
|
max: T,
|
||||||
|
default_min: T,
|
||||||
|
default_max: T,
|
||||||
|
onchange: Callback<(T, T)>,
|
||||||
|
) -> Html {
|
||||||
|
|
||||||
|
let onchange_min = {
|
||||||
|
let onchange = onchange.clone();
|
||||||
|
let default_min = default_min.clone();
|
||||||
|
let max = max.clone();
|
||||||
|
Callback::from(move |e: Event| {
|
||||||
|
let value = e.target_unchecked_into::<HtmlInputElement>().value();
|
||||||
|
let min_value = value.parse().unwrap_or(default_min.clone());
|
||||||
|
onchange.emit((min_value, max.clone()))
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
let onchange_max = {
|
||||||
|
let onchange = onchange.clone();
|
||||||
|
let default_max = default_max.clone();
|
||||||
|
let min = min.clone();
|
||||||
|
Callback::from(move |e: Event| {
|
||||||
|
let value = e.target_unchecked_into::<HtmlInputElement>().value();
|
||||||
|
let max_value = value.parse().unwrap_or(default_max.clone());
|
||||||
|
onchange.emit((min.clone(), max_value))
|
||||||
|
})
|
||||||
|
};
|
||||||
|
|
||||||
|
html! {
|
||||||
|
<div class="flex flex-row">
|
||||||
|
<input
|
||||||
|
value={min.to_string()}
|
||||||
|
class="w-5rem"
|
||||||
|
type="number"
|
||||||
|
placeholder={default_min.to_string()}
|
||||||
|
onchange={onchange_min}
|
||||||
|
/>
|
||||||
|
<div class="ml-1 mr-1">{ ".." }</div>
|
||||||
|
<input
|
||||||
|
value={max.to_string()}
|
||||||
|
class="w-5rem"
|
||||||
|
type="number"
|
||||||
|
placeholder={default_max.to_string()}
|
||||||
|
onchange={onchange_max}
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generator_picker(
|
||||||
|
column: &SQLColumn,
|
||||||
|
value: &SQLValueGuess,
|
||||||
|
onchange: Callback<SQLValueGuess>
|
||||||
|
) -> Html {
|
||||||
|
// TODO: Refacotr 'time', 'datetime', and 'date'. They are very similar
|
||||||
|
match value {
|
||||||
|
SQLValueGuess::Int(guess) => {
|
||||||
|
if column.primary_key {
|
||||||
|
return html!("Auto increment")
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut min = 0;
|
||||||
|
let mut max = 0;
|
||||||
|
if let SQLIntValueGuess::Range(range_min, range_max) = guess {
|
||||||
|
min = *range_min;
|
||||||
|
max = *range_max;
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: Disallow entering floating point numbers
|
||||||
|
show_range_picker(min, max, 0, 100, onchange.reform(|(min, max)| {
|
||||||
|
SQLValueGuess::Int(SQLIntValueGuess::Range(min, max))
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
SQLValueGuess::Float(min, max) => {
|
||||||
|
show_range_picker(*min, *max, 0.0, 100.0, onchange.reform(|(min, max)| {
|
||||||
|
SQLValueGuess::Float(min, max)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
SQLValueGuess::Date(guess) => {
|
||||||
|
let options = HashMap::from([
|
||||||
|
("Now".into() , SQLTimeValueGuess::Now),
|
||||||
|
("Future".into(), SQLTimeValueGuess::Future),
|
||||||
|
("Past".into() , SQLTimeValueGuess::Past),
|
||||||
|
]);
|
||||||
|
|
||||||
|
show_enum_dropdown(guess, options, onchange.reform(|enum_value| {
|
||||||
|
SQLValueGuess::Date(enum_value)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
SQLValueGuess::Time(guess) => {
|
||||||
|
let options = HashMap::from([
|
||||||
|
("Now".into() , SQLTimeValueGuess::Now),
|
||||||
|
("Future".into(), SQLTimeValueGuess::Future),
|
||||||
|
("Past".into() , SQLTimeValueGuess::Past),
|
||||||
|
]);
|
||||||
|
|
||||||
|
show_enum_dropdown(guess, options, onchange.reform(|enum_value| {
|
||||||
|
SQLValueGuess::Time(enum_value)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
SQLValueGuess::Datetime(guess) => {
|
||||||
|
let options = HashMap::from([
|
||||||
|
("Now".into() , SQLTimeValueGuess::Now),
|
||||||
|
("Future".into(), SQLTimeValueGuess::Future),
|
||||||
|
("Past".into() , SQLTimeValueGuess::Past),
|
||||||
|
]);
|
||||||
|
|
||||||
|
show_enum_dropdown(guess, options, onchange.reform(|enum_value| {
|
||||||
|
SQLValueGuess::Datetime(enum_value)
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
SQLValueGuess::Bool(guess) => {
|
||||||
|
let options = HashMap::from([
|
||||||
|
("Random".into(), SQLBoolValueGuess::Random),
|
||||||
|
("True".into() , SQLBoolValueGuess::True),
|
||||||
|
("False".into() , SQLBoolValueGuess::False),
|
||||||
|
]);
|
||||||
|
|
||||||
|
show_enum_dropdown(guess, options, onchange.reform(|enum_value| {
|
||||||
|
SQLValueGuess::Bool(enum_value)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
SQLValueGuess::String(max_size, guess) => {
|
||||||
|
if let Some(constraint) = &column.check_constraint {
|
||||||
|
if let SQLCheckConstraint::OneOf(_) = constraint {
|
||||||
|
return html!("Random Enum");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let options = HashMap::from([
|
||||||
|
("Lorem Ipsum".into() , SQLStringValueGuess::LoremIpsum),
|
||||||
|
("First Name".into() , SQLStringValueGuess::FirstName),
|
||||||
|
("Last Name".into() , SQLStringValueGuess::LastName),
|
||||||
|
("Full Name".into() , SQLStringValueGuess::FullName),
|
||||||
|
("Empty".into() , SQLStringValueGuess::Empty),
|
||||||
|
("Phone number".into() , SQLStringValueGuess::PhoneNumber),
|
||||||
|
("City name".into() , SQLStringValueGuess::CityName),
|
||||||
|
("Address".into() , SQLStringValueGuess::Address),
|
||||||
|
("Email".into() , SQLStringValueGuess::Email),
|
||||||
|
("URL".into() , SQLStringValueGuess::URL),
|
||||||
|
]);
|
||||||
|
|
||||||
|
let max_size = *max_size;
|
||||||
|
show_enum_dropdown(guess, options, onchange.reform(move |enum_value| {
|
||||||
|
SQLValueGuess::String(max_size, enum_value)
|
||||||
|
}))
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
@ -1 +1,2 @@
|
|||||||
pub mod sql_column_info;
|
pub mod sql_column_info;
|
||||||
|
pub mod generator_picker;
|
||||||
|
@ -1,12 +1,14 @@
|
|||||||
use std::rc::Rc;
|
use std::{rc::Rc, collections::HashMap, cell::RefCell};
|
||||||
|
|
||||||
use yew::{Properties, html, function_component, Html};
|
use yew::{Properties, html, function_component, Html, Callback};
|
||||||
|
|
||||||
use crate::magicdraw_parser::SQLTable;
|
use crate::{magicdraw_parser::SQLTable, generate_sql::SQLValueGuess, components::generator_picker::generator_picker};
|
||||||
|
|
||||||
#[derive(Properties, PartialEq)]
|
#[derive(Properties, PartialEq)]
|
||||||
pub struct SQLTableColumnInfoProps {
|
pub struct SQLTableColumnInfoProps {
|
||||||
pub table: Rc<SQLTable>
|
pub table: Rc<SQLTable>,
|
||||||
|
pub guessess: Rc<RefCell<HashMap<String, SQLValueGuess>>>,
|
||||||
|
pub onchange: Callback<(String, SQLValueGuess)>
|
||||||
}
|
}
|
||||||
|
|
||||||
const CHECK_MARK: &str = "✔️";
|
const CHECK_MARK: &str = "✔️";
|
||||||
@ -22,24 +24,36 @@ pub fn SQLTableColumnInfo(props: &SQLTableColumnInfoProps) -> Html {
|
|||||||
|
|
||||||
let rows = table.columns.iter()
|
let rows = table.columns.iter()
|
||||||
.map(|col| {
|
.map(|col| {
|
||||||
let foreign_key;
|
let guessess = &props.guessess.borrow();
|
||||||
if let Some((table_name, prop_name)) = &col.foreign_key {
|
let generator = guessess.get(&col.name);
|
||||||
foreign_key = format!("{} {}", table_name, prop_name);
|
|
||||||
} else {
|
|
||||||
foreign_key = CROSS_MARK.into();
|
|
||||||
}
|
|
||||||
|
|
||||||
html! {
|
let foreign_key;
|
||||||
<tr>
|
if let Some((table_name, prop_name)) = &col.foreign_key {
|
||||||
<td> { &col.name } </td>
|
foreign_key = format!("{} {}", table_name, prop_name);
|
||||||
<td> { &col.sql_type } </td>
|
} else {
|
||||||
<td> { bool_to_mark(col.primary_key) } </td>
|
foreign_key = CROSS_MARK.into();
|
||||||
<td> { bool_to_mark(col.nullable) } </td>
|
}
|
||||||
<td> { foreign_key } </td>
|
|
||||||
</tr>
|
let name = col.name.clone();
|
||||||
}
|
let onchange = props.onchange.reform(move |value: SQLValueGuess| (name.clone(), value));
|
||||||
}
|
html! {
|
||||||
);
|
<tr>
|
||||||
|
<td> { &col.name } </td>
|
||||||
|
<td> { &col.sql_type } </td>
|
||||||
|
<td> {
|
||||||
|
if let Some(generator) = generator {
|
||||||
|
generator_picker(col, generator, onchange)
|
||||||
|
} else {
|
||||||
|
html!(CROSS_MARK)
|
||||||
|
}
|
||||||
|
} </td>
|
||||||
|
<td> { bool_to_mark(col.primary_key) } </td>
|
||||||
|
<td> { bool_to_mark(col.nullable) } </td>
|
||||||
|
<td> { foreign_key } </td>
|
||||||
|
</tr>
|
||||||
|
}
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
html!{
|
html!{
|
||||||
<div
|
<div
|
||||||
@ -47,12 +61,11 @@ pub fn SQLTableColumnInfo(props: &SQLTableColumnInfoProps) -> Html {
|
|||||||
border="solid dark100 0.2rem collapse"
|
border="solid dark100 0.2rem collapse"
|
||||||
>
|
>
|
||||||
<p class="text-center"> { &table.name } </p>
|
<p class="text-center"> { &table.name } </p>
|
||||||
<table
|
<table border="solid dark100 t-0.2rem collapse">
|
||||||
border="solid dark100 t-0.2rem collapse"
|
|
||||||
>
|
|
||||||
<tr>
|
<tr>
|
||||||
<th> { "Column" } </th>
|
<th> { "Column" } </th>
|
||||||
<th> { "Type" } </th>
|
<th> { "Type" } </th>
|
||||||
|
<th> { "Generator" } </th>
|
||||||
<th> { "Primary?" } </th>
|
<th> { "Primary?" } </th>
|
||||||
<th> { "Nullable?" } </th>
|
<th> { "Nullable?" } </th>
|
||||||
<th> { "Foreign key?" } </th>
|
<th> { "Foreign key?" } </th>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use std::{rc::Rc, collections::HashSet};
|
use std::{rc::Rc, collections::{HashSet, HashMap}};
|
||||||
|
|
||||||
use anyhow::{Result, bail};
|
use anyhow::{Result, bail};
|
||||||
use rand::{seq::SliceRandom, Rng, rngs::ThreadRng};
|
use rand::{seq::SliceRandom, Rng, rngs::ThreadRng};
|
||||||
@ -9,20 +9,20 @@ use crate::magicdraw_parser::{SQLTable, SQLColumn, SQLType, SQLCheckConstraint};
|
|||||||
|
|
||||||
const INDENT: &str = " ";
|
const INDENT: &str = " ";
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum SQLIntValueGuess {
|
pub enum SQLIntValueGuess {
|
||||||
Range(i32, i32),
|
Range(i32, i32),
|
||||||
AutoIncrement
|
AutoIncrement
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum SQLTimeValueGuess {
|
pub enum SQLTimeValueGuess {
|
||||||
Now,
|
Now,
|
||||||
Future,
|
Future,
|
||||||
Past
|
Past
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum SQLStringValueGuess {
|
pub enum SQLStringValueGuess {
|
||||||
LoremIpsum,
|
LoremIpsum,
|
||||||
FirstName,
|
FirstName,
|
||||||
@ -37,14 +37,14 @@ pub enum SQLStringValueGuess {
|
|||||||
RandomEnum(Vec<String>),
|
RandomEnum(Vec<String>),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum SQLBoolValueGuess {
|
pub enum SQLBoolValueGuess {
|
||||||
True,
|
True,
|
||||||
False,
|
False,
|
||||||
Random,
|
Random,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq, Clone)]
|
||||||
pub enum SQLValueGuess {
|
pub enum SQLValueGuess {
|
||||||
Int(SQLIntValueGuess),
|
Int(SQLIntValueGuess),
|
||||||
Date(SQLTimeValueGuess),
|
Date(SQLTimeValueGuess),
|
||||||
@ -58,7 +58,7 @@ pub enum SQLValueGuess {
|
|||||||
// TODO: Check primary key constraint
|
// TODO: Check primary key constraint
|
||||||
pub fn generate_fake_entries(
|
pub fn generate_fake_entries(
|
||||||
tables: &[Rc<SQLTable>],
|
tables: &[Rc<SQLTable>],
|
||||||
value_guessess: &Vec<Vec<SQLValueGuess>>,
|
value_guessess: &Vec<HashMap<&str, SQLValueGuess>>,
|
||||||
rows_per_table: u32
|
rows_per_table: u32
|
||||||
) -> Result<String> {
|
) -> Result<String> {
|
||||||
let mut lines = vec![];
|
let mut lines = vec![];
|
||||||
@ -96,9 +96,9 @@ pub fn generate_fake_entries(
|
|||||||
for (table_idx, table) in tables.iter().enumerate() {
|
for (table_idx, table) in tables.iter().enumerate() {
|
||||||
let entries = &mut all_entries[table_idx];
|
let entries = &mut all_entries[table_idx];
|
||||||
|
|
||||||
for (column_idx, column) in table.columns.iter().enumerate() {
|
for column in &table.columns {
|
||||||
let mut auto_increment_counter = 0;
|
let mut auto_increment_counter = 0;
|
||||||
let value_guess = &value_guessess[table_idx][column_idx];
|
let value_guess = value_guessess[table_idx].get(column.name.as_str()).expect("Failed to get column guess");
|
||||||
for entry_idx in 0..(rows_per_table as usize) {
|
for entry_idx in 0..(rows_per_table as usize) {
|
||||||
if let Some(_) = &column.foreign_key {
|
if let Some(_) = &column.foreign_key {
|
||||||
entries_with_foreign_keys.insert((table_idx, entry_idx));
|
entries_with_foreign_keys.insert((table_idx, entry_idx));
|
||||||
@ -358,8 +358,9 @@ pub fn generate_guess(column: &SQLColumn) -> SQLValueGuess {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_table_guessess(table: &SQLTable) -> Vec<SQLValueGuess> {
|
pub fn generate_table_guessess(table: &SQLTable) -> HashMap<String, SQLValueGuess> {
|
||||||
table.columns.iter()
|
table.columns.iter()
|
||||||
.map(|column| generate_guess(column))
|
.filter(|column| column.foreign_key.is_none())
|
||||||
|
.map(|column| (column.name.clone(), generate_guess(column)))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
12
styles.css
12
styles.css
@ -7,3 +7,15 @@
|
|||||||
button {
|
button {
|
||||||
border: 0
|
border: 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Chrome, Safari, Edge, Opera */
|
||||||
|
input::-webkit-outer-spin-button,
|
||||||
|
input::-webkit-inner-spin-button {
|
||||||
|
-webkit-appearance: none;
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Firefox */
|
||||||
|
input[type=number] {
|
||||||
|
-moz-appearance: textfield;
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user