From 8378f1792152b74094222bc6dbea652cb97adb99 Mon Sep 17 00:00:00 2001 From: Theo Butler Date: Thu, 26 Jan 2023 21:33:23 -0500 Subject: [PATCH] Use graphql utils from toolshed (#44) --- agora/Cargo.toml | 6 +- lang/Cargo.toml | 8 +- lang/src/coercion.rs | 3 +- lang/src/context.rs | 3 +- lang/src/expressions/primitives.rs | 2 +- lang/src/graphql_utils.rs | 222 ----------------------------- lang/src/language.rs | 5 +- lang/src/lib.rs | 9 +- lang/src/matching.rs | 3 +- lang/src/parse_errors.rs | 5 +- lang/src/parser.rs | 2 +- lang/src/repeat.rs | 21 --- lang/src/tests.rs | 9 +- 13 files changed, 20 insertions(+), 278 deletions(-) delete mode 100644 lang/src/graphql_utils.rs delete mode 100644 lang/src/repeat.rs diff --git a/agora/Cargo.toml b/agora/Cargo.toml index dde1711..8ea9340 100644 --- a/agora/Cargo.toml +++ b/agora/Cargo.toml @@ -14,11 +14,11 @@ fraction = { version="0.6.3", features=["with-bigint"] } serde = { version="1.0.115", features = ["derive"] } serde_json = "1.0" tree-buf = "0.10.0" -shellexpand = "2.0.0" +shellexpand = "3.0.0" rayon = "1.4.0" -rand = "0.7.3" +rand = "0.8.5" structopt = "0.3.14" num-format = { version = "0.4.0", features = ["with-num-bigint"] } -graphql-parser = "0.3.0" +graphql-parser = "0.4.0" anyhow = "1.0.33" libflate = "1.1.0" diff --git a/lang/Cargo.toml b/lang/Cargo.toml index a19289f..6c76b79 100644 --- a/lang/Cargo.toml +++ b/lang/Cargo.toml @@ -7,15 +7,13 @@ edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -# Include the consume_definition API and nameless operations fix -graphql-parser = { git = "https://github.com/graphql-rust/graphql-parser", rev = "8a759df" } -# graphql-parser = "0.3.0" +lazy_static = "1.4.0" nom = "5.1.2" num-bigint = "0.2.6" num-traits = "0.2.12" +firestorm = "0.5" fraction = { version = "0.6.3", features = ["with-bigint"] } serde = { version = "1.0.116", features = ["derive"] } serde_json = "1.0" -lazy_static = "1.4.0" single = "1.0.0" -firestorm = "0.4" +toolshed = { git = "https://github.com/edgeandnode/toolshed", tag = "v0.1.1" } diff --git a/lang/src/coercion.rs b/lang/src/coercion.rs index a3affc0..2ae3136 100644 --- a/lang/src/coercion.rs +++ b/lang/src/coercion.rs @@ -1,7 +1,6 @@ -use graphql_parser::query as q; - use fraction::BigFraction; use q::Value::*; +use toolshed::graphql::graphql_parser::query as q; /// This is like TryInto, but more liberal pub trait Coerce { diff --git a/lang/src/context.rs b/lang/src/context.rs index 3f0816c..9b4097b 100644 --- a/lang/src/context.rs +++ b/lang/src/context.rs @@ -1,7 +1,6 @@ -use crate::graphql_utils::QueryVariables; use crate::prelude::*; use crate::{Captures, CostError}; -use graphql_parser::query as q; +use toolshed::graphql::{graphql_parser::query as q, QueryVariables}; pub struct Context<'a, T: q::Text<'a>> { pub operations: Vec>, diff --git a/lang/src/expressions/primitives.rs b/lang/src/expressions/primitives.rs index d36ee67..cce0aee 100644 --- a/lang/src/expressions/primitives.rs +++ b/lang/src/expressions/primitives.rs @@ -1,7 +1,7 @@ use super::*; use crate::coercion::Coerce; -use crate::graphql_utils::StaticValue; use std::marker::PhantomData; +use toolshed::graphql::StaticValue; #[derive(Debug, Copy, Clone, Eq, PartialEq)] struct Unowned(PhantomData<*const T>); diff --git a/lang/src/graphql_utils.rs b/lang/src/graphql_utils.rs deleted file mode 100644 index ffab9f6..0000000 --- a/lang/src/graphql_utils.rs +++ /dev/null @@ -1,222 +0,0 @@ -// TODO: This is all copy-pasted from graph-node. Needs to move to a common lib. -use crate::prelude::*; -use graphql_parser::query as q; -use serde::{ - self, - ser::{SerializeMap, SerializeSeq}, - Deserialize, Deserializer, Serialize, Serializer, -}; -use std::collections::{BTreeMap, HashMap}; -use std::convert::TryInto as _; - -// TODO: (Performance) may want to do zero-copy here later. -pub type StaticValue = q::Value<'static, String>; - -/// Variable value for a GraphQL query. -#[derive(Clone, Debug, Deserialize)] -struct DeserializableGraphQlValue(#[serde(with = "GraphQLValue")] StaticValue); - -#[derive(Clone, Debug, Serialize)] -struct SerializableGraphQlValue<'a>(#[serde(with = "GraphQLValue")] &'a StaticValue); - -fn deserialize_variables<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - profile_fn!(deserialize_variables); - let pairs: BTreeMap = - Deserialize::deserialize(deserializer)?; - Ok(pairs.into_iter().map(|(k, v)| (k, v.0)).collect()) -} - -fn serialize_variables(vars: &HashMap, ser: S) -> Result -where - S: Serializer, -{ - profile_fn!(serialize_variables); - - let mut seq = ser.serialize_map(Some(vars.len()))?; - for (key, value) in vars.iter() { - seq.serialize_key(key)?; - seq.serialize_value(&SerializableGraphQlValue(value))?; - } - seq.end() -} - -/// Variable values for a GraphQL query. -#[derive(Clone, Debug, Default, Serialize, Deserialize, PartialEq)] -pub struct QueryVariables( - #[serde( - deserialize_with = "deserialize_variables", - serialize_with = "serialize_variables" - )] - pub HashMap, -); - -impl QueryVariables { - pub fn new() -> Self { - QueryVariables(HashMap::new()) - } - - pub fn get(&self, name: &str) -> Option<&StaticValue> { - self.0.get(name) - } -} - -#[derive(Serialize, Deserialize)] -#[serde(untagged, remote = "StaticValue")] -enum GraphQLValue { - #[serde( - deserialize_with = "deserialize_number", - serialize_with = "serialize_number" - )] - Int(q::Number), - Float(f64), - String(String), - Boolean(bool), - Null, - Enum(String), - #[serde( - deserialize_with = "deserialize_list", - serialize_with = "serialize_list" - )] - List(Vec), - #[serde( - deserialize_with = "deserialize_object", - serialize_with = "serialize_object" - )] - Object(BTreeMap), - Variable(String), -} - -fn deserialize_number<'de, D>(deserializer: D) -> Result -where - D: Deserializer<'de>, -{ - let i: i32 = Deserialize::deserialize(deserializer)?; - Ok(q::Number::from(i)) -} - -fn serialize_number(number: &q::Number, ser: S) -> Result -where - S: Serializer, -{ - ser.serialize_i32(number.as_i64().unwrap().try_into().unwrap()) -} - -fn deserialize_list<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let values: Vec = Deserialize::deserialize(deserializer)?; - Ok(values.into_iter().map(|v| v.0).collect()) -} - -fn serialize_list(list: &Vec, ser: S) -> Result -where - S: Serializer, -{ - let mut seq = ser.serialize_seq(Some(list.len()))?; - for value in list.iter() { - seq.serialize_element(&SerializableGraphQlValue(value))?; - } - seq.end() -} - -fn deserialize_object<'de, D>(deserializer: D) -> Result, D::Error> -where - D: Deserializer<'de>, -{ - let pairs: BTreeMap = - Deserialize::deserialize(deserializer)?; - Ok(pairs.into_iter().map(|(k, v)| (k, v.0)).collect()) -} - -fn serialize_object(obj: &BTreeMap, ser: S) -> Result -where - S: Serializer, -{ - let mut seq = ser.serialize_map(Some(obj.len()))?; - for (key, value) in obj.iter() { - seq.serialize_key(key)?; - seq.serialize_value(&SerializableGraphQlValue(value))?; - } - seq.end() -} - -pub trait IntoStaticValue { - fn to_graphql(self) -> StaticValue; -} - -impl IntoStaticValue for i32 { - fn to_graphql(self) -> StaticValue { - StaticValue::Int(self.into()) - } -} - -impl IntoStaticValue for bool { - fn to_graphql(self) -> StaticValue { - StaticValue::Boolean(self) - } -} - -impl IntoStaticValue for StaticValue { - fn to_graphql(self) -> StaticValue { - self - } -} - -impl IntoStaticValue for String { - fn to_graphql(self) -> StaticValue { - StaticValue::String(self) - } -} - -impl<'a, T: q::Text<'a>> IntoStaticValue for &'_ q::Value<'a, T> { - fn to_graphql(self) -> StaticValue { - match self { - q::Value::Boolean(b) => StaticValue::Boolean(*b), - q::Value::Enum(t) => StaticValue::Enum(t.as_ref().to_string()), - q::Value::Float(f) => StaticValue::Float(*f), - q::Value::Int(i) => StaticValue::Int(i.clone()), - q::Value::Variable(v) => StaticValue::Variable(v.as_ref().to_string()), - q::Value::Object(o) => StaticValue::Object( - o.iter() - .map(|(k, v)| (k.as_ref().to_string(), v.to_graphql())) - .collect(), - ), - q::Value::List(l) => { - StaticValue::List(l.iter().map(IntoStaticValue::to_graphql).collect()) - } - q::Value::String(s) => StaticValue::String(s.to_string()), - q::Value::Null => StaticValue::Null, - } - } -} - -#[cfg(test)] -mod tests { - //! GraphQL parsing must not overflow the stack. - //! These tests are added to ensure that this is caught - //! in graphql-parser _and_ that it is an error. - //! We are relying on this being an error because there is - //! other GraphQL traversal code in this project that has - //! not been secured against stack overflow. - //! See also 01205a6c-4e1a-4b35-8dc6-d400c499d423 - - use super::*; - use crate::repeat::repeat; - #[test] - fn obj_recursion() { - let query = format!("query {}{}", repeat(21, "{ a "), repeat(21, "}")); - let query = q::parse_query::<&str>(&query); - assert!(query.is_err()); - } - - #[test] - fn list_recursion() { - let query = format!("query {{ a(l: {}1{} ) }}", repeat(19, "["), repeat(19, "]")); - let query = q::parse_query::<&str>(&query); - assert!(query.is_err()); - } -} diff --git a/lang/src/language.rs b/lang/src/language.rs index cede073..ff13668 100644 --- a/lang/src/language.rs +++ b/lang/src/language.rs @@ -1,12 +1,11 @@ use crate::coercion::Coerce; use crate::expressions::expr_stack::*; use crate::expressions::*; -use crate::graphql_utils::{IntoStaticValue, QueryVariables, StaticValue}; use crate::matching::{get_capture_names_field, match_query}; use crate::prelude::*; use fraction::BigFraction; -use graphql_parser::query as q; use std::collections::HashMap; +use toolshed::graphql::{graphql_parser::query as q, IntoStaticValue, QueryVariables, StaticValue}; #[derive(Debug, PartialEq)] pub struct Document<'a> { @@ -324,7 +323,7 @@ impl Captures { #[cfg(test)] pub(crate) mod test_helpers { use super::*; - use crate::graphql_utils::IntoStaticValue; + use toolshed::graphql::IntoStaticValue; impl From<()> for Captures { fn from(_: ()) -> Captures { diff --git a/lang/src/lib.rs b/lang/src/lib.rs index 9af3d52..4e69f0c 100644 --- a/lang/src/lib.rs +++ b/lang/src/lib.rs @@ -4,26 +4,23 @@ extern crate lazy_static; mod coercion; mod context; mod expressions; -mod graphql_utils; mod language; mod matching; #[macro_use] mod parse_errors; mod parser; -mod repeat; pub(crate) mod prelude; use prelude::*; use fraction::{BigFraction, GenericFraction, Sign}; -use graphql_parser::query as q; use language::*; use num_bigint::BigUint; use std::{error, fmt}; +use toolshed::graphql::graphql_parser::query as q; +use toolshed::graphql::QueryVariables; pub use context::Context; -// Hack for indexer selection -pub use graphql_utils::QueryVariables; pub struct CostModel { // Rust does not have a memory model, nor does it have a proper `uintptr_t` equivalent. So a @@ -93,7 +90,7 @@ pub(crate) fn parse_vars(vars: &str) -> Result> { fragments: &'frag [q::FragmentDefinition<'fragt, TF>], diff --git a/lang/src/parse_errors.rs b/lang/src/parse_errors.rs index 244d5bb..a0de769 100644 --- a/lang/src/parse_errors.rs +++ b/lang/src/parse_errors.rs @@ -1,11 +1,10 @@ use crate::prelude::*; -use crate::repeat::repeat; -use graphql_parser::query::ParseError as GraphQLParseError; use nom::error::{ErrorKind, ParseError}; use nom::{Err as NomErr, IResult, InputLength}; use std::cmp::Ordering; use std::fmt; use std::ops::Deref; +use toolshed::graphql::graphql_parser::query::ParseError as GraphQLParseError; /// If something failed, this notes what we were /// trying to do when it failed. @@ -385,7 +384,7 @@ impl<'a> AgoraParseError<&'a str> { )?; writeln!(f, "{}", pos.line)?; // Write a caret indicating the position. - writeln!(f, "{}^", repeat(pos.column_number, " "))?; + writeln!(f, "{}^", " ".repeat(pos.column_number))?; Ok(()) } } diff --git a/lang/src/parser.rs b/lang/src/parser.rs index f274f57..bdfde61 100644 --- a/lang/src/parser.rs +++ b/lang/src/parser.rs @@ -4,7 +4,6 @@ use crate::parse_errors::{ use crate::prelude::*; use crate::{expressions::*, language::*, parse_errors::*}; use fraction::BigFraction; -use graphql_parser::query as q; use nom::{ branch::alt, bytes::complete::{is_not, take_while1}, @@ -19,6 +18,7 @@ use nom::{ use num_bigint::BigUint; use num_traits::Pow as _; use single::Single as _; +use toolshed::graphql::graphql_parser::query as q; // Change Nom default error type from (I, ErrorKind) to ErrorAggregator type IResult> = NomIResult; diff --git a/lang/src/repeat.rs b/lang/src/repeat.rs deleted file mode 100644 index 37a76d2..0000000 --- a/lang/src/repeat.rs +++ /dev/null @@ -1,21 +0,0 @@ -use crate::prelude::*; -use std::fmt; - -// https://stackoverflow.com/a/62628492 -#[derive(Clone, Copy)] -pub struct DisplayRepeat(usize, T); - -impl fmt::Display for DisplayRepeat { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - profile_method!(fmt); - - for _ in 0..self.0 { - self.1.fmt(f)?; - } - Ok(()) - } -} - -pub fn repeat(times: usize, item: T) -> DisplayRepeat { - DisplayRepeat(times, item) -} diff --git a/lang/src/tests.rs b/lang/src/tests.rs index bad390b..13ecf7d 100644 --- a/lang/src/tests.rs +++ b/lang/src/tests.rs @@ -1,5 +1,4 @@ use crate::prelude::*; -use crate::repeat::repeat; use crate::*; use num_bigint::BigUint; @@ -72,7 +71,7 @@ fn query_match() { query { a } when true => 11; query { b } when false => 12; query { b } when 1 == 1 => 2 + 2; - # Never used, because the above matches the same conditions. + # Never used, because the above matches the same conditions. query { b } when true => 7; "; test(model, "query { a }", 11); @@ -536,11 +535,7 @@ mod recursions { #[test] fn substitute_globals() { - let model = format!( - "default => {}$a{};", - repeat(5000, "(1 + "), - repeat(5000, ")") - ); + let model = format!("default => {}$a{};", "(1 + ".repeat(5000), ")".repeat(5000)); test((model.as_str(), "{\"a\": 2}"), "{ a }", 5002); }