Skip to content

Commit

Permalink
Improve the output printer and remove object converter from core crate
Browse files Browse the repository at this point in the history
  • Loading branch information
AmrDeveloper committed Sep 28, 2024
1 parent 2658b38 commit 64ba7cc
Show file tree
Hide file tree
Showing 11 changed files with 130 additions and 96 deletions.
4 changes: 2 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/gitql-cli/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,5 @@ gitql-ast = { path = "../gitql-ast", version = "0.25.0" }
gitql-parser = { path = "../gitql-parser", version = "0.27.0" }
comfy-table = "7.1.0"
termcolor = "1.4.1"
serde_json = "1.0.115"
csv = "1.3.0"
2 changes: 1 addition & 1 deletion crates/gitql-cli/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
pub mod arguments;
pub mod colored_stream;
pub mod diagnostic_reporter;
pub mod render;
pub mod printer;
5 changes: 5 additions & 0 deletions crates/gitql-cli/src/printer/base.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
use gitql_core::object::GitQLObject;

pub trait OutputPrinter {
fn print(&self, object: &mut GitQLObject);
}
27 changes: 27 additions & 0 deletions crates/gitql-cli/src/printer/csv_printer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use csv::Writer;
use gitql_core::object::GitQLObject;

use super::base::OutputPrinter;

pub struct CSVPrinter;

impl OutputPrinter for CSVPrinter {
fn print(&self, object: &mut GitQLObject) {
let mut writer = Writer::from_writer(vec![]);
let _ = writer.write_record(object.titles.clone());
let row_len = object.titles.len();
if let Some(group) = object.groups.first() {
for row in &group.rows {
let mut values_row: Vec<String> = Vec::with_capacity(row_len);
for value in &row.values {
values_row.push(value.to_string());
}
let _ = writer.write_record(values_row);
}
}

if let Ok(writer_content) = writer.into_inner() {
println!("{:?}", String::from_utf8(writer_content));
}
}
}
29 changes: 29 additions & 0 deletions crates/gitql-cli/src/printer/json_printer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
use gitql_core::object::GitQLObject;

use super::base::OutputPrinter;

pub struct JSONPrinter;

impl OutputPrinter for JSONPrinter {
fn print(&self, object: &mut GitQLObject) {
let mut elements: Vec<serde_json::Value> = vec![];

if let Some(group) = object.groups.first() {
let titles = &object.titles;
for row in &group.rows {
let mut object = serde_json::Map::new();
for (i, value) in row.values.iter().enumerate() {
object.insert(
titles[i].to_string(),
serde_json::Value::String(value.to_string()),
);
}
elements.push(serde_json::Value::Object(object));
}
}

if let Ok(json_str) = serde_json::to_string(&serde_json::Value::Array(elements)) {
println!("{}", json_str);
}
}
}
4 changes: 4 additions & 0 deletions crates/gitql-cli/src/printer/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
pub mod base;
pub mod csv_printer;
pub mod json_printer;
pub mod table_printer;
Original file line number Diff line number Diff line change
@@ -1,54 +1,68 @@
use gitql_core::object::GitQLObject;
use gitql_core::object::Row;

use super::base::OutputPrinter;

enum PaginationInput {
NextPage,
PreviousPage,
Quit,
}

pub fn render_objects(groups: &mut GitQLObject, pagination: bool, page_size: usize) {
if groups.len() > 1 {
groups.flat()
}
pub struct TablePrinter {
pub pagination: bool,
pub page_size: usize,
}

if groups.is_empty() || groups.groups[0].is_empty() {
return;
impl TablePrinter {
pub fn new(pagination: bool, page_size: usize) -> Self {
TablePrinter {
pagination,
page_size,
}
}
}

let gql_group = groups.groups.first().unwrap();
let gql_group_len = gql_group.len();
impl OutputPrinter for TablePrinter {
fn print(&self, object: &mut gitql_core::object::GitQLObject) {
if object.is_empty() || object.groups[0].is_empty() {
return;
}

// Setup table headers
let header_color = comfy_table::Color::Green;
let mut table_headers = vec![];
for key in &groups.titles {
table_headers.push(comfy_table::Cell::new(key).fg(header_color));
}
let titles = &object.titles;
let group = object.groups.first().unwrap();
let group_len = group.len();

// Print all data without pagination
if !pagination || page_size >= gql_group_len {
print_group_as_table(&groups.titles, table_headers, &gql_group.rows);
return;
}
// Setup table headers
let header_color = comfy_table::Color::Green;
let mut table_headers = vec![];
for key in titles {
table_headers.push(comfy_table::Cell::new(key).fg(header_color));
}

// Print all data without pagination
if !self.pagination || self.page_size >= group_len {
print_group_as_table(titles, table_headers, &group.rows);
return;
}

// Setup the pagination mode
let number_of_pages = (gql_group_len as f64 / page_size as f64).ceil() as usize;
let mut current_page = 1;
// Setup the pagination mode
let number_of_pages = (group_len as f64 / self.page_size as f64).ceil() as usize;
let mut current_page = 1;

loop {
let start_index = (current_page - 1) * page_size;
let end_index = (start_index + page_size).min(gql_group_len);

let current_page_groups = &gql_group.rows[start_index..end_index];
println!("Page {}/{}", current_page, number_of_pages);
print_group_as_table(&groups.titles, table_headers.clone(), current_page_groups);

let pagination_input = handle_pagination_input(current_page, number_of_pages);
match pagination_input {
PaginationInput::NextPage => current_page += 1,
PaginationInput::PreviousPage => current_page -= 1,
PaginationInput::Quit => break,
loop {
let start_index = (current_page - 1) * self.page_size;
let end_index = (start_index + self.page_size).min(group_len);

let current_page_groups = &group.rows[start_index..end_index];
println!("Page {}/{}", current_page, number_of_pages);
print_group_as_table(titles, table_headers.clone(), current_page_groups);

let pagination_input = handle_pagination_input(current_page, number_of_pages);
match pagination_input {
PaginationInput::NextPage => current_page += 1,
PaginationInput::PreviousPage => current_page -= 1,
PaginationInput::Quit => break,
}
}
}
}
Expand Down
2 changes: 0 additions & 2 deletions crates/gitql-core/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,4 @@ keywords = ["cli", "gql", "language", "git", "sql"]
categories = ["command-line-utilities"]

[dependencies]
serde_json = "1.0.115"
csv = "1.3.0"
chrono = "0.4.38"
41 changes: 0 additions & 41 deletions crates/gitql-core/src/object.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,4 @@
use std::error::Error;

use crate::value::Value;
use csv::Writer;

/// In memory representation of the list of [`Value`] in one Row
#[derive(Clone, Default)]
Expand Down Expand Up @@ -55,42 +52,4 @@ impl GitQLObject {
pub fn len(&self) -> usize {
self.groups.len()
}

/// Export the GitQLObject as JSON String
pub fn as_json(&self) -> serde_json::Result<String> {
let mut elements: Vec<serde_json::Value> = vec![];

if let Some(group) = self.groups.first() {
let titles = &self.titles;
for row in &group.rows {
let mut object = serde_json::Map::new();
for (i, value) in row.values.iter().enumerate() {
object.insert(
titles[i].to_string(),
serde_json::Value::String(value.to_string()),
);
}
elements.push(serde_json::Value::Object(object));
}
}

serde_json::to_string(&serde_json::Value::Array(elements))
}

/// Export the GitQLObject as CSV String
pub fn as_csv(&self) -> Result<String, Box<dyn Error>> {
let mut writer = Writer::from_writer(vec![]);
writer.write_record(self.titles.clone())?;
let row_len = self.titles.len();
if let Some(group) = self.groups.first() {
for row in &group.rows {
let mut values_row: Vec<String> = Vec::with_capacity(row_len);
for value in &row.values {
values_row.push(value.to_string());
}
writer.write_record(values_row)?;
}
}
Ok(String::from_utf8(writer.into_inner()?)?)
}
}
24 changes: 10 additions & 14 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ use gitql_cli::arguments::Command;
use gitql_cli::arguments::OutputFormat;
use gitql_cli::diagnostic_reporter;
use gitql_cli::diagnostic_reporter::DiagnosticReporter;
use gitql_cli::render;
use gitql_cli::printer::base::OutputPrinter;
use gitql_cli::printer::csv_printer::CSVPrinter;
use gitql_cli::printer::json_printer::JSONPrinter;
use gitql_cli::printer::table_printer::TablePrinter;
use gitql_core::environment::Environment;
use gitql_core::schema::Schema;
use gitql_engine::data_provider::DataProvider;
Expand Down Expand Up @@ -197,21 +200,14 @@ fn execute_gitql_query(
// Render the result only if they are selected groups not any other statement
let engine_result = evaluation_result.ok().unwrap();
if let SelectedGroups(mut groups) = engine_result {
match arguments.output_format {
let printer: Box<dyn OutputPrinter> = match arguments.output_format {
OutputFormat::Render => {
render::render_objects(&mut groups, arguments.pagination, arguments.page_size);
Box::new(TablePrinter::new(arguments.pagination, arguments.page_size))
}
OutputFormat::JSON => {
if let Ok(json) = groups.as_json() {
println!("{}", json);
}
}
OutputFormat::CSV => {
if let Ok(csv) = groups.as_csv() {
println!("{}", csv);
}
}
}
OutputFormat::JSON => Box::new(JSONPrinter {}),
OutputFormat::CSV => Box::new(CSVPrinter {}),
};
printer.print(&mut groups);
}

if arguments.analysis {
Expand Down

0 comments on commit 64ba7cc

Please sign in to comment.