Skip to content

Commit

Permalink
Improve type system implementation and represent values as union not …
Browse files Browse the repository at this point in the history
…string
  • Loading branch information
AmrDeveloper committed Sep 1, 2023
1 parent 1d573a9 commit 53dd7a4
Show file tree
Hide file tree
Showing 15 changed files with 236 additions and 168 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ SELECT name FROM commits GROUP By name
SELECT name FROM commits GROUP By name having name = "AmrDeveloper"

SELECT * FROM branches
SELECT * FROM branches WHERE ishead = "true"
SELECT * FROM branches WHERE ishead = true
SELECT * FROM branches WHERE name ends_with "master"
SELECT * FROM branches WHERE name contains "origin"

Expand Down
40 changes: 21 additions & 19 deletions crates/gitql-ast/src/aggregation.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
use crate::{object::GQLObject, types::DataType};
use crate::object::GQLObject;
use crate::types::DataType;
use crate::value::Value;

use lazy_static::lazy_static;
use std::collections::HashMap;

type Aggregation = fn(&String, &Vec<GQLObject>) -> String;
type Aggregation = fn(&String, &Vec<GQLObject>) -> Value;

pub struct AggregationPrototype {
pub parameter: DataType,
Expand Down Expand Up @@ -64,50 +66,50 @@ lazy_static! {
};
}

fn aggregation_max(field_name: &String, objects: &Vec<GQLObject>) -> String {
fn aggregation_max(field_name: &String, objects: &Vec<GQLObject>) -> Value {
let mut max_length: i64 = 0;
for object in objects {
let field_value = &object.attributes.get(field_name).unwrap();
let int_value = field_value.parse::<i64>().unwrap();
let int_value = field_value.as_number();
if int_value > max_length {
max_length = int_value;
}
}
return max_length.to_string();
return Value::Number(max_length);
}

fn aggregation_min(field_name: &String, objects: &Vec<GQLObject>) -> String {
let mut max_length: i64 = 0;
fn aggregation_min(field_name: &String, objects: &Vec<GQLObject>) -> Value {
let mut min_length: i64 = 0;
for object in objects {
let field_value = &object.attributes.get(field_name).unwrap();
let int_value = field_value.parse::<i64>().unwrap();
if int_value < max_length {
max_length = int_value;
let int_value = field_value.as_number();
if int_value < min_length {
min_length = int_value;
}
}
return max_length.to_string();
return Value::Number(min_length);
}

fn aggregation_sum(field_name: &String, objects: &Vec<GQLObject>) -> String {
fn aggregation_sum(field_name: &String, objects: &Vec<GQLObject>) -> Value {
let mut sum: i64 = 0;
for object in objects {
let field_value = &object.attributes.get(field_name).unwrap();
sum += field_value.parse::<i64>().unwrap();
sum += field_value.as_number();
}
return sum.to_string();
return Value::Number(sum);
}

fn aggregation_average(field_name: &String, objects: &Vec<GQLObject>) -> String {
fn aggregation_average(field_name: &String, objects: &Vec<GQLObject>) -> Value {
let mut sum: i64 = 0;
let count: i64 = objects.len().try_into().unwrap();
for object in objects {
let field_value = &object.attributes.get(field_name).unwrap();
sum += field_value.parse::<i64>().unwrap();
sum += field_value.as_number();
}
let avg = sum / count;
return avg.to_string();
return Value::Number(avg);
}

fn aggregation_count(_field_name: &String, objects: &Vec<GQLObject>) -> String {
return objects.len().to_string();
fn aggregation_count(_field_name: &String, objects: &Vec<GQLObject>) -> Value {
return Value::Number(objects.len() as i64);
}
1 change: 1 addition & 0 deletions crates/gitql-ast/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ pub mod object;
pub mod statement;
pub mod transformation;
pub mod types;
pub mod value;
4 changes: 3 additions & 1 deletion crates/gitql-ast/src/object.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
use std::collections::HashMap;

use crate::value::Value;

#[derive(Clone)]
pub struct GQLObject {
pub attributes: HashMap<String, String>,
pub attributes: HashMap<String, Value>,
}
29 changes: 15 additions & 14 deletions crates/gitql-ast/src/transformation.rs
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
use crate::types::DataType;
use crate::value::Value;

use lazy_static::lazy_static;
use std::collections::HashMap;

type Transformation = fn(String) -> String;
type Transformation = fn(Value) -> Value;

pub struct TransformationPrototype {
pub parameters: Vec<DataType>,
Expand All @@ -13,10 +14,10 @@ pub struct TransformationPrototype {
lazy_static! {
pub static ref TRANSFORMATIONS: HashMap<&'static str, Transformation> = {
let mut map: HashMap<&'static str, Transformation> = HashMap::new();
map.insert("lower", transformation_lower);
map.insert("upper", transformation_upper);
map.insert("trim", transformtion_trim);
map.insert("length", transformation_length);
map.insert("lower", text_lowercase);
map.insert("upper", text_uppercase);
map.insert("trim", text_trim);
map.insert("len", text_len);
map
};
}
Expand Down Expand Up @@ -49,7 +50,7 @@ lazy_static! {
);

map.insert(
"length",
"len",
TransformationPrototype {
parameters: vec![DataType::Text],
result: DataType::Text,
Expand All @@ -59,18 +60,18 @@ lazy_static! {
};
}

fn transformation_lower(input: String) -> String {
return input.to_lowercase();
fn text_lowercase(input: Value) -> Value {
return Value::Text(input.as_text().to_lowercase());
}

fn transformation_upper(input: String) -> String {
return input.to_uppercase();
fn text_uppercase(input: Value) -> Value {
return Value::Text(input.as_text().to_uppercase());
}

fn transformtion_trim(input: String) -> String {
return input.trim().to_string();
fn text_trim(input: Value) -> Value {
return Value::Text(input.as_text().trim().to_string());
}

fn transformation_length(input: String) -> String {
return input.len().to_string();
fn text_len(input: Value) -> Value {
return Value::Number(input.as_text().len() as i64);
}
2 changes: 2 additions & 0 deletions crates/gitql-ast/src/types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ pub enum DataType {
Number,
Boolean,
Date,
Null,
}

impl DataType {
Expand All @@ -18,6 +19,7 @@ impl DataType {
DataType::Number => "Number",
DataType::Boolean => "Boolean",
DataType::Date => "Date",
DataType::Null => "Null",
};
}
}
Expand Down
60 changes: 60 additions & 0 deletions crates/gitql-ast/src/value.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
use crate::types::DataType;

#[derive(PartialEq, Clone)]
pub enum Value {
Number(i64),
Text(String),
Boolean(bool),
Date(i64),
Null,
}

impl Value {
pub fn data_type(&self) -> DataType {
return match self {
Value::Number(_) => DataType::Number,
Value::Text(_) => DataType::Text,
Value::Boolean(_) => DataType::Boolean,
Value::Date(_) => DataType::Date,
Value::Null => DataType::Null,
};
}

pub fn literal(&self) -> String {
return match self {
Value::Number(i) => i.to_string(),
Value::Text(s) => s.to_string(),
Value::Boolean(b) => b.to_string(),
Value::Date(d) => d.to_string(),
Value::Null => "Null".to_string(),
};
}

pub fn as_number(&self) -> i64 {
if let Value::Number(n) = self {
return *n;
}
return 0;
}

pub fn as_text(&self) -> String {
if let Value::Text(s) = self {
return s.to_string();
}
return "".to_owned();
}

pub fn as_bool(&self) -> bool {
if let Value::Boolean(b) = self {
return *b;
}
return false;
}

pub fn as_date(&self) -> i64 {
if let Value::Date(d) = self {
return *d;
}
return 0;
}
}
9 changes: 5 additions & 4 deletions crates/gitql-cli/src/render.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,13 +27,14 @@ pub fn render_objects(groups: &Vec<Vec<GQLObject>>, hidden_selections: &Vec<Stri
for object in group {
let mut table_row = Row::new(Vec::new());
for key in &titles {
let value = &object.attributes.get(&key as &str).unwrap();
if value.len() > table_field_max_len {
let wrapped = textwrap::wrap(value, table_field_max_len);
let value = &object.attributes.get(&key as &str).clone().unwrap();
let value_literal = value.literal();
if value_literal.len() > table_field_max_len {
let wrapped = textwrap::wrap(value_literal.as_str(), table_field_max_len);
let formatted = wrapped.join("\n");
table_row.add_cell(Cell::new(&formatted));
} else {
table_row.add_cell(Cell::new(value));
table_row.add_cell(Cell::new(value_literal.as_str()));
}
}
table.add_row(table_row);
Expand Down
Loading

0 comments on commit 53dd7a4

Please sign in to comment.