Skip to content

Commit

Permalink
Add container-like data types examples
Browse files Browse the repository at this point in the history
  • Loading branch information
slvrtrn committed Sep 10, 2024
1 parent 4625ca0 commit f58b921
Show file tree
Hide file tree
Showing 3 changed files with 159 additions and 1 deletion.
27 changes: 26 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -398,11 +398,36 @@ See [examples](https://github.com/ClickHouse/clickhouse-rs/tree/main/examples).
}
```
</details>
* `JSON` and `Geo` aren't supported for now.
* `Geo` types are supported. `Point` behaves like a tuple `(f64, f64)`, and the rest of the types are just slices of points.
<details>
<summary>Example</summary>

```rust,ignore
type Point = (f64, f64);
type Ring = Vec<Point>;
type Polygon = Vec<Ring>;
type MultiPolygon = Vec<Polygon>;
type LineString = Vec<Point>;
type MultiLineString = Vec<LineString>;
#[derive(Row, Serialize, Deserialize)]
struct MyRow {
point: Point,
ring: Ring,
polygon: Polygon,
multi_polygon: MultiPolygon,
line_string: LineString,
multi_line_string: MultiLineString,
}
```
</details>

* `JSON`, `Variant`, `Dynamic` types are not supported for now.

See also the additional examples:

* [Simpler ClickHouse data types](examples/data_types_derive_simple.rs)
* [Container-like ClickHouse data types](examples/data_types_derive_containers.rs)

## Mocking
The crate provides utils for mocking CH server and testing DDL, `SELECT`, `INSERT` and `WATCH` queries.
Expand Down
1 change: 1 addition & 0 deletions examples/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ If something is missing, or you found a mistake in one of these examples, please
### Data types

- [data_types_derive_simple.rs](data_types_derive_simple.rs) - deriving simpler ClickHouse data types in a struct. Required cargo features: `time`, `uuid`.
- [data_types_derive_containers.rs](data_types_derive_containers.rs) - deriving container-like (Array, Tuple, Map, Nested, Geo) ClickHouse data types in a struct.

### Special cases

Expand Down
132 changes: 132 additions & 0 deletions examples/data_types_derive_containers.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
use rand::distributions::Alphanumeric;
use rand::Rng;

use clickhouse::sql::Identifier;
use clickhouse::{error::Result, Client};

// This example covers derivation of container-like ClickHouse data types.
// See also:
// - https://clickhouse.com/docs/en/sql-reference/data-types
// - data_types_derive_simple.rs

#[tokio::main]
async fn main() -> Result<()> {
let table_name = "chrs_data_types_derive_containers";
let client = Client::default().with_url("http://localhost:8123");

client
.query(
"
CREATE OR REPLACE TABLE ?
(
arr Array(String),
arr2 Array(Array(String)),
map Map(String, UInt32),
tuple Tuple(String, UInt32),
nested Nested(name String, count UInt32),
point Point,
ring Ring,
polygon Polygon,
multi_polygon MultiPolygon,
line_string LineString,
multi_line_string MultiLineString
) ENGINE MergeTree ORDER BY ();
",
)
.bind(Identifier(table_name))
.execute()
.await?;

let mut insert = client.insert(table_name)?;
insert.write(&Row::new()).await?;
insert.end().await?;

let rows = client
.query("SELECT ?fields FROM ?")
.bind(Identifier(table_name))
.fetch_all::<Row>()
.await?;

println!("{rows:#?}");
Ok(())
}

// See https://clickhouse.com/docs/en/sql-reference/data-types/geo
type Point = (f64, f64);
type Ring = Vec<Point>;
type Polygon = Vec<Ring>;
type MultiPolygon = Vec<Polygon>;
type LineString = Vec<Point>;
type MultiLineString = Vec<LineString>;

#[derive(Clone, Debug, PartialEq)]
#[derive(clickhouse::Row, serde::Serialize, serde::Deserialize)]
pub struct Row {
arr: Vec<String>,
arr2: Vec<Vec<String>>,
map: Vec<(String, u32)>,
tuple: (String, u32),
// Nested columns are internally represented as arrays of the same length
// https://clickhouse.com/docs/en/sql-reference/data-types/nested-data-structures/nested
#[serde(rename = "nested.name")]
nested_name: Vec<String>,
#[serde(rename = "nested.count")]
nested_count: Vec<u32>,
// Geo types
point: Point,
ring: Ring,
polygon: Polygon,
multi_polygon: MultiPolygon,
line_string: LineString,
multi_line_string: MultiLineString,
}

impl Row {
pub fn new() -> Self {
let mut rng = rand::thread_rng();
Row {
arr: vec![random_str()],
arr2: vec![vec![random_str()]],
map: vec![(random_str(), 42)],
tuple: (random_str(), 144),
// Nested
// NB: the length of all vectors/slices representing Nested columns must be the same
nested_name: vec![random_str(), random_str()],
nested_count: vec![rng.gen(), rng.gen()],
// Geo
point: random_point(),
ring: random_ring(),
polygon: random_polygon(),
multi_polygon: vec![random_polygon()],
line_string: random_ring(), // on the type level, the same as the Ring
multi_line_string: random_polygon(), // on the type level, the same as the Polygon
}
}
}

impl Default for Row {
fn default() -> Self {
Self::new()
}
}

fn random_str() -> String {
rand::thread_rng()
.sample_iter(&Alphanumeric)
.take(3)
.map(char::from)
.collect()
}

fn random_point() -> Point {
let mut rng = rand::thread_rng();
(rng.gen(), rng.gen())
}

fn random_ring() -> Ring {
vec![random_point(), random_point()]
}

fn random_polygon() -> Polygon {
vec![random_ring(), random_ring()]
}

0 comments on commit f58b921

Please sign in to comment.