-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
add expression representation and refactor memo
This commit adds the `src/expression` module which contains a very simple representation of Cascades expressions. The `Memo` trait interface and implemenation has also changed, where it now correctly detects exact match duplicates, and it does not track fingerprints for physical expressions (only logical). TODO: Add more tests. TODO: Figure out how to test in CI.
- Loading branch information
1 parent
0e54957
commit 24df49f
Showing
19 changed files
with
646 additions
and
98 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
//! `SeaORM` Entity, @generated by sea-orm-codegen 1.1.0 | ||
use sea_orm::entity::prelude::*; | ||
|
||
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq)] | ||
#[sea_orm(table_name = "fingerprint")] | ||
pub struct Model { | ||
#[sea_orm(primary_key)] | ||
pub id: i32, | ||
pub logical_expression_id: i32, | ||
pub kind: i16, | ||
pub hash: i64, | ||
} | ||
|
||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)] | ||
pub enum Relation { | ||
#[sea_orm( | ||
belongs_to = "super::logical_expression::Entity", | ||
from = "Column::LogicalExpressionId", | ||
to = "super::logical_expression::Column::Id", | ||
on_update = "Cascade", | ||
on_delete = "Cascade" | ||
)] | ||
LogicalExpression, | ||
} | ||
|
||
impl Related<super::logical_expression::Entity> for Entity { | ||
fn to() -> RelationDef { | ||
Relation::LogicalExpression.def() | ||
} | ||
} | ||
|
||
impl ActiveModelBehavior for ActiveModel {} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
//! Definition of logical expressions / relations in the Cascades query optimization framework. | ||
//! | ||
//! FIXME: All fields are placeholders, and group IDs are just represented as i32 for now. | ||
//! | ||
//! TODO figure out if each relation should be in a different submodule. | ||
use crate::entities::*; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Clone, Debug)] | ||
pub enum LogicalExpression { | ||
Scan(Scan), | ||
Filter(Filter), | ||
Join(Join), | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Clone, Debug)] | ||
pub struct Scan { | ||
table_schema: String, | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Clone, Debug)] | ||
pub struct Filter { | ||
child: i32, | ||
expression: String, | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Clone, Debug)] | ||
pub struct Join { | ||
left: i32, | ||
right: i32, | ||
expression: String, | ||
} | ||
|
||
/// TODO Use a macro instead. | ||
impl From<logical_expression::Model> for LogicalExpression { | ||
fn from(value: logical_expression::Model) -> Self { | ||
match value.kind { | ||
0 => Self::Scan( | ||
serde_json::from_value(value.data) | ||
.expect("unable to deserialize data into a logical `Scan`"), | ||
), | ||
1 => Self::Filter( | ||
serde_json::from_value(value.data) | ||
.expect("Unable to deserialize data into a logical `Filter`"), | ||
), | ||
2 => Self::Join( | ||
serde_json::from_value(value.data) | ||
.expect("Unable to deserialize data into a logical `Join`"), | ||
), | ||
_ => panic!(), | ||
} | ||
} | ||
} | ||
|
||
/// TODO Use a macro instead. | ||
impl From<LogicalExpression> for logical_expression::Model { | ||
fn from(value: LogicalExpression) -> logical_expression::Model { | ||
fn create_logical_expression( | ||
kind: i16, | ||
data: serde_json::Value, | ||
) -> logical_expression::Model { | ||
logical_expression::Model { | ||
id: -1, | ||
group_id: -1, | ||
kind, | ||
data, | ||
} | ||
} | ||
|
||
match value { | ||
LogicalExpression::Scan(scan) => create_logical_expression( | ||
0, | ||
serde_json::to_value(scan).expect("unable to serialize logical `Scan`"), | ||
), | ||
LogicalExpression::Filter(filter) => create_logical_expression( | ||
1, | ||
serde_json::to_value(filter).expect("unable to serialize logical `Filter`"), | ||
), | ||
LogicalExpression::Join(join) => create_logical_expression( | ||
2, | ||
serde_json::to_value(join).expect("unable to serialize logical `Join`"), | ||
), | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
pub use build::*; | ||
|
||
#[cfg(test)] | ||
mod build { | ||
use super::*; | ||
use crate::expression::Expression; | ||
|
||
pub fn scan(table_schema: String) -> Expression { | ||
Expression::Logical(LogicalExpression::Scan(Scan { table_schema })) | ||
} | ||
|
||
pub fn filter(child_group: i32, expression: String) -> Expression { | ||
Expression::Logical(LogicalExpression::Filter(Filter { | ||
child: child_group, | ||
expression, | ||
})) | ||
} | ||
|
||
pub fn join(left_group: i32, right_group: i32, expression: String) -> Expression { | ||
Expression::Logical(LogicalExpression::Join(Join { | ||
left: left_group, | ||
right: right_group, | ||
expression, | ||
})) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
//! In-memory representation of Cascades logical and physical expression / operators / relations. | ||
//! | ||
//! TODO more docs. | ||
mod logical_expression; | ||
pub use logical_expression::*; | ||
|
||
mod physical_expression; | ||
pub use physical_expression::*; | ||
|
||
/// The representation of a Cascades expression. | ||
/// | ||
/// TODO more docs. | ||
#[derive(Clone, Debug)] | ||
pub enum Expression { | ||
Logical(LogicalExpression), | ||
Physical(PhysicalExpression), | ||
} | ||
|
||
/// Converts the database / JSON representation of a logical expression into an in-memory one. | ||
impl From<crate::entities::logical_expression::Model> for Expression { | ||
fn from(value: crate::entities::logical_expression::Model) -> Self { | ||
Self::Logical(value.into()) | ||
} | ||
} | ||
|
||
/// Converts the in-memory representation of a logical expression into the database / JSON version. | ||
/// | ||
/// # Panics | ||
/// | ||
/// This will panic if the [`Expression`] is [`Expression::Physical`]. | ||
impl From<Expression> for crate::entities::logical_expression::Model { | ||
fn from(value: Expression) -> Self { | ||
let Expression::Logical(expr) = value else { | ||
panic!("Attempted to convert an in-memory physical expression into a logical database / JSON expression"); | ||
}; | ||
|
||
expr.into() | ||
} | ||
} | ||
|
||
/// Converts the database / JSON representation of a physical expression into an in-memory one. | ||
impl From<crate::entities::physical_expression::Model> for Expression { | ||
fn from(value: crate::entities::physical_expression::Model) -> Self { | ||
Self::Physical(value.into()) | ||
} | ||
} | ||
|
||
/// Converts the in-memory representation of a physical expression into the database / JSON version. | ||
/// | ||
/// # Panics | ||
/// | ||
/// This will panic if the [`Expression`] is [`Expression::Physical`]. | ||
impl From<Expression> for crate::entities::physical_expression::Model { | ||
fn from(value: Expression) -> Self { | ||
let Expression::Physical(expr) = value else { | ||
panic!("Attempted to convert an in-memory logical expression into a physical database / JSON expression"); | ||
}; | ||
|
||
expr.into() | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
//! Definition of physical expressions / operators in the Cascades query optimization framework. | ||
//! | ||
//! FIXME: All fields are placeholders, and group IDs are just represented as i32 for now. | ||
//! | ||
//! TODO figure out if each operator should be in a different submodule. | ||
use crate::entities::*; | ||
use serde::{Deserialize, Serialize}; | ||
|
||
#[derive(Clone, Debug)] | ||
pub enum PhysicalExpression { | ||
TableScan(TableScan), | ||
Filter(PhysicalFilter), | ||
HashJoin(HashJoin), | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Clone, Debug)] | ||
pub struct TableScan { | ||
table_schema: String, | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Clone, Debug)] | ||
pub struct PhysicalFilter { | ||
child: i32, | ||
expression: String, | ||
} | ||
|
||
#[derive(Serialize, Deserialize, Clone, Debug)] | ||
pub struct HashJoin { | ||
left: i32, | ||
right: i32, | ||
expression: String, | ||
} | ||
|
||
/// TODO Use a macro instead. | ||
impl From<physical_expression::Model> for PhysicalExpression { | ||
fn from(value: physical_expression::Model) -> Self { | ||
match value.kind { | ||
0 => Self::TableScan( | ||
serde_json::from_value(value.data) | ||
.expect("unable to deserialize data into a physical `TableScan`"), | ||
), | ||
1 => Self::Filter( | ||
serde_json::from_value(value.data) | ||
.expect("Unable to deserialize data into a physical `Filter`"), | ||
), | ||
2 => Self::HashJoin( | ||
serde_json::from_value(value.data) | ||
.expect("Unable to deserialize data into a physical `HashJoin`"), | ||
), | ||
_ => panic!(), | ||
} | ||
} | ||
} | ||
|
||
/// TODO Use a macro instead. | ||
impl From<PhysicalExpression> for physical_expression::Model { | ||
fn from(value: PhysicalExpression) -> physical_expression::Model { | ||
fn create_physical_expression( | ||
kind: i16, | ||
data: serde_json::Value, | ||
) -> physical_expression::Model { | ||
physical_expression::Model { | ||
id: -1, | ||
group_id: -1, | ||
kind, | ||
data, | ||
} | ||
} | ||
|
||
match value { | ||
PhysicalExpression::TableScan(scan) => create_physical_expression( | ||
0, | ||
serde_json::to_value(scan).expect("unable to serialize physical `TableScan`"), | ||
), | ||
PhysicalExpression::Filter(filter) => create_physical_expression( | ||
1, | ||
serde_json::to_value(filter).expect("unable to serialize physical `Filter`"), | ||
), | ||
PhysicalExpression::HashJoin(join) => create_physical_expression( | ||
2, | ||
serde_json::to_value(join).expect("unable to serialize physical `HashJoin`"), | ||
), | ||
} | ||
} | ||
} | ||
|
||
#[cfg(test)] | ||
pub use build::*; | ||
|
||
#[cfg(test)] | ||
mod build { | ||
use super::*; | ||
use crate::expression::Expression; | ||
|
||
pub fn table_scan(table_schema: String) -> Expression { | ||
Expression::Physical(PhysicalExpression::TableScan(TableScan { table_schema })) | ||
} | ||
|
||
pub fn filter(child_group: i32, expression: String) -> Expression { | ||
Expression::Physical(PhysicalExpression::Filter(PhysicalFilter { | ||
child: child_group, | ||
expression, | ||
})) | ||
} | ||
|
||
pub fn hash_join(left_group: i32, right_group: i32, expression: String) -> Expression { | ||
Expression::Physical(PhysicalExpression::HashJoin(HashJoin { | ||
left: left_group, | ||
right: right_group, | ||
expression, | ||
})) | ||
} | ||
} |
Oops, something went wrong.