mirror of
https://github.com/GreptimeTeam/greptimedb.git
synced 2026-05-24 17:00:37 +00:00
feat: add insert/select generator & translator (#3240)
* feat: add insert into expr generator & translator * feat: add select expr generator & translator * chore: apply suggestions from CR * fix: fix unit tests
This commit is contained in:
@@ -33,7 +33,7 @@ pub struct TableContext {
|
||||
impl From<&CreateTableExpr> for TableContext {
|
||||
fn from(
|
||||
CreateTableExpr {
|
||||
name,
|
||||
table_name: name,
|
||||
columns,
|
||||
partition,
|
||||
primary_keys,
|
||||
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
pub mod alter_expr;
|
||||
pub mod create_expr;
|
||||
pub mod insert_expr;
|
||||
pub mod select_expr;
|
||||
|
||||
use std::fmt;
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ impl<R: Rng + 'static> Generator<AlterTableExpr, R> for AlterExprAddColumnGenera
|
||||
)
|
||||
.remove(0);
|
||||
Ok(AlterTableExpr {
|
||||
name: self.table_ctx.name.to_string(),
|
||||
table_name: self.table_ctx.name.to_string(),
|
||||
alter_options: AlterTableOperation::AddColumn { column, location },
|
||||
})
|
||||
}
|
||||
@@ -99,7 +99,7 @@ impl<R: Rng> Generator<AlterTableExpr, R> for AlterExprDropColumnGenerator<R> {
|
||||
.name
|
||||
.to_string();
|
||||
Ok(AlterTableExpr {
|
||||
name: self.table_ctx.name.to_string(),
|
||||
table_name: self.table_ctx.name.to_string(),
|
||||
alter_options: AlterTableOperation::DropColumn { name },
|
||||
})
|
||||
}
|
||||
@@ -120,7 +120,7 @@ impl<R: Rng> Generator<AlterTableExpr, R> for AlterExprRenameGenerator<R> {
|
||||
fn generate(&self, rng: &mut R) -> Result<AlterTableExpr> {
|
||||
let new_table_name = self.name_generator.gen(rng);
|
||||
Ok(AlterTableExpr {
|
||||
name: self.table_ctx.name.to_string(),
|
||||
table_name: self.table_ctx.name.to_string(),
|
||||
alter_options: AlterTableOperation::RenameTable { new_table_name },
|
||||
})
|
||||
}
|
||||
@@ -155,7 +155,7 @@ mod tests {
|
||||
.generate(&mut rng)
|
||||
.unwrap();
|
||||
let serialized = serde_json::to_string(&expr).unwrap();
|
||||
let expected = r#"{"name":"DigNissIMOS","alter_options":{"AddColumn":{"column":{"name":"sit","column_type":{"Boolean":null},"options":["PrimaryKey"]},"location":null}}}"#;
|
||||
let expected = r#"{"table_name":"DigNissIMOS","alter_options":{"AddColumn":{"column":{"name":"sit","column_type":{"Boolean":null},"options":["PrimaryKey"]},"location":null}}}"#;
|
||||
assert_eq!(expected, serialized);
|
||||
|
||||
let expr = AlterExprRenameGeneratorBuilder::default()
|
||||
@@ -165,7 +165,7 @@ mod tests {
|
||||
.generate(&mut rng)
|
||||
.unwrap();
|
||||
let serialized = serde_json::to_string(&expr).unwrap();
|
||||
let expected = r#"{"name":"DigNissIMOS","alter_options":{"RenameTable":{"new_table_name":"excepturi"}}}"#;
|
||||
let expected = r#"{"table_name":"DigNissIMOS","alter_options":{"RenameTable":{"new_table_name":"excepturi"}}}"#;
|
||||
assert_eq!(expected, serialized);
|
||||
|
||||
let expr = AlterExprDropColumnGeneratorBuilder::default()
|
||||
@@ -176,7 +176,7 @@ mod tests {
|
||||
.unwrap();
|
||||
let serialized = serde_json::to_string(&expr).unwrap();
|
||||
let expected =
|
||||
r#"{"name":"DigNissIMOS","alter_options":{"DropColumn":{"name":"INVentORE"}}}"#;
|
||||
r#"{"table_name":"DigNissIMOS","alter_options":{"DropColumn":{"name":"INVentORE"}}}"#;
|
||||
assert_eq!(expected, serialized);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -106,6 +106,7 @@ impl<R: Rng + 'static> Generator<CreateTableExpr, R> for CreateTableExprGenerato
|
||||
partition_bounds.push(PartitionBound::Value(generate_random_value(
|
||||
rng,
|
||||
&column.column_type,
|
||||
None,
|
||||
)));
|
||||
partition_bounds.sort();
|
||||
}
|
||||
@@ -133,6 +134,7 @@ impl<R: Rng + 'static> Generator<CreateTableExpr, R> for CreateTableExprGenerato
|
||||
partition_bounds.push(PartitionBound::Value(generate_random_value(
|
||||
rng,
|
||||
&column.column_type,
|
||||
None,
|
||||
)));
|
||||
partition_bounds.sort();
|
||||
}
|
||||
@@ -171,9 +173,9 @@ impl<R: Rng + 'static> Generator<CreateTableExpr, R> for CreateTableExprGenerato
|
||||
builder.engine(self.engine.to_string());
|
||||
builder.if_not_exists(self.if_not_exists);
|
||||
if self.name.is_empty() {
|
||||
builder.name(self.name_generator.gen(rng));
|
||||
builder.table_name(self.name_generator.gen(rng));
|
||||
} else {
|
||||
builder.name(self.name.to_string());
|
||||
builder.table_name(self.name.to_string());
|
||||
}
|
||||
builder.build().context(error::BuildCreateTableExprSnafu)
|
||||
}
|
||||
@@ -228,7 +230,7 @@ mod tests {
|
||||
.unwrap();
|
||||
|
||||
let serialized = serde_json::to_string(&expr).unwrap();
|
||||
let expected = r#"{"name":"iN","columns":[{"name":"CUlpa","column_type":{"Int16":{}},"options":["PrimaryKey","NotNull"]},{"name":"dEBiTiS","column_type":{"Timestamp":{"Second":null}},"options":["TimeIndex"]},{"name":"HArum","column_type":{"Int16":{}},"options":["NotNull"]},{"name":"NObIS","column_type":{"Int32":{}},"options":["PrimaryKey"]},{"name":"IMPEDiT","column_type":{"Int16":{}},"options":[{"DefaultValue":{"Int16":-25151}}]},{"name":"bLanDITIis","column_type":{"Boolean":null},"options":[{"DefaultValue":{"Boolean":true}}]},{"name":"Dolores","column_type":{"Float32":{}},"options":["PrimaryKey"]},{"name":"eSt","column_type":{"Float32":{}},"options":[{"DefaultValue":{"Float32":0.9152612}}]},{"name":"INVentORE","column_type":{"Int64":{}},"options":["PrimaryKey"]},{"name":"aDIpiSci","column_type":{"Float64":{}},"options":["Null"]}],"if_not_exists":true,"partition":{"partition_columns":["CUlpa"],"partition_bounds":[{"Value":{"Int16":15966}},{"Value":{"Int16":31925}},"MaxValue"]},"engine":"mito2","options":{},"primary_keys":[6,0,8,3]}"#;
|
||||
let expected = r#"{"table_name":"iN","columns":[{"name":"CUlpa","column_type":{"Int16":{}},"options":["PrimaryKey","NotNull"]},{"name":"dEBiTiS","column_type":{"Timestamp":{"Second":null}},"options":["TimeIndex"]},{"name":"HArum","column_type":{"Int16":{}},"options":["NotNull"]},{"name":"NObIS","column_type":{"Int32":{}},"options":["PrimaryKey"]},{"name":"IMPEDiT","column_type":{"Int16":{}},"options":[{"DefaultValue":{"Int16":-25151}}]},{"name":"bLanDITIis","column_type":{"Boolean":null},"options":[{"DefaultValue":{"Boolean":true}}]},{"name":"Dolores","column_type":{"Float32":{}},"options":["PrimaryKey"]},{"name":"eSt","column_type":{"Float32":{}},"options":[{"DefaultValue":{"Float32":0.9152612}}]},{"name":"INVentORE","column_type":{"Int64":{}},"options":["PrimaryKey"]},{"name":"aDIpiSci","column_type":{"Float64":{}},"options":["Null"]}],"if_not_exists":true,"partition":{"partition_columns":["CUlpa"],"partition_bounds":[{"Value":{"Int16":15966}},{"Value":{"Int16":31925}},"MaxValue"]},"engine":"mito2","options":{},"primary_keys":[6,0,8,3]}"#;
|
||||
assert_eq!(expected, serialized);
|
||||
}
|
||||
}
|
||||
|
||||
70
tests-fuzz/src/generator/insert_expr.rs
Normal file
70
tests-fuzz/src/generator/insert_expr.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
// Copyright 2023 Greptime Team
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use derive_builder::Builder;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::context::TableContextRef;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::fake::WordGenerator;
|
||||
use crate::generator::{Generator, Random};
|
||||
use crate::ir::generate_random_value;
|
||||
use crate::ir::insert_expr::InsertIntoExpr;
|
||||
|
||||
/// Generates [InsertIntoExpr].
|
||||
#[derive(Builder)]
|
||||
#[builder(pattern = "owned")]
|
||||
pub struct InsertExprGenerator<R: Rng + 'static> {
|
||||
table_ctx: TableContextRef,
|
||||
#[builder(default = "1")]
|
||||
rows: usize,
|
||||
#[builder(default = "Box::new(WordGenerator)")]
|
||||
word_generator: Box<dyn Random<String, R>>,
|
||||
#[builder(default)]
|
||||
_phantom: PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<R: Rng + 'static> Generator<InsertIntoExpr, R> for InsertExprGenerator<R> {
|
||||
type Error = Error;
|
||||
|
||||
/// Generates the [CreateTableExpr].
|
||||
fn generate(&self, rng: &mut R) -> Result<InsertIntoExpr> {
|
||||
let mut columns = self.table_ctx.columns.clone();
|
||||
columns.shuffle(rng);
|
||||
|
||||
let mut rows = Vec::with_capacity(self.rows);
|
||||
for _ in 0..self.rows {
|
||||
let mut row = Vec::with_capacity(columns.len());
|
||||
for column in &columns {
|
||||
// TODO(weny): generates the special cases
|
||||
row.push(generate_random_value(
|
||||
rng,
|
||||
&column.column_type,
|
||||
Some(self.word_generator.as_ref()),
|
||||
));
|
||||
}
|
||||
|
||||
rows.push(row);
|
||||
}
|
||||
|
||||
Ok(InsertIntoExpr {
|
||||
table_name: self.table_ctx.name.to_string(),
|
||||
columns,
|
||||
rows,
|
||||
})
|
||||
}
|
||||
}
|
||||
72
tests-fuzz/src/generator/select_expr.rs
Normal file
72
tests-fuzz/src/generator/select_expr.rs
Normal file
@@ -0,0 +1,72 @@
|
||||
// Copyright 2023 Greptime Team
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use derive_builder::Builder;
|
||||
use rand::seq::SliceRandom;
|
||||
use rand::Rng;
|
||||
|
||||
use crate::context::TableContextRef;
|
||||
use crate::error::{Error, Result};
|
||||
use crate::generator::Generator;
|
||||
use crate::ir::select_expr::{Direction, SelectExpr};
|
||||
|
||||
#[derive(Builder)]
|
||||
#[builder(pattern = "owned")]
|
||||
pub struct SelectExprGenerator<R: Rng + 'static> {
|
||||
table_ctx: TableContextRef,
|
||||
#[builder(default = "8192")]
|
||||
max_limit: usize,
|
||||
#[builder(default)]
|
||||
_phantom: PhantomData<R>,
|
||||
}
|
||||
|
||||
impl<R: Rng + 'static> Generator<SelectExpr, R> for SelectExprGenerator<R> {
|
||||
type Error = Error;
|
||||
|
||||
fn generate(&self, rng: &mut R) -> Result<SelectExpr> {
|
||||
let selection = rng.gen_range(1..self.table_ctx.columns.len());
|
||||
let mut selected_columns = self
|
||||
.table_ctx
|
||||
.columns
|
||||
.choose_multiple(rng, selection)
|
||||
.cloned()
|
||||
.collect::<Vec<_>>();
|
||||
selected_columns.shuffle(rng);
|
||||
|
||||
let order_by_selection = rng.gen_range(1..selection);
|
||||
|
||||
let order_by = selected_columns
|
||||
.choose_multiple(rng, order_by_selection)
|
||||
.map(|c| c.name.to_string())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let limit = rng.gen_range(1..self.max_limit);
|
||||
|
||||
let direction = if rng.gen_bool(1.0 / 2.0) {
|
||||
Direction::Asc
|
||||
} else {
|
||||
Direction::Desc
|
||||
};
|
||||
|
||||
Ok(SelectExpr {
|
||||
table_name: self.table_ctx.name.to_string(),
|
||||
columns: selected_columns,
|
||||
order_by,
|
||||
direction,
|
||||
limit,
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
pub(crate) mod alter_expr;
|
||||
pub(crate) mod create_expr;
|
||||
pub(crate) mod insert_expr;
|
||||
pub(crate) mod select_expr;
|
||||
|
||||
pub use alter_expr::AlterTableExpr;
|
||||
pub use create_expr::CreateTableExpr;
|
||||
@@ -71,7 +73,11 @@ pub struct TsColumnTypeGenerator;
|
||||
pub struct PartibleColumnTypeGenerator;
|
||||
|
||||
/// Generates a random [Value].
|
||||
pub fn generate_random_value<R: Rng>(rng: &mut R, datatype: &ConcreteDataType) -> Value {
|
||||
pub fn generate_random_value<R: Rng>(
|
||||
rng: &mut R,
|
||||
datatype: &ConcreteDataType,
|
||||
random_str: Option<&dyn Random<String, R>>,
|
||||
) -> Value {
|
||||
match datatype {
|
||||
&ConcreteDataType::Boolean(_) => Value::from(rng.gen::<bool>()),
|
||||
ConcreteDataType::Int16(_) => Value::from(rng.gen::<i16>()),
|
||||
@@ -79,9 +85,13 @@ pub fn generate_random_value<R: Rng>(rng: &mut R, datatype: &ConcreteDataType) -
|
||||
ConcreteDataType::Int64(_) => Value::from(rng.gen::<i64>()),
|
||||
ConcreteDataType::Float32(_) => Value::from(rng.gen::<f32>()),
|
||||
ConcreteDataType::Float64(_) => Value::from(rng.gen::<f64>()),
|
||||
ConcreteDataType::String(_) => Value::from(rng.gen::<char>().to_string()),
|
||||
ConcreteDataType::String(_) => match random_str {
|
||||
Some(random) => Value::from(random.gen(rng)),
|
||||
None => Value::from(rng.gen::<char>().to_string()),
|
||||
},
|
||||
ConcreteDataType::Date(_) => Value::from(rng.gen::<i32>()),
|
||||
ConcreteDataType::DateTime(_) => Value::from(rng.gen::<i64>()),
|
||||
&ConcreteDataType::Timestamp(_) => Value::from(rng.gen::<u64>()),
|
||||
|
||||
_ => unimplemented!("unsupported type: {datatype}"),
|
||||
}
|
||||
@@ -142,6 +152,7 @@ pub fn column_options_generator<R: Rng>(
|
||||
2 => vec![ColumnOption::DefaultValue(generate_random_value(
|
||||
rng,
|
||||
column_type,
|
||||
None,
|
||||
))],
|
||||
3 => vec![ColumnOption::PrimaryKey],
|
||||
_ => vec![],
|
||||
@@ -163,7 +174,7 @@ pub fn partible_column_options_generator<R: Rng + 'static>(
|
||||
1 => vec![ColumnOption::PrimaryKey, ColumnOption::NotNull],
|
||||
2 => vec![
|
||||
ColumnOption::PrimaryKey,
|
||||
ColumnOption::DefaultValue(generate_random_value(rng, column_type)),
|
||||
ColumnOption::DefaultValue(generate_random_value(rng, column_type, None)),
|
||||
],
|
||||
3 => vec![ColumnOption::PrimaryKey],
|
||||
_ => unreachable!(),
|
||||
|
||||
@@ -20,7 +20,7 @@ use crate::ir::Column;
|
||||
|
||||
#[derive(Debug, Builder, Clone, Serialize, Deserialize)]
|
||||
pub struct AlterTableExpr {
|
||||
pub name: String,
|
||||
pub table_name: String,
|
||||
pub alter_options: AlterTableOperation,
|
||||
}
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ impl Display for ColumnOption {
|
||||
#[derive(Debug, Builder, Clone, Serialize, Deserialize)]
|
||||
pub struct CreateTableExpr {
|
||||
#[builder(setter(into))]
|
||||
pub name: String,
|
||||
pub table_name: String,
|
||||
pub columns: Vec<Column>,
|
||||
#[builder(default)]
|
||||
pub if_not_exists: bool,
|
||||
|
||||
25
tests-fuzz/src/ir/insert_expr.rs
Normal file
25
tests-fuzz/src/ir/insert_expr.rs
Normal file
@@ -0,0 +1,25 @@
|
||||
// Copyright 2023 Greptime Team
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use datatypes::value::Value;
|
||||
|
||||
use crate::ir::Column;
|
||||
|
||||
pub type RowValue = Vec<Value>;
|
||||
|
||||
pub struct InsertIntoExpr {
|
||||
pub table_name: String,
|
||||
pub columns: Vec<Column>,
|
||||
pub rows: Vec<RowValue>,
|
||||
}
|
||||
39
tests-fuzz/src/ir/select_expr.rs
Normal file
39
tests-fuzz/src/ir/select_expr.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
// Copyright 2023 Greptime Team
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use std::fmt::Display;
|
||||
|
||||
use crate::ir::Column;
|
||||
|
||||
pub enum Direction {
|
||||
Asc,
|
||||
Desc,
|
||||
}
|
||||
|
||||
impl Display for Direction {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
Direction::Asc => write!(f, "ASC"),
|
||||
Direction::Desc => write!(f, "DESC"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SelectExpr {
|
||||
pub table_name: String,
|
||||
pub columns: Vec<Column>,
|
||||
pub order_by: Vec<String>,
|
||||
pub direction: Direction,
|
||||
pub limit: usize,
|
||||
}
|
||||
@@ -21,3 +21,6 @@ pub mod fake;
|
||||
pub mod generator;
|
||||
pub mod ir;
|
||||
pub mod translator;
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod test_utils;
|
||||
|
||||
59
tests-fuzz/src/test_utils.rs
Normal file
59
tests-fuzz/src/test_utils.rs
Normal file
@@ -0,0 +1,59 @@
|
||||
// Copyright 2023 Greptime Team
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use datatypes::data_type::ConcreteDataType;
|
||||
|
||||
use crate::context::TableContext;
|
||||
use crate::ir::create_expr::ColumnOption;
|
||||
use crate::ir::Column;
|
||||
|
||||
pub fn new_test_ctx() -> TableContext {
|
||||
TableContext {
|
||||
name: "test".to_string(),
|
||||
columns: vec![
|
||||
Column {
|
||||
name: "host".to_string(),
|
||||
column_type: ConcreteDataType::string_datatype(),
|
||||
options: vec![ColumnOption::PrimaryKey],
|
||||
},
|
||||
Column {
|
||||
name: "idc".to_string(),
|
||||
column_type: ConcreteDataType::string_datatype(),
|
||||
options: vec![ColumnOption::PrimaryKey],
|
||||
},
|
||||
Column {
|
||||
name: "cpu_util".to_string(),
|
||||
column_type: ConcreteDataType::float64_datatype(),
|
||||
options: vec![],
|
||||
},
|
||||
Column {
|
||||
name: "memory_util".to_string(),
|
||||
column_type: ConcreteDataType::float64_datatype(),
|
||||
options: vec![],
|
||||
},
|
||||
Column {
|
||||
name: "disk_util".to_string(),
|
||||
column_type: ConcreteDataType::float64_datatype(),
|
||||
options: vec![],
|
||||
},
|
||||
Column {
|
||||
name: "ts".to_string(),
|
||||
column_type: ConcreteDataType::timestamp_millisecond_datatype(),
|
||||
options: vec![ColumnOption::TimeIndex],
|
||||
},
|
||||
],
|
||||
partition: None,
|
||||
primary_keys: vec![],
|
||||
}
|
||||
}
|
||||
@@ -14,3 +14,5 @@
|
||||
|
||||
pub mod alter_expr;
|
||||
pub mod create_expr;
|
||||
pub mod insert_expr;
|
||||
pub mod select_expr;
|
||||
|
||||
@@ -30,11 +30,11 @@ impl DslTranslator<AlterTableExpr, String> for AlterTableExprTranslator {
|
||||
fn translate(&self, input: &AlterTableExpr) -> Result<String> {
|
||||
Ok(match &input.alter_options {
|
||||
AlterTableOperation::AddColumn { column, location } => {
|
||||
Self::format_add_column(&input.name, column, location)
|
||||
Self::format_add_column(&input.table_name, column, location)
|
||||
}
|
||||
AlterTableOperation::DropColumn { name } => Self::format_drop(&input.name, name),
|
||||
AlterTableOperation::DropColumn { name } => Self::format_drop(&input.table_name, name),
|
||||
AlterTableOperation::RenameTable { new_table_name } => {
|
||||
Self::format_rename(&input.name, new_table_name)
|
||||
Self::format_rename(&input.table_name, new_table_name)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -119,7 +119,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_alter_table_expr() {
|
||||
let alter_expr = AlterTableExpr {
|
||||
name: "test".to_string(),
|
||||
table_name: "test".to_string(),
|
||||
alter_options: AlterTableOperation::AddColumn {
|
||||
column: Column {
|
||||
name: "host".to_string(),
|
||||
@@ -137,7 +137,7 @@ mod tests {
|
||||
);
|
||||
|
||||
let alter_expr = AlterTableExpr {
|
||||
name: "test".to_string(),
|
||||
table_name: "test".to_string(),
|
||||
alter_options: AlterTableOperation::RenameTable {
|
||||
new_table_name: "foo".to_string(),
|
||||
},
|
||||
@@ -147,7 +147,7 @@ mod tests {
|
||||
assert_eq!("ALTER TABLE test RENAME foo;", output);
|
||||
|
||||
let alter_expr = AlterTableExpr {
|
||||
name: "test".to_string(),
|
||||
table_name: "test".to_string(),
|
||||
alter_options: AlterTableOperation::DropColumn {
|
||||
name: "foo".to_string(),
|
||||
},
|
||||
|
||||
@@ -31,7 +31,7 @@ impl DslTranslator<CreateTableExpr, String> for CreateTableExprTranslator {
|
||||
Ok(format!(
|
||||
"CREATE TABLE{}{}(\n{}\n)\n{};",
|
||||
Self::create_if_not_exists(input),
|
||||
input.name,
|
||||
input.table_name,
|
||||
Self::format_columns(input),
|
||||
Self::format_table_options(input)
|
||||
))
|
||||
@@ -149,51 +149,20 @@ impl CreateTableExprTranslator {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use datatypes::data_type::ConcreteDataType;
|
||||
use datatypes::value::Value;
|
||||
use partition::partition::{PartitionBound, PartitionDef};
|
||||
|
||||
use super::CreateTableExprTranslator;
|
||||
use crate::ir::create_expr::{ColumnOption, CreateTableExprBuilder};
|
||||
use crate::ir::Column;
|
||||
use crate::ir::create_expr::CreateTableExprBuilder;
|
||||
use crate::test_utils;
|
||||
use crate::translator::DslTranslator;
|
||||
|
||||
#[test]
|
||||
fn test_create_table_expr_translator() {
|
||||
let test_ctx = test_utils::new_test_ctx();
|
||||
let create_table_expr = CreateTableExprBuilder::default()
|
||||
.columns(vec![
|
||||
Column {
|
||||
name: "host".to_string(),
|
||||
column_type: ConcreteDataType::string_datatype(),
|
||||
options: vec![ColumnOption::PrimaryKey],
|
||||
},
|
||||
Column {
|
||||
name: "idc".to_string(),
|
||||
column_type: ConcreteDataType::string_datatype(),
|
||||
options: vec![ColumnOption::PrimaryKey],
|
||||
},
|
||||
Column {
|
||||
name: "cpu_util".to_string(),
|
||||
column_type: ConcreteDataType::float64_datatype(),
|
||||
options: vec![],
|
||||
},
|
||||
Column {
|
||||
name: "memory_util".to_string(),
|
||||
column_type: ConcreteDataType::float64_datatype(),
|
||||
options: vec![],
|
||||
},
|
||||
Column {
|
||||
name: "disk_util".to_string(),
|
||||
column_type: ConcreteDataType::float64_datatype(),
|
||||
options: vec![],
|
||||
},
|
||||
Column {
|
||||
name: "ts".to_string(),
|
||||
column_type: ConcreteDataType::timestamp_millisecond_datatype(),
|
||||
options: vec![ColumnOption::TimeIndex],
|
||||
},
|
||||
])
|
||||
.name("system_metrics")
|
||||
.columns(test_ctx.columns.clone())
|
||||
.table_name("system_metrics")
|
||||
.engine("mito")
|
||||
.primary_keys(vec![0, 1])
|
||||
.partition(PartitionDef::new(
|
||||
|
||||
93
tests-fuzz/src/translator/mysql/insert_expr.rs
Normal file
93
tests-fuzz/src/translator/mysql/insert_expr.rs
Normal file
@@ -0,0 +1,93 @@
|
||||
// Copyright 2023 Greptime Team
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ir::insert_expr::InsertIntoExpr;
|
||||
use crate::translator::DslTranslator;
|
||||
|
||||
pub struct InsertIntoExprTranslator;
|
||||
|
||||
impl DslTranslator<InsertIntoExpr, String> for InsertIntoExprTranslator {
|
||||
type Error = Error;
|
||||
|
||||
fn translate(&self, input: &InsertIntoExpr) -> Result<String> {
|
||||
let columns = input
|
||||
.columns
|
||||
.iter()
|
||||
.map(|c| c.name.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
.to_string();
|
||||
|
||||
Ok(format!(
|
||||
"INSERT INTO {} ({})\nVALUES\n{};",
|
||||
input.table_name,
|
||||
columns,
|
||||
Self::format_values(input)
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl InsertIntoExprTranslator {
|
||||
fn format_values(input: &InsertIntoExpr) -> String {
|
||||
input
|
||||
.rows
|
||||
.iter()
|
||||
.map(|row| {
|
||||
format!(
|
||||
"({})",
|
||||
row.iter()
|
||||
.map(|v| format!("'{v}'"))
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
)
|
||||
})
|
||||
.collect::<Vec<_>>()
|
||||
.join(",\n")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
|
||||
use rand::SeedableRng;
|
||||
|
||||
use super::InsertIntoExprTranslator;
|
||||
use crate::generator::insert_expr::InsertExprGeneratorBuilder;
|
||||
use crate::generator::Generator;
|
||||
use crate::test_utils;
|
||||
use crate::translator::DslTranslator;
|
||||
|
||||
#[test]
|
||||
fn test_insert_into_translator() {
|
||||
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(0);
|
||||
|
||||
let test_ctx = test_utils::new_test_ctx();
|
||||
let insert_expr_generator = InsertExprGeneratorBuilder::default()
|
||||
.table_ctx(Arc::new(test_ctx))
|
||||
.rows(2)
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let insert_expr = insert_expr_generator.generate(&mut rng).unwrap();
|
||||
|
||||
let output = InsertIntoExprTranslator.translate(&insert_expr).unwrap();
|
||||
let expected = r#"INSERT INTO test (host, idc, memory_util, ts, cpu_util, disk_util)
|
||||
VALUES
|
||||
('adipisci', 'debitis', '0.5495312687894465', '15292064470292927036', '0.9354265029131291', '0.8037816422279636'),
|
||||
('ut', 'sequi', '0.8807117723618908', '14214208091261382505', '0.5240550121500691', '0.350785883750684');"#;
|
||||
assert_eq!(output, expected);
|
||||
}
|
||||
}
|
||||
75
tests-fuzz/src/translator/mysql/select_expr.rs
Normal file
75
tests-fuzz/src/translator/mysql/select_expr.rs
Normal file
@@ -0,0 +1,75 @@
|
||||
// Copyright 2023 Greptime Team
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
use crate::error::{Error, Result};
|
||||
use crate::ir::select_expr::SelectExpr;
|
||||
use crate::translator::DslTranslator;
|
||||
|
||||
pub struct SelectExprTranslator;
|
||||
|
||||
impl DslTranslator<SelectExpr, String> for SelectExprTranslator {
|
||||
type Error = Error;
|
||||
|
||||
fn translate(&self, input: &SelectExpr) -> Result<String> {
|
||||
let columns = input
|
||||
.columns
|
||||
.iter()
|
||||
.map(|c| c.name.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
.to_string();
|
||||
|
||||
let order_by = input
|
||||
.order_by
|
||||
.iter()
|
||||
.map(|c| c.as_str())
|
||||
.collect::<Vec<_>>()
|
||||
.join(", ")
|
||||
.to_string();
|
||||
|
||||
Ok(format!(
|
||||
"SELECT {} FROM {} ORDER BY {} {};",
|
||||
columns, input.table_name, order_by, input.direction,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::sync::Arc;
|
||||
|
||||
use rand::SeedableRng;
|
||||
|
||||
use super::SelectExprTranslator;
|
||||
use crate::generator::select_expr::SelectExprGeneratorBuilder;
|
||||
use crate::generator::Generator;
|
||||
use crate::test_utils;
|
||||
use crate::translator::DslTranslator;
|
||||
|
||||
#[test]
|
||||
fn test_select_expr_translator() {
|
||||
let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(0);
|
||||
|
||||
let test_ctx = test_utils::new_test_ctx();
|
||||
let select_expr_generator = SelectExprGeneratorBuilder::default()
|
||||
.table_ctx(Arc::new(test_ctx))
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let select_expr = select_expr_generator.generate(&mut rng).unwrap();
|
||||
let output = SelectExprTranslator.translate(&select_expr).unwrap();
|
||||
let expected = r#"SELECT memory_util, ts, cpu_util, disk_util FROM test ORDER BY cpu_util, disk_util DESC;"#;
|
||||
assert_eq!(output, expected);
|
||||
}
|
||||
}
|
||||
@@ -30,11 +30,11 @@ impl DslTranslator<AlterTableExpr, String> for AlterTableExprTranslator {
|
||||
fn translate(&self, input: &AlterTableExpr) -> Result<String> {
|
||||
Ok(match &input.alter_options {
|
||||
AlterTableOperation::AddColumn { column, .. } => {
|
||||
Self::format_add_column(&input.name, column)
|
||||
Self::format_add_column(&input.table_name, column)
|
||||
}
|
||||
AlterTableOperation::DropColumn { name } => Self::format_drop(&input.name, name),
|
||||
AlterTableOperation::DropColumn { name } => Self::format_drop(&input.table_name, name),
|
||||
AlterTableOperation::RenameTable { new_table_name } => {
|
||||
Self::format_rename(&input.name, new_table_name)
|
||||
Self::format_rename(&input.table_name, new_table_name)
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -116,7 +116,7 @@ mod tests {
|
||||
#[test]
|
||||
fn test_alter_table_expr() {
|
||||
let alter_expr = AlterTableExpr {
|
||||
name: "test".to_string(),
|
||||
table_name: "test".to_string(),
|
||||
alter_options: AlterTableOperation::AddColumn {
|
||||
column: Column {
|
||||
name: "host".to_string(),
|
||||
@@ -132,7 +132,7 @@ mod tests {
|
||||
assert_eq!("ALTER TABLE test ADD COLUMN host STRING;", output);
|
||||
|
||||
let alter_expr = AlterTableExpr {
|
||||
name: "test".to_string(),
|
||||
table_name: "test".to_string(),
|
||||
alter_options: AlterTableOperation::RenameTable {
|
||||
new_table_name: "foo".to_string(),
|
||||
},
|
||||
@@ -142,7 +142,7 @@ mod tests {
|
||||
assert_eq!("ALTER TABLE test RENAME TO foo;", output);
|
||||
|
||||
let alter_expr = AlterTableExpr {
|
||||
name: "test".to_string(),
|
||||
table_name: "test".to_string(),
|
||||
alter_options: AlterTableOperation::DropColumn {
|
||||
name: "foo".to_string(),
|
||||
},
|
||||
|
||||
@@ -30,7 +30,7 @@ impl DslTranslator<CreateTableExpr, String> for CreateTableExprTranslator {
|
||||
Ok(format!(
|
||||
"CREATE TABLE{}{}(\n{}\n);",
|
||||
Self::create_if_not_exists(input),
|
||||
input.name,
|
||||
input.table_name,
|
||||
Self::format_columns(input),
|
||||
))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user