From b34676441bb3c0a6273b5d25a998b641dc517f7e Mon Sep 17 00:00:00 2001 From: Jonathan Turner Date: Tue, 28 May 2019 14:01:37 +1200 Subject: [PATCH] Add json support --- Cargo.lock | 3 +++ Cargo.toml | 3 +++ src/cli.rs | 5 ++++- src/commands.rs | 3 +++ src/commands/split.rs | 17 ++++++++++++++++- src/errors.rs | 4 ++-- src/object/base.rs | 37 ++++++++++++++++++++++++++++++++++++- src/object/desc.rs | 13 +++++++++++++ src/object/dict.rs | 14 ++++++++++++++ src/parser/tokens.rs | 3 ++- 10 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f8a923f5..e13075f82 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1012,6 +1012,9 @@ dependencies = [ "prettytable-rs 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.1.6 (registry+https://github.com/rust-lang/crates.io-index)", "rustyline 4.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.91 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", "subprocess 0.1.18 (registry+https://github.com/rust-lang/crates.io-index)", "sysinfo 0.8.4 (registry+https://github.com/rust-lang/crates.io-index)", "term 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)", diff --git a/Cargo.toml b/Cargo.toml index afaa014ba..ac126ae06 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -37,6 +37,9 @@ log = "0.4.6" pretty_env_logger = "0.3.0" lalrpop-util = "0.17.0" regex = "1.1.6" +serde = "1.0.91" +serde_json = "1.0.39" +serde_derive = "1.0.91" [dependencies.pancurses] version = "0.16" diff --git a/src/cli.rs b/src/cli.rs index c644bf7c3..15158f39e 100644 --- a/src/cli.rs +++ b/src/cli.rs @@ -48,10 +48,13 @@ pub async fn cli() -> Result<(), Box> { ("view", Arc::new(view::view)), ("skip", Arc::new(skip::skip)), ("first", Arc::new(take::take)), - ("select", Arc::new(select::select)), + ("from-json", Arc::new(from_json::from_json)), + ("open", Arc::new(open::open)), + ("column", Arc::new(select::select)), ("split", Arc::new(split::split)), ("reject", Arc::new(reject::reject)), ("to-array", Arc::new(to_array::to_array)), + ("to-json", Arc::new(to_json::to_json)), ("where", Arc::new(where_::r#where)), ("sort-by", Arc::new(sort_by::sort_by)), ]); diff --git a/src/commands.rs b/src/commands.rs index b48af5b02..784d192a6 100644 --- a/src/commands.rs +++ b/src/commands.rs @@ -2,7 +2,9 @@ crate mod args; crate mod cd; crate mod classified; crate mod command; +crate mod from_json; crate mod ls; +crate mod open; crate mod ps; crate mod reject; crate mod select; @@ -11,6 +13,7 @@ crate mod sort_by; crate mod split; crate mod take; crate mod to_array; +crate mod to_json; crate mod view; crate mod where_; diff --git a/src/commands/split.rs b/src/commands/split.rs index be6db7efc..49881a2d9 100644 --- a/src/commands/split.rs +++ b/src/commands/split.rs @@ -19,7 +19,22 @@ pub fn split(args: CommandArgs) -> Result { debug!("split result = {:?}", split_result); - if split_result.len() == (args.len() - 1) { + // If they didn't provide column names, make up our own + if (args.len() - 1) == 0 { + let mut gen_columns = vec![]; + for i in 0..split_result.len() { + gen_columns.push(format!("Column{}", i + 1)); + } + + let mut dict = crate::object::Dictionary::default(); + for (k, v) in split_result.iter().zip(gen_columns.iter()) { + dict.add( + v.clone(), + Value::Primitive(Primitive::String(k.to_string())), + ); + } + ReturnValue::Value(Value::Object(dict)) + } else if split_result.len() == (args.len() - 1) { let mut dict = crate::object::Dictionary::default(); for (k, v) in split_result.iter().zip(args.iter().skip(1)) { dict.add( diff --git a/src/errors.rs b/src/errors.rs index 2f4f6c212..1cbcf044b 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -1,9 +1,9 @@ #[allow(unused)] use crate::prelude::*; - +use serde_derive::Serialize; use derive_new::new; -#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, new, Clone)] +#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, new, Clone, Serialize)] pub struct ShellError { title: String, error: Value, diff --git a/src/object/base.rs b/src/object/base.rs index 0439aba77..de7bb26e4 100644 --- a/src/object/base.rs +++ b/src/object/base.rs @@ -9,6 +9,9 @@ use derive_new::new; use ordered_float::OrderedFloat; use std::time::SystemTime; +use serde::{Serialize, Serializer}; +use serde_derive::Serialize; + type OF64 = OrderedFloat; #[derive(Debug, Clone, Ord, PartialOrd, Eq, PartialEq)] @@ -23,6 +26,23 @@ pub enum Primitive { Date(DateTime), } +impl Serialize for Primitive { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + Primitive::Nothing => serializer.serialize_i32(0), + Primitive::Int(i) => serializer.serialize_i64(*i), + Primitive::Float(f) => serializer.serialize_f64(f.into_inner()), + Primitive::Bytes(b) => serializer.serialize_u128(*b), + Primitive::String(ref s) => serializer.serialize_str(s), + Primitive::Boolean(b) => serializer.serialize_bool(*b), + Primitive::Date(d) => serializer.serialize_str(&d.to_string()), + } + } +} + impl Primitive { crate fn format(&self, field_name: Option<&str>) -> String { match self { @@ -55,7 +75,7 @@ impl Primitive { } } -#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, new)] +#[derive(Debug, Ord, PartialOrd, Eq, PartialEq, Clone, new, Serialize)] pub struct Operation { crate left: Value, crate operator: Operator, @@ -73,6 +93,21 @@ pub enum Value { Error(Box), } +impl Serialize for Value { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self { + Value::Primitive(p) => p.serialize(serializer), + Value::Object(o) => o.serialize(serializer), + Value::List(l) => l.serialize(serializer), + Value::Operation(o) => o.serialize(serializer), + Value::Error(e) => e.serialize(serializer), + } + } +} + impl Value { crate fn from_leaf(leaf: &tokens::Leaf) -> Value { use tokens::*; diff --git a/src/object/desc.rs b/src/object/desc.rs index d34b64fe6..bf54bd44e 100644 --- a/src/object/desc.rs +++ b/src/object/desc.rs @@ -1,5 +1,6 @@ use crate::object::types::{AnyShell, Type}; use derive_new::new; +use serde::{Serialize, Serializer}; #[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] pub enum DescriptorName { @@ -37,6 +38,18 @@ pub struct DataDescriptor { crate ty: Box, } +impl Serialize for DataDescriptor { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + match self.name { + DescriptorName::String(ref s) => serializer.serialize_str(s), + DescriptorName::ValueOf => serializer.serialize_str("value_of") + } + } +} + impl From<&str> for DataDescriptor { fn from(input: &str) -> DataDescriptor { DataDescriptor { diff --git a/src/object/dict.rs b/src/object/dict.rs index e3d9914ff..612d8be42 100644 --- a/src/object/dict.rs +++ b/src/object/dict.rs @@ -3,6 +3,7 @@ use crate::prelude::*; use crate::object::DataDescriptor; use crate::object::{Primitive, Value}; use indexmap::IndexMap; +use serde::ser::{Serialize, Serializer, SerializeMap}; use std::cmp::{Ordering, PartialOrd}; #[derive(Debug, Default, Eq, PartialEq, Clone)] @@ -10,6 +11,19 @@ pub struct Dictionary { entries: IndexMap, } +impl Serialize for Dictionary { + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut map = serializer.serialize_map(Some(self.entries.len()))?; + for (k, v) in &self.entries { + map.serialize_entry(&k, &v)?; + } + map.end() + } +} + impl PartialOrd for Dictionary { // TODO: FIXME fn partial_cmp(&self, _other: &Dictionary) -> Option { diff --git a/src/parser/tokens.rs b/src/parser/tokens.rs index 51f9c1516..073450d64 100644 --- a/src/parser/tokens.rs +++ b/src/parser/tokens.rs @@ -1,7 +1,8 @@ use derive_new::new; use std::str::FromStr; +use serde_derive::{Deserialize, Serialize}; -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Deserialize, Serialize)] pub enum Operator { Equal, NotEqual,