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:
Weny Xu
2024-01-26 11:59:17 +09:00
committed by GitHub
parent 1fab7ab75a
commit f99b08796d
20 changed files with 487 additions and 65 deletions

View File

@@ -33,7 +33,7 @@ pub struct TableContext {
impl From<&CreateTableExpr> for TableContext {
fn from(
CreateTableExpr {
name,
table_name: name,
columns,
partition,
primary_keys,

View File

@@ -14,6 +14,8 @@
pub mod alter_expr;
pub mod create_expr;
pub mod insert_expr;
pub mod select_expr;
use std::fmt;

View File

@@ -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);
}
}

View File

@@ -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);
}
}

View 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,
})
}
}

View 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,
})
}
}

View File

@@ -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!(),

View File

@@ -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,
}

View File

@@ -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,

View 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>,
}

View 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,
}

View File

@@ -21,3 +21,6 @@ pub mod fake;
pub mod generator;
pub mod ir;
pub mod translator;
#[cfg(test)]
pub mod test_utils;

View 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![],
}
}

View File

@@ -14,3 +14,5 @@
pub mod alter_expr;
pub mod create_expr;
pub mod insert_expr;
pub mod select_expr;

View File

@@ -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(),
},

View File

@@ -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(

View 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);
}
}

View 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);
}
}

View File

@@ -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(),
},

View File

@@ -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),
))
}