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"
|
path = "benches/bench.rs"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = []
|
default = ["rustc-serialize"]
|
||||||
nightly = []
|
nightly = []
|
||||||
iron-handlers = ["iron"]
|
iron-handlers = ["iron", "rustc-serialize"]
|
||||||
expose-test-schema = []
|
expose-test-schema = []
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rustc-serialize = "^0.3.19"
|
rustc-serialize = { version = "^0.3.19", optional = true }
|
||||||
iron = { version = "^0.4.0", optional = true }
|
iron = { version = "^0.4.0", optional = true }
|
||||||
serde = { version = "^0.8.21", 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::vec;
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
|
||||||
use rustc_serialize::json::{ToJson, Json};
|
|
||||||
|
|
||||||
use parser::Spanning;
|
use parser::Spanning;
|
||||||
|
|
||||||
/// A type literal in the syntax tree
|
/// A type literal in the syntax tree
|
||||||
|
@ -266,26 +264,6 @@ impl InputValue {
|
||||||
InputValue::Object(o)
|
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.
|
/// Resolve all variables to their values.
|
||||||
pub fn into_const(self, vars: &HashMap<String, InputValue>) -> InputValue {
|
pub fn into_const(self, vars: &HashMap<String, InputValue>) -> InputValue {
|
||||||
match self {
|
match self {
|
||||||
|
@ -403,17 +381,38 @@ impl InputValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ToJson for InputValue {
|
impl fmt::Display for InputValue {
|
||||||
fn to_json(&self) -> Json {
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
match *self {
|
match *self {
|
||||||
InputValue::Null | InputValue::Variable(_) => Json::Null,
|
InputValue::Null => write!(f, "null"),
|
||||||
InputValue::Int(i) => Json::I64(i),
|
InputValue::Int(v) => write!(f, "{}", v),
|
||||||
InputValue::Float(f) => Json::F64(f),
|
InputValue::Float(v) => write!(f, "{}", v),
|
||||||
InputValue::String(ref s) | InputValue::Enum(ref s) => Json::String(s.clone()),
|
InputValue::String(ref v) => write!(f, "\"{}\"", v),
|
||||||
InputValue::Boolean(b) => Json::Boolean(b),
|
InputValue::Boolean(v) => write!(f, "{}", v),
|
||||||
InputValue::List(ref l) => Json::Array(l.iter().map(|x| x.item.to_json()).collect()),
|
InputValue::Enum(ref v) => write!(f, "{}", v),
|
||||||
InputValue::Object(ref o) => Json::Object(o.iter().map(|&(ref k, ref v)| (k.item.clone(), v.item.to_json())).collect()),
|
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()
|
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="iron-handlers")] pub mod iron_handlers;
|
||||||
|
#[cfg(feature="rustc-serialize")] pub mod rustc_serialize;
|
||||||
#[cfg(feature="serde")] pub mod serde;
|
#[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))]
|
#![cfg_attr(feature="nightly", feature(test))]
|
||||||
#![warn(missing_docs)]
|
#![warn(missing_docs)]
|
||||||
|
|
||||||
extern crate rustc_serialize;
|
#[cfg(feature="rustc-serialize")] extern crate rustc_serialize;
|
||||||
#[cfg(feature="serde")] extern crate serde;
|
#[cfg(feature="serde")] extern crate serde;
|
||||||
|
|
||||||
#[cfg(feature="nightly")] extern crate test;
|
#[cfg(feature="nightly")] extern crate test;
|
||||||
|
@ -211,9 +211,7 @@ mod integrations;
|
||||||
|
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use rustc_serialize::json::{ToJson, Json};
|
use parser::{parse_document_source, ParseError, Spanning};
|
||||||
|
|
||||||
use parser::{parse_document_source, ParseError, Spanning, SourcePosition};
|
|
||||||
use validation::{ValidatorContext, visit_all_rules, validate_input_values};
|
use validation::{ValidatorContext, visit_all_rules, validate_input_values};
|
||||||
use executor::execute_validated_query;
|
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)]
|
#[doc(hidden)]
|
||||||
pub fn to_camel_case(s: &str) -> String {
|
pub fn to_camel_case(s: &str) -> String {
|
||||||
let mut dest = String::new();
|
let mut dest = String::new();
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
use rustc_serialize::json::ToJson;
|
|
||||||
|
|
||||||
use types::base::{GraphQLType, Arguments, TypeKind};
|
use types::base::{GraphQLType, Arguments, TypeKind};
|
||||||
use executor::{Executor, Registry, ExecutionResult};
|
use executor::{Executor, Registry, ExecutionResult};
|
||||||
|
|
||||||
|
@ -191,7 +189,7 @@ graphql_object!(<'a> Argument<'a>: SchemaType<'a> as "__InputValue" |&self| {
|
||||||
}
|
}
|
||||||
|
|
||||||
field default_value() -> Option<String> {
|
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::collections::HashMap;
|
||||||
use std::hash::Hash;
|
use std::hash::Hash;
|
||||||
|
|
||||||
use rustc_serialize::json::{ToJson, Json};
|
|
||||||
|
|
||||||
use parser::Spanning;
|
use parser::Spanning;
|
||||||
use ast::{InputValue, ToInputValue};
|
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 {
|
impl ToInputValue for Value {
|
||||||
fn to(&self) -> InputValue {
|
fn to(&self) -> InputValue {
|
||||||
match *self {
|
match *self {
|
||||||
|
|
Loading…
Reference in a new issue