Make rustc-serialize optional
This extracts rustc-serialize JSON serialization into its own module, decoupling all core structures from its use. rustc-serialize can now be completely disabled, removing it as a dependency if serde (or none) is used instead. It is, however, still the default serializer. In Cargo, the `default-features` field must be set to `false` to disable it, e.g., [dependencies.juniper] version = "0.6" default-features = false features = ["serde"] The Iron handlers still require rustc-serialize. The default values for attributes changed from being formatted as JSON to how it is defined in [the reference implementation][printer.js]. [printer.js]: https://github.com/graphql/graphql-js/blob/v0.8.2/src/language/printer.js
This commit is contained in:
parent
8620eb1e7a
commit
b78aef715d
7 changed files with 193 additions and 115 deletions
|
@ -15,13 +15,13 @@ harness = false
|
|||
path = "benches/bench.rs"
|
||||
|
||||
[features]
|
||||
default = []
|
||||
default = ["rustc-serialize"]
|
||||
nightly = []
|
||||
iron-handlers = ["iron"]
|
||||
iron-handlers = ["iron", "rustc-serialize"]
|
||||
expose-test-schema = []
|
||||
|
||||
[dependencies]
|
||||
rustc-serialize = "^0.3.19"
|
||||
rustc-serialize = { version = "^0.3.19", optional = true }
|
||||
iron = { version = "^0.4.0", optional = true }
|
||||
serde = { version = "^0.8.21", optional = true }
|
||||
|
||||
|
|
104
src/ast.rs
104
src/ast.rs
|
@ -4,8 +4,6 @@ use std::hash::Hash;
|
|||
use std::vec;
|
||||
use std::slice;
|
||||
|
||||
use rustc_serialize::json::{ToJson, Json};
|
||||
|
||||
use parser::Spanning;
|
||||
|
||||
/// A type literal in the syntax tree
|
||||
|
@ -266,26 +264,6 @@ impl InputValue {
|
|||
InputValue::Object(o)
|
||||
}
|
||||
|
||||
/// Convert a `Json` structure into an `InputValue`.
|
||||
///
|
||||
/// This consumes the JSON instance.
|
||||
///
|
||||
/// Notes:
|
||||
/// * No enums or variables will be produced by this method.
|
||||
/// * All lists and objects will be unlocated
|
||||
pub fn from_json(json: Json) -> InputValue {
|
||||
match json {
|
||||
Json::I64(i) => InputValue::int(i),
|
||||
Json::U64(u) => InputValue::float(u as f64),
|
||||
Json::F64(f) => InputValue::float(f),
|
||||
Json::String(s) => InputValue::string(s),
|
||||
Json::Boolean(b) => InputValue::boolean(b),
|
||||
Json::Array(a) => InputValue::list(a.into_iter().map(InputValue::from_json).collect()),
|
||||
Json::Object(o) => InputValue::object(o.into_iter().map(|(k,v)| (k, InputValue::from_json(v))).collect()),
|
||||
Json::Null => InputValue::null(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Resolve all variables to their values.
|
||||
pub fn into_const(self, vars: &HashMap<String, InputValue>) -> InputValue {
|
||||
match self {
|
||||
|
@ -403,17 +381,38 @@ impl InputValue {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToJson for InputValue {
|
||||
fn to_json(&self) -> Json {
|
||||
impl fmt::Display for InputValue {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
InputValue::Null | InputValue::Variable(_) => Json::Null,
|
||||
InputValue::Int(i) => Json::I64(i),
|
||||
InputValue::Float(f) => Json::F64(f),
|
||||
InputValue::String(ref s) | InputValue::Enum(ref s) => Json::String(s.clone()),
|
||||
InputValue::Boolean(b) => Json::Boolean(b),
|
||||
InputValue::List(ref l) => Json::Array(l.iter().map(|x| x.item.to_json()).collect()),
|
||||
InputValue::Object(ref o) => Json::Object(o.iter().map(|&(ref k, ref v)| (k.item.clone(), v.item.to_json())).collect()),
|
||||
}
|
||||
InputValue::Null => write!(f, "null"),
|
||||
InputValue::Int(v) => write!(f, "{}", v),
|
||||
InputValue::Float(v) => write!(f, "{}", v),
|
||||
InputValue::String(ref v) => write!(f, "\"{}\"", v),
|
||||
InputValue::Boolean(v) => write!(f, "{}", v),
|
||||
InputValue::Enum(ref v) => write!(f, "{}", v),
|
||||
InputValue::Variable(ref v) => write!(f, "${}", v),
|
||||
InputValue::List(ref v) => {
|
||||
try!(write!(f, "["));
|
||||
|
||||
for (i, spanning) in v.iter().enumerate() {
|
||||
try!(spanning.item.fmt(f));
|
||||
if i < v.len() - 1 { try!(write!(f, ", ")); }
|
||||
}
|
||||
|
||||
write!(f, "]")
|
||||
},
|
||||
InputValue::Object(ref o) => {
|
||||
try!(write!(f, "{{"));
|
||||
|
||||
for (i, &(ref k, ref v)) in o.iter().enumerate() {
|
||||
try!(write!(f, "{}: ", k.item));
|
||||
try!(v.item.fmt(f));
|
||||
if i < o.len() - 1 { try!(write!(f, ", ")); }
|
||||
}
|
||||
|
||||
write!(f, "}}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -448,3 +447,44 @@ impl<'a> VariableDefinitions<'a> {
|
|||
self.items.iter()
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::InputValue;
|
||||
use parser::Spanning;
|
||||
|
||||
#[test]
|
||||
fn test_input_value_fmt() {
|
||||
let value = InputValue::null();
|
||||
assert_eq!(format!("{}", value), "null");
|
||||
|
||||
let value = InputValue::int(123);
|
||||
assert_eq!(format!("{}", value), "123");
|
||||
|
||||
let value = InputValue::float(12.3);
|
||||
assert_eq!(format!("{}", value), "12.3");
|
||||
|
||||
let value = InputValue::string("FOO".to_owned());
|
||||
assert_eq!(format!("{}", value), "\"FOO\"");
|
||||
|
||||
let value = InputValue::boolean(true);
|
||||
assert_eq!(format!("{}", value), "true");
|
||||
|
||||
let value = InputValue::enum_value("BAR".to_owned());
|
||||
assert_eq!(format!("{}", value), "BAR");
|
||||
|
||||
let value = InputValue::variable("baz".to_owned());
|
||||
assert_eq!(format!("{}", value), "$baz");
|
||||
|
||||
let list = vec![InputValue::int(1), InputValue::int(2)];
|
||||
let value = InputValue::list(list);
|
||||
assert_eq!(format!("{}", value), "[1, 2]");
|
||||
|
||||
let object = vec![
|
||||
(Spanning::unlocated("foo".to_owned()), Spanning::unlocated(InputValue::int(1))),
|
||||
(Spanning::unlocated("bar".to_owned()), Spanning::unlocated(InputValue::int(2))),
|
||||
];
|
||||
let value = InputValue::parsed_object(object);
|
||||
assert_eq!(format!("{}", value), "{foo: 1, bar: 2}");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,2 +1,3 @@
|
|||
#[cfg(feature="iron-handlers")] pub mod iron_handlers;
|
||||
#[cfg(feature="rustc-serialize")] pub mod rustc_serialize;
|
||||
#[cfg(feature="serde")] pub mod serde;
|
||||
|
|
114
src/integrations/rustc_serialize.rs
Normal file
114
src/integrations/rustc_serialize.rs
Normal file
|
@ -0,0 +1,114 @@
|
|||
use rustc_serialize::json::{ToJson, Json};
|
||||
|
||||
use ::{GraphQLError, Value};
|
||||
use ast::InputValue;
|
||||
use executor::ExecutionError;
|
||||
use parser::{ParseError, Spanning, SourcePosition};
|
||||
use validation::RuleError;
|
||||
|
||||
fn parse_error_to_json(err: &Spanning<ParseError>) -> Json {
|
||||
Json::Array(vec![
|
||||
Json::Object(vec![
|
||||
("message".to_owned(), format!("{}", err.item).to_json()),
|
||||
("locations".to_owned(), vec![
|
||||
Json::Object(vec![
|
||||
("line".to_owned(), (err.start.line() + 1).to_json()),
|
||||
("column".to_owned(), (err.start.column() + 1).to_json())
|
||||
].into_iter().collect()),
|
||||
].to_json()),
|
||||
].into_iter().collect()),
|
||||
])
|
||||
}
|
||||
|
||||
impl ToJson for ExecutionError {
|
||||
fn to_json(&self) -> Json {
|
||||
Json::Object(vec![
|
||||
("message".to_owned(), self.message().to_json()),
|
||||
("locations".to_owned(), vec![self.location().clone()].to_json()),
|
||||
("path".to_owned(), self.path().to_json()),
|
||||
].into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> ToJson for GraphQLError<'a> {
|
||||
fn to_json(&self) -> Json {
|
||||
match *self {
|
||||
GraphQLError::ParseError(ref err) => parse_error_to_json(err),
|
||||
GraphQLError::ValidationError(ref errs) => errs.to_json(),
|
||||
GraphQLError::MultipleOperationsProvided => Json::String(
|
||||
"Must provide operation name if query contains multiple operations".to_owned()),
|
||||
GraphQLError::NoOperationProvided => Json::String(
|
||||
"Must provide an operation".to_owned()),
|
||||
GraphQLError::UnknownOperationName => Json::String(
|
||||
"Unknown operation".to_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for InputValue {
|
||||
fn to_json(&self) -> Json {
|
||||
match *self {
|
||||
InputValue::Null | InputValue::Variable(_) => Json::Null,
|
||||
InputValue::Int(i) => Json::I64(i),
|
||||
InputValue::Float(f) => Json::F64(f),
|
||||
InputValue::String(ref s) | InputValue::Enum(ref s) => Json::String(s.clone()),
|
||||
InputValue::Boolean(b) => Json::Boolean(b),
|
||||
InputValue::List(ref l) => Json::Array(l.iter().map(|x| x.item.to_json()).collect()),
|
||||
InputValue::Object(ref o) => Json::Object(o.iter().map(|&(ref k, ref v)| (k.item.clone(), v.item.to_json())).collect()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InputValue {
|
||||
/// Convert a `Json` structure into an `InputValue`.
|
||||
///
|
||||
/// This consumes the JSON instance.
|
||||
///
|
||||
/// Notes:
|
||||
/// * No enums or variables will be produced by this method.
|
||||
/// * All lists and objects will be unlocated
|
||||
pub fn from_json(json: Json) -> InputValue {
|
||||
match json {
|
||||
Json::I64(i) => InputValue::int(i),
|
||||
Json::U64(u) => InputValue::float(u as f64),
|
||||
Json::F64(f) => InputValue::float(f),
|
||||
Json::String(s) => InputValue::string(s),
|
||||
Json::Boolean(b) => InputValue::boolean(b),
|
||||
Json::Array(a) => InputValue::list(a.into_iter().map(InputValue::from_json).collect()),
|
||||
Json::Object(o) => InputValue::object(o.into_iter().map(|(k, v)| (k, InputValue::from_json(v))).collect()),
|
||||
Json::Null => InputValue::null(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for RuleError {
|
||||
fn to_json(&self) -> Json {
|
||||
Json::Object(vec![
|
||||
("message".to_owned(), self.message().to_json()),
|
||||
("locations".to_owned(), self.locations().to_json()),
|
||||
].into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for SourcePosition {
|
||||
fn to_json(&self) -> Json {
|
||||
Json::Object(vec![
|
||||
("line".to_owned(), (self.line() + 1).to_json()),
|
||||
("column".to_owned(), (self.column() + 1).to_json()),
|
||||
].into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for Value {
|
||||
fn to_json(&self) -> Json {
|
||||
match *self {
|
||||
Value::Null => Json::Null,
|
||||
Value::Int(i) => Json::I64(i),
|
||||
Value::Float(f) => Json::F64(f),
|
||||
Value::String(ref s) => Json::String(s.clone()),
|
||||
Value::Boolean(b) => Json::Boolean(b),
|
||||
Value::List(ref l) => Json::Array(l.iter().map(|x| x.to_json()).collect()),
|
||||
Value::Object(ref o) => Json::Object(o.iter().map(|(k,v)| (k.clone(), v.to_json())).collect()),
|
||||
}
|
||||
}
|
||||
}
|
63
src/lib.rs
63
src/lib.rs
|
@ -186,7 +186,7 @@ built-in [GraphiQL][6] handler included.
|
|||
#![cfg_attr(feature="nightly", feature(test))]
|
||||
#![warn(missing_docs)]
|
||||
|
||||
extern crate rustc_serialize;
|
||||
#[cfg(feature="rustc-serialize")] extern crate rustc_serialize;
|
||||
#[cfg(feature="serde")] extern crate serde;
|
||||
|
||||
#[cfg(feature="nightly")] extern crate test;
|
||||
|
@ -211,9 +211,7 @@ mod integrations;
|
|||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use rustc_serialize::json::{ToJson, Json};
|
||||
|
||||
use parser::{parse_document_source, ParseError, Spanning, SourcePosition};
|
||||
use parser::{parse_document_source, ParseError, Spanning};
|
||||
use validation::{ValidatorContext, visit_all_rules, validate_input_values};
|
||||
use executor::execute_validated_query;
|
||||
|
||||
|
@ -285,63 +283,6 @@ impl<'a> From<Spanning<ParseError<'a>>> for GraphQLError<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> ToJson for GraphQLError<'a> {
|
||||
fn to_json(&self) -> Json {
|
||||
match *self {
|
||||
GraphQLError::ParseError(ref err) => parse_error_to_json(err),
|
||||
GraphQLError::ValidationError(ref errs) => errs.to_json(),
|
||||
GraphQLError::MultipleOperationsProvided => Json::String(
|
||||
"Must provide operation name if query contains multiple operations".to_owned()),
|
||||
GraphQLError::NoOperationProvided => Json::String(
|
||||
"Must provide an operation".to_owned()),
|
||||
GraphQLError::UnknownOperationName => Json::String(
|
||||
"Unknown operation".to_owned()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn parse_error_to_json(err: &Spanning<ParseError>) -> Json {
|
||||
Json::Array(vec![
|
||||
Json::Object(vec![
|
||||
("message".to_owned(), format!("{}", err.item).to_json()),
|
||||
("locations".to_owned(), vec![
|
||||
Json::Object(vec![
|
||||
("line".to_owned(), (err.start.line() + 1).to_json()),
|
||||
("column".to_owned(), (err.start.column() + 1).to_json())
|
||||
].into_iter().collect()),
|
||||
].to_json()),
|
||||
].into_iter().collect()),
|
||||
])
|
||||
}
|
||||
|
||||
impl ToJson for RuleError {
|
||||
fn to_json(&self) -> Json {
|
||||
Json::Object(vec![
|
||||
("message".to_owned(), self.message().to_json()),
|
||||
("locations".to_owned(), self.locations().to_json()),
|
||||
].into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for SourcePosition {
|
||||
fn to_json(&self) -> Json {
|
||||
Json::Object(vec![
|
||||
("line".to_owned(), (self.line() + 1).to_json()),
|
||||
("column".to_owned(), (self.column() + 1).to_json()),
|
||||
].into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToJson for ExecutionError {
|
||||
fn to_json(&self) -> Json {
|
||||
Json::Object(vec![
|
||||
("message".to_owned(), self.message().to_json()),
|
||||
("locations".to_owned(), vec![self.location().clone()].to_json()),
|
||||
("path".to_owned(), self.path().to_json()),
|
||||
].into_iter().collect())
|
||||
}
|
||||
}
|
||||
|
||||
#[doc(hidden)]
|
||||
pub fn to_camel_case(s: &str) -> String {
|
||||
let mut dest = String::new();
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
use rustc_serialize::json::ToJson;
|
||||
|
||||
use types::base::{GraphQLType, Arguments, TypeKind};
|
||||
use executor::{Executor, Registry, ExecutionResult};
|
||||
|
||||
|
@ -191,7 +189,7 @@ graphql_object!(<'a> Argument<'a>: SchemaType<'a> as "__InputValue" |&self| {
|
|||
}
|
||||
|
||||
field default_value() -> Option<String> {
|
||||
self.default_value.as_ref().map(|v| v.to_json().to_string())
|
||||
self.default_value.as_ref().map(|v| format!("{}", v))
|
||||
}
|
||||
});
|
||||
|
||||
|
|
16
src/value.rs
16
src/value.rs
|
@ -1,8 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
use std::hash::Hash;
|
||||
|
||||
use rustc_serialize::json::{ToJson, Json};
|
||||
|
||||
use parser::Spanning;
|
||||
use ast::{InputValue, ToInputValue};
|
||||
|
||||
|
@ -100,20 +98,6 @@ impl Value {
|
|||
}
|
||||
}
|
||||
|
||||
impl ToJson for Value {
|
||||
fn to_json(&self) -> Json {
|
||||
match *self {
|
||||
Value::Null => Json::Null,
|
||||
Value::Int(i) => Json::I64(i),
|
||||
Value::Float(f) => Json::F64(f),
|
||||
Value::String(ref s) => Json::String(s.clone()),
|
||||
Value::Boolean(b) => Json::Boolean(b),
|
||||
Value::List(ref l) => Json::Array(l.iter().map(|x| x.to_json()).collect()),
|
||||
Value::Object(ref o) => Json::Object(o.iter().map(|(k,v)| (k.clone(), v.to_json())).collect()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ToInputValue for Value {
|
||||
fn to(&self) -> InputValue {
|
||||
match *self {
|
||||
|
|
Loading…
Reference in a new issue