Skip to content

Commit

Permalink
docs: added documentation for the unique
Browse files Browse the repository at this point in the history
  • Loading branch information
christos-h authored Jul 9, 2021
1 parent 32fb486 commit ea98865
Show file tree
Hide file tree
Showing 5 changed files with 87 additions and 16 deletions.
18 changes: 9 additions & 9 deletions core/src/graph/unique.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use std::hash::{BuildHasher, Hash, Hasher};
const MAX_RETRIES: usize = 64;

type ValueFilter =
TryFilterMap<Box<Graph>, Box<dyn FnMut(Value) -> Result<Option<Value>, Error>>, Value>;
TryFilterMap<Box<Graph>, Box<dyn FnMut(Value) -> Result<Option<Value>, Error>>, Value>;

derive_generator! {
yield Token,
Expand All @@ -20,7 +20,7 @@ derive_generator! {
}

impl UniqueNode {
pub fn hash(inner: Graph) -> Self {
pub fn hash(inner: Graph, retries: Option<usize>) -> Self {
let mut seen: HashMap<u64, usize> = HashMap::new();
let filter = move |value: Value| {
let mut hasher = seen.hasher().build_hasher();
Expand All @@ -36,11 +36,11 @@ impl UniqueNode {

match *count {
0 => Ok(Some(value)),
x if x < MAX_RETRIES => Ok(None),
x if x < retries.unwrap_or(MAX_RETRIES) => Ok(None),
_ => Err(failed_crate!(
target: Release,
"Could not generate enough unique values from this generator:\
try reducing the number of values generated"
"Could not generate enough unique values from generator: \
try reducing the number of values generated"
)),
}
};
Expand All @@ -65,7 +65,7 @@ pub mod tests {
RandFaker::new("username", Default::default()).unwrap(),
)));
let mut rng = rand::thread_rng();
let output = UniqueNode::hash(usernames)
let output = UniqueNode::hash(usernames, None)
.repeat(NUM_GENERATED)
.complete(&mut rng)
.into_iter()
Expand All @@ -79,9 +79,9 @@ pub mod tests {
high: NUM_GENERATED as u64,
step: 1,
})
.unwrap(),
.unwrap(),
));
let output = UniqueNode::hash(numbers)
let output = UniqueNode::hash(numbers, None)
.repeat(NUM_GENERATED)
.complete(&mut rng)
.into_iter()
Expand All @@ -90,7 +90,7 @@ pub mod tests {
assert_eq!(output.len(), NUM_GENERATED);

let constant = Graph::Number(NumberNode::from(RandomU64::constant(44)));
let output = UniqueNode::hash(constant)
let output = UniqueNode::hash(constant, None)
.repeat(10)
.complete(&mut rng)
.into_iter()
Expand Down
6 changes: 3 additions & 3 deletions core/src/schema/content/unique.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ use serde::{Deserialize, Serialize};

#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
pub enum UniqueAlgorithm {
Hash,
Hash { retries: Option<usize> },
}

impl Default for UniqueAlgorithm {
fn default() -> Self {
Self::Hash
Self::Hash { retries: None }
}
}

Expand All @@ -27,7 +27,7 @@ impl Compile for UniqueContent {
fn compile<'a, C: Compiler<'a>>(&'a self, compiler: C) -> Result<Graph> {
let graph = self.content.compile(compiler)?;
let node = match self.algorithm {
UniqueAlgorithm::Hash => UniqueNode::hash(graph),
UniqueAlgorithm::Hash { retries } => UniqueNode::hash(graph, retries),
};
Ok(Graph::Unique(node))
}
Expand Down
16 changes: 13 additions & 3 deletions dist/playground/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@ impl State {
if stream.len() > self.max_size {
warn!("aborting: too large");
let text = format!(
"generated too many tokens: try generating less data by controlling (for example) the `length` parameter of arrays or using the `?size=` query parameter"
);
"generated too many tokens: try generating less data by controlling (for example) the `length` parameter of arrays or using the `?size=` query parameter"
);
let body = ErrorResponseBody {
kind: "illegal",
text: Some(text),
Expand Down Expand Up @@ -96,7 +96,17 @@ impl std::error::Error for ErrorResponseBody {}

async fn put_compile(mut req: Request<State>) -> tide::Result {
let query: CompileRequestQuery = req.query()?;
let body: Content = req.body_json().await?;
let body: Content = match req.body_json().await {
Ok(body) => body,
Err(e) => {
let error = ErrorResponseBody {
kind: "schema",
text: Some(e.to_string()),
};
let response = Response::builder(422).body(Body::from_json(&error)?).build();
return Ok(response);
}
};
info!(
"compile request with query={:?} for content of kind {}",
query,
Expand Down
61 changes: 61 additions & 0 deletions docs/docs/content/unique.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
---
title: unique
---

Synth's `unique` generator type generates values which are guaranteed to be unique from its child generator.

#### Example

```json synth
{
"type": "array",
"length": {
"type": "number",
"constant": 10
},
"content": {
"type": "object",
"ticker": {
"type": "unique",
"content": {
"type": "number",
"range": {
"low": 0,
"high": 10,
"step": 1
}
}
}
}
}
```

The unique generator works by trying the inner generator repeatedly until it receives a value which it hasn't seen yet.

By default, the unique generator will give up if it sees the same value more than 64 times but this value can be specified using the `retries` property.

Below is an example of a generator which will fail since the inner generator cannot generate 20 distinct values.

```json synth
{
"type": "array",
"length": {
"type": "number",
"constant": 20
},
"content": {
"type": "object",
"ticker": {
"type": "unique",
"content": {
"type": "number",
"range": {
"low": 0,
"high": 10,
"step": 1
}
}
}
}
}
```
2 changes: 1 addition & 1 deletion docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ module.exports = {
docsSidebar: {
"Getting Started": ['getting_started/synth', 'getting_started/installation', 'getting_started/hello-world', 'getting_started/core-concepts', 'getting_started/schema', 'getting_started/command-line', 'getting_started/how-it-works'],
"Examples": ['examples/bank'],
"Generators": ['content/null', 'content/bool', 'content/number', 'content/string', 'content/object', 'content/array', 'content/one-of', 'content/same-as', 'content/series'],
"Generators": ['content/null', 'content/bool', 'content/number', 'content/string', 'content/object', 'content/array', 'content/one-of', 'content/same-as', 'content/unique', 'content/series'],
"Other": ['other/telemetry']
},
};

0 comments on commit ea98865

Please sign in to comment.