add entry generation and column type guessing
This commit is contained in:
parent
f279900ac9
commit
1fa7c7bbc8
276
Cargo.lock
generated
276
Cargo.lock
generated
@ -17,6 +17,15 @@ dependencies = [
|
||||
"memchr",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "android_system_properties"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311"
|
||||
dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "anyhow"
|
||||
version = "1.0.69"
|
||||
@ -68,12 +77,43 @@ version = "1.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "14c189c53d098945499cdfa7ecc63567cf3886b3332b312a5b4585d8d3a6a610"
|
||||
|
||||
[[package]]
|
||||
name = "cc"
|
||||
version = "1.0.79"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "1.0.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.23"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "16b0a3d9ed01224b22057780a37bb8c5dbfe1be8ba48678e7bf57ec4b385411f"
|
||||
dependencies = [
|
||||
"iana-time-zone",
|
||||
"js-sys",
|
||||
"num-integer",
|
||||
"num-traits",
|
||||
"time",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "codespan-reporting"
|
||||
version = "0.11.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e"
|
||||
dependencies = [
|
||||
"termcolor",
|
||||
"unicode-width",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "console_error_panic_hook"
|
||||
version = "0.1.7"
|
||||
@ -84,6 +124,12 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "core-foundation-sys"
|
||||
version = "0.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5827cebf4670468b8772dd191856768aedcb1b0278a04f989f7766351917b9dc"
|
||||
|
||||
[[package]]
|
||||
name = "crc32fast"
|
||||
version = "1.3.2"
|
||||
@ -102,6 +148,59 @@ dependencies = [
|
||||
"cfg-if",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx"
|
||||
version = "1.0.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "86d3488e7665a7a483b57e25bdd90d0aeb2bc7608c8d0346acf2ad3f1caf1d62"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"cxxbridge-flags",
|
||||
"cxxbridge-macro",
|
||||
"link-cplusplus",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxx-build"
|
||||
version = "1.0.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "48fcaf066a053a41a81dfb14d57d99738b767febb8b735c3016e469fac5da690"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"codespan-reporting",
|
||||
"once_cell",
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"scratch",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-flags"
|
||||
version = "1.0.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a2ef98b8b717a829ca5603af80e1f9e2e48013ab227b68ef37872ef84ee479bf"
|
||||
|
||||
[[package]]
|
||||
name = "cxxbridge-macro"
|
||||
version = "1.0.91"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "086c685979a698443656e5cf7856c95c642295a38599f12fb1ff76fb28d19892"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fake"
|
||||
version = "2.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4d68f517805463f3a896a9d29c1d6ff09d3579ded64a7201b4069f8f9c0d52fd"
|
||||
dependencies = [
|
||||
"rand",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "flate2"
|
||||
version = "1.0.25"
|
||||
@ -198,6 +297,17 @@ dependencies = [
|
||||
"slab",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
version = "0.2.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
|
||||
dependencies = [
|
||||
"cfg-if",
|
||||
"libc",
|
||||
"wasi 0.11.0+wasi-snapshot-preview1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "gloo"
|
||||
version = "0.8.0"
|
||||
@ -378,6 +488,30 @@ dependencies = [
|
||||
"libc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone"
|
||||
version = "0.1.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "64c122667b287044802d6ce17ee2ddf13207ed924c712de9a66a5814d5b64765"
|
||||
dependencies = [
|
||||
"android_system_properties",
|
||||
"core-foundation-sys",
|
||||
"iana-time-zone-haiku",
|
||||
"js-sys",
|
||||
"wasm-bindgen",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "iana-time-zone-haiku"
|
||||
version = "0.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0703ae284fc167426161c2e3f1da3ea71d94b21bedbcc9494e92b28e334e3dca"
|
||||
dependencies = [
|
||||
"cxx",
|
||||
"cxx-build",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "implicit-clone"
|
||||
version = "0.3.5"
|
||||
@ -441,6 +575,15 @@ version = "0.2.139"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "201de327520df007757c1f0adce6e827fe8562fbc28bfd9c15571c66ca1f5f79"
|
||||
|
||||
[[package]]
|
||||
name = "link-cplusplus"
|
||||
version = "1.0.8"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ecd207c9c713c34f95a097a5b029ac2ce6010530c7b49d7fea24d977dede04f5"
|
||||
dependencies = [
|
||||
"cc",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.17"
|
||||
@ -456,9 +599,12 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
"chrono",
|
||||
"fake",
|
||||
"gloo",
|
||||
"js-sys",
|
||||
"lazy-regex",
|
||||
"rand",
|
||||
"serde",
|
||||
"thiserror",
|
||||
"web-sys",
|
||||
@ -482,6 +628,25 @@ dependencies = [
|
||||
"adler",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
"num-traits",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "578ede34cf02f8924ab9447f50c28075b4d3e5b269972345e7e0372b38c6cdcd"
|
||||
dependencies = [
|
||||
"autocfg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num_cpus"
|
||||
version = "1.15.0"
|
||||
@ -547,6 +712,12 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ppv-lite86"
|
||||
version = "0.2.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.1.23"
|
||||
@ -616,6 +787,36 @@ dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.8.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_chacha",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_chacha"
|
||||
version = "0.3.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88"
|
||||
dependencies = [
|
||||
"ppv-lite86",
|
||||
"rand_core",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.6.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
dependencies = [
|
||||
"getrandom",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "regex"
|
||||
version = "1.7.1"
|
||||
@ -645,6 +846,12 @@ version = "1.0.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7b4b9743ed687d4b4bcedf9ff5eaa7398495ae14e61cba0a295704edbc7decde"
|
||||
|
||||
[[package]]
|
||||
name = "scratch"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ddccb15bcce173023b3fedd9436f882a0739b8dfb45e4f6b6002bee5929f61b2"
|
||||
|
||||
[[package]]
|
||||
name = "serde"
|
||||
version = "1.0.152"
|
||||
@ -719,6 +926,15 @@ dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "termcolor"
|
||||
version = "1.2.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "be55cf8942feac5c765c2c993422806843c9a9a45d4d5c407ad6dd2ea95eb9b6"
|
||||
dependencies = [
|
||||
"winapi-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "thiserror"
|
||||
version = "1.0.38"
|
||||
@ -739,6 +955,17 @@ dependencies = [
|
||||
"syn",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "time"
|
||||
version = "0.1.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1b797afad3f312d1c66a56d11d0316f916356d11bd158fbc6ca6389ff6bf805a"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"wasi 0.10.0+wasi-snapshot-preview1",
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "tokio"
|
||||
version = "1.25.0"
|
||||
@ -799,12 +1026,30 @@ version = "1.0.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "84a22b9f218b40614adcb3f4ff08b703773ad44fa9423e4e0d346d5db86e4ebc"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
version = "0.1.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c0edd1e5b14653f783770bce4a4dabb4a5108a5370a5f5d8cfe8710c361f6c8b"
|
||||
|
||||
[[package]]
|
||||
name = "version_check"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.10.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"
|
||||
|
||||
[[package]]
|
||||
name = "wasi"
|
||||
version = "0.11.0+wasi-snapshot-preview1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
|
||||
|
||||
[[package]]
|
||||
name = "wasm-bindgen"
|
||||
version = "0.2.84"
|
||||
@ -881,6 +1126,37 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-util"
|
||||
version = "0.1.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178"
|
||||
dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.42.0"
|
||||
|
@ -14,6 +14,9 @@ js-sys = "0.3"
|
||||
base64 = "0.13.0"
|
||||
gloo = "0.8"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
fake = "2.5"
|
||||
rand = "0.8"
|
||||
chrono = "0.4.23"
|
||||
|
||||
[dependencies.zip]
|
||||
version = "0.6.4"
|
||||
|
365
src/generate_sql.rs
Normal file
365
src/generate_sql.rs
Normal file
@ -0,0 +1,365 @@
|
||||
use std::{rc::Rc, collections::HashSet};
|
||||
|
||||
use anyhow::{Result, bail};
|
||||
use rand::{seq::SliceRandom, Rng, rngs::ThreadRng};
|
||||
use chrono::{Local, NaiveDateTime, Days};
|
||||
use fake::{faker::{lorem::en::*, name::en::{FirstName, LastName, Name}, phone_number::en::PhoneNumber, internet::en::{DomainSuffix, FreeEmail}, company::en::BsNoun, address::{en::{CityName, StreetName}}}, Fake};
|
||||
|
||||
use crate::magicdraw_parser::{SQLTable, SQLColumn, SQLType, SQLCheckConstraint};
|
||||
|
||||
const INDENT: &str = " ";
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum SQLIntValueGuess {
|
||||
Range(i32, i32),
|
||||
AutoIncrement
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum SQLTimeValueGuess {
|
||||
Now,
|
||||
Future,
|
||||
Past
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum SQLStringValueGuess {
|
||||
LoremIpsum,
|
||||
FirstName,
|
||||
LastName,
|
||||
FullName,
|
||||
Empty,
|
||||
PhoneNumber,
|
||||
CityName,
|
||||
Address,
|
||||
Email,
|
||||
URL,
|
||||
RandomEnum(Vec<String>),
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum SQLBoolValueGuess {
|
||||
True,
|
||||
False,
|
||||
Random,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum SQLValueGuess {
|
||||
Int(SQLIntValueGuess),
|
||||
Date(SQLTimeValueGuess),
|
||||
Time(SQLTimeValueGuess),
|
||||
Datetime(SQLTimeValueGuess),
|
||||
Float(f32, f32),
|
||||
Bool(SQLBoolValueGuess),
|
||||
String(usize, SQLStringValueGuess),
|
||||
}
|
||||
|
||||
// TODO: Check primary key constraint
|
||||
pub fn generate_fake_entries(
|
||||
tables: &[Rc<SQLTable>],
|
||||
value_guessess: &Vec<Vec<SQLValueGuess>>,
|
||||
rows_per_table: u32
|
||||
) -> Result<String> {
|
||||
let mut lines = vec![];
|
||||
|
||||
let mut rng = rand::thread_rng();
|
||||
|
||||
let mut all_foreign_columns = vec![];
|
||||
let mut all_entries = vec![];
|
||||
for table in tables {
|
||||
let mut entries = vec![];
|
||||
for _ in 0..rows_per_table {
|
||||
entries.push(vec![]);
|
||||
}
|
||||
all_entries.push(entries);
|
||||
|
||||
let mut foreign_columns = vec![];
|
||||
for (i, column) in table.columns.iter().enumerate() {
|
||||
if let Some((table_name, column_name)) = &column.foreign_key {
|
||||
let (table_idx, table) = tables.iter()
|
||||
.enumerate()
|
||||
.find(|(_, table)| table.name.eq(table_name))
|
||||
.expect("Foreign table not found");
|
||||
let (column_idx, _) = table.columns
|
||||
.iter()
|
||||
.enumerate()
|
||||
.find(|(_, column)| column.name.eq(column_name))
|
||||
.expect("Foreign column not found");
|
||||
foreign_columns.push((i, table_idx, column_idx));
|
||||
}
|
||||
}
|
||||
all_foreign_columns.push(foreign_columns);
|
||||
}
|
||||
|
||||
let mut entries_with_foreign_keys = HashSet::new();
|
||||
for (table_idx, table) in tables.iter().enumerate() {
|
||||
let entries = &mut all_entries[table_idx];
|
||||
|
||||
for (column_idx, column) in table.columns.iter().enumerate() {
|
||||
let mut auto_increment_counter = 0;
|
||||
let value_guess = &value_guessess[table_idx][column_idx];
|
||||
for entry_idx in 0..(rows_per_table as usize) {
|
||||
if let Some(_) = &column.foreign_key {
|
||||
entries_with_foreign_keys.insert((table_idx, entry_idx));
|
||||
entries[entry_idx].push("".into());
|
||||
} else {
|
||||
entries[entry_idx].push(generate_value(&mut rng, &value_guess, &mut auto_increment_counter));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while !entries_with_foreign_keys.is_empty() {
|
||||
let entries_with_foreign_keys_copy = entries_with_foreign_keys.clone();
|
||||
let before_retain = entries_with_foreign_keys.len();
|
||||
|
||||
entries_with_foreign_keys.retain(|(table_idx, entry_idx)| {
|
||||
for (column_idx, foreign_table_idx, foreign_column_idx) in &all_foreign_columns[*table_idx] {
|
||||
let available_values: Vec<&str>;
|
||||
|
||||
// If the foreign column, is also a foreign of the other table, ...
|
||||
// Then we need to filter out available options which have not been filled in
|
||||
if all_foreign_columns[*foreign_table_idx].iter().find(|(idx, _, _)| idx == foreign_column_idx).is_some() {
|
||||
available_values = all_entries[*foreign_table_idx].iter()
|
||||
.enumerate()
|
||||
.filter(|(i, _)| entries_with_foreign_keys_copy.contains(&(*foreign_table_idx, *i)))
|
||||
.map(|(_, entry)| entry[*foreign_column_idx].as_str())
|
||||
.collect();
|
||||
} else {
|
||||
available_values = all_entries[*foreign_table_idx].iter()
|
||||
.map(|entry| entry[*foreign_column_idx].as_str())
|
||||
.collect();
|
||||
}
|
||||
|
||||
if let Some(chosen_value) = available_values.choose(&mut rng) {
|
||||
all_entries[*table_idx][*entry_idx][*column_idx] = chosen_value.to_string();
|
||||
} else {
|
||||
// Early break, thre are no currently available options
|
||||
// Try next time
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
});
|
||||
|
||||
// This is to stop infnite loop, where during each iteration nothing gets removed
|
||||
if before_retain == entries_with_foreign_keys.len() {
|
||||
bail!("Failed to resolve foreign keys")
|
||||
}
|
||||
}
|
||||
|
||||
for (i, table) in tables.iter().enumerate() {
|
||||
let mut column_names = vec![];
|
||||
for column in &table.columns {
|
||||
column_names.push(column.name.as_str());
|
||||
}
|
||||
|
||||
let entries = &all_entries[i];
|
||||
lines.push(format!("INSERT INTO {}", table.name));
|
||||
lines.push(format!("{}({})", INDENT, column_names.join(", ")));
|
||||
lines.push("VALUES".into());
|
||||
let entries_str = entries.iter()
|
||||
.map(|entry| format!("{}({})", INDENT, entry.join(", ")))
|
||||
.collect::<Vec<_>>()
|
||||
.join(",\n");
|
||||
lines.push(format!("{};\n", entries_str));
|
||||
}
|
||||
|
||||
Ok(lines.join("\n"))
|
||||
}
|
||||
|
||||
fn generate_time_value(rng: &mut ThreadRng, guess: &SQLTimeValueGuess) -> NaiveDateTime {
|
||||
let now = Local::now().naive_local();
|
||||
|
||||
match guess {
|
||||
SQLTimeValueGuess::Now => now,
|
||||
SQLTimeValueGuess::Future => {
|
||||
let days = rng.gen_range(1..=30);
|
||||
now.checked_add_days(Days::new(days)).unwrap()
|
||||
},
|
||||
SQLTimeValueGuess::Past => {
|
||||
let days = rng.gen_range(7..=365);
|
||||
now.checked_sub_days(Days::new(days)).unwrap()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_value(rng: &mut ThreadRng, guess: &SQLValueGuess, auto_increment_counter: &mut u32) -> String {
|
||||
match guess {
|
||||
SQLValueGuess::Int(int_guess) => {
|
||||
match int_guess {
|
||||
SQLIntValueGuess::Range(min, max) => {
|
||||
rng.gen_range((*min)..=(*max)).to_string()
|
||||
},
|
||||
SQLIntValueGuess::AutoIncrement => {
|
||||
let str = auto_increment_counter.to_string();
|
||||
*auto_increment_counter += 1;
|
||||
str
|
||||
},
|
||||
}
|
||||
},
|
||||
SQLValueGuess::Date(time_gues) => {
|
||||
let datetime = generate_time_value(rng, &time_gues);
|
||||
format!("'{}'", datetime.format("%Y-%m-%d"))
|
||||
},
|
||||
SQLValueGuess::Time(time_gues) => {
|
||||
let datetime = generate_time_value(rng, &time_gues);
|
||||
format!("'{}'", datetime.format("%H:%M:%S"))
|
||||
},
|
||||
SQLValueGuess::Datetime(time_gues) => {
|
||||
let datetime = generate_time_value(rng, &time_gues);
|
||||
format!("'{}'", datetime.format("%Y-%m-%d %H:%M:%S"))
|
||||
},
|
||||
SQLValueGuess::Bool(bool_guess) => {
|
||||
match bool_guess {
|
||||
SQLBoolValueGuess::True => "1".into(),
|
||||
SQLBoolValueGuess::False => "0".into(),
|
||||
SQLBoolValueGuess::Random => rng.gen_range(0..=1).to_string(),
|
||||
}
|
||||
},
|
||||
SQLValueGuess::Float(min, max) => {
|
||||
let value = rng.gen_range((*min)..(*max));
|
||||
((value * 100.0 as f32).round() / 100.0).to_string()
|
||||
},
|
||||
SQLValueGuess::String(max_size, string_guess) => {
|
||||
let mut str = match string_guess {
|
||||
SQLStringValueGuess::LoremIpsum => {
|
||||
|
||||
let mut current_len = 0;
|
||||
let mut text = vec![];
|
||||
let words: Vec<String> = Words(3..10).fake_with_rng(rng);
|
||||
for word in words {
|
||||
current_len += word.len() + 1;
|
||||
text.push(word);
|
||||
if current_len > *max_size { break; }
|
||||
}
|
||||
text.join(" ").to_string()
|
||||
},
|
||||
SQLStringValueGuess::FirstName => {
|
||||
FirstName().fake_with_rng(rng)
|
||||
},
|
||||
SQLStringValueGuess::LastName => {
|
||||
LastName().fake_with_rng(rng)
|
||||
},
|
||||
SQLStringValueGuess::FullName => {
|
||||
Name().fake_with_rng(rng)
|
||||
},
|
||||
SQLStringValueGuess::PhoneNumber => {
|
||||
PhoneNumber().fake_with_rng(rng)
|
||||
},
|
||||
SQLStringValueGuess::CityName => {
|
||||
CityName().fake_with_rng(rng)
|
||||
},
|
||||
SQLStringValueGuess::Address => {
|
||||
StreetName().fake_with_rng(rng)
|
||||
},
|
||||
SQLStringValueGuess::Email => {
|
||||
FreeEmail().fake_with_rng(rng)
|
||||
},
|
||||
SQLStringValueGuess::URL => {
|
||||
let suffix: String = DomainSuffix().fake_with_rng(rng);
|
||||
let noun: String = BsNoun().fake_with_rng(rng);
|
||||
let noun: String = noun.to_lowercase()
|
||||
.chars()
|
||||
.map(|c| if c.is_whitespace() { '-' } else { c })
|
||||
.collect();
|
||||
format!("www.{}.{}", noun, suffix)
|
||||
},
|
||||
SQLStringValueGuess::RandomEnum(options) => {
|
||||
options.choose(rng).unwrap().to_string()
|
||||
},
|
||||
SQLStringValueGuess::Empty => {
|
||||
"".into()
|
||||
}
|
||||
};
|
||||
|
||||
str.truncate(*max_size);
|
||||
format!("'{}'", str)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_string_guess(column: &SQLColumn) -> SQLStringValueGuess {
|
||||
if let Some(constraint) = &column.check_constraint {
|
||||
if let SQLCheckConstraint::OneOf(options) = constraint {
|
||||
return SQLStringValueGuess::RandomEnum(options.clone())
|
||||
} else {
|
||||
return SQLStringValueGuess::LoremIpsum
|
||||
}
|
||||
}
|
||||
|
||||
let name = column.name.to_lowercase();
|
||||
if name.contains("first") && name.contains("name") {
|
||||
SQLStringValueGuess::FirstName
|
||||
} else if (name.contains("last") && name.contains("name")) || name.contains("surname") {
|
||||
SQLStringValueGuess::LastName
|
||||
} else if name.contains("phone") && name.contains("number") {
|
||||
SQLStringValueGuess::PhoneNumber
|
||||
} else if name.contains("city") {
|
||||
SQLStringValueGuess::CityName
|
||||
} else if name.contains("address") {
|
||||
SQLStringValueGuess::Address
|
||||
} else if name.contains("email") {
|
||||
SQLStringValueGuess::Email
|
||||
} else if name.contains("homepage") || name.contains("website") || name.contains("url") {
|
||||
SQLStringValueGuess::URL
|
||||
} else {
|
||||
SQLStringValueGuess::LoremIpsum
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_guess(column: &SQLColumn) -> SQLValueGuess {
|
||||
match column.sql_type {
|
||||
SQLType::Int => {
|
||||
if column.primary_key {
|
||||
SQLValueGuess::Int(SQLIntValueGuess::AutoIncrement)
|
||||
} else {
|
||||
SQLValueGuess::Int(SQLIntValueGuess::Range(0, 100))
|
||||
}
|
||||
},
|
||||
SQLType::Float | SQLType::Decimal => {
|
||||
SQLValueGuess::Float(0.0, 100.0)
|
||||
},
|
||||
SQLType::Date => {
|
||||
let name = column.name.to_lowercase();
|
||||
if name.contains("create") || name.contains("update") {
|
||||
SQLValueGuess::Date(SQLTimeValueGuess::Past)
|
||||
} else {
|
||||
SQLValueGuess::Date(SQLTimeValueGuess::Now)
|
||||
}
|
||||
},
|
||||
SQLType::Time => {
|
||||
let name = column.name.to_lowercase();
|
||||
if name.contains("create") || name.contains("update") {
|
||||
SQLValueGuess::Time(SQLTimeValueGuess::Past)
|
||||
} else {
|
||||
SQLValueGuess::Time(SQLTimeValueGuess::Now)
|
||||
}
|
||||
},
|
||||
SQLType::Datetime => {
|
||||
let name = column.name.to_lowercase();
|
||||
if name.contains("create") || name.contains("update") {
|
||||
SQLValueGuess::Datetime(SQLTimeValueGuess::Past)
|
||||
} else {
|
||||
SQLValueGuess::Datetime(SQLTimeValueGuess::Now)
|
||||
}
|
||||
},
|
||||
SQLType::Bool => {
|
||||
SQLValueGuess::Bool(SQLBoolValueGuess::Random)
|
||||
},
|
||||
SQLType::Varchar(max_size) => {
|
||||
SQLValueGuess::String(max_size as usize, generate_string_guess(column))
|
||||
},
|
||||
SQLType::Char(max_size) => {
|
||||
SQLValueGuess::String(max_size as usize, generate_string_guess(column))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn generate_table_guessess(table: &SQLTable) -> Vec<SQLValueGuess> {
|
||||
table.columns.iter()
|
||||
.map(|column| generate_guess(column))
|
||||
.collect()
|
||||
}
|
@ -18,6 +18,8 @@ pub enum SQLType {
|
||||
Int,
|
||||
Decimal,
|
||||
Date,
|
||||
Time,
|
||||
Datetime,
|
||||
Float,
|
||||
Bool,
|
||||
Char(u8),
|
||||
@ -30,6 +32,8 @@ impl Display for SQLType {
|
||||
SQLType::Int => write!(f, "INT"),
|
||||
SQLType::Decimal => write!(f, "DECIMAL"),
|
||||
SQLType::Date => write!(f, "DATE"),
|
||||
SQLType::Time => write!(f, "TIME"),
|
||||
SQLType::Datetime => write!(f, "DATETIME"),
|
||||
SQLType::Float => write!(f, "FLOAT"),
|
||||
SQLType::Bool => write!(f, "BOOL"),
|
||||
SQLType::Char(size) => write!(f, "CHAR({})", size),
|
||||
|
@ -3,6 +3,7 @@ use app::App;
|
||||
mod magicdraw_parser;
|
||||
mod app;
|
||||
mod components;
|
||||
mod generate_sql;
|
||||
|
||||
// TODO: Make this work with enumation lookup tables
|
||||
// TODO: Dark theme switch button
|
||||
|
Loading…
Reference in New Issue
Block a user