Refine design
This commit is contained in:
parent
2a9220e55f
commit
ded7faf505
5 changed files with 139 additions and 4 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
/target
|
||||
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
# This file is automatically @generated by Cargo.
|
||||
# It is not intended for manual editing.
|
||||
version = 3
|
||||
|
||||
[[package]]
|
||||
name = "minisql"
|
||||
version = "0.1.0"
|
||||
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
[package]
|
||||
name = "minisql"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
121
DESIGN.md
121
DESIGN.md
|
|
@ -69,11 +69,45 @@ which will store the database as a file `path/to/db/my-db.db` and open a TCP ser
|
|||
how will the parsing output look like?
|
||||
Consider something like
|
||||
```
|
||||
// TODO: Parser has access to all table metadata
|
||||
|
||||
// Could also be called `SQLAbstractSyntaxTree`
|
||||
enum Operations {
|
||||
Select(Vector<FieldName>, TableName),
|
||||
Update(...)
|
||||
enum Operation {
|
||||
Select(TableName, ColumnSelection, Option<Condition>),
|
||||
Insert(TableName, Vec<(ColumnName, DbValue)>), // String because we don't yet know which type of value this is for sure
|
||||
Delete(TableName, Option<Condition>),
|
||||
// Update(...),
|
||||
}
|
||||
|
||||
enum ColumnSelection {
|
||||
All,
|
||||
Columns(Vec<ColumnName>),
|
||||
}
|
||||
|
||||
enum Condition = {
|
||||
// And(Condition, Condition),
|
||||
// Or(Condition, Condition),
|
||||
// Not(Condition),
|
||||
|
||||
Eq(ColumnName, DbValue)
|
||||
// LessOrEqual(ColumnName, DbValue)
|
||||
// Less(ColumnName, DbValue)
|
||||
|
||||
// StringCondition(StringCondition)
|
||||
}
|
||||
|
||||
enum StringCondition {
|
||||
Prefix(ColumnName, String)
|
||||
Substring(ColumnName, String)
|
||||
}
|
||||
|
||||
|
||||
enum Condition
|
||||
ColumnName, DbValue
|
||||
|
||||
|
||||
|
||||
INSERT 123
|
||||
```
|
||||
* We also have to write an interpreter for these operations. How will the db-state be represented in memory?
|
||||
For example how can we implement a table?
|
||||
|
|
@ -82,11 +116,46 @@ enum Operations {
|
|||
enum DbValue {
|
||||
DbString(String),
|
||||
DbNumber(Float),
|
||||
DbByte(u8),
|
||||
DbUUID(u32)
|
||||
}
|
||||
|
||||
// We also need a type of db-types
|
||||
enum DbType {
|
||||
TString,
|
||||
TNumber,
|
||||
TId,
|
||||
}
|
||||
|
||||
value_to_type(db_val: DbValue) -> DbType
|
||||
|
||||
|
||||
// table-metadata and data
|
||||
|
||||
type TableName = String
|
||||
|
||||
// Note that it is nice to split metadata from the data because
|
||||
// then you can give the metadata to the parser without giving it the data.
|
||||
struct TableMetaData {
|
||||
name: TableName, // TODO: Is this really necessary? probably not
|
||||
columns: Vec<(ColumnName, DbType, ColumnPosition)>
|
||||
}
|
||||
|
||||
fn column_position(TableMetaData, ColumnName) -> ColumnPosition
|
||||
|
||||
struct Table {
|
||||
meta: TableMetaData,
|
||||
rows: Rows // defined below
|
||||
indexes:
|
||||
BTree<ColumnName, Index> // TODO: Consider generalizing ColumnName to semething that would also apply to a pair of ColumnNames etc
|
||||
}
|
||||
|
||||
type Tables = HashMap<TableName, Table>
|
||||
|
||||
// We also need a function that for a given value computes its type (for validation)
|
||||
|
||||
|
||||
type ColumnName = String
|
||||
type ColumnPosition = u32
|
||||
|
||||
// The below type is a type of a table row
|
||||
type Row = HashMap<ColumnName, DbValue>
|
||||
|
|
@ -94,6 +163,9 @@ type Row = HashMap<ColumnName, DbValue>
|
|||
// Or you know... some appropriate Dictionary Type
|
||||
HashMap::make![("id", 1), ("name", "Alice"), ("salary", 20.0)] : Row
|
||||
|
||||
type Rows =
|
||||
BTree<Id, Row>
|
||||
|
||||
// possible optimization: have a mapping
|
||||
// column names ~> indexes
|
||||
// so that we could represent rows as
|
||||
|
|
@ -112,6 +184,47 @@ e.g. Row ~> vec![DbUUID 1, DbSTring "Alice"]
|
|||
Vec<Vec<DbValue>>
|
||||
|
||||
```
|
||||
* Interpreter
|
||||
```
|
||||
trait SqlConsumer {
|
||||
// TODO:
|
||||
???
|
||||
}
|
||||
|
||||
fn interpret<T: SqlConsumer>(operation: Operation, tables: &mut Tables, consumer: T) -> () {
|
||||
// TODO: lock stuff
|
||||
match operation {
|
||||
Select(table_name, column_selection, maybe_condition) => {
|
||||
let table: Table = ...
|
||||
// TODO: Wrap this into a response
|
||||
select(table, column_selection, maybe_condition, consumer)
|
||||
},
|
||||
Insert(table_name, Vec<(ColumnName, DbValue)>) => {
|
||||
insert(table, ???)
|
||||
}
|
||||
Delete(table_name, maybe_condition) => {
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
response = interpret(...)
|
||||
knows_how_to_respond(response, client)
|
||||
|
||||
|
||||
enum Response {
|
||||
Selected(impl Iter<???>) // TODO: How to do this? Some reference to an iterator somehow... slice..?
|
||||
Inserted(???),
|
||||
Deleted(usize), // how many were deleted
|
||||
}
|
||||
|
||||
fn select(table: Table, ColumnName
|
||||
|
||||
|
||||
|
||||
```
|
||||
|
||||
|
||||
* TODO: Consider streaming the response to the client and not just dumping 10K rows at once.
|
||||
|
||||
|
||||
|
|
|
|||
6
src/main.rs
Normal file
6
src/main.rs
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
|
||||
|
||||
|
||||
fn main() {
|
||||
println!("Hello, world!");
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue