Skip to content

Commit c3ea027

Browse files
committed
- add doc comments to generation traits and functions
- remove pick_index from places where it's possible to use pick instead - allow multiple values to be inserted in the insert-select property
1 parent 43f6c34 commit c3ea027

File tree

3 files changed

+60
-31
lines changed

3 files changed

+60
-31
lines changed

simulator/generation/mod.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,30 @@ pub mod property;
88
pub mod query;
99
pub mod table;
1010

11+
/// Arbitrary trait for generating random values
12+
/// An implementation of arbitrary is assumed to be a uniform sampling of
13+
/// the possible values of the type, with a bias towards smaller values for
14+
/// practicality.
1115
pub trait Arbitrary {
1216
fn arbitrary<R: Rng>(rng: &mut R) -> Self;
1317
}
1418

19+
/// ArbitraryFrom trait for generating random values from a given value
20+
/// ArbitraryFrom allows for constructing relations, where the generated
21+
/// value is dependent on the given value. These relations could be constraints
22+
/// such as generating an integer within an interval, or a value that fits in a table,
23+
/// or a predicate satisfying a given table row.
1524
pub trait ArbitraryFrom<T> {
1625
fn arbitrary_from<R: Rng>(rng: &mut R, t: T) -> Self;
1726
}
1827

28+
/// Frequency is a helper function for composing different generators with different frequency
29+
/// of occurences.
30+
/// The type signature for the `N` parameter is a bit complex, but it
31+
/// roughly corresponds to a type that can be summed, compared, subtracted and sampled, which are
32+
/// the operations we require for the implementation.
33+
// todo: switch to a simpler type signature that can accomodate all integer and float types, which
34+
// should be enough for our purposes.
1935
pub(crate) fn frequency<
2036
'a,
2137
T,
@@ -38,6 +54,7 @@ pub(crate) fn frequency<
3854
unreachable!()
3955
}
4056

57+
/// one_of is a helper function for composing different generators with equal probability of occurence.
4158
pub(crate) fn one_of<'a, T, R: rand::Rng>(
4259
choices: Vec<Box<dyn Fn(&mut R) -> T + 'a>>,
4360
rng: &mut R,
@@ -46,15 +63,20 @@ pub(crate) fn one_of<'a, T, R: rand::Rng>(
4663
choices[index](rng)
4764
}
4865

66+
/// pick is a helper function for uniformly picking a random element from a slice
4967
pub(crate) fn pick<'a, T, R: rand::Rng>(choices: &'a [T], rng: &mut R) -> &'a T {
5068
let index = rng.gen_range(0..choices.len());
5169
&choices[index]
5270
}
5371

72+
/// pick_index is typically used for picking an index from a slice to later refer to the element
73+
/// at that index.
5474
pub(crate) fn pick_index<R: rand::Rng>(choices: usize, rng: &mut R) -> usize {
5575
rng.gen_range(0..choices)
5676
}
5777

78+
/// gen_random_text uses `anarchist_readable_name_generator_lib` to generate random
79+
/// readable names for tables, columns, text values etc.
5880
fn gen_random_text<T: Rng>(rng: &mut T) -> String {
5981
let big_text = rng.gen_ratio(1, 1000);
6082
if big_text {

simulator/generation/property.rs

Lines changed: 22 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ use crate::{
77
};
88

99
use super::{
10-
frequency, pick, pick_index,
10+
frequency, pick,
1111
plan::{Assertion, Interaction, InteractionStats, ResultSet},
1212
ArbitraryFrom,
1313
};
@@ -66,20 +66,26 @@ impl Property {
6666
Property::DoubleCreateFailure { .. } => "Double-Create-Failure".to_string(),
6767
}
6868
}
69+
/// interactions construct a list of interactions, which is an executable representation of the property.
70+
/// the requirement of property -> vec<interaction> conversion emerges from the need to serialize the property,
71+
/// and `interaction` cannot be serialized directly.
6972
pub(crate) fn interactions(&self) -> Vec<Interaction> {
7073
match self {
7174
Property::InsertSelect {
7275
insert,
7376
queries,
7477
select,
7578
} => {
76-
// Check that the row is there
77-
let row = insert
78-
.values
79-
.first() // `.first` is safe, because we know we are inserting a row in the insert select property
80-
.expect("insert query should have at least 1 value")
81-
.clone();
79+
// Check that the insert query has at least 1 value
80+
assert!(
81+
!insert.values.is_empty(),
82+
"insert query should have at least 1 value"
83+
);
8284

85+
// Pick a random row within the insert values
86+
let row = pick(&insert.values, &mut rand::thread_rng()).clone();
87+
88+
// Assume that the table exists
8389
let assumption = Interaction::Assumption(Assertion {
8490
message: format!("table {} exists", insert.table),
8591
func: Box::new({
@@ -190,26 +196,18 @@ fn property_insert_select<R: rand::Rng>(
190196
) -> Property {
191197
// Get a random table
192198
let table = pick(&env.tables, rng);
193-
// Pick a random column
194-
let column_index = pick_index(table.columns.len(), rng);
195-
let column = &table.columns[column_index].clone();
196-
// Generate a random value of the column type
197-
let value = Value::arbitrary_from(rng, &column.column_type);
198-
// Create a whole new row
199-
let mut row = Vec::new();
200-
for (i, column) in table.columns.iter().enumerate() {
201-
if i == column_index {
202-
row.push(value.clone());
203-
} else {
204-
let value = Value::arbitrary_from(rng, &column.column_type);
205-
row.push(value);
206-
}
207-
}
199+
// Generate rows to insert
200+
let rows = (0..rng.gen_range(1..=5))
201+
.map(|_| Vec::<Value>::arbitrary_from(rng, table))
202+
.collect::<Vec<_>>();
203+
204+
// Pick a random row to select
205+
let row = pick(&rows, rng).clone();
208206

209-
// Insert the row
207+
// Insert the rows
210208
let insert_query = Insert {
211209
table: table.name.clone(),
212-
values: vec![row.clone()],
210+
values: rows,
213211
};
214212

215213
// Create random queries respecting the constraints

simulator/generation/table.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
use rand::Rng;
22

3-
use crate::generation::{
4-
gen_random_text, pick, pick_index, readable_name_custom, Arbitrary, ArbitraryFrom,
5-
};
3+
use crate::generation::{gen_random_text, pick, readable_name_custom, Arbitrary, ArbitraryFrom};
64
use crate::model::table::{Column, ColumnType, Name, Table, Value};
75

86
impl Arbitrary for Name {
@@ -45,6 +43,17 @@ impl Arbitrary for ColumnType {
4543
}
4644
}
4745

46+
impl ArbitraryFrom<&Table> for Vec<Value> {
47+
fn arbitrary_from<R: rand::Rng>(rng: &mut R, table: &Table) -> Self {
48+
let mut row = Vec::new();
49+
for column in table.columns.iter() {
50+
let value = Value::arbitrary_from(rng, &column.column_type);
51+
row.push(value);
52+
}
53+
row
54+
}
55+
}
56+
4857
impl ArbitraryFrom<&Vec<&Value>> for Value {
4958
fn arbitrary_from<R: Rng>(rng: &mut R, values: &Vec<&Self>) -> Self {
5059
if values.is_empty() {
@@ -74,8 +83,8 @@ impl ArbitraryFrom<&Vec<&Value>> for LTValue {
7483
return Self(Value::Null);
7584
}
7685

77-
let index = pick_index(values.len(), rng);
78-
Self::arbitrary_from(rng, values[index])
86+
let value = pick(values, rng);
87+
Self::arbitrary_from(rng, *value)
7988
}
8089
}
8190

@@ -134,8 +143,8 @@ impl ArbitraryFrom<&Vec<&Value>> for GTValue {
134143
return Self(Value::Null);
135144
}
136145

137-
let index = pick_index(values.len(), rng);
138-
Self::arbitrary_from(rng, values[index])
146+
let value = pick(values, rng);
147+
Self::arbitrary_from(rng, *value)
139148
}
140149
}
141150

0 commit comments

Comments
 (0)