From acb8a47911a4cdb2f30d26e057dcf5f36dc97a34 Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Tue, 3 Jun 2025 14:52:35 -0300 Subject: [PATCH 01/29] sanitize string for ast::Literal --- vendored/sqlite3-parser/src/to_sql_string/expr.rs | 8 +++++++- vendored/sqlite3-parser/src/to_sql_string/stmt/select.rs | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/vendored/sqlite3-parser/src/to_sql_string/expr.rs b/vendored/sqlite3-parser/src/to_sql_string/expr.rs index 7727543da..bb4cf4296 100644 --- a/vendored/sqlite3-parser/src/to_sql_string/expr.rs +++ b/vendored/sqlite3-parser/src/to_sql_string/expr.rs @@ -369,6 +369,12 @@ impl Display for ast::LikeOperator { } } +/// Sanitaizes a string literal by removing single quote at front and back +/// and escaping double single quotes +pub fn sanitize_string(input: &str) -> String { + input[1..input.len() - 1].replace("''", "'").to_string() +} + impl Display for ast::Literal { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!( @@ -382,7 +388,7 @@ impl Display for ast::Literal { Self::Keyword(keyword) => keyword.clone(), Self::Null => "NULL".to_string(), Self::Numeric(num) => num.clone(), - Self::String(s) => s.clone(), + Self::String(s) => format!("'{}'", sanitize_string(s)), } ) } diff --git a/vendored/sqlite3-parser/src/to_sql_string/stmt/select.rs b/vendored/sqlite3-parser/src/to_sql_string/stmt/select.rs index 240c490b4..84781b1be 100644 --- a/vendored/sqlite3-parser/src/to_sql_string/stmt/select.rs +++ b/vendored/sqlite3-parser/src/to_sql_string/stmt/select.rs @@ -77,6 +77,7 @@ impl ToSqlString for ast::OneSelect { impl ToSqlString for ast::SelectInner { fn to_sql_string(&self, context: &C) -> String { + dbg!(&self); let mut ret = Vec::with_capacity(2 + self.columns.len()); ret.push("SELECT".to_string()); if let Some(distinct) = self.distinctness { From f1146e716c51687d9051c82a7adf6fa7becbebdb Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Mon, 2 Jun 2025 14:39:32 -0300 Subject: [PATCH 02/29] inital implementation for ast generation --- Cargo.lock | 2 + simulator/Cargo.toml | 3 +- simulator/generation/expr.rs | 281 +++++++++++++++++++++++++++++++++++ simulator/generation/mod.rs | 1 + 4 files changed, 286 insertions(+), 1 deletion(-) create mode 100644 simulator/generation/expr.rs diff --git a/Cargo.lock b/Cargo.lock index f6fbb4826..95b643eb7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1960,7 +1960,9 @@ dependencies = [ "clap", "dirs 6.0.0", "env_logger 0.10.2", + "hex", "limbo_core", + "limbo_sqlite3_parser", "log", "notify", "rand 0.8.5", diff --git a/simulator/Cargo.toml b/simulator/Cargo.toml index 852a39cb7..0c7a76e45 100644 --- a/simulator/Cargo.toml +++ b/simulator/Cargo.toml @@ -35,4 +35,5 @@ chrono = { version = "0.4.40", features = ["serde"] } tracing = "0.1.41" tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } anyhow.workspace = true - +limbo_sqlite3_parser = { workspace = true } +hex = "0.4.3" diff --git a/simulator/generation/expr.rs b/simulator/generation/expr.rs new file mode 100644 index 000000000..86351786a --- /dev/null +++ b/simulator/generation/expr.rs @@ -0,0 +1,281 @@ +use limbo_sqlite3_parser::ast::{ + self, Expr, LikeOperator, Name, Operator, QualifiedName, Type, UnaryOperator, +}; + +use crate::{ + generation::{gen_random_text, pick, pick_index, Arbitrary, ArbitraryFrom}, + SimulatorEnv, +}; + +impl Arbitrary for Box +where + T: Arbitrary, +{ + fn arbitrary(rng: &mut R) -> Self { + Box::from(T::arbitrary(rng)) + } +} + +impl ArbitraryFrom for Box +where + T: ArbitraryFrom, +{ + fn arbitrary_from(rng: &mut R, t: A) -> Self { + Box::from(T::arbitrary_from(rng, t)) + } +} + +impl Arbitrary for Option +where + T: Arbitrary, +{ + fn arbitrary(rng: &mut R) -> Self { + rng.gen_bool(0.5).then_some(T::arbitrary(rng)) + } +} + +impl ArbitraryFrom for Option +where + T: ArbitraryFrom, +{ + fn arbitrary_from(rng: &mut R, t: A) -> Self { + rng.gen_bool(0.5).then_some(T::arbitrary_from(rng, t)) + } +} + +impl ArbitraryFrom for Vec +where + T: ArbitraryFrom, +{ + fn arbitrary_from(rng: &mut R, t: A) -> Self { + let size = rng.gen_range(0..5); + (0..size) + .into_iter() + .map(|_| T::arbitrary_from(rng, t)) + .collect() + } +} + +impl ArbitraryFrom<&SimulatorEnv> for Expr { + fn arbitrary_from(rng: &mut R, t: &SimulatorEnv) -> Self { + // Loop until we get an implmeneted expression + loop { + let choice = rng.gen_range(0..25); + let expr = match choice { + 0 => Expr::Between { + lhs: Box::arbitrary_from(rng, t), + not: rng.gen_bool(0.5), + start: Box::arbitrary_from(rng, t), + end: Box::arbitrary_from(rng, t), + }, + 1 => Expr::Binary( + Box::arbitrary_from(rng, t), + Operator::arbitrary(rng), + Box::arbitrary_from(rng, t), + ), + 2 => Expr::Case { + base: Option::arbitrary_from(rng, t), + when_then_pairs: { + let size = rng.gen_range(0..5); + (0..size) + .into_iter() + .map(|_| (Self::arbitrary_from(rng, t), Self::arbitrary_from(rng, t))) + .collect() + }, + else_expr: Option::arbitrary_from(rng, t), + }, + 3 => Expr::Cast { + expr: Box::arbitrary_from(rng, t), + type_name: Option::arbitrary(rng), + }, + 4 => Expr::Collate(Box::arbitrary_from(rng, t), CollateName::arbitrary(rng).0), + // TODO: Skip Column as this is not generated by Parser Normally + 5 => continue, + // TODO: Skip DoublyQualified for now + 6 => continue, + // TODO: skip Exists for now + 7 => continue, + // TODO: skip Function Call for now + 8 => continue, + // TODO: skip Function Call Star for now + 9 => continue, + // TODO: skip ID for now + 10 => continue, + 11 => Expr::InList { + lhs: Box::arbitrary_from(rng, t), + not: rng.gen_bool(0.5), + rhs: Option::arbitrary_from(rng, t), + }, + // TODO: skip InSelect as still need to implement ArbitratyFrom for Select + 12 => continue, + // TODO: skip InTable + 13 => continue, + 14 => Expr::IsNull(Box::arbitrary_from(rng, t)), + 15 => { + let op = LikeOperator::arbitrary_from(rng, t); + let escape = if matches!(op, LikeOperator::Like) { + Option::arbitrary_from(rng, t) + } else { + None + }; + Expr::Like { + lhs: Box::arbitrary_from(rng, t), + not: rng.gen_bool(0.5), + op, + rhs: Box::arbitrary_from(rng, t), + escape, + } + } + 16 => Expr::Literal(ast::Literal::arbitrary_from(rng, t)), + // TODO: skip Name + 17 => continue, + 18 => Expr::NotNull(Box::arbitrary_from(rng, t)), + // TODO: only support one paranthesized expression + 19 => Expr::Parenthesized(vec![Expr::arbitrary_from(rng, t)]), + 20 => { + let table_idx = pick_index(t.tables.len(), rng); + let table = &t.tables[table_idx]; + let col_idx = pick_index(table.columns.len(), rng); + let col = &table.columns[col_idx]; + Expr::Qualified(Name(table.name.clone()), Name(col.name.clone())) + } + // TODO: skip Raise + 21 => continue, + // TODO: skip RowId not emitted by parser + 22 => continue, + // TODO: skip subquery + 23 => continue, + 24 => Expr::Unary( + UnaryOperator::arbitrary_from(rng, t), + Box::arbitrary_from(rng, t), + ), + // TODO: skip Variable as it does not make much sense for the simulator + 25 => continue, + _ => unreachable!(), + }; + break expr; + } + } +} + +impl Arbitrary for Operator { + fn arbitrary(rng: &mut R) -> Self { + let choice = rng.gen_range(0..23); + match choice { + 0 => Operator::Add, + 1 => Operator::And, + 2 => Operator::ArrowRight, + 3 => Operator::ArrowRightShift, + 4 => Operator::BitwiseAnd, + 5 => Operator::BitwiseNot, + 6 => Operator::BitwiseOr, + 7 => Operator::Concat, + 8 => Operator::Divide, + 9 => Operator::Equals, + 10 => Operator::Greater, + 11 => Operator::GreaterEquals, + 12 => Operator::Is, + 13 => Operator::IsNot, + 14 => Operator::LeftShift, + 15 => Operator::Less, + 16 => Operator::LessEquals, + 17 => Operator::Modulus, + 18 => Operator::Multiply, + 19 => Operator::NotEquals, + 20 => Operator::Or, + 21 => Operator::RightShift, + 22 => Operator::Subtract, + _ => unreachable!(), + } + } +} + +impl Arbitrary for Type { + fn arbitrary(rng: &mut R) -> Self { + let name = pick(&["INT", "INTEGER", "REAL", "TEXT", "BLOB", "ANY"], rng).to_string(); + Self { + name, + size: None, // TODO: come back later here + } + } +} + +struct CollateName(String); + +impl Arbitrary for CollateName { + fn arbitrary(rng: &mut R) -> Self { + let choice = rng.gen_range(0..3); + CollateName( + match choice { + 0 => "BINARY", + 1 => "RTRIM", + 2 => "NOCASE", + _ => unreachable!(), + } + .to_string(), + ) + } +} + +impl ArbitraryFrom<&SimulatorEnv> for QualifiedName { + fn arbitrary_from(rng: &mut R, t: &SimulatorEnv) -> Self { + // TODO: for now just generate table name + let table_idx = pick_index(t.tables.len(), rng); + let table = &t.tables[table_idx]; + // TODO: for now forego alias + Self::single(Name(table.name.clone())) + } +} + +impl ArbitraryFrom<&SimulatorEnv> for LikeOperator { + fn arbitrary_from(rng: &mut R, _t: &SimulatorEnv) -> Self { + let choice = rng.gen_range(0..4); + match choice { + 0 => LikeOperator::Glob, + 1 => LikeOperator::Like, + 2 => LikeOperator::Match, + 3 => LikeOperator::Regexp, + _ => unreachable!(), + } + } +} + +// Current implementation does not take into account the columns affinity nor if table is Strict +impl ArbitraryFrom<&SimulatorEnv> for ast::Literal { + fn arbitrary_from(rng: &mut R, _t: &SimulatorEnv) -> Self { + loop { + let choice = rng.gen_range(0..8); + let lit = match choice { + 0 => ast::Literal::Numeric({ + let integer = rng.gen_bool(0.5); + if integer { + rng.gen_range(i64::MIN..i64::MAX).to_string() + } else { + rng.gen_range(-1e10..1e10).to_string() + } + }), + 1 => ast::Literal::String(gen_random_text(rng)), + 2 => ast::Literal::Blob(hex::encode(gen_random_text(rng).as_bytes().to_vec())), + // TODO: skip Keyword + 3 => continue, + 4 => ast::Literal::Null, + // TODO: Ignore CurrentDate stuff for now + _ => continue, + }; + break lit; + } + } +} + +impl ArbitraryFrom<&SimulatorEnv> for UnaryOperator { + fn arbitrary_from(rng: &mut R, _t: &SimulatorEnv) -> Self { + let choice = rng.gen_range(0..4); + match choice { + 0 => Self::BitwiseNot, + 1 => Self::Negative, + 2 => Self::Not, + 3 => Self::Positive, + _ => unreachable!(), + } + } +} diff --git a/simulator/generation/mod.rs b/simulator/generation/mod.rs index ac1f97f60..0fea1b704 100644 --- a/simulator/generation/mod.rs +++ b/simulator/generation/mod.rs @@ -3,6 +3,7 @@ use std::{iter::Sum, ops::SubAssign}; use anarchist_readable_name_generator_lib::readable_name_custom; use rand::{distributions::uniform::SampleUniform, Rng}; +mod expr; pub mod plan; pub mod property; pub mod query; From f535ff1398c313c2728644f542faa05ae867d59b Mon Sep 17 00:00:00 2001 From: pedrocarlo Date: Mon, 2 Jun 2025 16:20:48 -0300 Subject: [PATCH 03/29] add optional serde implementations for parser ast --- Cargo.lock | 4 + simulator/Cargo.toml | 2 +- simulator/model/query/expr.rs | 5 ++ simulator/model/query/mod.rs | 1 + vendored/sqlite3-parser/Cargo.toml | 1 + vendored/sqlite3-parser/src/parser/ast/mod.rs | 80 +++++++++++++++++++ 6 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 simulator/model/query/expr.rs diff --git a/Cargo.lock b/Cargo.lock index 95b643eb7..cd3ade11e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -240,6 +240,9 @@ name = "bitflags" version = "2.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5c8214115b7bf84099f1309324e63141d4c5d7cc26862f97a0a857dbefe165bd" +dependencies = [ + "serde", +] [[package]] name = "blake3" @@ -1428,6 +1431,7 @@ checksum = "3954d50fe15b02142bf25d3b8bdadb634ec3948f103d04ffe3031bc8fe9d7058" dependencies = [ "equivalent", "hashbrown 0.15.2", + "serde", ] [[package]] diff --git a/simulator/Cargo.toml b/simulator/Cargo.toml index 0c7a76e45..01d45f633 100644 --- a/simulator/Cargo.toml +++ b/simulator/Cargo.toml @@ -35,5 +35,5 @@ chrono = { version = "0.4.40", features = ["serde"] } tracing = "0.1.41" tracing-subscriber = { version = "0.3.19", features = ["env-filter"] } anyhow.workspace = true -limbo_sqlite3_parser = { workspace = true } +limbo_sqlite3_parser = { workspace = true, features = ["serde"]} hex = "0.4.3" diff --git a/simulator/model/query/expr.rs b/simulator/model/query/expr.rs new file mode 100644 index 000000000..7a5e0f89b --- /dev/null +++ b/simulator/model/query/expr.rs @@ -0,0 +1,5 @@ +use limbo_sqlite3_parser::ast; +use serde::{Deserialize, Serialize}; + +#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] +struct Predicate(ast::Expr); diff --git a/simulator/model/query/mod.rs b/simulator/model/query/mod.rs index ed947ca9b..a10f97d3b 100644 --- a/simulator/model/query/mod.rs +++ b/simulator/model/query/mod.rs @@ -15,6 +15,7 @@ pub mod create; pub mod create_index; pub mod delete; pub mod drop; +pub mod expr; pub mod insert; pub mod select; pub mod update; diff --git a/vendored/sqlite3-parser/Cargo.toml b/vendored/sqlite3-parser/Cargo.toml index f432c345b..43ba78283 100644 --- a/vendored/sqlite3-parser/Cargo.toml +++ b/vendored/sqlite3-parser/Cargo.toml @@ -22,6 +22,7 @@ YYNOERRORRECOVERY = [] YYCOVERAGE = [] NDEBUG = [] default = ["YYNOERRORRECOVERY", "NDEBUG"] +serde = ["dep:serde", "indexmap/serde", "bitflags/serde"] [dependencies] phf = { version = "0.11", features = ["uncased"] } diff --git a/vendored/sqlite3-parser/src/parser/ast/mod.rs b/vendored/sqlite3-parser/src/parser/ast/mod.rs index 6d92c07ba..e213ccdfd 100644 --- a/vendored/sqlite3-parser/src/parser/ast/mod.rs +++ b/vendored/sqlite3-parser/src/parser/ast/mod.rs @@ -69,6 +69,7 @@ pub(crate) enum ExplainKind { /// SQL statement // https://sqlite.org/syntax/sql-stmt.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Stmt { /// `ALTER TABLE`: table name, body AlterTable(Box<(QualifiedName, AlterTableBody)>), @@ -193,6 +194,7 @@ pub enum Stmt { /// `CREATE VIRTUAL TABLE` #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct CreateVirtualTable { /// `IF NOT EXISTS` pub if_not_exists: bool, @@ -206,6 +208,7 @@ pub struct CreateVirtualTable { /// `CREATE TRIGGER #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct CreateTrigger { /// `TEMPORARY` pub temporary: bool, @@ -229,6 +232,7 @@ pub struct CreateTrigger { /// `INSERT` #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Insert { /// CTE pub with: Option, @@ -246,6 +250,7 @@ pub struct Insert { /// `UPDATE` clause #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Update { /// CTE pub with: Option, @@ -271,6 +276,7 @@ pub struct Update { /// `DELETE` #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Delete { /// CTE pub with: Option, @@ -290,6 +296,7 @@ pub struct Delete { #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] /// Internal ID of a table reference. /// /// Used by [Expr::Column] and [Expr::RowId] to refer to a table. @@ -332,6 +339,7 @@ impl std::fmt::Display for TableInternalId { /// SQL expression // https://sqlite.org/syntax/expr.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Expr { /// `BETWEEN` Between { @@ -570,6 +578,7 @@ impl Expr { /// SQL literal #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Literal { /// Number Numeric(String), @@ -608,6 +617,7 @@ impl Literal { /// Textual comparison operator in an expression #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum LikeOperator { /// `GLOB` Glob, @@ -640,6 +650,7 @@ impl LikeOperator { /// SQL operators #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Operator { /// `+` Add, @@ -750,6 +761,7 @@ impl Operator { /// Unary operators #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum UnaryOperator { /// bitwise negation (`~`) BitwiseNot, @@ -777,6 +789,7 @@ impl From for UnaryOperator { // https://sqlite.org/lang_select.html // https://sqlite.org/syntax/factored-select-stmt.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Select { /// CTE pub with: Option, @@ -790,6 +803,7 @@ pub struct Select { /// `SELECT` body #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SelectBody { /// first select pub select: Box, @@ -821,6 +835,7 @@ impl SelectBody { /// Compound select #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct CompoundSelect { /// operator pub operator: CompoundOperator, @@ -831,6 +846,7 @@ pub struct CompoundSelect { /// Compound operators // https://sqlite.org/syntax/compound-operator.html #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum CompoundOperator { /// `UNION` Union, @@ -845,6 +861,7 @@ pub enum CompoundOperator { /// `SELECT` core // https://sqlite.org/syntax/select-core.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum OneSelect { /// `SELECT` Select(Box), @@ -853,6 +870,7 @@ pub enum OneSelect { } #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] /// `SELECT` core pub struct SelectInner { /// `DISTINCT` @@ -872,6 +890,7 @@ pub struct SelectInner { /// `SELECT` ... `FROM` clause // https://sqlite.org/syntax/join-clause.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct FromClause { /// table pub select: Option>, // FIXME mandatory @@ -928,6 +947,7 @@ impl FromClause { /// `SELECT` distinctness #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Distinctness { /// `DISTINCT` Distinct, @@ -938,6 +958,7 @@ pub enum Distinctness { /// `SELECT` or `RETURNING` result column // https://sqlite.org/syntax/result-column.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum ResultColumn { /// expression Expr(Expr, Option), @@ -949,6 +970,7 @@ pub enum ResultColumn { /// Alias #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum As { /// `AS` As(Name), @@ -959,6 +981,7 @@ pub enum As { /// `JOIN` clause // https://sqlite.org/syntax/join-clause.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct JoinedSelectTable { /// operator pub operator: JoinOperator, @@ -971,6 +994,7 @@ pub struct JoinedSelectTable { /// Table or subquery // https://sqlite.org/syntax/table-or-subquery.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum SelectTable { /// table Table(QualifiedName, Option, Option), @@ -985,6 +1009,7 @@ pub enum SelectTable { /// Join operators // https://sqlite.org/syntax/join-operator.html #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum JoinOperator { /// `,` Comma, @@ -1028,6 +1053,7 @@ impl JoinOperator { bitflags::bitflags! { /// `JOIN` types #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct JoinType: u8 { /// `INNER` const INNER = 0x01; @@ -1072,6 +1098,8 @@ impl TryFrom<&[u8]> for JoinType { /// `JOIN` constraint #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] + pub enum JoinConstraint { /// `ON` On(Expr), @@ -1081,6 +1109,7 @@ pub enum JoinConstraint { /// `GROUP BY` #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct GroupBy { /// expressions pub exprs: Vec, @@ -1090,6 +1119,7 @@ pub struct GroupBy { /// identifier or one of several keywords or `INDEXED` #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Id(pub String); impl Id { @@ -1103,6 +1133,7 @@ impl Id { /// identifier or string or `CROSS` or `FULL` or `INNER` or `LEFT` or `NATURAL` or `OUTER` or `RIGHT`. #[derive(Clone, Debug, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Name(pub String); // TODO distinction between Name and "Name"/[Name]/`Name` impl Name { @@ -1199,6 +1230,7 @@ impl PartialEq<&str> for Name { /// Qualified name #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct QualifiedName { /// schema pub db_name: Option, @@ -1245,6 +1277,7 @@ impl QualifiedName { /// Ordered set of distinct column names #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct DistinctNames(IndexSet); impl DistinctNames { @@ -1280,6 +1313,7 @@ impl Deref for DistinctNames { /// `ALTER TABLE` body // https://sqlite.org/lang_altertable.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum AlterTableBody { /// `RENAME TO`: new table name RenameTo(Name), @@ -1300,6 +1334,7 @@ pub enum AlterTableBody { // https://sqlite.org/lang_createtable.html // https://sqlite.org/syntax/create-table-stmt.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum CreateTableBody { /// columns and constraints ColumnsAndConstraints { @@ -1332,6 +1367,7 @@ impl CreateTableBody { /// Table column definition // https://sqlite.org/syntax/column-def.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ColumnDefinition { /// column name pub col_name: Name, @@ -1403,6 +1439,7 @@ impl ColumnDefinition { /// Named column constraint // https://sqlite.org/syntax/column-constraint.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct NamedColumnConstraint { /// constraint name pub name: Option, @@ -1413,6 +1450,7 @@ pub struct NamedColumnConstraint { /// Column constraint // https://sqlite.org/syntax/column-constraint.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum ColumnConstraint { /// `PRIMARY KEY` PrimaryKey { @@ -1462,6 +1500,7 @@ pub enum ColumnConstraint { /// Named table constraint // https://sqlite.org/syntax/table-constraint.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct NamedTableConstraint { /// constraint name pub name: Option, @@ -1472,6 +1511,7 @@ pub struct NamedTableConstraint { /// Table constraint // https://sqlite.org/syntax/table-constraint.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum TableConstraint { /// `PRIMARY KEY` PrimaryKey { @@ -1505,6 +1545,7 @@ pub enum TableConstraint { bitflags::bitflags! { /// `CREATE TABLE` options #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] + #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct TableOptions: u8 { /// None const NONE = 0; @@ -1517,6 +1558,7 @@ bitflags::bitflags! { /// Sort orders #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum SortOrder { /// `ASC` Asc, @@ -1526,6 +1568,7 @@ pub enum SortOrder { /// `NULLS FIRST` or `NULLS LAST` #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum NullsOrder { /// `NULLS FIRST` First, @@ -1536,6 +1579,7 @@ pub enum NullsOrder { /// `REFERENCES` clause // https://sqlite.org/syntax/foreign-key-clause.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct ForeignKeyClause { /// foreign table name pub tbl_name: Name, @@ -1547,6 +1591,7 @@ pub struct ForeignKeyClause { /// foreign-key reference args #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum RefArg { /// `ON DELETE` OnDelete(RefAct), @@ -1560,6 +1605,7 @@ pub enum RefArg { /// foreign-key reference actions #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum RefAct { /// `SET NULL` SetNull, @@ -1575,6 +1621,7 @@ pub enum RefAct { /// foreign-key defer clause #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct DeferSubclause { /// `DEFERRABLE` pub deferrable: bool, @@ -1584,6 +1631,7 @@ pub struct DeferSubclause { /// `INITIALLY` `DEFERRED` / `IMMEDIATE` #[derive(Copy, Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum InitDeferredPred { /// `INITIALLY DEFERRED` InitiallyDeferred, @@ -1594,6 +1642,7 @@ pub enum InitDeferredPred { /// Indexed column // https://sqlite.org/syntax/indexed-column.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct IndexedColumn { /// column name pub col_name: Name, @@ -1605,6 +1654,7 @@ pub struct IndexedColumn { /// `INDEXED BY` / `NOT INDEXED` #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum Indexed { /// `INDEXED BY`: idx name IndexedBy(Name), @@ -1614,6 +1664,7 @@ pub enum Indexed { /// Sorted column #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct SortedColumn { /// expression pub expr: Expr, @@ -1625,6 +1676,7 @@ pub struct SortedColumn { /// `LIMIT` #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub struct Limit { /// count pub expr: Expr, @@ -1636,6 +1688,7 @@ pub struct Limit { // https://sqlite.org/lang_insert.html // https://sqlite.org/syntax/insert-stmt.html #[derive(Clone, Debug, PartialEq, Eq)] +#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))] pub enum InsertBody { /// `SELECT` or `VALUES` Select(Box