├── .github └── workflows │ └── rust.yml ├── .gitignore ├── Cargo.toml ├── LICENSE ├── README.md └── core ├── Cargo.toml ├── examples └── music.rs └── src ├── database.rs ├── database ├── evaluate.rs ├── expression_ext.rs ├── helpers.rs ├── instance.rs └── validate.rs ├── expression.rs ├── expression ├── builder.rs ├── dependency.rs ├── difference.rs ├── empty.rs ├── full.rs ├── intersect.rs ├── join.rs ├── mono.rs ├── product.rs ├── project.rs ├── relation.rs ├── select.rs ├── singleton.rs ├── union.rs └── view.rs ├── lib.rs └── macros.rs /.github/workflows/rust.yml: -------------------------------------------------------------------------------- 1 | name: Rust 2 | 3 | on: 4 | push: 5 | branches: [ master ] 6 | pull_request: 7 | branches: [ master ] 8 | 9 | jobs: 10 | build: 11 | 12 | runs-on: ubuntu-latest 13 | 14 | steps: 15 | - uses: actions/checkout@v2 16 | - name: Build 17 | run: cargo build --verbose 18 | - name: Run tests 19 | run: cargo test --verbose 20 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /target 2 | Cargo.lock 3 | -------------------------------------------------------------------------------- /Cargo.toml: -------------------------------------------------------------------------------- 1 | [workspace] 2 | members = ["core"] -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Salman Saghafi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # codd 2 | 3 | [`codd`](https://en.wikipedia.org/wiki/Edgar_F._Codd) is a library for evaluating *typed* relational expressions in a monotonically growing minimal database in memory. `codd` is primarily developed to support an implementation of [`razor`](https://github.com/salmans/rusty-razor) based on relational algebra, however, its design is consistent with common concepts of database theory and may be used as a minimal general purpose database. 4 | 5 | The implementation of database instances in `codd` is borrowed from [`datafrog`](https://github.com/rust-lang/datafrog): 6 | * `Instance` (`Variable` in `datafrog`) contains tuples of type `T`, 7 | * Incremental view maintenance is implemented by maintaining tuples of `Instance` in three sets of `to_add` (candidate tuples to be inserted), `recent` (recently added tuples), and `stable` (old tuples that have been reflected in all views). 8 | 9 | In contrast, `codd` distinguishes relation instances from views and offers the trait `Expression` and types that implement `Expression` to query a database. 10 | 11 | The relational algebra and database terminology in `codd` is adopted from [Alice's book](http://webdam.inria.fr/Alice/). 12 | 13 | ## Build 14 | 15 | `codd` is written in [Rust](https://www.rust-lang.org). You can use Rust 1.54.0 or newer to build the library: 16 | 17 | ``` 18 | git clone https://github.com/salmans/codd.git 19 | cd codd 20 | cargo build 21 | ``` 22 | 23 | ## Example: [music](https://github.com/salmans/codd/blob/master/core/examples/music.rs) 24 | 25 | Add `codd` to your project dependencies in Cargo.toml: 26 | 27 | ``` 28 | [dependencies] 29 | codd = "0.1" 30 | ``` 31 | 32 | Use `codd` in your code: 33 | 34 | ```rust 35 | use codd::{Database, Error, Expression}; 36 | ``` 37 | 38 | Create a new database: 39 | 40 | ```rust 41 | let mut music = Database::new(); // music database 42 | ``` 43 | 44 | Add relations to the database: 45 | 46 | ```rust 47 | // `musician`, `band` and `song` are `Relation` expressions. 48 | let musician = music.add_relation("musician")?; 49 | let band = music.add_relation("band")?; 50 | let song = music.add_relation("song")?; 51 | ``` 52 | 53 | Insert tuples (records) to your database relations: 54 | 55 | ```rust 56 | music.insert( 57 | &musician, 58 | vec![ 59 | Musician { 60 | name: "John Petrucci".into(), 61 | band: Some("Dream Theater".into()), 62 | instruments: vec![Guitar], 63 | }, 64 | Musician { 65 | name: "Taylor Swift".into(), 66 | band: None, 67 | instruments: vec![Vocals], 68 | }, 69 | // more tuples... 70 | ] 71 | .into(), 72 | )?; 73 | 74 | // add tuples to other relations... 75 | ``` 76 | 77 | Construct query expressions and evaluate them in the database: 78 | 79 | ```rust 80 | 81 | let guitarist_name = musician 82 | .builder() 83 | .select(|m| m.instruments.contains(&Guitar)) 84 | .project(|g| g.name.to_string()) 85 | .build(); 86 | 87 | assert_eq!( 88 | vec![ 89 | "Alex Turner".to_string(), 90 | "Conor Mason".into(), 91 | "John Petrucci".into(), 92 | ], 93 | music.evaluate(&guitarist_name)?.into_tuples() // evaluate the query and get the results 94 | ); 95 | ``` 96 | 97 | Here is a more complex query: 98 | 99 | ```rust 100 | let dt_member = musician 101 | .builder() 102 | .with_key(|m| m.band.clone()) 103 | // use `band` as the join key for `musician` 104 | .join(band.builder().with_key(|b| Some(b.name.clone()))) 105 | // join with `band` with `name` as the join key 106 | .on(|_, m, b| (m.name.to_string(), b.name.to_string())) 107 | // combine tuples of `musician` and `band` in a new relation 108 | .select(|m| m.1 == "Dream Theater") 109 | .project(|m| m.0.to_string()) 110 | .build(); 111 | 112 | assert_eq!( 113 | vec!["John Petrucci".to_string(), "Jordan Rudess".into()], 114 | music.evaluate(&dt_member)?.into_tuples() 115 | ); 116 | ``` 117 | 118 | Store views of expressions: 119 | 120 | ```rust 121 | let dt_member_view = music.store_view(dt_members)?; // view on `dt_member` 122 | let drummer_view = music.store_view( // drummers view 123 | musician 124 | .builder() 125 | .select(|m| m.instruments.contains(&Drums)) 126 | .build(), 127 | )?; 128 | 129 | // inserting more tuples: 130 | music.insert( 131 | &musician, 132 | vec![ 133 | Musician { 134 | name: "John Myung".into(), 135 | band: Some("Dream Theater".into()), 136 | instruments: vec![Guitar], 137 | }, 138 | Musician { 139 | name: "Mike Mangini".into(), 140 | band: Some("Dream Theater".into()), 141 | instruments: vec![Drums], 142 | }, 143 | ] 144 | .into(), 145 | )?; 146 | 147 | // views are up-to-date: 148 | assert_eq!( 149 | vec![ 150 | Musician { 151 | name: "Lars Ulrich".into(), 152 | band: Some("Metallica".into()), 153 | instruments: vec![Drums] 154 | }, 155 | Musician { 156 | name: "Mike Mangini".into(), 157 | band: Some("Dream Theater".into()), 158 | instruments: vec![Drums] 159 | } 160 | ], 161 | music.evaluate(&drummer_view)?.into_tuples() 162 | ); 163 | assert_eq!( 164 | vec![ 165 | "John Myung".to_string(), 166 | "John Petrucci".into(), 167 | "Jordan Rudess".into(), 168 | "Mike Mangini".into() 169 | ], 170 | music.evaluate(&dt_member_view)?.into_tuples() 171 | ); 172 | 173 | Ok(()) 174 | } 175 | ``` 176 | -------------------------------------------------------------------------------- /core/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "codd" 3 | version = "0.1.0" 4 | authors = ["Salman Saghafi "] 5 | edition = "2018" 6 | license = "MIT" 7 | description = "codd is a minimal in-memory database with relational algebraic expressions as queries." 8 | homepage = "https://github.com/salmans/codd" 9 | repository = "https://github.com/salmans/codd" 10 | keywords = ["codd", "relational-algebra", "database"] 11 | categories = ["mathematics", "database-implementations"] 12 | readme = "../README.md" 13 | 14 | [dependencies] 15 | thiserror = "^1.0" 16 | either = "^1.6" 17 | 18 | [features] 19 | unstable = [] -------------------------------------------------------------------------------- /core/examples/music.rs: -------------------------------------------------------------------------------- 1 | use codd::{Database, Error, Expression}; 2 | use either::Either; 3 | 4 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] 5 | 6 | enum Instrument { 7 | Guitar, 8 | Piano, 9 | Keyboard, 10 | Drums, 11 | Vocals, 12 | } 13 | use Instrument::*; 14 | 15 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] 16 | struct Musician { 17 | name: String, 18 | band: Option, 19 | instruments: Vec, 20 | } 21 | 22 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] 23 | struct Band { 24 | name: String, 25 | genre: String, 26 | } 27 | 28 | #[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] 29 | struct Song { 30 | title: String, 31 | artist: Either, 32 | } 33 | 34 | fn main() -> Result<(), Error> { 35 | let mut music = Database::new(); 36 | let musician = music.add_relation("musician")?; 37 | let band = music.add_relation("band")?; 38 | let song = music.add_relation("song")?; 39 | music.insert( 40 | &musician, 41 | vec![ 42 | Musician { 43 | name: "John Petrucci".into(), 44 | band: Some("Dream Theater".into()), 45 | instruments: vec![Guitar], 46 | }, 47 | Musician { 48 | name: "Taylor Swift".into(), 49 | band: None, 50 | instruments: vec![Vocals], 51 | }, 52 | Musician { 53 | name: "Conor Mason".into(), 54 | band: Some("Nothing But Thieves".into()), 55 | instruments: vec![Vocals, Guitar], 56 | }, 57 | Musician { 58 | name: "Stevie Wonder".into(), 59 | band: None, 60 | instruments: vec![Vocals, Piano], 61 | }, 62 | Musician { 63 | name: "Jordan Rudess".into(), 64 | band: Some("Dream Theater".into()), 65 | instruments: vec![Keyboard], 66 | }, 67 | Musician { 68 | name: "Alex Turner".into(), 69 | band: Some("Arctic Monkeys".into()), 70 | instruments: vec![Vocals, Guitar, Piano], 71 | }, 72 | Musician { 73 | name: "Billie Eilish".into(), 74 | band: None, 75 | instruments: vec![Vocals, Piano], 76 | }, 77 | Musician { 78 | name: "Lars Ulrich".into(), 79 | band: Some("Metallica".into()), 80 | instruments: vec![Drums], 81 | }, 82 | ] 83 | .into(), 84 | )?; 85 | 86 | music.insert( 87 | &band, 88 | vec![ 89 | Band { 90 | name: "Dream Theater".into(), 91 | genre: "Progressive Metal".into(), 92 | }, 93 | Band { 94 | name: "Nothing But Thieves".into(), 95 | genre: "Alternative Rock".into(), 96 | }, 97 | Band { 98 | name: "Metallica".into(), 99 | genre: "Heavy Metal".into(), 100 | }, 101 | Band { 102 | name: "Arctic Monkeys".into(), 103 | genre: "Indie Rock".into(), 104 | }, 105 | ] 106 | .into(), 107 | )?; 108 | 109 | music.insert( 110 | &song, 111 | vec![ 112 | Song { 113 | title: "pull me under".into(), 114 | artist: Either::Right("Dream Theater".into()), 115 | }, 116 | Song { 117 | title: "bad guy".into(), 118 | artist: Either::Left("Billie Eilish".into()), 119 | }, 120 | Song { 121 | title: "excuse me".into(), 122 | artist: Either::Left("Nothing But Thieves".into()), 123 | }, 124 | Song { 125 | title: "enter sandman".into(), 126 | artist: Either::Right("Metallica".into()), 127 | }, 128 | Song { 129 | title: "panic attack".into(), 130 | artist: Either::Right("Dream Theater".into()), 131 | }, 132 | Song { 133 | title: "shake it off".into(), 134 | artist: Either::Left("Taylor Swift".into()), 135 | }, 136 | Song { 137 | title: "r u mine".into(), 138 | artist: Either::Right("Artcic Monkeys".into()), 139 | }, 140 | Song { 141 | title: "as I am".into(), 142 | artist: Either::Right("Dream Theater".into()), 143 | }, 144 | ] 145 | .into(), 146 | )?; 147 | 148 | let guitarist_name = musician 149 | .builder() 150 | .select(|m| m.instruments.contains(&Guitar)) 151 | .project(|g| g.name.to_string()) 152 | .build(); 153 | 154 | assert_eq!( 155 | vec![ 156 | "Alex Turner".to_string(), 157 | "Conor Mason".into(), 158 | "John Petrucci".into(), 159 | ], 160 | music.evaluate(&guitarist_name)?.into_tuples() 161 | ); 162 | 163 | let dt_member = musician 164 | .builder() 165 | .with_key(|m| m.band.clone()) 166 | .join(band.builder().with_key(|b| Some(b.name.clone()))) 167 | .on(|_, m, b| (m.name.to_string(), b.name.to_string())) 168 | .select(|m| m.1 == "Dream Theater") 169 | .project(|m| m.0.to_string()) 170 | .build(); 171 | 172 | assert_eq!( 173 | vec!["John Petrucci".to_string(), "Jordan Rudess".into()], 174 | music.evaluate(&dt_member)?.into_tuples() 175 | ); 176 | 177 | let dt_member_view = music.store_view(dt_member)?; 178 | let drummer_view = music.store_view( 179 | musician 180 | .builder() 181 | .select(|m| m.instruments.contains(&Drums)) 182 | .build(), 183 | )?; 184 | 185 | music.insert( 186 | &musician, 187 | vec![ 188 | Musician { 189 | name: "John Myung".into(), 190 | band: Some("Dream Theater".into()), 191 | instruments: vec![Guitar], 192 | }, 193 | Musician { 194 | name: "Mike Mangini".into(), 195 | band: Some("Dream Theater".into()), 196 | instruments: vec![Drums], 197 | }, 198 | ] 199 | .into(), 200 | )?; 201 | 202 | assert_eq!( 203 | vec![ 204 | Musician { 205 | name: "Lars Ulrich".into(), 206 | band: Some("Metallica".into()), 207 | instruments: vec![Drums] 208 | }, 209 | Musician { 210 | name: "Mike Mangini".into(), 211 | band: Some("Dream Theater".into()), 212 | instruments: vec![Drums] 213 | } 214 | ], 215 | music.evaluate(&drummer_view)?.into_tuples() 216 | ); 217 | assert_eq!( 218 | vec![ 219 | "John Myung".to_string(), 220 | "John Petrucci".into(), 221 | "Jordan Rudess".into(), 222 | "Mike Mangini".into() 223 | ], 224 | music.evaluate(&dt_member_view)?.into_tuples() 225 | ); 226 | 227 | Ok(()) 228 | } 229 | -------------------------------------------------------------------------------- /core/src/database.rs: -------------------------------------------------------------------------------- 1 | /*! Implements a minimal database with the following features: 2 | * Relation and view instances are generic over [`Tuple`] types. 3 | * Supports incremental view update by keeping track of recently added tuples. 4 | * Relation instances monotonically grow (supports insertion but not deletion). 5 | */ 6 | mod evaluate; 7 | mod expression_ext; 8 | mod helpers; 9 | mod instance; 10 | mod validate; 11 | 12 | use crate::{ 13 | expression::{dependency, view::ViewRef, Expression, IntoExpression, Relation, View}, 14 | Error, Tuple, 15 | }; 16 | use expression_ext::ExpressionExt; 17 | pub use instance::Tuples; 18 | use std::{ 19 | cell::Cell, 20 | collections::{HashMap, HashSet}, 21 | }; 22 | 23 | use instance::{DynInstance, Instance}; 24 | 25 | /// Contains the information about an instance in the database. 26 | struct RelationEntry { 27 | /// Is the [`Instance`] containing the tuples of this relation. 28 | instance: Box, 29 | 30 | /// Contains references to the views that this relation appears in their 31 | /// expression. These are the views that depend on the content of this relation. 32 | dependent_views: HashSet, 33 | 34 | /// A flag that indicating if this relation is being stabilized. 35 | stabilizing: Cell, 36 | } 37 | 38 | impl RelationEntry { 39 | /// Creates a new [`RelationEntry`] with the given `instance`. 40 | fn new() -> Self 41 | where 42 | T: Tuple + 'static, 43 | { 44 | Self { 45 | instance: Box::new(Instance::::new()), 46 | dependent_views: HashSet::new(), 47 | stabilizing: Cell::new(false), 48 | } 49 | } 50 | 51 | /// Adds a dependency from a view (identified by `view_ref`) to this relation. 52 | fn add_dependent_view(&mut self, view_ref: ViewRef) { 53 | self.dependent_views.insert(view_ref); 54 | } 55 | } 56 | 57 | impl Clone for RelationEntry { 58 | fn clone(&self) -> Self { 59 | Self { 60 | instance: self.instance.clone_box(), 61 | dependent_views: self.dependent_views.clone(), 62 | stabilizing: self.stabilizing.clone(), 63 | } 64 | } 65 | } 66 | 67 | use instance::{DynViewInstance, ViewInstance}; 68 | 69 | /// Contains the information about a view in the database. 70 | struct ViewEntry { 71 | /// Is the underlying [`Instance`] storing the tuples of the view. 72 | instance: Box, 73 | 74 | /// Contains references (relation names) to the relations that 75 | /// appear in the view's expression. These are the relations to 76 | /// which the content of this view depends. 77 | dependee_relations: HashSet, 78 | 79 | /// Contains references to the views that appear in the view's 80 | /// expression. These are the views to which the content of this 81 | /// view depends. 82 | dependee_views: HashSet, 83 | 84 | /// Contains references to the views that this view appears in 85 | /// their expressions. These are the views that depend on the 86 | /// content of this view. 87 | dependent_views: HashSet, 88 | 89 | /// A flag that indicating if this view is being stabilized. 90 | stabilizing: Cell, 91 | } 92 | 93 | impl ViewEntry { 94 | /// Creates a new [`ViewEntry`] with the given [`ViewInstance`]. 95 | fn new(view_instance: ViewInstance) -> Self 96 | where 97 | T: Tuple + 'static, 98 | E: ExpressionExt + 'static, 99 | { 100 | Self { 101 | instance: Box::new(view_instance), 102 | dependee_relations: HashSet::new(), 103 | dependee_views: HashSet::new(), 104 | dependent_views: HashSet::new(), 105 | stabilizing: Cell::new(false), 106 | } 107 | } 108 | 109 | /// Adds a dependency from a view (identified by `view_ref`) to this view. 110 | fn add_dependent_view(&mut self, view_ref: ViewRef) { 111 | self.dependent_views.insert(view_ref); 112 | } 113 | } 114 | 115 | impl Clone for ViewEntry { 116 | fn clone(&self) -> Self { 117 | Self { 118 | instance: self.instance.clone_box(), 119 | dependee_views: self.dependee_views.clone(), 120 | dependee_relations: self.dependee_relations.clone(), 121 | dependent_views: self.dependent_views.clone(), 122 | stabilizing: self.stabilizing.clone(), 123 | } 124 | } 125 | } 126 | 127 | /// Stores data in relation instances and implements incremental view maintenance over them. 128 | /// 129 | /// **Example**: 130 | /// ```rust 131 | /// use codd::{Database, expression::Select}; 132 | /// 133 | /// // create a new database: 134 | /// let mut db = Database::new(); 135 | /// 136 | /// // add a new relation "numbers" with tuples of type `u32` to `db`: 137 | /// let numbers = db.add_relation::("numbers").unwrap(); 138 | /// 139 | /// // create a view for odd numbers in `numbers`: 140 | /// let odds = db.store_view(Select::new(numbers.clone(), |i| i % 2 == 1)).unwrap(); 141 | /// 142 | /// // insert some items in `numbers`: 143 | /// db.insert(&numbers, vec![4, 8, 15, 16, 23, 42].into()).unwrap(); 144 | /// 145 | /// // query `db` for `numbers` and `odds`: 146 | /// let numbers_data = db.evaluate(&numbers).unwrap(); 147 | /// let odds_data = db.evaluate(&odds).unwrap(); 148 | /// 149 | /// assert_eq!(vec![4, 8, 15, 16, 23, 42], numbers_data.into_tuples()); 150 | /// assert_eq!(vec![15, 23], odds_data.into_tuples()); 151 | /// 152 | /// // go nuts: 153 | /// db.insert(&numbers, vec![8, 888, 23, 1001, 8008, 101].into()).unwrap(); 154 | /// 155 | /// // query `db` again: 156 | /// let numbers_data = db.evaluate(&numbers).unwrap(); 157 | /// let odds_data = db.evaluate(&odds).unwrap(); 158 | /// 159 | /// assert_eq!(vec![4, 8, 15, 16, 23, 42, 101, 888, 1001, 8008], numbers_data.into_tuples()); 160 | /// assert_eq!(vec![15, 23, 101, 1001], odds_data.into_tuples()); 161 | /// ``` 162 | pub struct Database { 163 | relations: HashMap, 164 | views: HashMap, 165 | view_counter: i32, 166 | } 167 | 168 | impl Database { 169 | /// Creates a new empty database. 170 | pub fn new() -> Self { 171 | Self { 172 | relations: HashMap::new(), 173 | views: HashMap::new(), 174 | view_counter: 0, 175 | } 176 | } 177 | 178 | /// Evaluates `expression` in the database and returns the result in a [`Tuples`] object. 179 | pub fn evaluate(&self, expression: &E) -> Result, Error> 180 | where 181 | T: Tuple, 182 | E: ExpressionExt, 183 | { 184 | expression.collect_recent(&evaluate::Evaluator::new(self)) 185 | } 186 | 187 | /// Adds a new relation instance identified by `name` to the database and returns a 188 | /// [`Relation`] object that can be used to access the instance. 189 | pub fn add_relation(&mut self, name: &str) -> Result, Error> 190 | where 191 | T: Tuple + 'static, 192 | { 193 | if !self.relations.contains_key(name) { 194 | self.relations 195 | .insert(name.into(), RelationEntry::new::()); 196 | Ok(Relation::new(name)) 197 | } else { 198 | Err(Error::InstanceExists { name: name.into() }) 199 | } 200 | } 201 | 202 | /// Inserts tuples in the instance corresponding to `relation`. 203 | pub fn insert(&self, relation: &Relation, tuples: Tuples) -> Result<(), Error> 204 | where 205 | T: Tuple + 'static, 206 | { 207 | let instance = self.relation_instance(&relation)?; 208 | instance.insert(tuples); 209 | Ok(()) 210 | } 211 | 212 | /// Returns the instance for `relation` if it exists. 213 | fn relation_instance(&self, relation: &Relation) -> Result<&Instance, Error> 214 | where 215 | T: Tuple + 'static, 216 | { 217 | let result = self 218 | .relations 219 | .get(relation.name()) 220 | .and_then(|r| r.instance.as_any().downcast_ref::>()) 221 | .ok_or(Error::InstanceNotFound { 222 | name: relation.name().into(), 223 | })?; 224 | Ok(result) 225 | } 226 | 227 | /// Stores a new view over `expression` and returns a [`View`] objeect that can be 228 | /// evaluated as a view. 229 | pub fn store_view(&mut self, expression: I) -> Result, Error> 230 | where 231 | T: Tuple + 'static, 232 | E: ExpressionExt + 'static, 233 | I: IntoExpression, 234 | { 235 | let expression = expression.into_expression(); 236 | // `validator` rejects views over `Difference` (not supported): 237 | validate::validate_view_expression(&expression)?; 238 | 239 | let (relation_deps, view_deps) = dependency::expression_dependencies(&expression); 240 | 241 | let mut entry = ViewEntry::new(ViewInstance::new(expression)); 242 | let reference = ViewRef(self.view_counter); 243 | 244 | // track relation dependencies of this view: 245 | for r in relation_deps.into_iter() { 246 | if let Some(rs) = self.relations.get_mut(&r) { 247 | rs.add_dependent_view(reference.clone()) 248 | } 249 | entry.dependee_relations.insert(r); 250 | } 251 | 252 | // track view dependencies of this view: 253 | for r in view_deps.into_iter() { 254 | if let Some(rs) = self.views.get_mut(&r) { 255 | rs.add_dependent_view(reference.clone()) 256 | } 257 | entry.dependee_views.insert(r.clone()); 258 | } 259 | 260 | entry.instance.initialize(self)?; 261 | 262 | self.views.insert(reference.clone(), entry); 263 | self.view_counter += 1; 264 | 265 | Ok(View::new(reference)) 266 | } 267 | 268 | /// Returns the instance for `view` if it exists. 269 | fn view_instance(&self, view: &View) -> Result<&Instance, Error> 270 | where 271 | T: Tuple + 'static, 272 | E: Expression + 'static, 273 | { 274 | let result = self 275 | .views 276 | .get(view.reference()) 277 | .and_then(|v| v.instance.as_any().downcast_ref::>()) 278 | .ok_or(Error::InstanceNotFound { 279 | name: format!("{:?}", view.reference()), 280 | })?; 281 | Ok(result.instance()) 282 | } 283 | 284 | /// Stabilizes the view identified by `view_ref` by stabilizing its dependees and 285 | /// dependencies. It also applies `changed()` on the view's instance, moving all 286 | /// relevant `to_add` tuples to `recent` and `recent` tuples to `stable`. 287 | fn stabilize_view(&self, view_ref: &ViewRef) -> Result<(), Error> { 288 | if let Some(entry) = self.views.get(view_ref) { 289 | // do nothing if the view is already stabilizing: 290 | if entry.stabilizing.get() { 291 | return Ok(()); 292 | } 293 | 294 | entry.stabilizing.set(true); 295 | 296 | for r in entry.dependee_relations.iter() { 297 | self.stabilize_relation(r)?; 298 | } 299 | for r in entry.dependee_views.iter() { 300 | self.stabilize_view(r)?; 301 | } 302 | 303 | while entry.instance.instance().changed() { 304 | for r in entry.dependent_views.iter() { 305 | self.views.get(r).unwrap().instance.stabilize(&self)?; 306 | } 307 | } 308 | 309 | entry.stabilizing.set(false); 310 | } 311 | 312 | Ok(()) 313 | } 314 | 315 | /// Stabilizes the relation identified by `name`. It also stabilizes 316 | /// all views depending on this `name`. 317 | fn stabilize_relation(&self, name: &str) -> Result<(), Error> { 318 | if let Some(entry) = self.relations.get(name) { 319 | // do nothing if relation is already stabilizing: 320 | if entry.stabilizing.get() { 321 | return Ok(()); 322 | } 323 | 324 | entry.stabilizing.set(true); 325 | 326 | while entry.instance.changed() { 327 | for r in entry.dependent_views.iter() { 328 | self.views.get(r).unwrap().instance.stabilize(&self)?; 329 | } 330 | } 331 | 332 | entry.stabilizing.set(false); 333 | } 334 | 335 | Ok(()) 336 | } 337 | } 338 | 339 | impl Default for Database { 340 | fn default() -> Self { 341 | Self::new() 342 | } 343 | } 344 | 345 | impl Clone for Database { 346 | fn clone(&self) -> Self { 347 | let mut relations = HashMap::new(); 348 | let mut views = HashMap::new(); 349 | 350 | self.relations.iter().for_each(|(k, v)| { 351 | relations.insert(k.clone(), v.clone()); 352 | }); 353 | self.views.iter().for_each(|(k, v)| { 354 | views.insert(k.clone(), v.clone()); 355 | }); 356 | 357 | Self { 358 | relations, 359 | views, 360 | view_counter: self.view_counter, 361 | } 362 | } 363 | } 364 | 365 | #[cfg(test)] 366 | mod tests { 367 | use super::*; 368 | use crate::expression::{Join, Project, Select}; 369 | 370 | #[test] 371 | fn test_insert() { 372 | { 373 | let mut database = Database::new(); 374 | let r = database.add_relation::("r").unwrap(); 375 | assert!(database.insert(&r, vec![1, 2, 3].into()).is_ok()); 376 | assert_eq!( 377 | Tuples::::from(vec![1, 2, 3]), 378 | database.relation_instance(&r).unwrap().to_add()[0] 379 | ); 380 | } 381 | { 382 | let mut database = Database::new(); 383 | let r = database.add_relation::("r").unwrap(); 384 | assert!(database.insert(&r, vec![1, 2, 3].into()).is_ok()); 385 | assert!(database.insert(&r, vec![1, 4].into()).is_ok()); 386 | assert_eq!( 387 | Tuples::::from(vec![1, 2, 3]), 388 | database.relation_instance(&r).unwrap().to_add()[0] 389 | ); 390 | assert_eq!( 391 | Tuples::::from(vec![1, 4]), 392 | database.relation_instance(&r).unwrap().to_add()[1] 393 | ); 394 | } 395 | { 396 | let database = Database::new(); 397 | let r = Database::new().add_relation("r").unwrap(); // dummy database 398 | assert!(database.insert(&r, vec![1, 2, 3].into()).is_err()); 399 | } 400 | } 401 | 402 | #[test] 403 | fn test_database_new() { 404 | let database = Database::new(); 405 | assert!(database.relations.is_empty()); 406 | assert!(database.views.is_empty()); 407 | assert_eq!(0, database.view_counter); 408 | } 409 | 410 | #[test] 411 | fn test_clone_database() { 412 | { 413 | let database = Database::new(); 414 | let cloned = database.clone(); 415 | assert!(cloned.relations.is_empty()); 416 | assert!(cloned.views.is_empty()); 417 | assert_eq!(0, cloned.view_counter); 418 | } 419 | { 420 | let mut database = Database::new(); 421 | let a = database.add_relation::("a").unwrap(); 422 | let v = database.store_view(a.clone()).unwrap(); 423 | database.insert(&a, vec![1, 2, 3].into()).unwrap(); 424 | 425 | let cloned = database.clone(); 426 | database.insert(&a, vec![1, 4].into()).unwrap(); 427 | 428 | assert_eq!( 429 | vec![1, 2, 3, 4], 430 | database.evaluate(&v).unwrap().into_tuples() 431 | ); 432 | assert_eq!(vec![1, 2, 3], cloned.evaluate(&v).unwrap().into_tuples()); 433 | 434 | cloned.insert(&a, vec![1, 5].into()).unwrap(); 435 | assert_eq!( 436 | vec![1, 2, 3, 4], 437 | database.evaluate(&v).unwrap().into_tuples() 438 | ); 439 | assert_eq!(vec![1, 2, 3, 5], cloned.evaluate(&v).unwrap().into_tuples()); 440 | } 441 | } 442 | 443 | #[test] 444 | fn test_add_relation() { 445 | let mut database = Database::new(); 446 | assert!(database.add_relation::("a").is_ok()); 447 | assert!(database.add_relation::("a").is_err()); // duplicate 448 | assert!(database.relations.get("a").is_some()); 449 | assert!(database.relations.get("b").is_none()); 450 | } 451 | 452 | #[test] 453 | fn test_get_relation() { 454 | let mut database = Database::new(); 455 | let mut dummy = Database::new(); 456 | let relation_i32 = database.add_relation::("a").unwrap(); 457 | let relation_string = dummy.add_relation::("a").unwrap(); 458 | 459 | assert!(database.relation_instance(&relation_i32).is_ok()); 460 | assert!(database.relation_instance(&relation_string).is_err()); 461 | } 462 | 463 | #[test] 464 | fn test_store_view() { 465 | { 466 | let mut database = Database::new(); 467 | let a = database.add_relation::("a").unwrap(); 468 | database.store_view(a.clone()).unwrap(); 469 | assert!(database.views.get(&ViewRef(0)).is_some()); 470 | assert!(database.views.get(&ViewRef(1000)).is_none()); 471 | } 472 | { 473 | let mut database = Database::new(); 474 | let _ = database.add_relation::("a").unwrap(); 475 | database.store_view(Relation::::new("a")).unwrap(); 476 | assert!(database.views.get(&ViewRef(0)).is_some()); 477 | assert!(database.views.get(&ViewRef(1000)).is_none()); 478 | } 479 | { 480 | let mut database = Database::new(); 481 | assert!(database.store_view(Relation::::new("a")).is_err()); 482 | } 483 | 484 | { 485 | let mut database = Database::new(); 486 | let a = database.add_relation::("a").unwrap(); 487 | database.store_view(Select::new(a, |&t| t != 0)).unwrap(); 488 | 489 | assert!(database.views.get(&ViewRef(0)).is_some()); 490 | assert!(database.views.get(&ViewRef(1000)).is_none()); 491 | } 492 | 493 | { 494 | let mut database = Database::new(); 495 | let a = database.add_relation::("a").unwrap(); 496 | database.store_view(Project::new(a, |t| t + 1)).unwrap(); 497 | 498 | assert!(database.views.get(&ViewRef(0)).is_some()); 499 | assert!(database.views.get(&ViewRef(1000)).is_none()); 500 | } 501 | 502 | { 503 | let mut database = Database::new(); 504 | let a = database.add_relation::<(i32, i32)>("a").unwrap(); 505 | let b = database.add_relation::<(i32, i32)>("b").unwrap(); 506 | database 507 | .store_view(Join::new(a, b, |t| t.0, |t| t.0, |_, &l, &r| (l, r))) 508 | .unwrap(); 509 | 510 | assert!(database.views.get(&ViewRef(0)).is_some()); 511 | assert!(database.views.get(&ViewRef(1000)).is_none()); 512 | } 513 | 514 | { 515 | let mut database = Database::new(); 516 | let a = database.add_relation::("a").unwrap(); 517 | let view = database.store_view(a).unwrap(); 518 | 519 | database.store_view(view).unwrap(); 520 | assert!(database.views.get(&ViewRef(0)).is_some()); 521 | assert!(database.views.get(&ViewRef(1)).is_some()); 522 | assert!(database.views.get(&ViewRef(1000)).is_none()); 523 | } 524 | } 525 | 526 | #[test] 527 | fn test_get_view() { 528 | let mut database = Database::new(); 529 | let _ = database.add_relation::("a").unwrap(); 530 | let view = database.store_view(Relation::::new("a")).unwrap(); 531 | 532 | assert!(database.view_instance(&view).is_ok()); 533 | } 534 | } 535 | -------------------------------------------------------------------------------- /core/src/database/expression_ext.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | expression::{view::ViewRef, *}, 3 | Error, Tuple, Tuples, 4 | }; 5 | 6 | /// Extends [`Expression`] with methods required for incremental database update. 7 | pub trait ExpressionExt: Expression { 8 | /// Visits this node by a [`RecentCollector`] and returns the recent tuples of the 9 | /// database according to the logic implemented by `collector`. 10 | /// 11 | /// **Note**: 12 | /// Recent tuples are those tuples that got inserted into relation instances of a 13 | /// database before any dependent (materialized) views are updated. 14 | fn collect_recent(&self, collector: &C) -> Result, Error> 15 | where 16 | C: RecentCollector; 17 | 18 | /// Visits this node by a [`StableCollector`] and returns the stable tuples of the 19 | /// database according to the logic implemented by `collector`. 20 | /// 21 | /// **Note**: 22 | /// Stable tuples are those tuples that have already been reflected in (materialized) 23 | /// views that are affected by those tuples. 24 | fn collect_stable(&self, collector: &C) -> Result>, Error> 25 | where 26 | C: StableCollector; 27 | 28 | /// Returns an iterator over the relation dependencies of this expression. These are 29 | /// the name of relations that show up in the receiver expression. 30 | fn relation_dependencies(&self) -> &[String]; 31 | 32 | /// Returns an iterator over the view dependencies of this expression. These are 33 | /// references to views that show up in the receiver expression. 34 | fn view_dependencies(&self) -> &[ViewRef]; 35 | } 36 | 37 | impl ExpressionExt for &E 38 | where 39 | T: Tuple, 40 | E: ExpressionExt, 41 | { 42 | fn collect_recent(&self, collector: &C) -> Result, Error> 43 | where 44 | C: RecentCollector, 45 | { 46 | (*self).collect_recent(collector) 47 | } 48 | 49 | fn collect_stable(&self, collector: &C) -> Result>, Error> 50 | where 51 | C: StableCollector, 52 | { 53 | (*self).collect_stable(collector) 54 | } 55 | 56 | fn relation_dependencies(&self) -> &[String] { 57 | (*self).relation_dependencies() 58 | } 59 | 60 | fn view_dependencies(&self) -> &[ViewRef] { 61 | (*self).view_dependencies() 62 | } 63 | } 64 | 65 | impl ExpressionExt for Box 66 | where 67 | T: Tuple, 68 | E: ExpressionExt, 69 | { 70 | fn collect_recent(&self, collector: &C) -> Result, Error> 71 | where 72 | C: RecentCollector, 73 | { 74 | (**self).collect_recent(collector) 75 | } 76 | 77 | fn collect_stable(&self, collector: &C) -> Result>, Error> 78 | where 79 | C: StableCollector, 80 | { 81 | (**self).collect_stable(collector) 82 | } 83 | 84 | fn relation_dependencies(&self) -> &[String] { 85 | (**self).relation_dependencies() 86 | } 87 | 88 | fn view_dependencies(&self) -> &[ViewRef] { 89 | (**self).view_dependencies() 90 | } 91 | } 92 | 93 | /// Is the trait of objects that implement the logic for collecting the recent tuples of 94 | /// a database when the visited expression is evaluated. 95 | pub trait RecentCollector { 96 | /// Collects the recent tuples for the [`Full`] expression. 97 | fn collect_full(&self, full: &Full) -> Result, Error> 98 | where 99 | T: Tuple; 100 | 101 | /// Collects the recent tuples for the [`Empty`] expression. 102 | fn collect_empty(&self, empty: &Empty) -> Result, Error> 103 | where 104 | T: Tuple; 105 | 106 | /// Collects the recent tuples for a [`Singleton`] expression. 107 | fn collect_singleton(&self, singleton: &Singleton) -> Result, Error> 108 | where 109 | T: Tuple; 110 | 111 | /// Collects the recent tuples for a [`Relation`] expression. 112 | fn collect_relation(&self, relation: &Relation) -> Result, Error> 113 | where 114 | T: Tuple + 'static; 115 | 116 | /// Collects the recent tuples for a [`Select`] expression. 117 | fn collect_select(&self, select: &Select) -> Result, Error> 118 | where 119 | T: Tuple, 120 | E: ExpressionExt; 121 | 122 | /// Collects the recent tuples for a [`Union`] expression. 123 | fn collect_union(&self, union: &Union) -> Result, Error> 124 | where 125 | T: Tuple, 126 | L: ExpressionExt, 127 | R: ExpressionExt; 128 | 129 | /// Collects the recent tuples for an [`Intersect`] expression. 130 | fn collect_intersect( 131 | &self, 132 | intersect: &Intersect, 133 | ) -> Result, Error> 134 | where 135 | T: Tuple, 136 | L: ExpressionExt, 137 | R: ExpressionExt; 138 | 139 | /// Collects the recent tuples for a [`Difference`] expression. 140 | fn collect_difference( 141 | &self, 142 | difference: &Difference, 143 | ) -> Result, Error> 144 | where 145 | T: Tuple, 146 | L: ExpressionExt, 147 | R: ExpressionExt; 148 | 149 | /// Collects the recent tuples for a [`Project`] expression. 150 | fn collect_project(&self, project: &Project) -> Result, Error> 151 | where 152 | T: Tuple, 153 | S: Tuple, 154 | E: ExpressionExt; 155 | 156 | /// Collects the recent tuples for a [`Product`] expression. 157 | fn collect_product( 158 | &self, 159 | product: &Product, 160 | ) -> Result, Error> 161 | where 162 | L: Tuple, 163 | R: Tuple, 164 | T: Tuple, 165 | Left: ExpressionExt, 166 | Right: ExpressionExt; 167 | 168 | /// Collects the recent tuples for a [`Join`] expression. 169 | fn collect_join( 170 | &self, 171 | join: &Join, 172 | ) -> Result, Error> 173 | where 174 | K: Tuple, 175 | L: Tuple, 176 | R: Tuple, 177 | T: Tuple, 178 | Left: ExpressionExt, 179 | Right: ExpressionExt; 180 | 181 | /// Collects the recent tuples for a [`View`] expression. 182 | fn collect_view(&self, view: &View) -> Result, Error> 183 | where 184 | T: Tuple + 'static, 185 | E: ExpressionExt + 'static; 186 | } 187 | 188 | /// Is the trait of objects that implement the logic for collecting the stable tuples of 189 | /// a database when the visited expression is evaluated. 190 | pub trait StableCollector { 191 | /// Collects the stable tuples for the [`Full`] expression. 192 | fn collect_full(&self, full: &Full) -> Result>, Error> 193 | where 194 | T: Tuple; 195 | 196 | /// Collects the stable tuples for the [`Empty`] expression. 197 | fn collect_empty(&self, empty: &Empty) -> Result>, Error> 198 | where 199 | T: Tuple; 200 | 201 | /// Collects the stable tuples for a [`Singleton`] expression. 202 | fn collect_singleton(&self, singleton: &Singleton) -> Result>, Error> 203 | where 204 | T: Tuple; 205 | 206 | /// Collects the stable tuples for a [`Relation`] expression. 207 | fn collect_relation(&self, relation: &Relation) -> Result>, Error> 208 | where 209 | T: Tuple + 'static; 210 | 211 | /// Collects the stable tuples for a [`Select`] expression. 212 | fn collect_select(&self, select: &Select) -> Result>, Error> 213 | where 214 | T: Tuple, 215 | E: ExpressionExt; 216 | 217 | /// Collects the stable tuples for a [`Union`] expression. 218 | fn collect_union(&self, union: &Union) -> Result>, Error> 219 | where 220 | T: Tuple, 221 | L: ExpressionExt, 222 | R: ExpressionExt; 223 | 224 | /// Collects the stable tuples for an [`Intersect`] expression. 225 | fn collect_intersect( 226 | &self, 227 | intersect: &Intersect, 228 | ) -> Result>, Error> 229 | where 230 | T: Tuple, 231 | L: ExpressionExt, 232 | R: ExpressionExt; 233 | 234 | /// Collects the stable tuples for a [`Difference`] expression. 235 | fn collect_difference( 236 | &self, 237 | difference: &Difference, 238 | ) -> Result>, Error> 239 | where 240 | T: Tuple, 241 | L: ExpressionExt, 242 | R: ExpressionExt; 243 | 244 | /// Collects the stable tuples for a [`Project`] expression. 245 | fn collect_project(&self, project: &Project) -> Result>, Error> 246 | where 247 | T: Tuple, 248 | S: Tuple, 249 | E: ExpressionExt; 250 | 251 | /// Collects the stable tuples for a [`Product`] expression. 252 | fn collect_product( 253 | &self, 254 | product: &Product, 255 | ) -> Result>, Error> 256 | where 257 | L: Tuple, 258 | R: Tuple, 259 | T: Tuple, 260 | Left: ExpressionExt, 261 | Right: ExpressionExt; 262 | 263 | /// Collects the stable tuples for a [`Join`] expression. 264 | fn collect_join( 265 | &self, 266 | join: &Join, 267 | ) -> Result>, Error> 268 | where 269 | K: Tuple, 270 | L: Tuple, 271 | R: Tuple, 272 | T: Tuple, 273 | Left: ExpressionExt, 274 | Right: ExpressionExt; 275 | 276 | /// Collects the stable tuples for a [`View`] expression. 277 | fn collect_view(&self, view: &View) -> Result>, Error> 278 | where 279 | T: Tuple + 'static, 280 | E: ExpressionExt + 'static; 281 | } 282 | 283 | mod r#impl { 284 | use super::{ExpressionExt, RecentCollector, StableCollector}; 285 | use crate::{ 286 | expression::view::{View, ViewRef}, 287 | Error, Tuple, Tuples, 288 | }; 289 | 290 | impl ExpressionExt for View 291 | where 292 | T: Tuple + 'static, 293 | E: ExpressionExt + 'static, 294 | { 295 | fn collect_recent(&self, collector: &C) -> Result, Error> 296 | where 297 | C: RecentCollector, 298 | { 299 | collector.collect_view(&self) 300 | } 301 | 302 | fn collect_stable(&self, collector: &C) -> Result>, Error> 303 | where 304 | C: StableCollector, 305 | { 306 | collector.collect_view(&self) 307 | } 308 | 309 | fn relation_dependencies(&self) -> &[String] { 310 | &[] 311 | } 312 | 313 | fn view_dependencies(&self) -> &[ViewRef] { 314 | self.view_deps() 315 | } 316 | } 317 | 318 | use crate::expression::Intersect; 319 | 320 | impl ExpressionExt for Intersect 321 | where 322 | T: Tuple, 323 | L: ExpressionExt, 324 | R: ExpressionExt, 325 | { 326 | fn collect_recent(&self, collector: &C) -> Result, Error> 327 | where 328 | C: RecentCollector, 329 | { 330 | collector.collect_intersect(&self) 331 | } 332 | 333 | fn collect_stable(&self, collector: &C) -> Result>, Error> 334 | where 335 | C: StableCollector, 336 | { 337 | collector.collect_intersect(&self) 338 | } 339 | 340 | fn relation_dependencies(&self) -> &[String] { 341 | self.relation_deps() 342 | } 343 | 344 | fn view_dependencies(&self) -> &[ViewRef] { 345 | self.view_deps() 346 | } 347 | } 348 | 349 | use crate::expression::Union; 350 | 351 | impl ExpressionExt for Union 352 | where 353 | T: Tuple, 354 | L: ExpressionExt, 355 | R: ExpressionExt, 356 | { 357 | fn collect_recent(&self, collector: &C) -> Result, Error> 358 | where 359 | C: RecentCollector, 360 | { 361 | collector.collect_union(&self) 362 | } 363 | 364 | fn collect_stable(&self, collector: &C) -> Result>, Error> 365 | where 366 | C: StableCollector, 367 | { 368 | collector.collect_union(&self) 369 | } 370 | 371 | fn relation_dependencies(&self) -> &[String] { 372 | self.relation_deps() 373 | } 374 | 375 | fn view_dependencies(&self) -> &[ViewRef] { 376 | self.view_deps() 377 | } 378 | } 379 | 380 | use crate::expression::Difference; 381 | 382 | impl ExpressionExt for Difference 383 | where 384 | T: Tuple, 385 | L: ExpressionExt, 386 | R: ExpressionExt, 387 | { 388 | fn collect_recent(&self, collector: &C) -> Result, Error> 389 | where 390 | C: RecentCollector, 391 | { 392 | collector.collect_difference(&self) 393 | } 394 | 395 | fn collect_stable(&self, collector: &C) -> Result>, Error> 396 | where 397 | C: StableCollector, 398 | { 399 | collector.collect_difference(&self) 400 | } 401 | 402 | fn relation_dependencies(&self) -> &[String] { 403 | self.relation_deps() 404 | } 405 | 406 | fn view_dependencies(&self) -> &[ViewRef] { 407 | self.view_deps() 408 | } 409 | } 410 | 411 | use crate::expression::Empty; 412 | 413 | impl ExpressionExt for Empty 414 | where 415 | T: Tuple, 416 | { 417 | fn collect_recent(&self, collector: &C) -> Result, Error> 418 | where 419 | C: RecentCollector, 420 | { 421 | collector.collect_empty(&self) 422 | } 423 | 424 | fn collect_stable(&self, collector: &C) -> Result>, Error> 425 | where 426 | C: StableCollector, 427 | { 428 | collector.collect_empty(&self) 429 | } 430 | 431 | fn relation_dependencies(&self) -> &[String] { 432 | &[] 433 | } 434 | 435 | fn view_dependencies(&self) -> &[ViewRef] { 436 | &[] 437 | } 438 | } 439 | 440 | use crate::expression::Full; 441 | 442 | impl ExpressionExt for Full 443 | where 444 | T: Tuple, 445 | { 446 | fn collect_recent(&self, collector: &C) -> Result, Error> 447 | where 448 | C: RecentCollector, 449 | { 450 | collector.collect_full(&self) 451 | } 452 | 453 | fn collect_stable(&self, collector: &C) -> Result>, Error> 454 | where 455 | C: StableCollector, 456 | { 457 | collector.collect_full(&self) 458 | } 459 | 460 | fn relation_dependencies(&self) -> &[String] { 461 | &[] 462 | } 463 | 464 | fn view_dependencies(&self) -> &[ViewRef] { 465 | &[] 466 | } 467 | } 468 | 469 | use crate::expression::Join; 470 | 471 | impl ExpressionExt for Join 472 | where 473 | K: Tuple, 474 | L: Tuple, 475 | R: Tuple, 476 | T: Tuple, 477 | Left: ExpressionExt, 478 | Right: ExpressionExt, 479 | { 480 | fn collect_recent(&self, collector: &C) -> Result, Error> 481 | where 482 | C: RecentCollector, 483 | { 484 | collector.collect_join(&self) 485 | } 486 | 487 | fn collect_stable(&self, collector: &C) -> Result>, Error> 488 | where 489 | C: StableCollector, 490 | { 491 | collector.collect_join(&self) 492 | } 493 | 494 | fn relation_dependencies(&self) -> &[String] { 495 | self.relation_deps() 496 | } 497 | 498 | fn view_dependencies(&self) -> &[ViewRef] { 499 | self.view_deps() 500 | } 501 | } 502 | 503 | use crate::expression::Mono; 504 | 505 | impl ExpressionExt for Mono { 506 | fn collect_recent(&self, collector: &C) -> Result, Error> 507 | where 508 | C: RecentCollector, 509 | { 510 | match self { 511 | Mono::Full(exp) => exp.collect_recent(collector), 512 | Mono::Empty(exp) => exp.collect_recent(collector), 513 | Mono::Singleton(exp) => exp.collect_recent(collector), 514 | Mono::Relation(exp) => exp.collect_recent(collector), 515 | Mono::Select(exp) => exp.collect_recent(collector), 516 | Mono::Project(exp) => exp.collect_recent(collector), 517 | Mono::Union(exp) => exp.collect_recent(collector), 518 | Mono::Intersect(exp) => exp.collect_recent(collector), 519 | Mono::Difference(exp) => exp.collect_recent(collector), 520 | Mono::Product(exp) => exp.collect_recent(collector), 521 | Mono::Join(exp) => exp.collect_recent(collector), 522 | Mono::View(exp) => exp.collect_recent(collector), 523 | } 524 | } 525 | fn collect_stable(&self, collector: &C) -> Result>, Error> 526 | where 527 | C: StableCollector, 528 | { 529 | match self { 530 | Mono::Full(exp) => exp.collect_stable(collector), 531 | Mono::Empty(exp) => exp.collect_stable(collector), 532 | Mono::Singleton(exp) => exp.collect_stable(collector), 533 | Mono::Relation(exp) => exp.collect_stable(collector), 534 | Mono::Select(exp) => exp.collect_stable(collector), 535 | Mono::Project(exp) => exp.collect_stable(collector), 536 | Mono::Union(exp) => exp.collect_stable(collector), 537 | Mono::Intersect(exp) => exp.collect_stable(collector), 538 | Mono::Difference(exp) => exp.collect_stable(collector), 539 | Mono::Product(exp) => exp.collect_stable(collector), 540 | Mono::Join(exp) => exp.collect_stable(collector), 541 | Mono::View(exp) => exp.collect_stable(collector), 542 | } 543 | } 544 | 545 | fn relation_dependencies(&self) -> &[String] { 546 | match self { 547 | Mono::Full(exp) => exp.relation_dependencies(), 548 | Mono::Empty(exp) => exp.relation_dependencies(), 549 | Mono::Singleton(exp) => exp.relation_dependencies(), 550 | Mono::Relation(exp) => exp.relation_dependencies(), 551 | Mono::Select(exp) => exp.relation_dependencies(), 552 | Mono::Project(exp) => exp.relation_dependencies(), 553 | Mono::Union(exp) => exp.relation_dependencies(), 554 | Mono::Intersect(exp) => exp.relation_dependencies(), 555 | Mono::Difference(exp) => exp.relation_dependencies(), 556 | Mono::Product(exp) => exp.relation_dependencies(), 557 | Mono::Join(exp) => exp.relation_dependencies(), 558 | Mono::View(exp) => exp.relation_dependencies(), 559 | } 560 | } 561 | 562 | fn view_dependencies(&self) -> &[ViewRef] { 563 | match self { 564 | Mono::Full(exp) => exp.view_dependencies(), 565 | Mono::Empty(exp) => exp.view_dependencies(), 566 | Mono::Singleton(exp) => exp.view_dependencies(), 567 | Mono::Relation(exp) => exp.view_dependencies(), 568 | Mono::Select(exp) => exp.view_dependencies(), 569 | Mono::Project(exp) => exp.view_dependencies(), 570 | Mono::Union(exp) => exp.view_dependencies(), 571 | Mono::Intersect(exp) => exp.view_dependencies(), 572 | Mono::Difference(exp) => exp.view_dependencies(), 573 | Mono::Product(exp) => exp.view_dependencies(), 574 | Mono::Join(exp) => exp.view_dependencies(), 575 | Mono::View(exp) => exp.view_dependencies(), 576 | } 577 | } 578 | } 579 | 580 | use crate::expression::Product; 581 | 582 | impl ExpressionExt for Product 583 | where 584 | L: Tuple, 585 | R: Tuple, 586 | T: Tuple, 587 | Left: ExpressionExt, 588 | Right: ExpressionExt, 589 | { 590 | fn collect_recent(&self, collector: &C) -> Result, Error> 591 | where 592 | C: RecentCollector, 593 | { 594 | collector.collect_product(&self) 595 | } 596 | 597 | fn collect_stable(&self, collector: &C) -> Result>, Error> 598 | where 599 | C: StableCollector, 600 | { 601 | collector.collect_product(&self) 602 | } 603 | 604 | fn relation_dependencies(&self) -> &[String] { 605 | self.relation_deps() 606 | } 607 | 608 | fn view_dependencies(&self) -> &[ViewRef] { 609 | self.view_deps() 610 | } 611 | } 612 | 613 | use crate::expression::Project; 614 | 615 | impl ExpressionExt for Project 616 | where 617 | S: Tuple, 618 | T: Tuple, 619 | E: ExpressionExt, 620 | { 621 | fn collect_recent(&self, collector: &C) -> Result, Error> 622 | where 623 | C: RecentCollector, 624 | { 625 | collector.collect_project(&self) 626 | } 627 | 628 | fn collect_stable(&self, collector: &C) -> Result>, Error> 629 | where 630 | C: StableCollector, 631 | { 632 | collector.collect_project(&self) 633 | } 634 | 635 | fn relation_dependencies(&self) -> &[String] { 636 | self.relation_deps() 637 | } 638 | 639 | fn view_dependencies(&self) -> &[ViewRef] { 640 | self.view_deps() 641 | } 642 | } 643 | 644 | use crate::expression::Relation; 645 | 646 | impl ExpressionExt for Relation 647 | where 648 | T: Tuple + 'static, 649 | { 650 | fn collect_recent(&self, collector: &C) -> Result, Error> 651 | where 652 | C: RecentCollector, 653 | { 654 | collector.collect_relation(&self) 655 | } 656 | 657 | fn collect_stable(&self, collector: &C) -> Result>, Error> 658 | where 659 | C: StableCollector, 660 | { 661 | collector.collect_relation(&self) 662 | } 663 | 664 | fn relation_dependencies(&self) -> &[String] { 665 | self.relation_deps() 666 | } 667 | 668 | fn view_dependencies(&self) -> &[ViewRef] { 669 | &[] 670 | } 671 | } 672 | 673 | use crate::expression::Select; 674 | 675 | impl ExpressionExt for Select 676 | where 677 | T: Tuple, 678 | E: ExpressionExt, 679 | { 680 | fn collect_recent(&self, collector: &C) -> Result, Error> 681 | where 682 | C: RecentCollector, 683 | { 684 | collector.collect_select(&self) 685 | } 686 | 687 | fn collect_stable(&self, collector: &C) -> Result>, Error> 688 | where 689 | C: StableCollector, 690 | { 691 | collector.collect_select(&self) 692 | } 693 | 694 | fn relation_dependencies(&self) -> &[String] { 695 | self.relation_deps() 696 | } 697 | 698 | fn view_dependencies(&self) -> &[ViewRef] { 699 | self.view_deps() 700 | } 701 | } 702 | 703 | use crate::expression::Singleton; 704 | 705 | impl ExpressionExt for Singleton 706 | where 707 | T: Tuple, 708 | { 709 | fn collect_recent(&self, collector: &C) -> Result, Error> 710 | where 711 | C: RecentCollector, 712 | { 713 | collector.collect_singleton(&self) 714 | } 715 | 716 | fn collect_stable(&self, collector: &C) -> Result>, Error> 717 | where 718 | C: StableCollector, 719 | { 720 | collector.collect_singleton(&self) 721 | } 722 | 723 | fn relation_dependencies(&self) -> &[String] { 724 | &[] 725 | } 726 | 727 | fn view_dependencies(&self) -> &[ViewRef] { 728 | &[] 729 | } 730 | } 731 | } 732 | -------------------------------------------------------------------------------- /core/src/database/helpers.rs: -------------------------------------------------------------------------------- 1 | /// Moves an ordered `slice` forward until `cmp` is true on the elements of `slice`. 2 | /// 3 | /// **Note**: `gallop` is directly borrowed from [`datafrog`]. 4 | /// 5 | /// [`datafrog`]: https://github.com/rust-lang/datafrog 6 | #[inline(always)] 7 | pub(crate) fn gallop(mut slice: &[T], mut cmp: impl FnMut(&T) -> bool) -> &[T] { 8 | if !slice.is_empty() && cmp(&slice[0]) { 9 | let mut step = 1; 10 | while step < slice.len() && cmp(&slice[step]) { 11 | slice = &slice[step..]; 12 | step <<= 1; 13 | } 14 | 15 | step >>= 1; 16 | while step > 0 { 17 | if step < slice.len() && cmp(&slice[step]) { 18 | slice = &slice[step..]; 19 | } 20 | step >>= 1; 21 | } 22 | 23 | slice = &slice[1..]; 24 | } 25 | slice 26 | } 27 | 28 | /// Applies `result` on elements of `slice`. 29 | #[inline(always)] 30 | pub(crate) fn project_helper(slice: &[T], mut result: impl FnMut(&T)) { 31 | let slice = &slice[..]; 32 | for tuple in slice { 33 | result(tuple); 34 | } 35 | } 36 | 37 | /// Applies `result` on every pair of `left` and `right` slices. 38 | #[inline(always)] 39 | pub(crate) fn product_helper(left: &[L], right: &[R], mut result: impl FnMut(&L, &R)) { 40 | let left = &left[..]; 41 | let right = &right[..]; 42 | 43 | for l in left { 44 | for r in right { 45 | result(&l, &r); 46 | } 47 | } 48 | } 49 | 50 | /// For two slices `left` and `right` that are sorted by the first element of their tuples, 51 | /// applies `result` on those pairs of `left` and `right` that agree on their first 52 | /// element as the key. 53 | /// 54 | /// **Note**: `join_helper` is directly borrowed from [`datafrog`]. 55 | /// 56 | /// [`datafrog`]: https://github.com/rust-lang/datafrog 57 | #[inline(always)] 58 | pub(crate) fn join_helper( 59 | left: &[(Key, L)], 60 | right: &[(Key, R)], 61 | mut result: impl FnMut(&Key, &L, &R), 62 | ) { 63 | let mut slice1 = &left[..]; 64 | let mut slice2 = &right[..]; 65 | 66 | while !slice1.is_empty() && !slice2.is_empty() { 67 | use std::cmp::Ordering; 68 | 69 | match slice1[0].0.cmp(&slice2[0].0) { 70 | Ordering::Less => slice1 = gallop(slice1, |x| x.0 < slice2[0].0), 71 | Ordering::Equal => { 72 | let count1 = slice1.iter().take_while(|x| x.0 == slice1[0].0).count(); 73 | let count2 = slice2.iter().take_while(|x| x.0 == slice2[0].0).count(); 74 | 75 | for index1 in 0..count1 { 76 | for item in slice2.iter().take(count2) { 77 | result(&slice1[0].0, &slice1[index1].1, &item.1); 78 | } 79 | } 80 | 81 | slice1 = &slice1[count1..]; 82 | slice2 = &slice2[count2..]; 83 | } 84 | Ordering::Greater => slice2 = gallop(slice2, |x| x.0 < slice1[0].0), 85 | } 86 | } 87 | } 88 | 89 | /// For two sorted slices `left` and `right`, applies `result` on those elements of `left` and `right` 90 | /// that are equal. 91 | #[inline(always)] 92 | pub(crate) fn intersect_helper(left: &[T], right: &[T], mut result: impl FnMut(&T)) { 93 | let mut left = &left[..]; 94 | let mut right = &right[..]; 95 | 96 | while !left.is_empty() && !right.is_empty() { 97 | use std::cmp::Ordering; 98 | 99 | match left[0].cmp(&right[0]) { 100 | Ordering::Less => left = gallop(left, |x| x < &right[0]), 101 | Ordering::Equal => { 102 | result(&left[0]); 103 | left = &left[1..]; 104 | right = &right[1..]; 105 | } 106 | Ordering::Greater => right = gallop(right, |x| x < &left[0]), 107 | } 108 | } 109 | } 110 | 111 | /// For two sorted slices `left` and `right`, applies `result` on those elements of `left` that appear 112 | /// in none of the slices of `right`. 113 | #[inline(always)] 114 | pub(crate) fn diff_helper(left: &[T], right: &[&[T]], mut result: impl FnMut(&T)) { 115 | let left = &left[..]; 116 | let mut right = right.iter().map(|sl| &sl[..]).collect::>(); 117 | 118 | for tuple in left { 119 | let mut to_add = true; 120 | for mut to_find in &mut right { 121 | use std::cmp::Ordering; 122 | 123 | if !to_find.is_empty() { 124 | match tuple.cmp(&to_find[0]) { 125 | Ordering::Less => {} 126 | Ordering::Equal => { 127 | to_add = false; 128 | } 129 | Ordering::Greater => { 130 | let mut temp = gallop(to_find, |x| x < tuple); 131 | to_find = &mut temp; 132 | if !to_find.is_empty() && tuple == &to_find[0] { 133 | to_add = false; 134 | } 135 | } 136 | } 137 | } 138 | } 139 | 140 | if to_add { 141 | result(tuple); 142 | } 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /core/src/database/instance.rs: -------------------------------------------------------------------------------- 1 | use super::{evaluate, expression_ext::ExpressionExt, helpers::gallop, Database}; 2 | use crate::{expression::Expression, Error, Tuple}; 3 | use std::any::Any; 4 | use std::{ 5 | cell::{Ref, RefCell}, 6 | ops::Deref, 7 | rc::Rc, 8 | }; 9 | 10 | /// Is a wrapper around a vector of tuples. As an invariant, the content of [`Tuples`] is sorted. 11 | /// 12 | /// **Note**: [`Tuples`] is borrowed from `Relation` in [`datafrog`]. 13 | /// 14 | /// [`datafrog`]: https://github.com/rust-lang/datafrog 15 | #[derive(Clone, Debug, PartialEq)] 16 | pub struct Tuples { 17 | /// Is the vector of tuples in this instance. 18 | items: Vec, 19 | } 20 | 21 | impl> From for Tuples { 22 | fn from(iterator: I) -> Self { 23 | let mut items: Vec = iterator.into_iter().collect(); 24 | items.sort_unstable(); 25 | items.dedup(); 26 | Tuples { items } 27 | } 28 | } 29 | 30 | impl Tuples { 31 | /// Merges the instances of the reciver with `other` and returns a new [`Tuples`] 32 | /// instance. 33 | pub(crate) fn merge(self, other: Self) -> Self { 34 | let mut tuples = Vec::with_capacity(self.items.len() + other.items.len()); 35 | tuples.extend(self.items.into_iter()); 36 | tuples.extend(other.items.into_iter()); 37 | tuples.into() 38 | } 39 | 40 | /// Returns an immutable reference to the tuples of the receiver. 41 | pub fn items(&self) -> &[T] { 42 | &self.items 43 | } 44 | 45 | /// Consumes the receiver and returns the underlying (sorted) vector of tuples. 46 | #[inline(always)] 47 | pub fn into_tuples(self) -> Vec { 48 | self.items 49 | } 50 | } 51 | 52 | impl Deref for Tuples { 53 | type Target = Vec; 54 | 55 | fn deref(&self) -> &Self::Target { 56 | &self.items 57 | } 58 | } 59 | 60 | impl core::ops::DerefMut for Tuples { 61 | fn deref_mut(&mut self) -> &mut Self::Target { 62 | &mut self.items 63 | } 64 | } 65 | 66 | /// Is used to store instances of a database in a map by hiding their (generic) type. 67 | pub(super) trait DynInstance { 68 | /// Returns the instance as [`Any`] 69 | fn as_any(&self) -> &dyn Any; 70 | 71 | /// Returns true if the instance has been affected by last updates. It also moves all 72 | /// `to_add` tuples to `recent` and `recent` tuples to `stable`. 73 | fn changed(&self) -> bool; 74 | 75 | /// Clones the instance in a [`Box`]. 76 | fn clone_box(&self) -> Box; 77 | } 78 | 79 | /// Is used to store `ViewInstance`s in a map by hiding their (generic) types. 80 | pub(super) trait DynViewInstance { 81 | /// Returns the view instance as `Any`. 82 | fn as_any(&self) -> &dyn Any; 83 | 84 | /// Returns the `Instance` storing the tuples of the view as a trait object. 85 | fn instance(&self) -> &dyn DynInstance; 86 | 87 | /// Initializes the view with the existing tuples in `db`. 88 | fn initialize(&self, db: &Database) -> Result<(), Error>; 89 | 90 | /// Stabilizes the view from the `recent` tuples in the instances of `db`. 91 | fn stabilize(&self, db: &Database) -> Result<(), Error>; 92 | 93 | /// Clones the instance in a [`Box`]. 94 | fn clone_box(&self) -> Box; 95 | } 96 | 97 | /// Contains the tuples of a relation in the database. 98 | /// 99 | /// **Note**: `Instance` mirrors `Variable` in [`datafrog`]. 100 | /// 101 | /// [`datafrog`]: https://github.com/rust-lang/datafrog 102 | #[derive(Debug, PartialEq)] 103 | pub(super) struct Instance { 104 | /// Is the set of tuples that are already considered when updating views. 105 | stable: Rc>>>, 106 | 107 | /// Is the set of tuples that have not yet been reflected in views. 108 | recent: Rc>>, 109 | 110 | /// Is the set of tuples to add: they may be duplicates of existing tuples 111 | /// in which case they are ignored. 112 | to_add: Rc>>>, 113 | } 114 | 115 | impl Instance { 116 | /// Creates a new empty isntance. 117 | pub fn new() -> Self { 118 | Self { 119 | stable: Rc::new(RefCell::new(Vec::new())), 120 | recent: Rc::new(RefCell::new(Vec::new().into())), 121 | to_add: Rc::new(RefCell::new(Vec::new())), 122 | } 123 | } 124 | 125 | /// Adds a [`Tuples`] data to `to_add` tuples. These tuples will be ultimately 126 | /// added to the instance if they already don't exist. 127 | pub fn insert(&self, tuples: Tuples) { 128 | if !tuples.is_empty() { 129 | self.to_add.borrow_mut().push(tuples); 130 | } 131 | } 132 | 133 | /// Returns an immutable reference (of type [`Ref`]) to the stable tuples 134 | /// of this instance. 135 | #[inline(always)] 136 | pub fn stable(&self) -> Ref>> { 137 | self.stable.borrow() 138 | } 139 | 140 | /// Returns an immutable reference (of type [`Ref`]) to the recent tuples 141 | /// of this instance. 142 | #[inline(always)] 143 | pub fn recent(&self) -> Ref> { 144 | self.recent.borrow() 145 | } 146 | 147 | /// Returns an immutable reference (of type [`Ref`]) to the candidates to 148 | /// be added to the recent tuples of this instance (if they already don't exist). 149 | #[inline(always)] 150 | pub fn to_add(&self) -> Ref>> { 151 | self.to_add.borrow() 152 | } 153 | } 154 | 155 | impl Clone for Instance { 156 | fn clone(&self) -> Self { 157 | Self { 158 | stable: Rc::new(RefCell::new(self.stable.borrow().clone())), 159 | recent: Rc::new(RefCell::new(self.recent.borrow().clone())), 160 | to_add: Rc::new(RefCell::new(self.to_add.borrow().clone())), 161 | } 162 | } 163 | } 164 | 165 | impl DynInstance for Instance 166 | where 167 | T: Tuple + 'static, 168 | { 169 | fn as_any(&self) -> &dyn Any { 170 | self 171 | } 172 | 173 | fn changed(&self) -> bool { 174 | if !self.recent.borrow().is_empty() { 175 | let mut recent = 176 | ::std::mem::replace(&mut (*self.recent.borrow_mut()), Vec::new().into()); 177 | while self 178 | .stable 179 | .borrow() 180 | .last() 181 | .map(|x| x.len() <= 2 * recent.len()) 182 | == Some(true) 183 | { 184 | let last = self.stable.borrow_mut().pop().unwrap(); 185 | recent = recent.merge(last); 186 | } 187 | self.stable.borrow_mut().push(recent); 188 | } 189 | 190 | let to_add = self.to_add.borrow_mut().pop(); 191 | if let Some(mut to_add) = to_add { 192 | while let Some(to_add_more) = self.to_add.borrow_mut().pop() { 193 | to_add = to_add.merge(to_add_more); 194 | } 195 | for batch in self.stable.borrow().iter() { 196 | let mut slice = &batch[..]; 197 | to_add.items.retain(|x| { 198 | slice = gallop(slice, |y| y < x); 199 | slice.is_empty() || &slice[0] != x 200 | }); 201 | } 202 | *self.recent.borrow_mut() = to_add; 203 | } 204 | 205 | !self.recent.borrow().is_empty() 206 | } 207 | 208 | fn clone_box(&self) -> Box { 209 | let mut to_add = Vec::new(); 210 | for batch in self.to_add.borrow().iter() { 211 | to_add.push(batch.clone()); 212 | } 213 | 214 | let recent = (*self.recent.borrow()).clone(); 215 | 216 | let mut stable: Vec> = Vec::new(); 217 | for batch in self.stable.borrow().iter() { 218 | stable.push(batch.clone()); 219 | } 220 | 221 | Box::new(Self { 222 | stable: Rc::new(RefCell::new(stable)), 223 | recent: Rc::new(RefCell::new(recent)), 224 | to_add: Rc::new(RefCell::new(to_add)), 225 | }) 226 | } 227 | } 228 | 229 | /// Is a wrapper around the `Instance` storing the tuples of a view and 230 | /// the relational expression to which the view evaluates. 231 | pub(super) struct ViewInstance 232 | where 233 | T: Tuple, 234 | E: Expression, 235 | { 236 | /// Is the `Instance` storing the tuples of the view. 237 | instance: Instance, 238 | 239 | /// Is the view expression. 240 | expression: E, 241 | } 242 | 243 | impl ViewInstance 244 | where 245 | T: Tuple, 246 | E: Expression, 247 | { 248 | pub fn new(expression: E) -> Self { 249 | Self { 250 | instance: Instance::new(), 251 | expression, 252 | } 253 | } 254 | 255 | /// Returns the `Instance` storing the tuples of this view. 256 | pub fn instance(&self) -> &Instance { 257 | &self.instance 258 | } 259 | } 260 | 261 | impl DynViewInstance for ViewInstance 262 | where 263 | T: Tuple + 'static, 264 | E: ExpressionExt + 'static, 265 | { 266 | fn as_any(&self) -> &dyn Any { 267 | self 268 | } 269 | 270 | fn instance(&self) -> &dyn DynInstance { 271 | &self.instance 272 | } 273 | 274 | fn initialize(&self, db: &Database) -> Result<(), Error> { 275 | let incremental = evaluate::IncrementalCollector::new(db); 276 | let stable = self.expression.collect_stable(&incremental)?; 277 | 278 | for batch in stable { 279 | self.instance.insert(batch); 280 | } 281 | Ok(()) 282 | } 283 | 284 | fn stabilize(&self, db: &Database) -> Result<(), Error> { 285 | let incremental = evaluate::IncrementalCollector::new(db); 286 | let recent = self.expression.collect_recent(&incremental)?; 287 | 288 | self.instance.insert(recent); 289 | Ok(()) 290 | } 291 | 292 | fn clone_box(&self) -> Box { 293 | Box::new(Self { 294 | instance: self.instance.clone(), 295 | expression: self.expression.clone(), 296 | }) 297 | } 298 | } 299 | 300 | #[cfg(test)] 301 | mod tests { 302 | use super::*; 303 | 304 | #[test] 305 | fn test_clone_instance() { 306 | { 307 | let instance = Instance::::new(); 308 | assert_eq!(instance, instance.clone()); 309 | } 310 | { 311 | let instance = Instance:: { 312 | stable: Rc::new(RefCell::new(vec![vec![1, 2].into()])), 313 | recent: Rc::new(RefCell::new(vec![2, 3, 4].into())), 314 | to_add: Rc::new(RefCell::new(vec![vec![4, 5].into()])), 315 | }; 316 | let cloned = instance.clone(); 317 | assert_eq!(instance, cloned); 318 | } 319 | } 320 | 321 | #[test] 322 | fn test_tuples_from_list() { 323 | { 324 | let tuples = Tuples::::from(vec![]); 325 | assert_eq!(Vec::::new(), tuples.items()); 326 | } 327 | { 328 | let tuples = Tuples::::from(vec![5, 4, 2, 1, 3]); 329 | assert_eq!(vec![1, 2, 3, 4, 5], tuples.items()); 330 | } 331 | { 332 | let tuples = Tuples::::from(vec![3, 2, 2, 1, 3]); 333 | assert_eq!(vec![1, 2, 3], tuples.items()); 334 | } 335 | } 336 | 337 | #[test] 338 | fn test_tuples_merge() { 339 | { 340 | let tuples = Tuples::::from(vec![]); 341 | assert_eq!(Vec::::new(), tuples.merge(vec![].into()).items()); 342 | } 343 | { 344 | let tuples = Tuples::::from(vec![5, 4]); 345 | assert_eq!(vec![2, 3, 4, 5], tuples.merge(vec![2, 3].into()).items()); 346 | } 347 | { 348 | let tuples = Tuples::::from(vec![5, 4, 4]); 349 | assert_eq!(vec![3, 4, 5], tuples.merge(vec![5, 3].into()).items()); 350 | } 351 | } 352 | 353 | #[test] 354 | fn test_instance_insert() { 355 | { 356 | let relation = Instance:: { 357 | stable: Rc::new(RefCell::new(vec![])), 358 | recent: Rc::new(RefCell::new(vec![].into())), 359 | to_add: Rc::new(RefCell::new(vec![])), 360 | }; 361 | relation.insert(vec![].into()); 362 | assert_eq!(Vec::>::new(), *relation.stable.borrow()); 363 | assert_eq!(Vec::::new(), relation.recent.borrow().items); 364 | assert_eq!(Vec::>::new(), *relation.to_add.borrow()); 365 | } 366 | 367 | { 368 | let relation: Instance = Instance { 369 | stable: Rc::new(RefCell::new(vec![])), 370 | recent: Rc::new(RefCell::new(vec![1, 2, 3].into())), 371 | to_add: Rc::new(RefCell::new(vec![])), 372 | }; 373 | relation.insert(vec![].into()); 374 | assert_eq!(Vec::>::new(), *relation.stable.borrow()); 375 | assert_eq!(vec![1, 2, 3], relation.recent.borrow().items); 376 | assert_eq!(Vec::>::new(), *relation.to_add.borrow()); 377 | } 378 | 379 | { 380 | let relation: Instance = Instance { 381 | stable: Rc::new(RefCell::new(vec![])), 382 | recent: Rc::new(RefCell::new(vec![1, 2, 3].into())), 383 | to_add: Rc::new(RefCell::new(vec![])), 384 | }; 385 | relation.insert(vec![5, 4].into()); 386 | assert_eq!(Vec::>::new(), *relation.stable.borrow()); 387 | assert_eq!(vec![1, 2, 3], relation.recent.borrow().items); 388 | assert_eq!( 389 | Vec::>::from(vec![vec![4, 5].into()]), 390 | *relation.to_add.borrow(), 391 | ); 392 | } 393 | } 394 | 395 | #[test] 396 | fn test_instance_changed() { 397 | { 398 | let relation: Instance = Instance { 399 | stable: Rc::new(RefCell::new(vec![])), 400 | recent: Rc::new(RefCell::new(vec![].into())), 401 | to_add: Rc::new(RefCell::new(vec![])), 402 | }; 403 | relation.changed(); 404 | assert_eq!(Vec::>::new(), *relation.stable.borrow()); 405 | assert_eq!(Vec::::new(), relation.recent.borrow().items); 406 | assert_eq!(Vec::>::new(), *relation.to_add.borrow()); 407 | } 408 | 409 | { 410 | let relation = Instance:: { 411 | stable: Rc::new(RefCell::new(vec![])), 412 | recent: Rc::new(RefCell::new(vec![].into())), 413 | to_add: Rc::new(RefCell::new(vec![vec![1, 2].into()])), 414 | }; 415 | assert!(relation.changed()); 416 | assert_eq!(Vec::>::new(), *relation.stable.borrow()); 417 | assert_eq!(vec![1, 2], relation.recent.borrow().items); 418 | assert_eq!(Vec::>::new(), *relation.to_add.borrow()); 419 | } 420 | 421 | { 422 | let relation = Instance:: { 423 | stable: Rc::new(RefCell::new(vec![])), 424 | recent: Rc::new(RefCell::new(vec![1, 2].into())), 425 | to_add: Rc::new(RefCell::new(vec![])), 426 | }; 427 | assert!(!relation.changed()); 428 | assert_eq!( 429 | Vec::>::from(vec![vec![1, 2].into()]), 430 | *relation.stable.borrow() 431 | ); 432 | assert_eq!(Vec::::new(), relation.recent.borrow().items); 433 | assert_eq!(Vec::>::new(), *relation.to_add.borrow()); 434 | } 435 | 436 | { 437 | let relation = Instance:: { 438 | stable: Rc::new(RefCell::new(vec![])), 439 | recent: Rc::new(RefCell::new(vec![1, 2].into())), 440 | to_add: Rc::new(RefCell::new(vec![vec![3, 4].into()])), 441 | }; 442 | assert!(relation.changed()); 443 | assert_eq!( 444 | Vec::>::from(vec![vec![1, 2].into()]), 445 | *relation.stable.borrow() 446 | ); 447 | assert_eq!(vec![3, 4], relation.recent.borrow().items); 448 | assert_eq!(Vec::>::new(), *relation.to_add.borrow()); 449 | } 450 | 451 | { 452 | let relation = Instance:: { 453 | stable: Rc::new(RefCell::new(vec![vec![1, 2].into()])), 454 | recent: Rc::new(RefCell::new(vec![2, 3, 4].into())), 455 | to_add: Rc::new(RefCell::new(vec![vec![4, 5].into()])), 456 | }; 457 | assert!(relation.changed()); 458 | assert_eq!( 459 | Vec::>::from(vec![vec![1, 2, 3, 4].into()]), 460 | *relation.stable.borrow() 461 | ); 462 | assert_eq!(vec![5], relation.recent.borrow().items); 463 | assert_eq!(Vec::>::new(), *relation.to_add.borrow()); 464 | } 465 | 466 | { 467 | let relation = Instance:: { 468 | stable: Rc::new(RefCell::new(vec![vec![1, 2].into()])), 469 | recent: Rc::new(RefCell::new(vec![2, 3, 4].into())), 470 | to_add: Rc::new(RefCell::new(vec![vec![1, 5].into()])), 471 | }; 472 | assert!(relation.changed()); 473 | assert_eq!( 474 | Vec::>::from(vec![vec![1, 2, 3, 4].into()]), 475 | *relation.stable.borrow() 476 | ); 477 | assert_eq!(vec![5], relation.recent.borrow().items); 478 | assert_eq!(Vec::>::new(), *relation.to_add.borrow()); 479 | } 480 | } 481 | } 482 | -------------------------------------------------------------------------------- /core/src/database/validate.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | expression::{Difference, Expression, Visitor}, 3 | Error, Tuple, 4 | }; 5 | 6 | /// Is a [`Visitor`] that validates if an expression can be turned into a [`View`]. 7 | /// Currently, expressions containing `Difference` are not supported. 8 | pub(crate) struct ViewExpressionValidator(Option); 9 | 10 | impl ViewExpressionValidator { 11 | pub fn new() -> Self { 12 | Self(None) 13 | } 14 | 15 | #[inline] 16 | pub fn into_error(self) -> Option { 17 | self.0 18 | } 19 | } 20 | 21 | impl Visitor for ViewExpressionValidator { 22 | fn visit_difference(&mut self, _: &Difference) 23 | where 24 | T: Tuple, 25 | L: Expression, 26 | R: Expression, 27 | { 28 | self.0 = Some(Error::UnsupportedExpression { 29 | name: "Difference".to_string(), 30 | operation: "Create View".to_string(), 31 | }) 32 | } 33 | } 34 | 35 | /// Validates `expression` and returns an error if it cannot be turned into a [`View`]. 36 | pub(super) fn validate_view_expression(expression: &E) -> Result<(), Error> 37 | where 38 | T: Tuple, 39 | E: Expression, 40 | { 41 | let mut validator = ViewExpressionValidator::new(); 42 | expression.visit(&mut validator); 43 | if let Some(e) = validator.into_error() { 44 | Err(e) 45 | } else { 46 | Ok(()) 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /core/src/expression.rs: -------------------------------------------------------------------------------- 1 | /*! Defines relational algebraic expressions as generic types over [`Tuple`] types.*/ 2 | mod builder; 3 | pub(crate) mod dependency; 4 | mod difference; 5 | mod empty; 6 | mod full; 7 | mod intersect; 8 | mod join; 9 | mod mono; 10 | mod product; 11 | mod project; 12 | mod relation; 13 | mod select; 14 | mod singleton; 15 | mod union; 16 | pub(crate) mod view; 17 | 18 | use crate::Tuple; 19 | pub use builder::Builder; 20 | pub use difference::Difference; 21 | pub use empty::Empty; 22 | pub use full::Full; 23 | pub use intersect::Intersect; 24 | pub use join::Join; 25 | pub use mono::Mono; 26 | pub use product::Product; 27 | pub use project::Project; 28 | pub use relation::Relation; 29 | pub use select::Select; 30 | pub use singleton::Singleton; 31 | pub use union::Union; 32 | pub use view::View; 33 | 34 | /// Is the trait of expressions in relational algebra that can be evaluated in a database. 35 | pub trait Expression: Clone + std::fmt::Debug { 36 | /// Visits this expression by a [`Visitor`]. 37 | fn visit(&self, visitor: &mut V) 38 | where 39 | V: Visitor; 40 | 41 | /// Returns an expression builder over this expression. 42 | fn builder(&self) -> Builder { 43 | Builder::from(self.clone()) 44 | } 45 | } 46 | 47 | impl Expression for &E 48 | where 49 | T: Tuple, 50 | E: Expression, 51 | { 52 | fn visit(&self, visitor: &mut V) 53 | where 54 | V: Visitor, 55 | { 56 | (*self).visit(visitor) 57 | } 58 | } 59 | 60 | impl Expression for Box 61 | where 62 | T: Tuple, 63 | E: Expression, 64 | { 65 | fn visit(&self, visitor: &mut V) 66 | where 67 | V: Visitor, 68 | { 69 | (**self).visit(visitor) 70 | } 71 | } 72 | 73 | /// Is the trait of types that can be turned into an [`Expression`]. 74 | pub trait IntoExpression 75 | where 76 | T: Tuple, 77 | E: Expression, 78 | { 79 | /// Consumes the receiver and returns an expression. 80 | fn into_expression(self) -> E; 81 | } 82 | 83 | impl IntoExpression for E 84 | where 85 | T: Tuple, 86 | E: Expression, 87 | { 88 | fn into_expression(self) -> E { 89 | self 90 | } 91 | } 92 | 93 | /// Is the trait of objects that visit sub-expressions of an [`Expression`]. The default 94 | /// implementation guides the visitor through all sub-expressions of the expressions that 95 | /// is visited. 96 | pub trait Visitor: Sized { 97 | /// Visits the [`Full`] expression. 98 | fn visit_full(&mut self, full: &Full) 99 | where 100 | T: Tuple, 101 | { 102 | walk_full(self, full) 103 | } 104 | 105 | /// Visits the [`Empty`] expression. 106 | fn visit_empty(&mut self, empty: &Empty) 107 | where 108 | T: Tuple, 109 | { 110 | walk_empty(self, empty) 111 | } 112 | 113 | /// Visits a [`Singleton`] expression. 114 | fn visit_singleton(&mut self, singleton: &Singleton) 115 | where 116 | T: Tuple, 117 | { 118 | walk_singlenton(self, singleton) 119 | } 120 | 121 | /// Visits a [`Relation`] expression. 122 | fn visit_relation(&mut self, relation: &Relation) 123 | where 124 | T: Tuple, 125 | { 126 | walk_relation(self, relation) 127 | } 128 | 129 | /// Visits a [`Select`] expression. 130 | fn visit_select(&mut self, select: &Select) 131 | where 132 | T: Tuple, 133 | E: Expression, 134 | { 135 | walk_select(self, select); 136 | } 137 | 138 | /// Visits a [`Union`] expression. 139 | fn visit_union(&mut self, union: &Union) 140 | where 141 | T: Tuple, 142 | L: Expression, 143 | R: Expression, 144 | { 145 | walk_union(self, union); 146 | } 147 | 148 | /// Visits an [`Intersect`] expression. 149 | fn visit_intersect(&mut self, intersect: &Intersect) 150 | where 151 | T: Tuple, 152 | L: Expression, 153 | R: Expression, 154 | { 155 | walk_intersect(self, intersect); 156 | } 157 | 158 | /// Visits a [`Difference`] expression. 159 | fn visit_difference(&mut self, difference: &Difference) 160 | where 161 | T: Tuple, 162 | L: Expression, 163 | R: Expression, 164 | { 165 | walk_difference(self, difference); 166 | } 167 | 168 | /// Visits a [`Project`] expression. 169 | fn visit_project(&mut self, project: &Project) 170 | where 171 | T: Tuple, 172 | S: Tuple, 173 | E: Expression, 174 | { 175 | walk_project(self, project); 176 | } 177 | 178 | /// Visits a [`Product`] expression. 179 | fn visit_product(&mut self, product: &Product) 180 | where 181 | L: Tuple, 182 | R: Tuple, 183 | T: Tuple, 184 | Left: Expression, 185 | Right: Expression, 186 | { 187 | walk_product(self, product); 188 | } 189 | 190 | /// Visits a [`Join`] expression. 191 | fn visit_join(&mut self, join: &Join) 192 | where 193 | K: Tuple, 194 | L: Tuple, 195 | R: Tuple, 196 | T: Tuple, 197 | Left: Expression, 198 | Right: Expression, 199 | { 200 | walk_join(self, join); 201 | } 202 | 203 | /// Visits a [`View`] expression. 204 | fn visit_view(&mut self, view: &View) 205 | where 206 | T: Tuple, 207 | E: Expression, 208 | { 209 | walk_view(self, view); 210 | } 211 | } 212 | 213 | fn walk_full(_: &mut V, _: &Full) 214 | where 215 | T: Tuple, 216 | V: Visitor, 217 | { 218 | // nothing to do 219 | } 220 | 221 | fn walk_empty(_: &mut V, _: &Empty) 222 | where 223 | T: Tuple, 224 | V: Visitor, 225 | { 226 | // nothing to do 227 | } 228 | 229 | fn walk_singlenton(_: &mut V, _: &Singleton) 230 | where 231 | T: Tuple, 232 | V: Visitor, 233 | { 234 | // nothing to do 235 | } 236 | 237 | fn walk_relation(_: &mut V, _: &Relation) 238 | where 239 | T: Tuple, 240 | V: Visitor, 241 | { 242 | // nothing to do 243 | } 244 | 245 | fn walk_select(visitor: &mut V, select: &Select) 246 | where 247 | T: Tuple, 248 | E: Expression, 249 | V: Visitor, 250 | { 251 | select.expression().visit(visitor); 252 | } 253 | 254 | fn walk_union(visitor: &mut V, union: &Union) 255 | where 256 | T: Tuple, 257 | L: Expression, 258 | R: Expression, 259 | V: Visitor, 260 | { 261 | union.left().visit(visitor); 262 | union.right().visit(visitor); 263 | } 264 | 265 | fn walk_intersect(visitor: &mut V, intersect: &Intersect) 266 | where 267 | T: Tuple, 268 | L: Expression, 269 | R: Expression, 270 | V: Visitor, 271 | { 272 | intersect.left().visit(visitor); 273 | intersect.right().visit(visitor); 274 | } 275 | 276 | fn walk_difference(visitor: &mut V, difference: &Difference) 277 | where 278 | T: Tuple, 279 | L: Expression, 280 | R: Expression, 281 | V: Visitor, 282 | { 283 | difference.left().visit(visitor); 284 | difference.right().visit(visitor); 285 | } 286 | 287 | fn walk_project(visitor: &mut V, project: &Project) 288 | where 289 | T: Tuple, 290 | S: Tuple, 291 | E: Expression, 292 | V: Visitor, 293 | { 294 | project.expression().visit(visitor); 295 | } 296 | 297 | fn walk_product(visitor: &mut V, product: &Product) 298 | where 299 | L: Tuple, 300 | R: Tuple, 301 | T: Tuple, 302 | Left: Expression, 303 | Right: Expression, 304 | V: Visitor, 305 | { 306 | product.left().visit(visitor); 307 | product.right().visit(visitor); 308 | } 309 | 310 | fn walk_join(visitor: &mut V, join: &Join) 311 | where 312 | K: Tuple, 313 | L: Tuple, 314 | R: Tuple, 315 | T: Tuple, 316 | Left: Expression, 317 | Right: Expression, 318 | V: Visitor, 319 | { 320 | join.left().visit(visitor); 321 | join.right().visit(visitor); 322 | } 323 | 324 | fn walk_view(_: &mut V, _: &View) 325 | where 326 | T: Tuple, 327 | E: Expression, 328 | V: Visitor, 329 | { 330 | // nothing to do 331 | } 332 | -------------------------------------------------------------------------------- /core/src/expression/builder.rs: -------------------------------------------------------------------------------- 1 | use super::*; 2 | use crate::Tuple; 3 | use std::marker::PhantomData; 4 | 5 | /// Is a builder for building [`Expression`] values. 6 | pub struct Builder 7 | where 8 | L: Tuple, 9 | Left: Expression, 10 | { 11 | /// Is the expression constructed by this builder. 12 | expression: Left, 13 | _marker: PhantomData, 14 | } 15 | 16 | impl Builder 17 | where 18 | L: Tuple, 19 | Left: Expression, 20 | { 21 | /// Builds a [`Project`] expression over the receiver's expression. 22 | /// 23 | /// **Example**: 24 | /// ```rust 25 | /// use codd::{Database, Expression}; 26 | /// 27 | /// let mut db = Database::new(); 28 | /// let fruit = db.add_relation::("R").unwrap(); 29 | /// 30 | /// db.insert(&fruit, vec!["Apple".to_string(), "BANANA".into(), "cherry".into()].into()); 31 | /// 32 | /// let lower = fruit.builder().project(|t| t.to_lowercase()).build(); 33 | /// 34 | /// assert_eq!(vec!["apple", "banana", "cherry"], db.evaluate(&lower).unwrap().into_tuples()); 35 | /// ``` 36 | pub fn project(self, f: impl FnMut(&L) -> T + 'static) -> Builder> 37 | where 38 | T: Tuple, 39 | { 40 | Builder { 41 | expression: Project::new(self.expression, f), 42 | _marker: PhantomData, 43 | } 44 | } 45 | 46 | /// Builds a [`Select`] expression over the receiver's expression. 47 | /// 48 | /// **Example**: 49 | /// ```rust 50 | /// use codd::{Database, Expression}; 51 | /// 52 | /// let mut db = Database::new(); 53 | /// let fruit = db.add_relation::("Fruit").unwrap(); 54 | /// 55 | /// db.insert(&fruit, vec!["Apple".to_string(), "BANANA".into(), "cherry".into()].into()); 56 | /// 57 | /// let select = fruit.builder().select(|t| t.contains('A')).build(); 58 | /// 59 | /// assert_eq!(vec!["Apple", "BANANA"], db.evaluate(&select).unwrap().into_tuples()); 60 | /// ``` 61 | pub fn select(self, f: impl FnMut(&L) -> bool + 'static) -> Builder> { 62 | Builder { 63 | expression: Select::new(self.expression, f), 64 | _marker: PhantomData, 65 | } 66 | } 67 | 68 | /// Builds an [`Intersect`] expression with the receiver's expression on left and `other` on right. 69 | /// 70 | /// **Example**: 71 | /// ```rust 72 | /// use codd::{Database, Expression}; 73 | /// 74 | /// let mut db = Database::new(); 75 | /// let r = db.add_relation::("R").unwrap(); 76 | /// let s = db.add_relation::("S").unwrap(); 77 | /// 78 | /// db.insert(&r, vec![0, 1, 2].into()); 79 | /// db.insert(&s, vec![2, 4].into()); 80 | /// 81 | /// let intersect = r.builder().intersect(s).build(); 82 | /// 83 | /// assert_eq!(vec![2], db.evaluate(&intersect).unwrap().into_tuples()); 84 | /// ``` 85 | pub fn intersect(self, other: I) -> Builder> 86 | where 87 | Right: Expression, 88 | I: IntoExpression, 89 | { 90 | Builder { 91 | expression: Intersect::new(self.expression, other.into_expression()), 92 | _marker: PhantomData, 93 | } 94 | } 95 | 96 | /// Builds a [`Difference`] expression with the receiver's expression on left and `other` on right. 97 | /// 98 | /// **Example**: 99 | /// ```rust 100 | /// use codd::{Database, Expression}; 101 | /// 102 | /// let mut db = Database::new(); 103 | /// let r = db.add_relation::("R").unwrap(); 104 | /// let s = db.add_relation::("S").unwrap(); 105 | /// 106 | /// db.insert(&r, vec![0, 1, 2].into()); 107 | /// db.insert(&s, vec![2, 4].into()); 108 | /// 109 | /// let r_s = r.builder().difference(&s).build(); 110 | /// let s_r = s.builder().difference(r).build(); 111 | /// 112 | /// assert_eq!(vec![0, 1], db.evaluate(&r_s).unwrap().into_tuples()); 113 | /// assert_eq!(vec![4], db.evaluate(&s_r).unwrap().into_tuples()); 114 | /// ``` 115 | pub fn difference(self, other: I) -> Builder> 116 | where 117 | Right: Expression, 118 | I: IntoExpression, 119 | { 120 | Builder { 121 | expression: Difference::new(self.expression, other.into_expression()), 122 | _marker: PhantomData, 123 | } 124 | } 125 | 126 | /// Builds a [`Union`] expression with the receiver's expression on left and `other` on right. 127 | /// 128 | /// **Example**: 129 | /// ```rust 130 | /// use codd::{Database, Expression}; 131 | /// 132 | /// let mut db = Database::new(); 133 | /// let r = db.add_relation::("R").unwrap(); 134 | /// let s = db.add_relation::("S").unwrap(); 135 | /// 136 | /// db.insert(&r, vec![0, 1, 2].into()); 137 | /// db.insert(&s, vec![2, 4].into()); 138 | /// 139 | /// let union = r.builder().union(s).build(); 140 | /// 141 | /// assert_eq!(vec![0, 1, 2, 4], db.evaluate(&union).unwrap().into_tuples()); 142 | /// ``` 143 | pub fn union(self, other: I) -> Builder> 144 | where 145 | Right: Expression, 146 | I: IntoExpression, 147 | { 148 | Builder { 149 | expression: Union::new(self.expression, other.into_expression()), 150 | _marker: PhantomData, 151 | } 152 | } 153 | 154 | /// Combines the receiver's expression with `other` in a temporary builder, which then can be turned into 155 | /// a [`Product`] expression using a combining closure provided by method `on`. 156 | /// 157 | /// **Example**: 158 | /// ```rust 159 | /// use codd::{Database, Expression}; 160 | /// 161 | /// let mut db = Database::new(); 162 | /// let r = db.add_relation::("R").unwrap(); 163 | /// let s = db.add_relation::("S").unwrap(); 164 | /// 165 | /// db.insert(&r, vec![0, 1, 2].into()); 166 | /// db.insert(&s, vec![2, 4].into()); 167 | /// 168 | /// let prod = r.builder().product(s).on(|l, r| l*r).build(); 169 | /// 170 | /// assert_eq!(vec![0, 2, 4, 8], db.evaluate(&prod).unwrap().into_tuples()); 171 | /// ``` 172 | pub fn product(self, other: I) -> ProductBuilder 173 | where 174 | R: Tuple, 175 | Right: Expression, 176 | I: IntoExpression, 177 | { 178 | ProductBuilder { 179 | left: self.expression, 180 | right: other.into_expression(), 181 | _marker: PhantomData, 182 | } 183 | } 184 | 185 | /// Combines the receiver's expression with closure `f` as the join key. This value can then be joined with 186 | /// another expression and it's key to create a temporary join builder. Finally, the temporary builder 187 | /// can be turned into a [`Join`] expression using a combining closure provided by method `on`. 188 | /// 189 | /// **Example**: 190 | /// ```rust 191 | /// use codd::{Database, Expression}; 192 | /// 193 | /// let mut db = Database::new(); 194 | /// let fruit = db.add_relation::<(i32, String)>("R").unwrap(); 195 | /// let numbers = db.add_relation::("S").unwrap(); 196 | /// 197 | /// db.insert(&fruit, vec![ 198 | /// (0, "Apple".to_string()), 199 | /// (1, "Banana".into()), 200 | /// (2, "Cherry".into()) 201 | /// ].into()); 202 | /// db.insert(&numbers, vec![0, 2].into()); 203 | /// 204 | /// let join = fruit 205 | /// .builder() 206 | /// .with_key(|t| t.0) // first element of tuples in `r` is the key for join 207 | /// .join(numbers.builder().with_key(|&t| t)) 208 | /// .on(|k, l, r| format!("{}{}", l.1, k + r)) 209 | /// // combine the key `k`, left tuple `l` and right tuple `r`: 210 | /// .build(); 211 | /// 212 | /// assert_eq!(vec!["Apple0", "Cherry4"], db.evaluate(&join).unwrap().into_tuples()); 213 | /// ``` 214 | pub fn with_key(self, f: impl FnMut(&L) -> K + 'static) -> WithKeyBuilder 215 | where 216 | K: Tuple, 217 | { 218 | WithKeyBuilder { 219 | expression: self.expression, 220 | key: Box::new(f), 221 | } 222 | } 223 | 224 | /// Builds an expression from the receiver. 225 | pub fn build(self) -> Left { 226 | self.into_expression() 227 | } 228 | } 229 | 230 | impl IntoExpression for Builder 231 | where 232 | T: Tuple, 233 | E: Expression, 234 | { 235 | fn into_expression(self) -> E { 236 | self.expression 237 | } 238 | } 239 | 240 | impl From for Builder 241 | where 242 | T: Tuple, 243 | E: Expression, 244 | { 245 | fn from(expression: E) -> Self { 246 | Builder { 247 | expression, 248 | _marker: PhantomData, 249 | } 250 | } 251 | } 252 | 253 | pub struct ProductBuilder 254 | where 255 | L: Tuple, 256 | R: Tuple, 257 | Left: Expression, 258 | Right: Expression, 259 | { 260 | left: Left, 261 | right: Right, 262 | _marker: PhantomData<(L, R)>, 263 | } 264 | 265 | impl ProductBuilder 266 | where 267 | L: Tuple, 268 | R: Tuple, 269 | Left: Expression, 270 | Right: Expression, 271 | { 272 | pub fn on( 273 | self, 274 | f: impl FnMut(&L, &R) -> T + 'static, 275 | ) -> Builder> { 276 | Builder { 277 | expression: Product::new(self.left, self.right, f), 278 | _marker: PhantomData, 279 | } 280 | } 281 | } 282 | 283 | pub struct WithKeyBuilder 284 | where 285 | K: Tuple + 'static, 286 | L: Tuple + 'static, 287 | Left: Expression, 288 | { 289 | expression: Left, 290 | key: Box K>, 291 | } 292 | 293 | impl WithKeyBuilder 294 | where 295 | K: Tuple, 296 | L: Tuple, 297 | Left: Expression, 298 | { 299 | pub fn join( 300 | self, 301 | other: WithKeyBuilder, 302 | ) -> JoinBuilder 303 | where 304 | R: Tuple, 305 | Right: Expression, 306 | { 307 | JoinBuilder { 308 | left: self, 309 | right: other, 310 | } 311 | } 312 | } 313 | 314 | pub struct JoinBuilder 315 | where 316 | K: Tuple + 'static, 317 | L: Tuple + 'static, 318 | R: Tuple + 'static, 319 | Left: Expression, 320 | Right: Expression, 321 | { 322 | left: WithKeyBuilder, 323 | right: WithKeyBuilder, 324 | } 325 | 326 | impl JoinBuilder 327 | where 328 | K: Tuple + 'static, 329 | L: Tuple + 'static, 330 | R: Tuple + 'static, 331 | Left: Expression, 332 | Right: Expression, 333 | { 334 | pub fn on( 335 | self, 336 | f: impl FnMut(&K, &L, &R) -> T + 'static, 337 | ) -> Builder> { 338 | Builder { 339 | expression: Join::new( 340 | self.left.expression, 341 | self.right.expression, 342 | self.left.key, 343 | self.right.key, 344 | f, 345 | ), 346 | _marker: PhantomData, 347 | } 348 | } 349 | } 350 | -------------------------------------------------------------------------------- /core/src/expression/dependency.rs: -------------------------------------------------------------------------------- 1 | use crate::{ 2 | expression::{view::ViewRef, Expression, Relation, View, Visitor}, 3 | Tuple, 4 | }; 5 | use std::collections::HashSet; 6 | 7 | /// Implements the [`Visitor`] to collect the relations and views to which 8 | /// the visited expression depends. 9 | pub(crate) struct DependencyVisitor { 10 | relations: HashSet, 11 | views: HashSet, 12 | } 13 | 14 | impl DependencyVisitor { 15 | /// Creates a new [`DependencyVisitor`]. 16 | pub fn new() -> Self { 17 | Self { 18 | relations: HashSet::new(), 19 | views: HashSet::new(), 20 | } 21 | } 22 | 23 | /// Consumes the reciever and returns a pair of relation and view dependencies. 24 | pub fn into_dependencies(self) -> (HashSet, HashSet) { 25 | (self.relations, self.views) 26 | } 27 | } 28 | 29 | impl Visitor for DependencyVisitor { 30 | fn visit_relation(&mut self, relation: &Relation) 31 | where 32 | T: Tuple, 33 | { 34 | self.relations.insert(relation.name().into()); 35 | } 36 | 37 | fn visit_view(&mut self, view: &View) 38 | where 39 | T: Tuple, 40 | E: Expression, 41 | { 42 | self.views.insert(view.reference().clone()); 43 | } 44 | } 45 | 46 | pub(crate) fn expression_dependencies(expression: &E) -> (HashSet, HashSet) 47 | where 48 | T: Tuple, 49 | E: Expression, 50 | { 51 | let mut deps = DependencyVisitor::new(); 52 | expression.visit(&mut deps); 53 | 54 | deps.into_dependencies() 55 | } 56 | -------------------------------------------------------------------------------- /core/src/expression/difference.rs: -------------------------------------------------------------------------------- 1 | use super::{view::ViewRef, Expression, IntoExpression, Visitor}; 2 | use crate::Tuple; 3 | use std::marker::PhantomData; 4 | 5 | /// Evaluates to the tuples that are in its `left` but not in its `right` sub-expressions (`left - right`). 6 | /// 7 | /// **Example**: 8 | /// ```rust 9 | /// use codd::{Database, expression::Difference}; 10 | /// 11 | /// let mut db = Database::new(); 12 | /// let r = db.add_relation::("R").unwrap(); 13 | /// let s = db.add_relation::("S").unwrap(); 14 | /// 15 | /// db.insert(&r, vec![0, 1, 2].into()); 16 | /// db.insert(&s, vec![2, 4].into()); 17 | /// 18 | /// let r_s = Difference::new(&r, &s); 19 | /// let s_r = Difference::new(&s, &r); 20 | /// 21 | /// assert_eq!(vec![0, 1], db.evaluate(&r_s).unwrap().into_tuples()); 22 | /// assert_eq!(vec![4], db.evaluate(&s_r).unwrap().into_tuples()); 23 | /// ``` 24 | #[derive(Clone, Debug)] 25 | pub struct Difference 26 | where 27 | T: Tuple, 28 | L: Expression, 29 | R: Expression, 30 | { 31 | left: L, 32 | right: R, 33 | relation_deps: Vec, 34 | view_deps: Vec, 35 | _marker: PhantomData, 36 | } 37 | 38 | impl Difference 39 | where 40 | T: Tuple, 41 | L: Expression, 42 | R: Expression, 43 | { 44 | /// Creates a new instance of [`Difference`] corresponding to `left` - `right`. 45 | pub fn new(left: IL, right: IR) -> Self 46 | where 47 | IL: IntoExpression, 48 | IR: IntoExpression, 49 | { 50 | use super::dependency; 51 | 52 | let left = left.into_expression(); 53 | let right = right.into_expression(); 54 | 55 | let mut deps = dependency::DependencyVisitor::new(); 56 | left.visit(&mut deps); 57 | right.visit(&mut deps); 58 | let (relation_deps, view_deps) = deps.into_dependencies(); 59 | 60 | Self { 61 | left, 62 | right, 63 | relation_deps: relation_deps.into_iter().collect(), 64 | view_deps: view_deps.into_iter().collect(), 65 | _marker: PhantomData, 66 | } 67 | } 68 | 69 | /// Returns a reference to the left sub-expression. 70 | #[inline(always)] 71 | pub fn left(&self) -> &L { 72 | &self.left 73 | } 74 | 75 | /// Returns a reference to the right sub-expression. 76 | #[inline(always)] 77 | pub fn right(&self) -> &R { 78 | &self.right 79 | } 80 | 81 | /// Returns a reference to the relation dependencies of the receiver. 82 | #[inline(always)] 83 | pub(crate) fn relation_deps(&self) -> &[String] { 84 | &self.relation_deps 85 | } 86 | 87 | /// Returns a reference to the view dependencies of the receiver. 88 | #[inline(always)] 89 | pub(crate) fn view_deps(&self) -> &[ViewRef] { 90 | &self.view_deps 91 | } 92 | } 93 | 94 | impl Expression for Difference 95 | where 96 | T: Tuple, 97 | L: Expression, 98 | R: Expression, 99 | { 100 | fn visit(&self, visitor: &mut V) 101 | where 102 | V: Visitor, 103 | { 104 | visitor.visit_difference(&self); 105 | } 106 | } 107 | 108 | #[cfg(test)] 109 | mod tests { 110 | use super::*; 111 | use crate::{Database, Tuples}; 112 | 113 | #[test] 114 | fn test_clone() { 115 | let mut database = Database::new(); 116 | let r = database.add_relation::("r").unwrap(); 117 | let s = database.add_relation::("s").unwrap(); 118 | database.insert(&r, vec![1, 2, 3, 6].into()).unwrap(); 119 | database.insert(&s, vec![1, 4, 3, 5].into()).unwrap(); 120 | let u = Difference::new(&r, &s).clone(); 121 | assert_eq!( 122 | Tuples::::from(vec![2, 6]), 123 | database.evaluate(&u).unwrap() 124 | ); 125 | } 126 | } 127 | -------------------------------------------------------------------------------- /core/src/expression/empty.rs: -------------------------------------------------------------------------------- 1 | use super::{Expression, Visitor}; 2 | use crate::Tuple; 3 | use std::marker::PhantomData; 4 | 5 | /// Represents an empty instance containing no tuples. 6 | /// 7 | /// **Example**: 8 | /// ```rust 9 | /// use codd::{Database, expression::Empty}; 10 | /// 11 | /// let mut db = Database::new(); 12 | /// let empty = Empty::::new(); 13 | /// 14 | /// assert_eq!(Vec::::new(), db.evaluate(&empty).unwrap().into_tuples()); 15 | /// ``` 16 | #[derive(Clone, Debug)] 17 | pub struct Empty 18 | where 19 | T: Tuple, 20 | { 21 | _phantom: PhantomData, 22 | } 23 | 24 | impl Empty 25 | where 26 | T: Tuple, 27 | { 28 | /// Creates a new instance of [`Empty`]. 29 | pub fn new() -> Self { 30 | Self { 31 | _phantom: PhantomData, 32 | } 33 | } 34 | } 35 | 36 | impl Expression for Empty 37 | where 38 | T: Tuple, 39 | { 40 | fn visit(&self, visitor: &mut V) 41 | where 42 | V: Visitor, 43 | { 44 | visitor.visit_empty(&self); 45 | } 46 | } 47 | 48 | impl Default for Empty { 49 | fn default() -> Self { 50 | Self::new() 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /core/src/expression/full.rs: -------------------------------------------------------------------------------- 1 | use super::{Expression, Visitor}; 2 | use crate::Tuple; 3 | use std::marker::PhantomData; 4 | 5 | /// Is a placeholder for a "full" instance, containing *all* tuples of its type. 6 | /// 7 | /// **Note**: because [`Full`] expression cannot be described by a range-restricted 8 | /// (see [chapter 2] of Foundations of Databases) query, any query containing 9 | /// `Full` as a subexpression cannot be evaluated in a database safely. 10 | /// 11 | /// **Example**: 12 | /// ```rust 13 | /// use codd::{Database, expression::Full}; 14 | /// 15 | /// let mut db = Database::new(); 16 | /// let full = Full::::new(); 17 | /// 18 | /// assert!(db.evaluate(&full).is_err()); // cannot be evaluated 19 | /// ``` 20 | /// 21 | /// [chapter 2]: http://webdam.inria.fr/Alice/pdfs/Chapter-5.pdf 22 | #[derive(Clone, Debug)] 23 | pub struct Full 24 | where 25 | T: Tuple, 26 | { 27 | _phantom: PhantomData, 28 | } 29 | 30 | impl Full 31 | where 32 | T: Tuple, 33 | { 34 | /// Creates a new instance of [`Full`]. 35 | pub fn new() -> Self { 36 | Self { 37 | _phantom: PhantomData, 38 | } 39 | } 40 | } 41 | 42 | impl Expression for Full 43 | where 44 | T: Tuple, 45 | { 46 | fn visit(&self, visitor: &mut V) 47 | where 48 | V: Visitor, 49 | { 50 | visitor.visit_full(&self); 51 | } 52 | } 53 | 54 | impl Default for Full { 55 | fn default() -> Self { 56 | Self::new() 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /core/src/expression/intersect.rs: -------------------------------------------------------------------------------- 1 | use super::{view::ViewRef, Expression, IntoExpression, Visitor}; 2 | use crate::Tuple; 3 | use std::marker::PhantomData; 4 | 5 | /// Evaluates to all tuples that are in its both `left` and `right` sub-expressions. 6 | /// 7 | /// **Example**: 8 | /// ```rust 9 | /// use codd::{Database, expression::Intersect}; 10 | /// 11 | /// let mut db = Database::new(); 12 | /// let r = db.add_relation::("R").unwrap(); 13 | /// let s = db.add_relation::("S").unwrap(); 14 | /// 15 | /// db.insert(&r, vec![0, 1, 2].into()); 16 | /// db.insert(&s, vec![2, 4].into()); 17 | /// 18 | /// let intersect = Intersect::new(&r, &s); 19 | /// 20 | /// assert_eq!(vec![2], db.evaluate(&intersect).unwrap().into_tuples()); 21 | /// ``` 22 | #[derive(Clone, Debug)] 23 | pub struct Intersect 24 | where 25 | T: Tuple, 26 | L: Expression, 27 | R: Expression, 28 | { 29 | left: L, 30 | right: R, 31 | relation_deps: Vec, 32 | view_deps: Vec, 33 | _marker: PhantomData, 34 | } 35 | 36 | impl Intersect 37 | where 38 | T: Tuple, 39 | L: Expression, 40 | R: Expression, 41 | { 42 | /// Creates a new instance of [`Intersect`] for `left ∩ right`. 43 | pub fn new(left: IL, right: IR) -> Self 44 | where 45 | IL: IntoExpression, 46 | IR: IntoExpression, 47 | { 48 | use super::dependency; 49 | let left = left.into_expression(); 50 | let right = right.into_expression(); 51 | 52 | let mut deps = dependency::DependencyVisitor::new(); 53 | left.visit(&mut deps); 54 | right.visit(&mut deps); 55 | let (relation_deps, view_deps) = deps.into_dependencies(); 56 | 57 | Self { 58 | left, 59 | right, 60 | relation_deps: relation_deps.into_iter().collect(), 61 | view_deps: view_deps.into_iter().collect(), 62 | _marker: PhantomData, 63 | } 64 | } 65 | 66 | /// Returns a reference to the left sub-expression. 67 | #[inline(always)] 68 | pub fn left(&self) -> &L { 69 | &self.left 70 | } 71 | 72 | /// Returns a reference to the right sub-expression. 73 | #[inline(always)] 74 | pub fn right(&self) -> &R { 75 | &self.right 76 | } 77 | 78 | /// Returns a reference to the relation dependencies of the receiver. 79 | #[inline(always)] 80 | pub(crate) fn relation_deps(&self) -> &[String] { 81 | &self.relation_deps 82 | } 83 | 84 | /// Returns a reference to the view dependencies of the receiver. 85 | #[inline(always)] 86 | pub(crate) fn view_deps(&self) -> &[ViewRef] { 87 | &self.view_deps 88 | } 89 | } 90 | 91 | impl Expression for Intersect 92 | where 93 | T: Tuple, 94 | L: Expression, 95 | R: Expression, 96 | { 97 | fn visit(&self, visitor: &mut V) 98 | where 99 | V: Visitor, 100 | { 101 | visitor.visit_intersect(&self); 102 | } 103 | } 104 | 105 | #[cfg(test)] 106 | mod tests { 107 | use super::*; 108 | use crate::{Database, Tuples}; 109 | 110 | #[test] 111 | fn test_clone() { 112 | let mut database = Database::new(); 113 | let r = database.add_relation::("r").unwrap(); 114 | let s = database.add_relation::("s").unwrap(); 115 | database.insert(&r, vec![1, 2, 3].into()).unwrap(); 116 | database.insert(&s, vec![1, 4, 3, 5].into()).unwrap(); 117 | let u = Intersect::new(r, s).clone(); 118 | assert_eq!( 119 | Tuples::::from(vec![1, 3]), 120 | database.evaluate(&u).unwrap() 121 | ); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /core/src/expression/join.rs: -------------------------------------------------------------------------------- 1 | use super::{view::ViewRef, Expression, IntoExpression, Visitor}; 2 | use crate::Tuple; 3 | use std::{ 4 | cell::{RefCell, RefMut}, 5 | marker::PhantomData, 6 | rc::Rc, 7 | }; 8 | 9 | /// Is the type of [`Join`] mapping closures for constructing tuples of type `T` from a key 10 | /// of type `K`, a left tuple of type `L`, and a right tuple of type `R`. 11 | type Mapper = dyn FnMut(&K, &L, &R) -> T; 12 | 13 | /// Represents the join of its `left` and `right` sub-expressions. 14 | /// 15 | /// **Example**: 16 | /// ```rust 17 | /// use codd::{Database, expression::Join}; 18 | /// 19 | /// let mut db = Database::new(); 20 | /// let fruit = db.add_relation::<(i32, String)>("R").unwrap(); 21 | /// let numbers = db.add_relation::("S").unwrap(); 22 | /// 23 | /// db.insert(&fruit, vec![ 24 | /// (0, "Apple".to_string()), 25 | /// (1, "Banana".to_string()), 26 | /// (2, "Cherry".to_string()) 27 | /// ].into()); 28 | /// db.insert(&numbers, vec![0, 2].into()); 29 | /// 30 | /// let join = Join::new( 31 | /// &fruit, 32 | /// &numbers, 33 | /// |t| t.0, // first element of tuples in `r` is the key for join 34 | /// |&t| t, // the values in `s` are keys for join 35 | /// // make resulting values from key `k`, left value `l` and right value `r`: 36 | /// |k, l, r| format!("{}{}", l.1, k + r) 37 | /// ); 38 | /// 39 | /// assert_eq!(vec!["Apple0", "Cherry4"], db.evaluate(&join).unwrap().into_tuples()); 40 | /// ``` 41 | #[derive(Clone)] 42 | pub struct Join 43 | where 44 | K: Tuple, 45 | L: Tuple, 46 | R: Tuple, 47 | T: Tuple, 48 | Left: Expression, 49 | Right: Expression, 50 | { 51 | left: Left, 52 | right: Right, 53 | left_key: Rc K>>, 54 | right_key: Rc K>>, 55 | mapper: Rc>>, 56 | relation_deps: Vec, 57 | view_deps: Vec, 58 | } 59 | 60 | impl Join 61 | where 62 | K: Tuple, 63 | L: Tuple, 64 | R: Tuple, 65 | T: Tuple, 66 | Left: Expression, 67 | Right: Expression, 68 | { 69 | /// Creates a new [`Join`] expression over `left` and `right` where `left_key` 70 | /// and `right_key` are closures that return the join key for tuples of 71 | /// `left` and `right` respectively. The closure `mapper` computes the tuples 72 | /// of the resulting expression from the join key and the tuples of `left` and 73 | /// `right`. 74 | pub fn new( 75 | left: IL, 76 | right: IR, 77 | left_key: impl FnMut(&L) -> K + 'static, 78 | right_key: impl FnMut(&R) -> K + 'static, 79 | mapper: impl FnMut(&K, &L, &R) -> T + 'static, 80 | ) -> Self 81 | where 82 | IL: IntoExpression, 83 | IR: IntoExpression, 84 | { 85 | use super::dependency; 86 | let left = left.into_expression(); 87 | let right = right.into_expression(); 88 | 89 | let mut deps = dependency::DependencyVisitor::new(); 90 | left.visit(&mut deps); 91 | right.visit(&mut deps); 92 | let (relation_deps, view_deps) = deps.into_dependencies(); 93 | 94 | Self { 95 | left, 96 | right, 97 | left_key: Rc::new(RefCell::new(left_key)), 98 | right_key: Rc::new(RefCell::new(right_key)), 99 | mapper: Rc::new(RefCell::new(mapper)), 100 | relation_deps: relation_deps.into_iter().collect(), 101 | view_deps: view_deps.into_iter().collect(), 102 | } 103 | } 104 | 105 | /// Returns a reference to the left sub-expression. 106 | #[inline(always)] 107 | pub fn left(&self) -> &Left { 108 | &self.left 109 | } 110 | 111 | /// Returns a reference to the right sub-expression. 112 | #[inline(always)] 113 | pub fn right(&self) -> &Right { 114 | &self.right 115 | } 116 | 117 | /// Returns a mutable reference (of type [`RefMut`]) of the key closure for 118 | /// the left sub-expression. 119 | #[inline(always)] 120 | pub(crate) fn left_key_mut(&self) -> RefMut K> { 121 | self.left_key.borrow_mut() 122 | } 123 | 124 | /// Returns a mutable reference (of type [`RefMut`]) of the key closure for 125 | /// the right sub-expression. 126 | #[inline(always)] 127 | pub(crate) fn right_key_mut(&self) -> RefMut K> { 128 | self.right_key.borrow_mut() 129 | } 130 | 131 | /// Returns a mutable reference (of type [`RefMut`]) to the joining closure. 132 | #[inline(always)] 133 | pub(crate) fn mapper_mut(&self) -> RefMut T> { 134 | self.mapper.borrow_mut() 135 | } 136 | 137 | /// Returns a reference to the relation dependencies of the receiver. 138 | #[inline(always)] 139 | pub(crate) fn relation_deps(&self) -> &[String] { 140 | &self.relation_deps 141 | } 142 | 143 | /// Returns a reference to the view dependencies of the receiver. 144 | #[inline(always)] 145 | pub(crate) fn view_deps(&self) -> &[ViewRef] { 146 | &self.view_deps 147 | } 148 | } 149 | 150 | impl Expression for Join 151 | where 152 | K: Tuple, 153 | L: Tuple, 154 | R: Tuple, 155 | T: Tuple, 156 | Left: Expression, 157 | Right: Expression, 158 | { 159 | fn visit(&self, visitor: &mut V) 160 | where 161 | V: Visitor, 162 | { 163 | visitor.visit_join(&self); 164 | } 165 | } 166 | 167 | // A hack for debugging purposes: 168 | #[derive(Debug)] 169 | struct Debuggable 170 | where 171 | L: Tuple, 172 | R: Tuple, 173 | Left: Expression, 174 | Right: Expression, 175 | { 176 | left: Left, 177 | right: Right, 178 | _marker: PhantomData<(L, R)>, 179 | } 180 | 181 | impl std::fmt::Debug for Join 182 | where 183 | K: Tuple, 184 | L: Tuple, 185 | R: Tuple, 186 | T: Tuple, 187 | Left: Expression, 188 | Right: Expression, 189 | { 190 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 191 | Debuggable { 192 | left: self.left.clone(), 193 | right: self.right.clone(), 194 | _marker: PhantomData, 195 | } 196 | .fmt(f) 197 | } 198 | } 199 | 200 | #[cfg(test)] 201 | mod tests { 202 | use super::*; 203 | use crate::{Database, Tuples}; 204 | 205 | #[test] 206 | fn test_clone() { 207 | let mut database = Database::new(); 208 | let r = database.add_relation::<(i32, i32)>("r").unwrap(); 209 | let s = database.add_relation::<(i32, i32)>("s").unwrap(); 210 | database.insert(&r, vec![(1, 10)].into()).unwrap(); 211 | database.insert(&s, vec![(1, 100)].into()).unwrap(); 212 | let v = Join::new(&r, &s, |t| t.0, |t| t.0, |_, &l, &r| (l.1, r.1)).clone(); 213 | assert_eq!( 214 | Tuples::<(i32, i32)>::from(vec![(10, 100)]), 215 | database.evaluate(&v).unwrap() 216 | ); 217 | } 218 | } 219 | -------------------------------------------------------------------------------- /core/src/expression/mono.rs: -------------------------------------------------------------------------------- 1 | /*! Implements [`Mono`], a recursive expression where all subexpressions act on the 2 | same [`Tuple`] type. 3 | */ 4 | 5 | use super::*; 6 | 7 | /// Is a recursive [`Expression`] where all subexpressions act on the same [`Tuple`] type.; 8 | #[derive(Clone, Debug)] 9 | #[allow(clippy::type_complexity)] 10 | pub enum Mono 11 | where 12 | T: Tuple + 'static, 13 | { 14 | Full(Full), 15 | Empty(Empty), 16 | Singleton(Singleton), 17 | Relation(Relation), 18 | Select(Box>>), 19 | Project(Box>>), 20 | Union(Box, Mono>>), 21 | Intersect(Box, Mono>>), 22 | Difference(Box, Mono>>), 23 | Product(Box, Mono, T>>), 24 | Join(Box, Mono, T>>), 25 | View(Box>>), 26 | } 27 | 28 | impl Mono { 29 | /// Wraps the receiver in a `Box`. 30 | pub fn boxed(self) -> Box { 31 | Box::new(self) 32 | } 33 | } 34 | 35 | impl From> for Mono { 36 | fn from(full: Full) -> Self { 37 | Self::Full(full) 38 | } 39 | } 40 | 41 | impl From> for Mono { 42 | fn from(empty: Empty) -> Self { 43 | Self::Empty(empty) 44 | } 45 | } 46 | 47 | impl From> for Mono { 48 | fn from(singleton: Singleton) -> Self { 49 | Self::Singleton(singleton) 50 | } 51 | } 52 | 53 | impl From> for Mono { 54 | fn from(relation: Relation) -> Self { 55 | Self::Relation(relation) 56 | } 57 | } 58 | 59 | impl From>> for Mono { 60 | fn from(select: Select>) -> Self { 61 | Self::Select(Box::new(select)) 62 | } 63 | } 64 | 65 | impl From>> for Mono { 66 | fn from(project: Project>) -> Self { 67 | Self::Project(Box::new(project)) 68 | } 69 | } 70 | 71 | impl From, Mono>> for Mono { 72 | fn from(union: Union, Mono>) -> Self { 73 | Self::Union(Box::new(union)) 74 | } 75 | } 76 | 77 | impl From, Mono>> for Mono { 78 | fn from(intersect: Intersect, Mono>) -> Self { 79 | Self::Intersect(Box::new(intersect)) 80 | } 81 | } 82 | 83 | impl From, Mono>> for Mono { 84 | fn from(difference: Difference, Mono>) -> Self { 85 | Self::Difference(Box::new(difference)) 86 | } 87 | } 88 | 89 | impl From, Mono, T>> for Mono { 90 | fn from(product: Product, Mono, T>) -> Self { 91 | Self::Product(Box::new(product)) 92 | } 93 | } 94 | 95 | impl From, Mono, T>> for Mono { 96 | fn from(join: Join, Mono, T>) -> Self { 97 | Self::Join(Box::new(join)) 98 | } 99 | } 100 | 101 | impl From>> for Mono { 102 | fn from(view: View>) -> Self { 103 | Self::View(Box::new(view)) 104 | } 105 | } 106 | 107 | impl Expression for Mono { 108 | fn visit(&self, visitor: &mut V) 109 | where 110 | V: Visitor, 111 | { 112 | match self { 113 | Mono::Full(exp) => exp.visit(visitor), 114 | Mono::Empty(exp) => exp.visit(visitor), 115 | Mono::Singleton(exp) => exp.visit(visitor), 116 | Mono::Relation(exp) => exp.visit(visitor), 117 | Mono::Select(exp) => exp.visit(visitor), 118 | Mono::Project(exp) => exp.visit(visitor), 119 | Mono::Union(exp) => exp.visit(visitor), 120 | Mono::Intersect(exp) => exp.visit(visitor), 121 | Mono::Difference(exp) => exp.visit(visitor), 122 | Mono::Product(exp) => exp.visit(visitor), 123 | Mono::Join(exp) => exp.visit(visitor), 124 | Mono::View(exp) => exp.visit(visitor), 125 | } 126 | } 127 | } 128 | -------------------------------------------------------------------------------- /core/src/expression/product.rs: -------------------------------------------------------------------------------- 1 | use super::{view::ViewRef, Expression, IntoExpression, Visitor}; 2 | use crate::Tuple; 3 | use std::{ 4 | cell::{RefCell, RefMut}, 5 | marker::PhantomData, 6 | rc::Rc, 7 | }; 8 | 9 | /// Corresponds to the cartesian product of two expression. 10 | /// 11 | /// **Example**: 12 | /// ```rust 13 | /// use codd::{Database, expression::Product}; 14 | /// 15 | /// let mut db = Database::new(); 16 | /// let r = db.add_relation::("R").unwrap(); 17 | /// let s = db.add_relation::("S").unwrap(); 18 | /// 19 | /// db.insert(&r, vec![0, 1, 2].into()); 20 | /// db.insert(&s, vec![2, 4].into()); 21 | /// 22 | /// let prod = Product::new(&r, &s, |l, r| l*r); 23 | /// 24 | /// assert_eq!(vec![0, 2, 4, 8], db.evaluate(&prod).unwrap().into_tuples()); 25 | /// ``` 26 | #[derive(Clone)] 27 | pub struct Product 28 | where 29 | L: Tuple, 30 | R: Tuple, 31 | T: Tuple, 32 | Left: Expression, 33 | Right: Expression, 34 | { 35 | left: Left, 36 | right: Right, 37 | mapper: Rc T>>, 38 | relation_deps: Vec, 39 | view_deps: Vec, 40 | } 41 | 42 | impl Product 43 | where 44 | L: Tuple, 45 | R: Tuple, 46 | T: Tuple, 47 | Left: Expression, 48 | Right: Expression, 49 | { 50 | /// Creates a [`Product`] expression over `left` and `right` with `mapper` as the closure 51 | /// that produces the tuples of the resulting expression from tuples of `left` and `right`. 52 | pub fn new(left: IL, right: IR, project: impl FnMut(&L, &R) -> T + 'static) -> Self 53 | where 54 | IL: IntoExpression, 55 | IR: IntoExpression, 56 | { 57 | use super::dependency; 58 | let left = left.into_expression(); 59 | let right = right.into_expression(); 60 | 61 | let mut deps = dependency::DependencyVisitor::new(); 62 | left.visit(&mut deps); 63 | right.visit(&mut deps); 64 | let (relation_deps, view_deps) = deps.into_dependencies(); 65 | 66 | Self { 67 | left, 68 | right, 69 | mapper: Rc::new(RefCell::new(project)), 70 | relation_deps: relation_deps.into_iter().collect(), 71 | view_deps: view_deps.into_iter().collect(), 72 | } 73 | } 74 | 75 | /// Returns a reference to the left sub-expression. 76 | #[inline(always)] 77 | pub fn left(&self) -> &Left { 78 | &self.left 79 | } 80 | 81 | /// Returns a reference to the right sub-expression. 82 | #[inline(always)] 83 | pub fn right(&self) -> &Right { 84 | &self.right 85 | } 86 | 87 | /// Returns a mutable reference (of type [`RefMut`]) to the mapping closure. 88 | #[inline(always)] 89 | pub fn mapper_mut(&self) -> RefMut T> { 90 | self.mapper.borrow_mut() 91 | } 92 | 93 | /// Returns a reference to the relation dependencies of the receiver. 94 | #[inline(always)] 95 | pub(crate) fn relation_deps(&self) -> &[String] { 96 | &self.relation_deps 97 | } 98 | 99 | /// Returns a reference to the view dependencies of the receiver. 100 | #[inline(always)] 101 | pub(crate) fn view_deps(&self) -> &[ViewRef] { 102 | &self.view_deps 103 | } 104 | } 105 | 106 | impl Expression for Product 107 | where 108 | L: Tuple, 109 | R: Tuple, 110 | T: Tuple, 111 | Left: Expression, 112 | Right: Expression, 113 | { 114 | fn visit(&self, visitor: &mut V) 115 | where 116 | V: Visitor, 117 | { 118 | visitor.visit_product(&self); 119 | } 120 | } 121 | 122 | // A hack for debugging purposes: 123 | #[derive(Debug)] 124 | struct Debuggable 125 | where 126 | L: Tuple, 127 | R: Tuple, 128 | Left: Expression, 129 | Right: Expression, 130 | { 131 | left: Left, 132 | right: Right, 133 | _marker: PhantomData<(L, R)>, 134 | } 135 | 136 | impl std::fmt::Debug for Product 137 | where 138 | L: Tuple, 139 | R: Tuple, 140 | T: Tuple, 141 | Left: Expression, 142 | Right: Expression, 143 | { 144 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 145 | Debuggable { 146 | left: self.left.clone(), 147 | right: self.right.clone(), 148 | _marker: PhantomData, 149 | } 150 | .fmt(f) 151 | } 152 | } 153 | 154 | #[cfg(test)] 155 | mod tests { 156 | use super::*; 157 | use crate::{Database, Tuples}; 158 | 159 | #[test] 160 | fn test_clone() { 161 | let mut database = Database::new(); 162 | let r = database.add_relation::("r").unwrap(); 163 | let s = database.add_relation::("s").unwrap(); 164 | database.insert(&r, vec![1, 10].into()).unwrap(); 165 | database.insert(&s, vec![1, 100].into()).unwrap(); 166 | let v = Product::new(&r, &s, |&l, &r| l + r).clone(); 167 | assert_eq!( 168 | Tuples::from(vec![2, 11, 101, 110]), 169 | database.evaluate(&v).unwrap() 170 | ); 171 | } 172 | } 173 | -------------------------------------------------------------------------------- /core/src/expression/project.rs: -------------------------------------------------------------------------------- 1 | use super::{view::ViewRef, Expression, IntoExpression, Visitor}; 2 | use crate::Tuple; 3 | use std::{ 4 | cell::{RefCell, RefMut}, 5 | marker::PhantomData, 6 | rc::Rc, 7 | }; 8 | 9 | /// Projects the tuples of an inner sub-expression of type `S` to tuples of type `T`. 10 | /// 11 | /// **Example**: 12 | /// ```rust 13 | /// use codd::{Database, expression::Project}; 14 | /// 15 | /// let mut db = Database::new(); 16 | /// let fruit = db.add_relation::("R").unwrap(); 17 | /// 18 | /// db.insert(&fruit, vec!["Apple".to_string(), "BANANA".to_string(), "cherry".to_string()].into()); 19 | /// 20 | /// let lower = Project::new( 21 | /// &fruit, 22 | /// |t| t.to_lowercase(), // projecting closure 23 | /// ); 24 | /// 25 | /// assert_eq!(vec!["apple", "banana", "cherry"], db.evaluate(&lower).unwrap().into_tuples()); 26 | /// ``` 27 | #[derive(Clone)] 28 | pub struct Project 29 | where 30 | S: Tuple, 31 | T: Tuple, 32 | E: Expression, 33 | { 34 | expression: E, 35 | mapper: Rc T>>, 36 | relation_deps: Vec, 37 | view_deps: Vec, 38 | } 39 | 40 | impl Project 41 | where 42 | S: Tuple, 43 | T: Tuple, 44 | E: Expression, 45 | { 46 | /// Creates a new [`Project`] expression over `expression` with a closure `mapper` that 47 | /// projects tuples of `expression` to the resulting tuples. 48 | pub fn new(expression: I, mapper: impl FnMut(&S) -> T + 'static) -> Self 49 | where 50 | I: IntoExpression, 51 | { 52 | use super::dependency; 53 | let expression = expression.into_expression(); 54 | 55 | let mut deps = dependency::DependencyVisitor::new(); 56 | expression.visit(&mut deps); 57 | let (relation_deps, view_deps) = deps.into_dependencies(); 58 | 59 | Self { 60 | expression, 61 | mapper: Rc::new(RefCell::new(mapper)), 62 | relation_deps: relation_deps.into_iter().collect(), 63 | view_deps: view_deps.into_iter().collect(), 64 | } 65 | } 66 | 67 | /// Returns a reference to the underlying sub-expression. 68 | #[inline(always)] 69 | pub fn expression(&self) -> &E { 70 | &self.expression 71 | } 72 | 73 | /// Returns a mutable reference (of type [`RefMut`]) to the projecting closure. 74 | #[inline(always)] 75 | pub(crate) fn mapper_mut(&self) -> RefMut T> { 76 | self.mapper.borrow_mut() 77 | } 78 | 79 | /// Returns a reference to the relation dependencies of the receiver. 80 | #[inline(always)] 81 | pub(crate) fn relation_deps(&self) -> &[String] { 82 | &self.relation_deps 83 | } 84 | 85 | /// Returns a reference to the view dependencies of the receiver. 86 | #[inline(always)] 87 | pub(crate) fn view_deps(&self) -> &[ViewRef] { 88 | &self.view_deps 89 | } 90 | } 91 | 92 | impl Expression for Project 93 | where 94 | S: Tuple, 95 | T: Tuple, 96 | E: Expression, 97 | { 98 | fn visit(&self, visitor: &mut V) 99 | where 100 | V: Visitor, 101 | { 102 | visitor.visit_project(&self); 103 | } 104 | } 105 | 106 | // A hack: 107 | #[derive(Debug)] 108 | struct Debuggable 109 | where 110 | S: Tuple, 111 | E: Expression, 112 | { 113 | expression: E, 114 | _marker: PhantomData, 115 | } 116 | 117 | impl std::fmt::Debug for Project 118 | where 119 | S: Tuple, 120 | T: Tuple, 121 | E: Expression, 122 | { 123 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 124 | Debuggable { 125 | expression: self.expression.clone(), 126 | _marker: PhantomData, 127 | } 128 | .fmt(f) 129 | } 130 | } 131 | 132 | #[cfg(test)] 133 | mod tests { 134 | use super::*; 135 | use crate::{Database, Tuples}; 136 | 137 | #[test] 138 | fn test_clone() { 139 | let mut database = Database::new(); 140 | let r = database.add_relation::("r").unwrap(); 141 | database.insert(&r, vec![1, 2, 3].into()).unwrap(); 142 | let p = Project::new(&r, |&t| t * 10).clone(); 143 | assert_eq!( 144 | Tuples::::from(vec![10, 20, 30]), 145 | database.evaluate(&p).unwrap() 146 | ); 147 | } 148 | } 149 | -------------------------------------------------------------------------------- /core/src/expression/relation.rs: -------------------------------------------------------------------------------- 1 | use super::{Expression, Visitor}; 2 | use crate::Tuple; 3 | use std::marker::PhantomData; 4 | 5 | /// Is an expression corresponding to a relation with tuples of type `T` that is identified 6 | /// by a `name`. 7 | /// 8 | /// **Example**: 9 | /// ```rust 10 | /// use codd::{Database, expression::Relation}; 11 | /// 12 | /// let mut db = Database::new(); 13 | /// let r = db.add_relation("R").unwrap(); 14 | /// 15 | /// db.insert(&r, vec![0, 1, 2, 3].into()).unwrap(); // insert into the relation instance 16 | /// 17 | /// assert_eq!(vec![0, 1, 2, 3], db.evaluate(&r).unwrap().into_tuples()); 18 | /// ``` 19 | #[derive(Clone, Debug)] 20 | pub struct Relation 21 | where 22 | T: Tuple, 23 | { 24 | name: String, 25 | relation_deps: Vec, 26 | _phantom: PhantomData, 27 | } 28 | 29 | impl Relation 30 | where 31 | T: Tuple, 32 | { 33 | /// Creates a new [`Relation`] with a given `name`. 34 | pub fn new(name: S) -> Self 35 | where 36 | S: Into, 37 | { 38 | let name = name.into(); 39 | Self { 40 | relation_deps: vec![name.clone()], 41 | name, 42 | _phantom: PhantomData, 43 | } 44 | } 45 | 46 | /// Returns a reference to the name by which the relation is identified. 47 | #[inline(always)] 48 | pub fn name(&self) -> &str { 49 | &self.name 50 | } 51 | 52 | /// Returns a reference to the relation dependencies of the receiver. 53 | #[inline(always)] 54 | pub(crate) fn relation_deps(&self) -> &[String] { 55 | &self.relation_deps 56 | } 57 | } 58 | 59 | impl Expression for Relation 60 | where 61 | T: Tuple + 'static, 62 | { 63 | fn visit(&self, visitor: &mut V) 64 | where 65 | V: Visitor, 66 | { 67 | visitor.visit_relation(&self); 68 | } 69 | } 70 | 71 | #[cfg(test)] 72 | mod tests { 73 | use super::*; 74 | use crate::{Database, Tuples}; 75 | 76 | #[test] 77 | fn test_new() { 78 | assert_eq!("a".to_string(), Relation::::new("a").name); 79 | } 80 | 81 | #[test] 82 | fn test_clone() { 83 | let mut database = Database::new(); 84 | let r = database.add_relation::("r").unwrap(); 85 | database.insert(&r, vec![1, 2, 3].into()).unwrap(); 86 | assert_eq!( 87 | Tuples::::from(vec![1, 2, 3]), 88 | database.evaluate(&r.clone()).unwrap() 89 | ); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /core/src/expression/select.rs: -------------------------------------------------------------------------------- 1 | use super::{view::ViewRef, Expression, IntoExpression, Visitor}; 2 | use crate::Tuple; 3 | use std::{ 4 | cell::{RefCell, RefMut}, 5 | marker::PhantomData, 6 | rc::Rc, 7 | }; 8 | 9 | /// Selects tuples of the underlying sub-expression according to a given predicate. 10 | /// 11 | /// **Example**: 12 | /// ```rust 13 | /// use codd::{Database, expression::Select}; 14 | /// 15 | /// let mut db = Database::new(); 16 | /// let fruit = db.add_relation::("Fruit").unwrap(); 17 | /// 18 | /// db.insert(&fruit, vec!["Apple".to_string(), "BANANA".to_string(), "cherry".to_string()].into()); 19 | /// 20 | /// let select = Select::new( 21 | /// &fruit, 22 | /// |t| t.contains('A'), // select predicate 23 | /// ); 24 | /// 25 | /// assert_eq!(vec!["Apple", "BANANA"], db.evaluate(&select).unwrap().into_tuples()); 26 | /// ``` 27 | #[derive(Clone)] 28 | pub struct Select 29 | where 30 | T: Tuple, 31 | E: Expression, 32 | { 33 | expression: E, 34 | predicate: Rc bool>>, 35 | relation_deps: Vec, 36 | view_deps: Vec, 37 | } 38 | 39 | impl Select 40 | where 41 | T: Tuple, 42 | E: Expression, 43 | { 44 | /// Creates a new [`Select`] expression over `expression` according to the `predicate` closure. 45 | pub fn new(expression: I, predicate: P) -> Self 46 | where 47 | I: IntoExpression, 48 | P: FnMut(&T) -> bool + 'static, 49 | { 50 | use super::dependency; 51 | let expression = expression.into_expression(); 52 | 53 | let mut deps = dependency::DependencyVisitor::new(); 54 | expression.visit(&mut deps); 55 | let (relation_deps, view_deps) = deps.into_dependencies(); 56 | 57 | Self { 58 | expression, 59 | predicate: Rc::new(RefCell::new(predicate)), 60 | relation_deps: relation_deps.into_iter().collect(), 61 | view_deps: view_deps.into_iter().collect(), 62 | } 63 | } 64 | 65 | /// Returns a reference to the underlying sub-expression. 66 | #[inline(always)] 67 | pub fn expression(&self) -> &E { 68 | &self.expression 69 | } 70 | 71 | /// Returns a mutable reference (of type [`RefMut`]) to the select predicate. 72 | #[inline(always)] 73 | pub(crate) fn predicate_mut(&self) -> RefMut bool> { 74 | self.predicate.borrow_mut() 75 | } 76 | 77 | /// Returns a reference to the relation dependencies of the receiver. 78 | #[inline(always)] 79 | pub(crate) fn relation_deps(&self) -> &[String] { 80 | &self.relation_deps 81 | } 82 | 83 | /// Returns a reference to the view dependencies of the receiver. 84 | #[inline(always)] 85 | pub(crate) fn view_deps(&self) -> &[ViewRef] { 86 | &self.view_deps 87 | } 88 | } 89 | 90 | impl Expression for Select 91 | where 92 | T: Tuple, 93 | E: Expression, 94 | { 95 | fn visit(&self, visitor: &mut V) 96 | where 97 | V: Visitor, 98 | { 99 | visitor.visit_select(&self); 100 | } 101 | } 102 | 103 | #[derive(Debug)] 104 | struct Debuggable 105 | where 106 | T: Tuple, 107 | E: Expression, 108 | { 109 | expression: E, 110 | _marker: PhantomData, 111 | } 112 | 113 | impl std::fmt::Debug for Select 114 | where 115 | T: Tuple, 116 | E: Expression, 117 | { 118 | fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 119 | Debuggable { 120 | expression: self.expression.clone(), 121 | _marker: PhantomData, 122 | } 123 | .fmt(f) 124 | } 125 | } 126 | 127 | #[cfg(test)] 128 | mod tests { 129 | use super::*; 130 | use crate::{Database, Tuples}; 131 | 132 | #[test] 133 | fn test_clone() { 134 | let mut database = Database::new(); 135 | let r = database.add_relation::("r").unwrap(); 136 | database.insert(&r, vec![1, 2, 3].into()).unwrap(); 137 | let p = Select::new(&r, |&t| t % 2 == 1).clone(); 138 | assert_eq!( 139 | Tuples::::from(vec![1, 3]), 140 | database.evaluate(&p).unwrap() 141 | ); 142 | } 143 | } 144 | -------------------------------------------------------------------------------- /core/src/expression/singleton.rs: -------------------------------------------------------------------------------- 1 | use super::Expression; 2 | use crate::Tuple; 3 | 4 | /// Represents a single tuple of type `T`. 5 | /// 6 | /// **Example**: 7 | /// ```rust 8 | /// use codd::{Database, expression::Singleton}; 9 | /// 10 | /// let mut db = Database::new(); 11 | /// let hello = Singleton::new("Hello".to_string()); 12 | /// 13 | /// assert_eq!(vec!["Hello".to_string()], db.evaluate(&hello).unwrap().into_tuples()); 14 | /// ``` 15 | #[derive(Clone, Debug)] 16 | pub struct Singleton(T) 17 | where 18 | T: Tuple; 19 | 20 | impl Singleton { 21 | /// Create a new instance of [`Singleton`] with `tuple` as the inner value. 22 | pub fn new(tuple: T) -> Self { 23 | Self(tuple) 24 | } 25 | 26 | /// Returns a reference to the inner value of the receiver. 27 | #[inline(always)] 28 | pub fn tuple(&self) -> &T { 29 | &self.0 30 | } 31 | 32 | /// Consumes the receiver and returns its inner value. 33 | #[inline(always)] 34 | pub fn into_tuple(self) -> T { 35 | self.0 36 | } 37 | } 38 | 39 | impl Expression for Singleton 40 | where 41 | T: Tuple, 42 | { 43 | fn visit(&self, visitor: &mut V) 44 | where 45 | V: super::Visitor, 46 | { 47 | visitor.visit_singleton(&self) 48 | } 49 | } 50 | 51 | #[cfg(test)] 52 | mod tests { 53 | use super::*; 54 | 55 | #[test] 56 | fn test_new() { 57 | assert_eq!(42, Singleton::new(42).into_tuple()); 58 | } 59 | 60 | #[test] 61 | fn test_clone() { 62 | let s = Singleton::new(42); 63 | assert_eq!(42, s.clone().into_tuple()); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /core/src/expression/union.rs: -------------------------------------------------------------------------------- 1 | use super::{view::ViewRef, Expression, IntoExpression, Visitor}; 2 | use crate::Tuple; 3 | use std::marker::PhantomData; 4 | 5 | /// Evaluates to the union of the tuples in its `left` and `right` sub-expressions. 6 | /// 7 | /// **Example**: 8 | /// ```rust 9 | /// use codd::{Database, expression::Union}; 10 | /// 11 | /// let mut db = Database::new(); 12 | /// let r = db.add_relation::("R").unwrap(); 13 | /// let s = db.add_relation::("S").unwrap(); 14 | /// 15 | /// db.insert(&r, vec![0, 1, 2].into()); 16 | /// db.insert(&s, vec![2, 4].into()); 17 | /// 18 | /// let union = Union::new(&r, &s); 19 | /// 20 | /// assert_eq!(vec![0, 1, 2, 4], db.evaluate(&union).unwrap().into_tuples()); 21 | /// ``` 22 | #[derive(Clone, Debug)] 23 | pub struct Union 24 | where 25 | T: Tuple, 26 | L: Expression, 27 | R: Expression, 28 | { 29 | left: L, 30 | right: R, 31 | relation_deps: Vec, 32 | view_deps: Vec, 33 | _marker: PhantomData, 34 | } 35 | 36 | impl Union 37 | where 38 | T: Tuple, 39 | L: Expression, 40 | R: Expression, 41 | { 42 | /// Creates a new instance of [`Union`] corresponding to `left ∪ right`. 43 | pub fn new(left: IL, right: IR) -> Self 44 | where 45 | IL: IntoExpression, 46 | IR: IntoExpression, 47 | { 48 | use super::dependency; 49 | let left = left.into_expression(); 50 | let right = right.into_expression(); 51 | 52 | let mut deps = dependency::DependencyVisitor::new(); 53 | left.visit(&mut deps); 54 | right.visit(&mut deps); 55 | let (relation_deps, view_deps) = deps.into_dependencies(); 56 | 57 | Self { 58 | left, 59 | right, 60 | relation_deps: relation_deps.into_iter().collect(), 61 | view_deps: view_deps.into_iter().collect(), 62 | _marker: PhantomData, 63 | } 64 | } 65 | 66 | /// Returns a reference to the left sub-expression. 67 | #[inline(always)] 68 | pub fn left(&self) -> &L { 69 | &self.left 70 | } 71 | 72 | /// Returns a reference to the right sub-expression. 73 | #[inline(always)] 74 | pub fn right(&self) -> &R { 75 | &self.right 76 | } 77 | 78 | /// Returns a reference to the relation dependencies of the receiver. 79 | #[inline(always)] 80 | pub(crate) fn relation_deps(&self) -> &[String] { 81 | &self.relation_deps 82 | } 83 | 84 | /// Returns a reference to the view dependencies of the receiver. 85 | #[inline(always)] 86 | pub(crate) fn view_deps(&self) -> &[ViewRef] { 87 | &self.view_deps 88 | } 89 | } 90 | 91 | impl Expression for Union 92 | where 93 | T: Tuple, 94 | L: Expression, 95 | R: Expression, 96 | { 97 | fn visit(&self, visitor: &mut V) 98 | where 99 | V: Visitor, 100 | { 101 | visitor.visit_union(&self); 102 | } 103 | } 104 | 105 | #[cfg(test)] 106 | mod tests { 107 | use super::*; 108 | use crate::{Database, Tuples}; 109 | 110 | #[test] 111 | fn test_clone() { 112 | let mut database = Database::new(); 113 | let r = database.add_relation::("r").unwrap(); 114 | let s = database.add_relation::("s").unwrap(); 115 | database.insert(&r, vec![1, 2, 3].into()).unwrap(); 116 | database.insert(&s, vec![4, 5].into()).unwrap(); 117 | let u = Union::new(&r, &s).clone(); 118 | assert_eq!( 119 | Tuples::::from(vec![1, 2, 3, 4, 5]), 120 | database.evaluate(&u).unwrap() 121 | ); 122 | } 123 | } 124 | -------------------------------------------------------------------------------- /core/src/expression/view.rs: -------------------------------------------------------------------------------- 1 | use super::{Expression, Visitor}; 2 | use crate::Tuple; 3 | use std::marker::PhantomData; 4 | 5 | /// Is the type of the view identifiers in a database. 6 | #[derive(PartialEq, Eq, Clone, Hash, Debug)] 7 | pub struct ViewRef(pub(crate) i32); 8 | 9 | /// Represents a view in the database. 10 | /// 11 | /// **Example**: 12 | /// ```rust 13 | /// use codd::{Database, expression::{Product, View}}; 14 | /// 15 | /// let mut db = Database::new(); 16 | /// let dividends = db.add_relation("dividends").unwrap(); 17 | /// let divisors = db.add_relation("divisors").unwrap(); 18 | /// 19 | /// db.insert(÷nds, vec![6, 12, 18].into()).unwrap(); 20 | /// db.insert(&divisors, vec![2, 3].into()).unwrap(); 21 | /// 22 | /// // divide all elements of `dividends` by all elements of `divisors`: 23 | /// let quotients = Product::new( 24 | /// dividends.clone(), 25 | /// divisors.clone(), 26 | /// |&l, &r| l/r 27 | /// ); 28 | /// let view = db.store_view(quotients.clone()).unwrap(); 29 | /// 30 | /// // `view` and `quotients` evaluate to the same result: 31 | /// assert_eq!(vec![2, 3, 4, 6, 9], db.evaluate("ients).unwrap().into_tuples()); 32 | /// assert_eq!(vec![2, 3, 4, 6, 9], db.evaluate(&view).unwrap().into_tuples()); 33 | /// 34 | /// db.insert(÷nds, vec![24, 30].into()); 35 | /// db.insert(&divisors, vec![1].into()); 36 | /// 37 | /// // the view gets updated automatically: 38 | /// assert_eq!( 39 | /// vec![2, 3, 4, 6, 8, 9, 10, 12, 15, 18, 24, 30], 40 | /// db.evaluate(&view).unwrap().into_tuples() 41 | /// ); 42 | /// 43 | /// use codd::expression::Difference; 44 | /// // incremental view update for `Difference` is currently not supported: 45 | /// assert!(db.store_view(Difference::new(dividends, divisors)).is_err()); 46 | /// ``` 47 | #[derive(PartialEq, Eq, Clone, Debug)] 48 | pub struct View 49 | where 50 | T: Tuple, 51 | E: Expression, 52 | { 53 | reference: ViewRef, 54 | view_deps: Vec, 55 | _phantom: PhantomData<(T, E)>, 56 | } 57 | 58 | impl View 59 | where 60 | T: Tuple, 61 | E: Expression, 62 | { 63 | /// Creates a new [`View`] with a given reference. 64 | pub(crate) fn new(reference: ViewRef) -> Self { 65 | Self { 66 | view_deps: vec![reference.clone()], 67 | reference, 68 | _phantom: PhantomData, 69 | } 70 | } 71 | 72 | /// Returns the reference to this view. 73 | #[inline(always)] 74 | pub(crate) fn reference(&self) -> &ViewRef { 75 | &self.reference 76 | } 77 | 78 | /// Returns a reference to the view dependencies of the receiver. 79 | #[inline(always)] 80 | pub(crate) fn view_deps(&self) -> &[ViewRef] { 81 | &self.view_deps 82 | } 83 | } 84 | 85 | impl Expression for View 86 | where 87 | T: Tuple + 'static, 88 | E: Expression + 'static, 89 | { 90 | fn visit(&self, visitor: &mut V) 91 | where 92 | V: Visitor, 93 | { 94 | visitor.visit_view(&self); 95 | } 96 | } 97 | 98 | #[cfg(test)] 99 | mod tests { 100 | use crate::{Database, Tuples}; 101 | 102 | #[test] 103 | fn test_clone() { 104 | let mut database = Database::new(); 105 | let r = database.add_relation::("r").unwrap(); 106 | let v = database.store_view(r.clone()).unwrap().clone(); 107 | database.insert(&r, vec![1, 2, 3].into()).unwrap(); 108 | assert_eq!( 109 | Tuples::::from(vec![1, 2, 3]), 110 | database.evaluate(&v).unwrap() 111 | ); 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /core/src/lib.rs: -------------------------------------------------------------------------------- 1 | /*! Implements a minimal [database][Database] and relational algebraic [expressions][expression] for evaluating queries in the database. 2 | */ 3 | mod database; 4 | pub mod expression; 5 | 6 | #[cfg(feature = "unstable")] 7 | mod macros; 8 | 9 | pub use database::{Database, Tuples}; 10 | pub use expression::Expression; 11 | use thiserror::Error; 12 | 13 | /// Is the trait of tuples. Tuples are the smallest unit of data stored in databases. 14 | /// 15 | /// **Note**: Tuples are analogous to the rows of a table in a conventional database. 16 | pub trait Tuple: Ord + Clone + std::fmt::Debug {} 17 | impl Tuple for T {} 18 | 19 | /// Is the type of errors returned by `codd`. 20 | #[derive(Error, Debug)] 21 | pub enum Error { 22 | /// Is returned when an unsupported operation is performed on an expression. 23 | #[error("unsopported operation `{operation:?}` on expression `{name:?}`")] 24 | UnsupportedExpression { name: String, operation: String }, 25 | 26 | /// Is returned when a given relation instance doesn't exist. 27 | #[error("database instance `{name:?}` not found")] 28 | InstanceNotFound { name: String }, 29 | 30 | /// Is returned when attempting to re-define an existing instance in a database. 31 | #[error("database instance `{name:?}` already exists")] 32 | InstanceExists { name: String }, 33 | } 34 | -------------------------------------------------------------------------------- /core/src/macros.rs: -------------------------------------------------------------------------------- 1 | #[macro_export] 2 | macro_rules! query { 3 | (select [$proj:expr] from ($($rel_exp:tt)*) $(where [$($pred:tt)*])?) => { 4 | $crate::relexp!(@select ($($rel_exp)*) @proj -> [$proj] $(@pred -> [$($pred)*])?) 5 | }; 6 | (select * from ($($rel_exp:tt)*) $(where [$($pred:tt)*])?) => { 7 | $crate::relexp!(@select ($($rel_exp)*) $(@pred -> [$($pred)*])?) 8 | }; 9 | ($db:ident, create relation $name:literal:<$schema:ty>) => { 10 | $db.add_relation::<$schema>($name); 11 | }; 12 | ($db:ident, create view as 13 | (select [$proj:expr] from ($($rel_exp:tt)*) $(where [$($pred:tt)*])?)) => { 14 | { 15 | let inner_exp = $crate::relexp!(@select ($($rel_exp)*) 16 | @proj -> [$proj] 17 | $(@pred -> [$($pred)*])?); 18 | $db.store_view(inner_exp.clone()) 19 | } 20 | }; 21 | ($db:ident, create view as 22 | (select * from ($($rel_exp:tt)*) $(where [$($pred:tt)*])?)) => { 23 | { 24 | let inner_exp = $crate::relexp!(@select ($($rel_exp)*) $(@pred -> [$($pred)*])?); 25 | $db.store_view(inner_exp.clone()) 26 | } 27 | }; 28 | ($db:ident, insert into ($relation:ident) values [$($value:expr),*]) => { 29 | { 30 | $db.insert(&$relation, vec![$($value,)*].into()) 31 | } 32 | }; 33 | ($db:ident, insert into ($relation:ident) values [$($value:expr),+,]) => { 34 | { 35 | $db.insert(&$relation, vec![$($value,)+].into()) 36 | } 37 | }; 38 | } 39 | 40 | #[macro_export] 41 | macro_rules! relexp { 42 | ($r:ident) => { 43 | (&$r).clone() 44 | }; 45 | ([$s:expr]) => { 46 | $crate::expression::Singleton::new($s) 47 | }; 48 | (select [$proj:expr] from ($($rel_exp:tt)*) $(where [$($pred:tt)*])?) => { 49 | $crate::relexp!(@select ($($rel_exp)*) @proj -> [$proj] $(@pred -> [$($pred)*])?) 50 | }; 51 | (select * from ($($rel_exp:tt)*) $(where [$($pred:tt)*])?) => { 52 | $crate::relexp!(@select ($($rel_exp)*) $(@pred -> [$($pred)*])?) 53 | }; 54 | (($($left:tt)*) cross ($($right:tt)*) on [$mapper:expr]) => { 55 | $crate::relexp!(@cross ($($left)*) ($($right)*) @mapper -> [$mapper]) 56 | }; 57 | (($($left:tt)*) join ($($right:tt)*) on [$lkey:expr ; $rkey:expr] with [$mapper:expr]) => { 58 | $crate::relexp!(@join ($($left)*) @lkey -> [$lkey] ($($right)*) @rkey -> [$rkey] @mapper -> [$mapper]) 59 | }; 60 | (($($left:tt)*) union ($($right:tt)*)) => { 61 | $crate::relexp!(@union ($($left)*) ($($right)*)) 62 | }; 63 | (($($left:tt)*) intersect ($($right:tt)*)) => { 64 | $crate::relexp!(@intersect ($($left)*) ($($right)*)) 65 | }; 66 | (($($left:tt)*) minus ($($right:tt)*)) => { 67 | $crate::relexp!(@minus ($($left)*) ($($right)*)) 68 | }; 69 | (@select ($($rel_exp:tt)*) @proj -> [$proj:expr] @pred -> [$($pred:tt)*]) => {{ 70 | let rel_exp = $crate::relexp!($($rel_exp)*); 71 | let sel_exp = $crate::expression::Select::new(rel_exp, $($pred)*); 72 | $crate::expression::Project::new(sel_exp, $proj) 73 | }}; 74 | (@select ($($rel_exp:tt)*) @proj -> [$proj:expr]) => {{ 75 | let rel_exp = $crate::relexp!($($rel_exp)*); 76 | $crate::expression::Project::new(rel_exp, $proj) 77 | }}; 78 | (@select ($($rel_exp:tt)*) @pred -> [$($pred:tt)*]) => {{ 79 | let rel_exp = $crate::relexp!($($rel_exp)*); 80 | $crate::expression::Select::new(rel_exp, $($pred)*) 81 | }}; 82 | (@select ($($rel_exp:tt)*)) => {{ 83 | $crate::relexp!($($rel_exp)*) 84 | }}; 85 | (@cross ($($left:tt)*) ($($right:tt)*) @mapper -> [$mapper:expr]) => {{ 86 | let left = $crate::relexp!($($left)*); 87 | let right = $crate::relexp!($($right)*); 88 | $crate::expression::Product::new(left, right, $mapper) 89 | }}; 90 | (@join ($($left:tt)*) @lkey -> [$lkey:expr] ($($right:tt)*) @rkey -> [$rkey:expr] @mapper -> [$mapper:expr]) => {{ 91 | let left = $crate::relexp!($($left)*); 92 | let right = $crate::relexp!($($right)*); 93 | $crate::expression::Join::new(left, right, $lkey, $rkey, $mapper) 94 | }}; 95 | (@union ($($left:tt)*) ($($right:tt)*)) => {{ 96 | let left = $crate::relexp!($($left)*); 97 | let right = $crate::relexp!($($right)*); 98 | $crate::expression::Union::new(left, right) 99 | }}; 100 | (@intersect ($($left:tt)*) ($($right:tt)*)) => {{ 101 | let left = $crate::relexp!($($left)*); 102 | let right = $crate::relexp!($($right)*); 103 | $crate::expression::Intersect::new(left, right) 104 | }}; 105 | (@minus ($($left:tt)*) ($($right:tt)*)) => {{ 106 | let left = $crate::relexp!($($left)*); 107 | let right = $crate::relexp!($($right)*); 108 | $crate::expression::Difference::new(left, right) 109 | }}; 110 | } 111 | 112 | #[cfg(test)] 113 | mod tests { 114 | use crate::{query, relexp}; 115 | use crate::{Database, Tuples}; 116 | 117 | macro_rules! create_relation { 118 | ($db: ident, $n:literal, $t: ty) => {{ 119 | let relation = query! {$db, create relation $n:<$t>}; 120 | relation.unwrap() 121 | }}; 122 | } 123 | 124 | #[test] 125 | fn test_query() { 126 | { 127 | let mut database = Database::new(); 128 | let r = create_relation!(database, "r", i32); 129 | assert!(database.evaluate(&r).is_ok()); 130 | } 131 | { 132 | let mut database = Database::new(); 133 | let r = create_relation!(database, "r", i32); 134 | query! (database, insert into (r) values [1, 2, 3, 4]).unwrap(); 135 | let exp = query! { select * from(r) }; 136 | let result = database.evaluate(&exp).unwrap(); 137 | assert_eq!(Tuples::::from(vec![1, 2, 3, 4]), result); 138 | } 139 | { 140 | let mut database = Database::new(); 141 | let r = create_relation!(database, "r", i32); 142 | let exp = query!(select * from (r) where [|tuple| tuple % 2 == 0]); 143 | query! (database, insert into (r) values [1, 2, 3, 4]).unwrap(); 144 | let result = database.evaluate(&exp).unwrap(); 145 | assert_eq!(Tuples::::from(vec![2, 4]), result); 146 | } 147 | { 148 | let mut database = Database::new(); 149 | let r = create_relation!(database, "r", i32); 150 | let exp = query!( 151 | select * from 152 | (select * from (r) where [|&tuple| tuple > 2]) 153 | where [|tuple| tuple % 2 == 0] 154 | ); 155 | query! (database, insert into (r) values [1, 2, 3, 4]).unwrap(); 156 | let result = database.evaluate(&exp).unwrap(); 157 | assert_eq!(Tuples::::from(vec![4]), result); 158 | } 159 | { 160 | let mut database = Database::new(); 161 | let r = create_relation!(database, "r", i32); 162 | let exp = query!(select [|t| t + 1] from 163 | (select * from (r) where [|&tuple| tuple > 2])); 164 | query! (database, insert into (r) values [1, 2, 3, 4]).unwrap(); 165 | let result = database.evaluate(&exp).unwrap(); 166 | assert_eq!(Tuples::::from(vec![4, 5]), result); 167 | } 168 | { 169 | let mut database = Database::new(); 170 | let r = create_relation!(database, "r", i32); 171 | let v = query! { database, create view as (select * from (r))}.unwrap(); 172 | assert!(database.evaluate(&v).is_ok()); 173 | } 174 | { 175 | let mut database = Database::new(); 176 | let r = create_relation!(database, "r", i32); 177 | let v = query! { database, create view as (select [|&x| x > 0] from (r))}.unwrap(); 178 | assert!(database.evaluate(&v).is_ok()); 179 | } 180 | { 181 | let database = Database::new(); 182 | let exp = query! { select * from (([42]) union ([43]))}; 183 | let result = database.evaluate(&exp).unwrap(); 184 | assert_eq!(Tuples::::from(vec![42, 43]), result); 185 | } 186 | { 187 | let database = Database::new(); 188 | let exp = query! { select * from (([42]) intersect ([42]))}; 189 | let result = database.evaluate(&exp).unwrap(); 190 | assert_eq!(Tuples::::from(vec![42]), result); 191 | } 192 | { 193 | let database = Database::new(); 194 | let exp = query! { select * from (([42]) minus ([43]))}; 195 | let result = database.evaluate(&exp).unwrap(); 196 | assert_eq!(Tuples::::from(vec![42]), result); 197 | } 198 | } 199 | 200 | #[test] 201 | fn test_relexp() { 202 | { 203 | let database = Database::new(); 204 | let exp = relexp!([42]); 205 | let result = database.evaluate(&exp).unwrap(); 206 | assert_eq!(Tuples::::from(vec![42]), result); 207 | } 208 | { 209 | let mut database = Database::new(); 210 | let r = create_relation!(database, "r", i32); 211 | let exp = relexp!(r); 212 | query! (database, insert into (r) values [1, 2, 3, 4]).unwrap(); 213 | let result = database.evaluate(&exp).unwrap(); 214 | assert_eq!(Tuples::::from(vec![1, 2, 3, 4]), result); 215 | } 216 | { 217 | let mut database = Database::new(); 218 | let r = create_relation!(database, "r", i32); 219 | let exp = relexp!(select * from (r) where [|tuple| tuple % 2 == 0]); 220 | query! (database, insert into (r) values [1, 2, 3, 4]).unwrap(); 221 | let result = database.evaluate(&exp).unwrap(); 222 | assert_eq!(Tuples::::from(vec![2, 4]), result); 223 | } 224 | { 225 | let mut database = Database::new(); 226 | let r = create_relation!(database, "r", i32); 227 | let exp = relexp!(select * from 228 | (select * from (r) where [|&tuple| tuple > 2]) 229 | where [|tuple| tuple % 2 == 0]); 230 | query! (database, insert into (r) values [1, 2, 3, 4]).unwrap(); 231 | let result = database.evaluate(&exp).unwrap(); 232 | assert_eq!(Tuples::::from(vec![4]), result); 233 | } 234 | { 235 | let mut database = Database::new(); 236 | let r = create_relation!(database, "r", i32); 237 | let exp = relexp!(select [|t| t + 1] from (r)); 238 | query! (database, insert into (r) values [3, 4, 5, 6]).unwrap(); 239 | let result = database.evaluate(&exp).unwrap(); 240 | assert_eq!(Tuples::::from(vec![4, 5, 6, 7]), result); 241 | } 242 | { 243 | let mut database = Database::new(); 244 | let r = create_relation!(database, "r", i32); 245 | let exp = relexp!(select [|t| t + 1] from 246 | (select * from (r) where [|&tuple| tuple > 2])); 247 | query! (database, insert into (r) values [1, 2, 3, 4]).unwrap(); 248 | let result = database.evaluate(&exp).unwrap(); 249 | assert_eq!(Tuples::::from(vec![4, 5]), result); 250 | } 251 | { 252 | let mut database = Database::new(); 253 | let r = create_relation!(database, "r", i32); 254 | let exp = relexp!(select * from(r)); 255 | query! (database, insert into (r) values [1, 2, 3, 4]).unwrap(); 256 | let result = database.evaluate(&exp).unwrap(); 257 | assert_eq!(Tuples::::from(vec![1, 2, 3, 4]), result); 258 | } 259 | { 260 | let mut database = Database::new(); 261 | let r = create_relation!(database, "r", i32); 262 | let s = create_relation!(database, "s", i32); 263 | let exp = relexp!((r) cross (s) on [|&l, &r| l + r]); 264 | query! (database, insert into (r) values [ 265 | 1, 2, 3 266 | ]) 267 | .unwrap(); 268 | query! (database, insert into (s) values [ 269 | 10, 20, 30 270 | ]) 271 | .unwrap(); 272 | 273 | let result = database.evaluate(&exp).unwrap(); 274 | assert_eq!( 275 | Tuples::from(vec![11, 12, 13, 21, 22, 23, 31, 32, 33]), 276 | result 277 | ); 278 | } 279 | { 280 | let mut database = Database::new(); 281 | let r = create_relation!(database, "r", (i32, String)); 282 | let s = create_relation!(database, "s", (i32, String)); 283 | let exp = relexp!((r) join (s) on [|t| t.0; |t| t.0] with [|_, x, y| { 284 | let mut s = x.1.clone(); s.push_str(&y.1); s 285 | }]); 286 | query! (database, insert into (r) values [ 287 | (1, "a".to_string()), 288 | (2, "b".to_string()), 289 | (1, "a".to_string()), 290 | (4, "b".to_string()), 291 | ]) 292 | .unwrap(); 293 | query! (database, insert into (s) values [ 294 | (1, "x".to_string()), (2, "y".to_string()) 295 | ]) 296 | .unwrap(); 297 | 298 | let result = database.evaluate(&exp).unwrap(); 299 | assert_eq!( 300 | Tuples::from(vec!["ax".to_string(), "by".to_string()]), 301 | result 302 | ); 303 | } 304 | { 305 | let mut database = Database::new(); 306 | let r = create_relation!(database, "r", String); 307 | let s = create_relation!(database, "s", String); 308 | let exp = relexp!((r) union (s)); 309 | query! (database, insert into (r) values [ 310 | "a".to_string(), 311 | "b".to_string(), 312 | ]) 313 | .unwrap(); 314 | query! (database, insert into (s) values [ 315 | "x".to_string(), "b".to_string(), "y".to_string() 316 | ]) 317 | .unwrap(); 318 | 319 | let result = database.evaluate(&exp).unwrap(); 320 | assert_eq!( 321 | Tuples::from(vec![ 322 | "a".to_string(), 323 | "b".to_string(), 324 | "x".to_string(), 325 | "y".to_string() 326 | ]), 327 | result 328 | ); 329 | } 330 | { 331 | let mut database = Database::new(); 332 | let r = create_relation!(database, "r", String); 333 | let s = create_relation!(database, "s", String); 334 | let exp = relexp!((r) intersect (s)); 335 | query! (database, insert into (r) values [ 336 | "a".to_string(), 337 | "b".to_string(), 338 | ]) 339 | .unwrap(); 340 | query! (database, insert into (s) values [ 341 | "x".to_string(), "b".to_string(), "y".to_string() 342 | ]) 343 | .unwrap(); 344 | 345 | let result = database.evaluate(&exp).unwrap(); 346 | assert_eq!(Tuples::from(vec!["b".to_string(),]), result); 347 | } 348 | { 349 | let mut database = Database::new(); 350 | let r = create_relation!(database, "r", String); 351 | let s = create_relation!(database, "s", String); 352 | let exp = relexp!((r) minus (s)); 353 | query! (database, insert into (r) values [ 354 | "a".to_string(), 355 | "b".to_string(), 356 | ]) 357 | .unwrap(); 358 | query! (database, insert into (s) values [ 359 | "x".to_string(), "b".to_string(), "y".to_string() 360 | ]) 361 | .unwrap(); 362 | 363 | let result = database.evaluate(&exp).unwrap(); 364 | assert_eq!(Tuples::from(vec!["a".to_string(),]), result); 365 | } 366 | { 367 | let mut database = Database::new(); 368 | let r = create_relation!(database, "r", i32); 369 | let v = query! { database, create view as (select * from (r))}.unwrap(); 370 | let exp = relexp!(select * from(v)); 371 | query! (database, insert into (r) values [1, 2, 3, 4]).unwrap(); 372 | let result = database.evaluate(&exp).unwrap(); 373 | assert_eq!(Tuples::::from(vec![1, 2, 3, 4]), result); 374 | 375 | // updating the view 376 | query! (database, insert into (r) values [100, 200, 300]).unwrap(); 377 | let exp = relexp!(select [|&x| x + 1] from (v) where [|&tuple| tuple >= 100]); 378 | let result = database.evaluate(&exp).unwrap(); 379 | assert_eq!(Tuples::::from(vec![101, 201, 301]), result); 380 | } 381 | } 382 | } 383 | --------------------------------------------------------------------------------