add serde, schemars and garde to profiles and options

This commit is contained in:
pedrocarlo
2025-08-28 02:22:34 -03:00
parent faa943fc76
commit a1407869d4
8 changed files with 273 additions and 83 deletions

109
Cargo.lock generated
View File

@@ -426,6 +426,15 @@ version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]]
name = "castaway"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dec551ab6e7578819132c713a93c022a05d60159dc86e7a7050223577484c55a"
dependencies = [
"rustversion",
]
[[package]]
name = "cc"
version = "1.2.17"
@@ -601,6 +610,21 @@ dependencies = [
"unicode-width 0.2.0",
]
[[package]]
name = "compact_str"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3b79c4069c6cad78e2e0cdfcbd26275770669fb39fd308a752dc110e83b9af32"
dependencies = [
"castaway",
"cfg-if",
"itoa",
"rustversion",
"ryu",
"serde",
"static_assertions",
]
[[package]]
name = "concurrent-queue"
version = "2.5.0"
@@ -1402,6 +1426,29 @@ dependencies = [
"slab",
]
[[package]]
name = "garde"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6a989bd2fd12136080f7825ff410d9239ce84a2a639487fc9d924ee42e2fb84f"
dependencies = [
"compact_str",
"garde_derive",
"serde",
"smallvec",
]
[[package]]
name = "garde_derive"
version = "0.22.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1f7f0545bbbba0a37d4d445890fa5759814e0716f02417b39f6fab292193df68"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "genawaiter"
version = "0.99.1"
@@ -2132,6 +2179,7 @@ dependencies = [
"clap",
"dirs 6.0.0",
"env_logger 0.10.2",
"garde",
"hex",
"itertools 0.14.0",
"log",
@@ -2141,6 +2189,7 @@ dependencies = [
"regex",
"regex-syntax 0.8.5",
"rusqlite",
"schemars 1.0.4",
"serde",
"serde_json",
"sql_generation",
@@ -3109,6 +3158,26 @@ dependencies = [
"thiserror 2.0.12",
]
[[package]]
name = "ref-cast"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4a0ae411dbe946a674d89546582cea4ba2bb8defac896622d6496f14c23ba5cf"
dependencies = [
"ref-cast-impl",
]
[[package]]
name = "ref-cast-impl"
version = "1.0.24"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1165225c21bff1f3bbce98f5a1f889949bc902d3575308cc7b0de30b4f6d27c7"
dependencies = [
"proc-macro2",
"quote",
"syn 2.0.100",
]
[[package]]
name = "regex"
version = "1.11.1"
@@ -3355,7 +3424,20 @@ checksum = "3fbf2ae1b8bc8e02df939598064d22402220cd5bbcca1c76f7d6a310974d5615"
dependencies = [
"dyn-clone",
"indexmap 1.9.3",
"schemars_derive",
"schemars_derive 0.8.22",
"serde",
"serde_json",
]
[[package]]
name = "schemars"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "82d20c4491bc164fa2f6c5d44565947a52ad80b9505d8e36f8d54c27c739fcd0"
dependencies = [
"dyn-clone",
"ref-cast",
"schemars_derive 1.0.4",
"serde",
"serde_json",
]
@@ -3372,6 +3454,18 @@ dependencies = [
"syn 2.0.100",
]
[[package]]
name = "schemars_derive"
version = "1.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "33d020396d1d138dc19f1165df7545479dcd58d93810dc5d646a16e55abefa80"
dependencies = [
"proc-macro2",
"quote",
"serde_derive_internals",
"syn 2.0.100",
]
[[package]]
name = "scopeguard"
version = "1.2.0"
@@ -3474,6 +3568,9 @@ name = "smallvec"
version = "1.15.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03"
dependencies = [
"serde",
]
[[package]]
name = "socket2"
@@ -3503,10 +3600,12 @@ version = "0.1.4"
dependencies = [
"anarchist-readable-name-generator-lib 0.2.0",
"anyhow",
"garde",
"hex",
"itertools 0.14.0",
"rand 0.9.2",
"rand_chacha 0.9.0",
"schemars 1.0.4",
"serde",
"tracing",
"turso_core",
@@ -3528,6 +3627,12 @@ version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "str_stack"
version = "0.1.0"
@@ -4038,7 +4143,7 @@ dependencies = [
"mimalloc",
"nu-ansi-term 0.50.1",
"rustyline",
"schemars",
"schemars 0.8.22",
"serde",
"serde_json",
"shlex",

View File

@@ -67,6 +67,8 @@ rusqlite = { version = "0.37.0", features = ["bundled"] }
itertools = "0.14.0"
rand = "0.9.2"
tracing = "0.1.41"
schemars = "1.0.4"
garde = "0.22"
[profile.release]
debug = "line-tables-only"

View File

@@ -38,3 +38,5 @@ hex = "0.4.3"
itertools = "0.14.0"
sql_generation = { workspace = true }
turso_parser = { workspace = true }
schemars = { workspace = true }
garde = { workspace = true, features = ["derive", "serde"] }

View File

@@ -1,7 +1,17 @@
#[derive(Debug, Clone)]
use garde::Validate;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use super::{max_dependent, min_dependent};
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Validate)]
#[serde(deny_unknown_fields, default)]
pub struct IOProfile {
#[garde(skip)]
pub enable: bool,
#[garde(dive)]
pub latency: LatencyProfile,
// TODO: expand here with header corruption options and faults on specific IO operations
}
impl Default for IOProfile {
@@ -13,13 +23,18 @@ impl Default for IOProfile {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Validate)]
#[serde(deny_unknown_fields, default)]
pub struct LatencyProfile {
#[garde(skip)]
pub enable: bool,
#[garde(range(min = 0, max = 100))]
/// Added IO latency probability
pub latency_probability: usize,
#[garde(custom(max_dependent(&self.max_tick)))]
/// Minimum tick time in microseconds for simulated time
pub min_tick: u64,
#[garde(custom(min_dependent(&self.min_tick)))]
/// Maximum tick time in microseconds for simulated time
pub max_tick: u64,
}

View File

@@ -1,13 +1,22 @@
use std::fmt::Display;
use garde::Validate;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::profiles::{io::IOProfile, query::QueryProfile};
mod io;
mod query;
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Validate)]
pub struct Profile {
#[garde(skip)]
/// Experimental MVCC feature
pub experimental_mvcc: bool,
#[garde(dive)]
pub io: IOProfile,
#[garde(dive)]
pub query: QueryProfile,
}
@@ -20,3 +29,27 @@ impl Default for Profile {
}
}
}
/// Minimum value of field is dependent on another field in the struct
fn min_dependent<T: PartialOrd + Display>(min: &T) -> impl FnOnce(&T, &()) -> garde::Result + '_ {
move |value, _| {
if value < min {
return Err(garde::Error::new(format!(
"`{value}` is smaller than `{min}`"
)));
}
Ok(())
}
}
/// Maximum value of field is dependent on another field in the struct
fn max_dependent<T: PartialOrd + Display>(max: &T) -> impl FnOnce(&T, &()) -> garde::Result + '_ {
move |value, _| {
if value > max {
return Err(garde::Error::new(format!(
"`{value}` is bigger than `{max}`"
)));
}
Ok(())
}
}

View File

@@ -1,75 +1,37 @@
#[derive(Debug, Default, Clone)]
use garde::Validate;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use sql_generation::generation::Opts;
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Validate)]
#[serde(deny_unknown_fields, default)]
pub struct QueryProfile {
pub create_table: CreateTableProfile,
pub create_index: CreateIndexProfile,
pub insert: InsertProfile,
pub update: UpdateProfile,
pub delete: DeleteProfile,
pub drop_table: DropTableProfile,
#[garde(dive)]
pub gen_opts: Opts,
#[garde(skip)]
pub create_table: bool,
#[garde(skip)]
pub create_index: bool,
#[garde(skip)]
pub insert: bool,
#[garde(skip)]
pub update: bool,
#[garde(skip)]
pub delete: bool,
#[garde(skip)]
pub drop_table: bool,
}
#[derive(Debug, Clone)]
pub struct CreateTableProfile {
pub enable: bool,
}
impl Default for CreateTableProfile {
impl Default for QueryProfile {
fn default() -> Self {
Self { enable: true }
}
}
#[derive(Debug, Clone)]
pub struct CreateIndexProfile {
pub enable: bool,
}
impl Default for CreateIndexProfile {
fn default() -> Self {
Self { enable: true }
}
}
#[derive(Debug, Clone)]
pub struct InsertProfile {
pub enable: bool,
}
impl Default for InsertProfile {
fn default() -> Self {
Self { enable: true }
}
}
#[derive(Debug, Clone)]
pub struct UpdateProfile {
pub enable: bool,
}
impl Default for UpdateProfile {
fn default() -> Self {
Self { enable: true }
}
}
#[derive(Debug, Clone)]
pub struct DeleteProfile {
pub enable: bool,
}
impl Default for DeleteProfile {
fn default() -> Self {
Self { enable: true }
}
}
#[derive(Debug, Clone)]
pub struct DropTableProfile {
pub enable: bool,
}
impl Default for DropTableProfile {
fn default() -> Self {
Self { enable: true }
Self {
gen_opts: Opts::default(),
create_table: true,
create_index: true,
insert: true,
update: true,
delete: true,
drop_table: true,
}
}
}

View File

@@ -19,6 +19,8 @@ anarchist-readable-name-generator-lib = "0.2.0"
itertools = { workspace = true }
anyhow = { workspace = true }
tracing = { workspace = true }
schemars = { workspace = true }
garde = { workspace = true, features = ["derive", "serde"] }
[dev-dependencies]
rand_chacha = "0.9.0"

View File

@@ -1,9 +1,13 @@
use std::{
fmt::Display,
num::{NonZero, NonZeroU32},
ops::Range,
};
use garde::Validate;
use rand::distr::weighted::WeightedIndex;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use crate::model::table::Table;
@@ -13,11 +17,15 @@ pub trait GenerationContext {
fn opts(&self) -> &Opts;
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Validate)]
#[serde(deny_unknown_fields, default)]
pub struct Opts {
#[garde(skip)]
/// Indexes enabled
pub indexes: bool,
#[garde(dive)]
pub table: TableOpts,
#[garde(dive)]
pub query: QueryOpts,
}
@@ -31,10 +39,13 @@ impl Default for Opts {
}
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Validate)]
#[serde(deny_unknown_fields, default)]
pub struct TableOpts {
#[garde(dive)]
pub large_table: LargeTableOpts,
/// Range of numbers of columns to generate
#[garde(custom(range_struct_min(1)))]
pub column_range: Range<u32>,
}
@@ -49,11 +60,16 @@ impl Default for TableOpts {
}
/// Options for generating large tables
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Validate)]
#[serde(deny_unknown_fields, default)]
pub struct LargeTableOpts {
#[garde(skip)]
pub enable: bool,
#[garde(range(min = 0.0, max = 1.0))]
pub large_table_prob: f64,
/// Range of numbers of columns to generate
#[garde(custom(range_struct_min(1)))]
pub column_range: Range<u32>,
}
@@ -68,16 +84,23 @@ impl Default for LargeTableOpts {
}
}
#[derive(Debug, Default, Clone)]
#[derive(Debug, Default, Clone, Serialize, Deserialize, JsonSchema, Validate)]
#[serde(deny_unknown_fields, default)]
pub struct QueryOpts {
#[garde(dive)]
pub select: SelectOpts,
#[garde(dive)]
pub from_clause: FromClauseOpts,
#[garde(dive)]
pub insert: InsertOpts,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Validate)]
#[serde(deny_unknown_fields, default)]
pub struct SelectOpts {
#[garde(range(min = 0.0, max = 1.0))]
pub order_by_prob: f64,
#[garde(length(min = 1))]
pub compound_selects: Vec<CompoundSelectWeight>,
}
@@ -109,14 +132,17 @@ impl SelectOpts {
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct CompoundSelectWeight {
pub num_compound_selects: u32,
pub weight: u32,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Validate)]
#[serde(deny_unknown_fields)]
pub struct FromClauseOpts {
#[garde(length(min = 1))]
pub joins: Vec<JoinWeight>,
}
@@ -147,15 +173,19 @@ impl FromClauseOpts {
}
}
#[derive(Debug, Clone, PartialEq, PartialOrd)]
#[derive(Debug, Clone, PartialEq, PartialOrd, Serialize, Deserialize, JsonSchema)]
#[serde(deny_unknown_fields)]
pub struct JoinWeight {
pub num_joins: u32,
pub weight: u32,
}
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Serialize, Deserialize, JsonSchema, Validate)]
#[serde(deny_unknown_fields)]
pub struct InsertOpts {
#[garde(skip)]
pub min_rows: NonZeroU32,
#[garde(skip)]
pub max_rows: NonZeroU32,
}
@@ -167,3 +197,42 @@ impl Default for InsertOpts {
}
}
}
fn range_struct_min<T: PartialOrd + Display>(
min: T,
) -> impl FnOnce(&Range<T>, &()) -> garde::Result {
move |value, _| {
if value.start < min {
return Err(garde::Error::new(format!(
"range start `{}` is smaller than {min}",
value.start
)));
} else if value.end < min {
return Err(garde::Error::new(format!(
"range end `{}` is smaller than {min}",
value.end
)));
}
Ok(())
}
}
#[allow(dead_code)]
fn range_struct_max<T: PartialOrd + Display>(
max: T,
) -> impl FnOnce(&Range<T>, &()) -> garde::Result {
move |value, _| {
if value.start > max {
return Err(garde::Error::new(format!(
"range start `{}` is smaller than {max}",
value.start
)));
} else if value.end > max {
return Err(garde::Error::new(format!(
"range end `{}` is smaller than {max}",
value.end
)));
}
Ok(())
}
}