mirror of
https://github.com/aljazceru/turso.git
synced 2026-02-02 06:44:23 +01:00
change gen.range based queries into frequency and one_of calls
This commit is contained in:
@@ -30,7 +30,7 @@ pub(crate) fn frequency<'a, T, R: rand::Rng>(
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
pub(crate) fn one_of<T, R: rand::Rng>(choices: Vec<Box<dyn Fn(&mut R) -> T>>, rng: &mut R) -> T {
|
||||
pub(crate) fn one_of<'a, T, R: rand::Rng>(choices: Vec<Box<dyn Fn(&mut R) -> T + 'a>>, rng: &mut R) -> T {
|
||||
let index = rng.gen_range(0..choices.len());
|
||||
choices[index](rng)
|
||||
}
|
||||
|
||||
@@ -1,10 +1,12 @@
|
||||
use crate::generation::table::{GTValue, LTValue};
|
||||
use crate::generation::{Arbitrary, ArbitraryFrom};
|
||||
use crate::generation::{one_of, Arbitrary, ArbitraryFrom};
|
||||
|
||||
use crate::model::query::{Create, Delete, Insert, Predicate, Query, Select};
|
||||
use crate::model::table::{Table, Value};
|
||||
use rand::Rng;
|
||||
|
||||
use super::{frequency, pick};
|
||||
|
||||
impl Arbitrary for Create {
|
||||
fn arbitrary<R: Rng>(rng: &mut R) -> Self {
|
||||
Create {
|
||||
@@ -15,20 +17,20 @@ impl Arbitrary for Create {
|
||||
|
||||
impl ArbitraryFrom<Vec<Table>> for Select {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, tables: &Vec<Table>) -> Self {
|
||||
let table = rng.gen_range(0..tables.len());
|
||||
let table = pick(tables, rng);
|
||||
Select {
|
||||
table: tables[table].name.clone(),
|
||||
predicate: Predicate::arbitrary_from(rng, &tables[table]),
|
||||
table: table.name.clone(),
|
||||
predicate: Predicate::arbitrary_from(rng, table),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ArbitraryFrom<Vec<&Table>> for Select {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, tables: &Vec<&Table>) -> Self {
|
||||
let table = rng.gen_range(0..tables.len());
|
||||
let table = pick(tables, rng);
|
||||
Select {
|
||||
table: tables[table].name.clone(),
|
||||
predicate: Predicate::arbitrary_from(rng, tables[table]),
|
||||
table: table.name.clone(),
|
||||
predicate: Predicate::arbitrary_from(rng, *table),
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -58,15 +60,24 @@ impl ArbitraryFrom<Table> for Delete {
|
||||
|
||||
impl ArbitraryFrom<Table> for Query {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, table: &Table) -> Self {
|
||||
match rng.gen_range(0..=200) {
|
||||
0 => Query::Create(Create::arbitrary(rng)),
|
||||
1..=100 => Query::Select(Select::arbitrary_from(rng, &vec![table])),
|
||||
101..=200 => Query::Insert(Insert::arbitrary_from(rng, table)),
|
||||
// todo: This branch is currently never taken, as DELETE is not yet implemented.
|
||||
// Change this when DELETE is implemented.
|
||||
201..=300 => Query::Delete(Delete::arbitrary_from(rng, table)),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
frequency(
|
||||
vec![
|
||||
(1, Box::new(|rng| Query::Create(Create::arbitrary(rng)))),
|
||||
(
|
||||
100,
|
||||
Box::new(|rng| Query::Select(Select::arbitrary_from(rng, &vec![table]))),
|
||||
),
|
||||
(
|
||||
100,
|
||||
Box::new(|rng| Query::Insert(Insert::arbitrary_from(rng, table))),
|
||||
),
|
||||
(
|
||||
0,
|
||||
Box::new(|rng| Query::Delete(Delete::arbitrary_from(rng, table))),
|
||||
),
|
||||
],
|
||||
rng,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,35 +95,53 @@ impl ArbitraryFrom<(&Table, bool)> for SimplePredicate {
|
||||
.map(|r| &r[column_index])
|
||||
.collect::<Vec<_>>();
|
||||
// Pick an operator
|
||||
let operator = match rng.gen_range(0..3) {
|
||||
0 => {
|
||||
if *predicate_value {
|
||||
Predicate::Eq(
|
||||
column.name.clone(),
|
||||
Value::arbitrary_from(rng, &column_values),
|
||||
)
|
||||
} else {
|
||||
Predicate::Eq(
|
||||
column.name.clone(),
|
||||
Value::arbitrary_from(rng, &column.column_type),
|
||||
)
|
||||
}
|
||||
}
|
||||
1 => Predicate::Gt(
|
||||
column.name.clone(),
|
||||
match predicate_value {
|
||||
true => GTValue::arbitrary_from(rng, &column_values).0,
|
||||
false => LTValue::arbitrary_from(rng, &column_values).0,
|
||||
},
|
||||
let operator = match predicate_value {
|
||||
true => one_of(
|
||||
vec![
|
||||
Box::new(|rng| {
|
||||
Predicate::Eq(
|
||||
column.name.clone(),
|
||||
Value::arbitrary_from(rng, &column_values),
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
Predicate::Gt(
|
||||
column.name.clone(),
|
||||
GTValue::arbitrary_from(rng, &column_values).0,
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
Predicate::Lt(
|
||||
column.name.clone(),
|
||||
LTValue::arbitrary_from(rng, &column_values).0,
|
||||
)
|
||||
}),
|
||||
],
|
||||
rng,
|
||||
),
|
||||
2 => Predicate::Lt(
|
||||
column.name.clone(),
|
||||
match predicate_value {
|
||||
true => LTValue::arbitrary_from(rng, &column_values).0,
|
||||
false => GTValue::arbitrary_from(rng, &column_values).0,
|
||||
},
|
||||
false => one_of(
|
||||
vec![
|
||||
Box::new(|rng| {
|
||||
Predicate::Neq(
|
||||
column.name.clone(),
|
||||
Value::arbitrary_from(rng, &column.column_type),
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
Predicate::Gt(
|
||||
column.name.clone(),
|
||||
LTValue::arbitrary_from(rng, &column_values).0,
|
||||
)
|
||||
}),
|
||||
Box::new(|rng| {
|
||||
Predicate::Lt(
|
||||
column.name.clone(),
|
||||
GTValue::arbitrary_from(rng, &column_values).0,
|
||||
)
|
||||
}),
|
||||
],
|
||||
rng,
|
||||
),
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
SimplePredicate(operator)
|
||||
@@ -191,17 +220,10 @@ impl ArbitraryFrom<Table> for Predicate {
|
||||
|
||||
impl ArbitraryFrom<(&str, &Value)> for Predicate {
|
||||
fn arbitrary_from<R: Rng>(rng: &mut R, (column_name, value): &(&str, &Value)) -> Self {
|
||||
match rng.gen_range(0..3) {
|
||||
0 => Predicate::Eq(column_name.to_string(), (*value).clone()),
|
||||
1 => Predicate::Gt(
|
||||
column_name.to_string(),
|
||||
LTValue::arbitrary_from(rng, *value).0,
|
||||
),
|
||||
2 => Predicate::Lt(
|
||||
column_name.to_string(),
|
||||
LTValue::arbitrary_from(rng, *value).0,
|
||||
),
|
||||
_ => unreachable!(),
|
||||
}
|
||||
one_of(vec![
|
||||
Box::new(|rng| Predicate::Eq(column_name.to_string(), (*value).clone())),
|
||||
Box::new(|rng| Predicate::Gt(column_name.to_string(), GTValue::arbitrary_from(rng, *value).0)),
|
||||
Box::new(|rng| Predicate::Lt(column_name.to_string(), LTValue::arbitrary_from(rng, *value).0)),
|
||||
], rng)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use rand::Rng;
|
||||
|
||||
use crate::generation::{gen_random_text, readable_name_custom, Arbitrary, ArbitraryFrom};
|
||||
use crate::generation::{pick_index, gen_random_text, pick, readable_name_custom, Arbitrary, ArbitraryFrom};
|
||||
use crate::model::table::{Column, ColumnType, Name, Table, Value};
|
||||
|
||||
impl Arbitrary for Name {
|
||||
@@ -13,7 +13,7 @@ impl Arbitrary for Name {
|
||||
impl Arbitrary for Table {
|
||||
fn arbitrary<R: Rng>(rng: &mut R) -> Self {
|
||||
let name = Name::arbitrary(rng).0;
|
||||
let columns = (1..=rng.gen_range(1..10))
|
||||
let columns = (1..=rng.gen_range(1..5))
|
||||
.map(|_| Column::arbitrary(rng))
|
||||
.collect();
|
||||
Table {
|
||||
@@ -39,13 +39,16 @@ impl Arbitrary for Column {
|
||||
|
||||
impl Arbitrary for ColumnType {
|
||||
fn arbitrary<R: Rng>(rng: &mut R) -> Self {
|
||||
match rng.gen_range(0..4) {
|
||||
0 => ColumnType::Integer,
|
||||
1 => ColumnType::Float,
|
||||
2 => ColumnType::Text,
|
||||
3 => ColumnType::Blob,
|
||||
_ => unreachable!(),
|
||||
}
|
||||
pick(
|
||||
&vec![
|
||||
ColumnType::Integer,
|
||||
ColumnType::Float,
|
||||
ColumnType::Text,
|
||||
ColumnType::Blob,
|
||||
],
|
||||
rng,
|
||||
)
|
||||
.to_owned()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -55,8 +58,7 @@ impl ArbitraryFrom<Vec<&Value>> for Value {
|
||||
return Value::Null;
|
||||
}
|
||||
|
||||
let index = rng.gen_range(0..values.len());
|
||||
values[index].clone()
|
||||
pick(values, rng).to_owned().clone()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,8 +80,8 @@ impl ArbitraryFrom<Vec<&Value>> for LTValue {
|
||||
if values.is_empty() {
|
||||
return LTValue(Value::Null);
|
||||
}
|
||||
|
||||
let index = rng.gen_range(0..values.len());
|
||||
|
||||
let index = pick_index(values.len(), rng);
|
||||
LTValue::arbitrary_from(rng, values[index])
|
||||
}
|
||||
}
|
||||
@@ -139,7 +141,7 @@ impl ArbitraryFrom<Vec<&Value>> for GTValue {
|
||||
return GTValue(Value::Null);
|
||||
}
|
||||
|
||||
let index = rng.gen_range(0..values.len());
|
||||
let index = pick_index(values.len(), rng);
|
||||
GTValue::arbitrary_from(rng, values[index])
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use generation::plan::{Interaction, ResultSet};
|
||||
use generation::{pick, pick_index, Arbitrary, ArbitraryFrom};
|
||||
use limbo_core::{Connection, Database, File, OpenFlags, PlatformIO, Result, RowResult, IO};
|
||||
use model::query::{Insert, Predicate, Query, Select};
|
||||
use model::query::{Create, Insert, Predicate, Query, Select};
|
||||
use model::table::{Column, Name, Table, Value};
|
||||
use properties::{property_insert_select, property_select_all};
|
||||
use rand::prelude::*;
|
||||
@@ -189,7 +189,12 @@ fn maybe_add_table(env: &mut SimulatorEnv, conn: &mut Rc<Connection>) -> Result<
|
||||
.map(|_| Column::arbitrary(&mut env.rng))
|
||||
.collect(),
|
||||
};
|
||||
let rows = get_all_rows(env, conn, table.to_create_str().as_str())?;
|
||||
let query = Query::Create(Create { table: table.clone() });
|
||||
let rows = get_all_rows(
|
||||
env,
|
||||
conn,
|
||||
query.to_string().as_str(),
|
||||
)?;
|
||||
log::debug!("{:?}", rows);
|
||||
let rows = get_all_rows(
|
||||
env,
|
||||
@@ -207,7 +212,7 @@ fn maybe_add_table(env: &mut SimulatorEnv, conn: &mut Rc<Connection>) -> Result<
|
||||
_ => unreachable!(),
|
||||
};
|
||||
assert!(
|
||||
*as_text != table.to_create_str(),
|
||||
*as_text != query.to_string(),
|
||||
"table was not inserted correctly"
|
||||
);
|
||||
env.tables.push(table);
|
||||
|
||||
@@ -7,6 +7,7 @@ pub(crate) enum Predicate {
|
||||
And(Vec<Predicate>), // p1 AND p2 AND p3... AND pn
|
||||
Or(Vec<Predicate>), // p1 OR p2 OR p3... OR pn
|
||||
Eq(String, Value), // column = Value
|
||||
Neq(String, Value), // column != Value
|
||||
Gt(String, Value), // column > Value
|
||||
Lt(String, Value), // column < Value
|
||||
}
|
||||
@@ -44,6 +45,7 @@ impl Display for Predicate {
|
||||
}
|
||||
}
|
||||
Predicate::Eq(name, value) => write!(f, "{} = {}", name, value),
|
||||
Predicate::Neq(name, value) => write!(f, "{} != {}", name, value),
|
||||
Predicate::Gt(name, value) => write!(f, "{} > {}", name, value),
|
||||
Predicate::Lt(name, value) => write!(f, "{} < {}", name, value),
|
||||
}
|
||||
@@ -85,7 +87,18 @@ pub(crate) struct Delete {
|
||||
impl Display for Query {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Query::Create(Create { table }) => write!(f, "{}", table.to_create_str()),
|
||||
Query::Create(Create { table }) => {
|
||||
write!(f, "CREATE TABLE {} (", table.name)?;
|
||||
|
||||
for (i, column) in table.columns.iter().enumerate() {
|
||||
if i != 0 {
|
||||
write!(f, ",")?;
|
||||
}
|
||||
write!(f, "{} {}", column.name, column.column_type)?;
|
||||
}
|
||||
|
||||
write!(f, ")")
|
||||
},
|
||||
Query::Select(Select {
|
||||
table,
|
||||
predicate: guard,
|
||||
|
||||
@@ -17,24 +17,6 @@ pub(crate) struct Table {
|
||||
pub(crate) columns: Vec<Column>,
|
||||
}
|
||||
|
||||
impl Table {
|
||||
pub fn to_create_str(&self) -> String {
|
||||
let mut out = String::new();
|
||||
|
||||
out.push_str(format!("CREATE TABLE {} (", self.name).as_str());
|
||||
|
||||
assert!(!self.columns.is_empty());
|
||||
for column in &self.columns {
|
||||
out.push_str(format!("{} {},", column.name, column.column_type.as_str()).as_str());
|
||||
}
|
||||
// remove last comma
|
||||
out.pop();
|
||||
|
||||
out.push_str(");");
|
||||
out
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub(crate) struct Column {
|
||||
pub(crate) name: String,
|
||||
@@ -51,13 +33,13 @@ pub(crate) enum ColumnType {
|
||||
Blob,
|
||||
}
|
||||
|
||||
impl ColumnType {
|
||||
pub fn as_str(&self) -> &str {
|
||||
impl Display for ColumnType {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
ColumnType::Integer => "INTEGER",
|
||||
ColumnType::Float => "FLOAT",
|
||||
ColumnType::Text => "TEXT",
|
||||
ColumnType::Blob => "BLOB",
|
||||
ColumnType::Integer => write!(f, "INTEGER"),
|
||||
ColumnType::Float => write!(f, "REAL"),
|
||||
ColumnType::Text => write!(f, "TEXT"),
|
||||
ColumnType::Blob => write!(f, "BLOB"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user