Skip to content

Commit cc564c1

Browse files
committed
graph, graphql, server: Encapsulate maps in Value in a new type
1 parent 753cee7 commit cc564c1

File tree

17 files changed

+136
-50
lines changed

17 files changed

+136
-50
lines changed

graph/src/data/graphql/object_macro.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1+
use crate::data::value::Object;
12
use crate::prelude::q;
23
use crate::prelude::r;
3-
use std::collections::BTreeMap;
44
use std::iter::FromIterator;
55

66
/// Creates a `graphql_parser::query::Value::Object` from key/value pairs.
77
/// If you don't need to determine which keys are included dynamically at runtime
88
/// consider using the `object! {}` macro instead.
99
pub fn object_value(data: Vec<(&str, r::Value)>) -> r::Value {
10-
r::Value::Object(BTreeMap::from_iter(
10+
r::Value::Object(Object::from_iter(
1111
data.into_iter().map(|(k, v)| (k.to_string(), v)),
1212
))
1313
}
@@ -93,7 +93,7 @@ macro_rules! object {
9393
let value = $crate::data::graphql::object_macro::IntoValue::into_value($value);
9494
result.insert(stringify!($name).to_string(), value);
9595
)*
96-
$crate::prelude::r::Value::Object(result)
96+
$crate::prelude::r::Value::object(result)
9797
}
9898
};
9999
($($name:ident: $value:expr),*) => {

graph/src/data/graphql/values.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,9 @@
11
use anyhow::{anyhow, Error};
2-
use std::collections::{BTreeMap, HashMap};
2+
use std::collections::HashMap;
33
use std::convert::TryFrom;
44
use std::str::FromStr;
55

6+
use crate::data::value::Object;
67
use crate::prelude::{r, BigInt, Entity};
78
use web3::types::{H160, H256};
89

@@ -166,7 +167,7 @@ impl ValueMap for r::Value {
166167
}
167168
}
168169

169-
impl ValueMap for &BTreeMap<String, r::Value> {
170+
impl ValueMap for &Object {
170171
fn get_required<T>(&self, key: &str) -> Result<T, Error>
171172
where
172173
T: TryFromValue,

graph/src/data/query/result.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
use super::error::{QueryError, QueryExecutionError};
2+
use crate::data::value::Object;
23
use crate::prelude::{r, CacheWeight, DeploymentHash};
34
use http::header::{
45
ACCESS_CONTROL_ALLOW_HEADERS, ACCESS_CONTROL_ALLOW_METHODS, ACCESS_CONTROL_ALLOW_ORIGIN,
56
CONTENT_TYPE,
67
};
78
use serde::ser::*;
89
use serde::Serialize;
9-
use std::collections::BTreeMap;
1010
use std::convert::TryFrom;
1111
use std::sync::Arc;
1212

@@ -39,7 +39,7 @@ where
3939
ser.end()
4040
}
4141

42-
pub type Data = BTreeMap<String, r::Value>;
42+
pub type Data = Object;
4343

4444
#[derive(Debug)]
4545
/// A collection of query results that is serialized as a single result.
@@ -270,8 +270,8 @@ impl From<Vec<QueryExecutionError>> for QueryResult {
270270
}
271271
}
272272

273-
impl From<Data> for QueryResult {
274-
fn from(val: Data) -> Self {
273+
impl From<Object> for QueryResult {
274+
fn from(val: Object) -> Self {
275275
QueryResult::new(val)
276276
}
277277
}
@@ -309,7 +309,7 @@ fn multiple_data_items() {
309309
use serde_json::json;
310310

311311
fn make_obj(key: &str, value: &str) -> Arc<QueryResult> {
312-
let mut map = BTreeMap::new();
312+
let mut map = Object::new();
313313
map.insert(key.to_owned(), r::Value::String(value.to_owned()));
314314
Arc::new(map.into())
315315
}

graph/src/data/value.rs

Lines changed: 78 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,78 @@ use serde::ser::{SerializeMap, SerializeSeq, Serializer};
33
use serde::Serialize;
44
use std::collections::BTreeMap;
55
use std::convert::TryFrom;
6+
use std::iter::FromIterator;
7+
8+
#[derive(Debug, Clone, PartialEq)]
9+
pub struct Object(BTreeMap<String, Value>);
10+
11+
impl Object {
12+
pub fn new() -> Self {
13+
Self(BTreeMap::default())
14+
}
15+
16+
pub fn get(&self, key: &str) -> Option<&Value> {
17+
self.0.get(key)
18+
}
19+
20+
pub fn remove(&mut self, key: &str) -> Option<Value> {
21+
self.0.remove(key)
22+
}
23+
24+
pub fn iter(&self) -> std::collections::btree_map::Iter<String, Value> {
25+
self.into_iter()
26+
}
27+
28+
fn len(&self) -> usize {
29+
self.0.len()
30+
}
31+
32+
pub fn extend(&mut self, other: Object) {
33+
self.0.extend(other.0)
34+
}
35+
36+
pub fn insert(&mut self, key: String, value: Value) -> Option<Value> {
37+
self.0.insert(key, value)
38+
}
39+
}
40+
41+
impl FromIterator<(String, Value)> for Object {
42+
fn from_iter<T: IntoIterator<Item = (String, Value)>>(iter: T) -> Self {
43+
Object(BTreeMap::from_iter(iter))
44+
}
45+
}
46+
47+
impl IntoIterator for Object {
48+
type Item = (String, Value);
49+
50+
type IntoIter = std::collections::btree_map::IntoIter<String, Value>;
51+
52+
fn into_iter(self) -> Self::IntoIter {
53+
self.0.into_iter()
54+
}
55+
}
56+
57+
impl<'a> IntoIterator for &'a Object {
58+
type Item = (&'a String, &'a Value);
59+
60+
type IntoIter = std::collections::btree_map::Iter<'a, String, Value>;
61+
62+
fn into_iter(self) -> Self::IntoIter {
63+
self.0.iter()
64+
}
65+
}
66+
67+
impl CacheWeight for Object {
68+
fn indirect_weight(&self) -> usize {
69+
self.0.indirect_weight()
70+
}
71+
}
72+
73+
impl Default for Object {
74+
fn default() -> Self {
75+
Self(BTreeMap::default())
76+
}
77+
}
678

779
#[derive(Debug, Clone, PartialEq)]
880
pub enum Value {
@@ -13,10 +85,14 @@ pub enum Value {
1385
Null,
1486
Enum(String),
1587
List(Vec<Value>),
16-
Object(BTreeMap<String, Value>),
88+
Object(Object),
1789
}
1890

1991
impl Value {
92+
pub fn object(map: BTreeMap<String, Value>) -> Self {
93+
Value::Object(Object(map))
94+
}
95+
2096
pub fn is_null(&self) -> bool {
2197
matches!(self, Value::Null)
2298
}
@@ -164,7 +240,7 @@ impl TryFrom<q::Value> for Value {
164240
let value = Value::try_from(value)?;
165241
rmap.insert(key, value);
166242
}
167-
Ok(Value::Object(rmap))
243+
Ok(Value::object(rmap))
168244
}
169245
}
170246
}

graphql/src/execution/execution.rs

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use super::cache::{QueryBlockCache, QueryCache};
22
use crossbeam::atomic::AtomicCell;
33
use graph::{
4-
data::schema::META_FIELD_NAME,
4+
data::{schema::META_FIELD_NAME, value::Object},
55
prelude::{s, CheapClone},
66
util::timed_rw_lock::TimedMutex,
77
};
@@ -11,7 +11,7 @@ use stable_hash::crypto::SetHasher;
1111
use stable_hash::prelude::*;
1212
use stable_hash::utils::stable_hash;
1313
use std::borrow::ToOwned;
14-
use std::collections::{BTreeMap, HashMap, HashSet};
14+
use std::collections::{HashMap, HashSet};
1515
use std::iter;
1616
use std::time::Instant;
1717

@@ -128,7 +128,7 @@ impl CacheWeight for WeightedResult {
128128
impl Default for WeightedResult {
129129
fn default() -> Self {
130130
WeightedResult {
131-
result: Arc::new(QueryResult::new(BTreeMap::default())),
131+
result: Arc::new(QueryResult::new(Object::default())),
132132
weight: 0,
133133
}
134134
}
@@ -290,7 +290,7 @@ pub fn execute_root_selection_set_uncached(
290290
ctx: &ExecutionContext<impl Resolver>,
291291
selection_set: &q::SelectionSet,
292292
root_type: &s::ObjectType,
293-
) -> Result<BTreeMap<String, r::Value>, Vec<QueryExecutionError>> {
293+
) -> Result<Object, Vec<QueryExecutionError>> {
294294
// Split the top-level fields into introspection fields and
295295
// regular data fields
296296
let mut data_set = q::SelectionSet {
@@ -320,7 +320,7 @@ pub fn execute_root_selection_set_uncached(
320320

321321
// If we are getting regular data, prefetch it from the database
322322
let mut values = if data_set.items.is_empty() && meta_items.is_empty() {
323-
BTreeMap::default()
323+
Object::default()
324324
} else {
325325
let initial_data = ctx.resolver.prefetch(&ctx, &data_set)?;
326326
data_set.items.extend(meta_items);
@@ -506,14 +506,14 @@ fn execute_selection_set_to_map<'a>(
506506
selection_sets: impl Iterator<Item = &'a q::SelectionSet>,
507507
object_type: &s::ObjectType,
508508
prefetched_value: Option<r::Value>,
509-
) -> Result<BTreeMap<String, r::Value>, Vec<QueryExecutionError>> {
509+
) -> Result<Object, Vec<QueryExecutionError>> {
510510
let mut prefetched_object = match prefetched_value {
511511
Some(r::Value::Object(object)) => Some(object),
512512
Some(_) => unreachable!(),
513513
None => None,
514514
};
515515
let mut errors: Vec<QueryExecutionError> = Vec::new();
516-
let mut result_map: BTreeMap<String, r::Value> = BTreeMap::new();
516+
let mut result_map = Object::new();
517517

518518
// Group fields with the same response key, so we can execute them together
519519
let grouped_field_set = collect_fields(ctx, object_type, selection_sets);
@@ -1063,7 +1063,7 @@ pub fn coerce_argument_values<'a>(
10631063
if argument_def.name == "text".to_string() {
10641064
coerced_values.insert(
10651065
argument_def.name.as_str(),
1066-
r::Value::Object(BTreeMap::from_iter(vec![(field.name.clone(), value)])),
1066+
r::Value::Object(Object::from_iter(vec![(field.name.clone(), value)])),
10671067
);
10681068
} else {
10691069
coerced_values.insert(&argument_def.name, value);

graphql/src/execution/resolver.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,7 @@ pub trait Resolver: Sized + Send + Sync + 'static {
9595
) -> Option<&'a s::ObjectType> {
9696
let concrete_type_name = match object_value {
9797
// All objects contain `__typename`
98-
r::Value::Object(data) => match &data["__typename"] {
98+
r::Value::Object(data) => match &data.get("__typename").unwrap() {
9999
r::Value::String(name) => name.clone(),
100100
_ => unreachable!("__typename must be a string"),
101101
},

graphql/src/store/prefetch.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
44
use anyhow::{anyhow, Error};
55
use graph::constraint_violation;
6+
use graph::data::value::Object;
67
use graph::prelude::{r, CacheWeight};
78
use graph::slog::warn;
89
use graph::util::cache_weight;
@@ -208,7 +209,7 @@ impl From<Node> for r::Value {
208209
for (key, nodes) in node.children.into_iter() {
209210
map.insert(format!("prefetch:{}", key), node_list_as_value(nodes));
210211
}
211-
r::Value::Object(map)
212+
r::Value::object(map)
212213
}
213214
}
214215

@@ -541,8 +542,7 @@ pub fn run(
541542
) -> Result<r::Value, Vec<QueryExecutionError>> {
542543
execute_root_selection_set(resolver, ctx, selection_set).map(|nodes| {
543544
result_size.observe(nodes.weight());
544-
let map = BTreeMap::default();
545-
r::Value::Object(nodes.into_iter().fold(map, |mut map, node| {
545+
r::Value::Object(nodes.into_iter().fold(Object::default(), |mut map, node| {
546546
// For root nodes, we only care about the children
547547
for (key, nodes) in node.children.into_iter() {
548548
map.insert(format!("prefetch:{}", key), node_list_as_value(nodes));

graphql/src/store/query.rs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet, VecDeque};
22
use std::mem::discriminant;
33

4+
use graph::data::value::Object;
45
use graph::prelude::*;
56
use graph::{components::store::EntityType, data::graphql::ObjectOrInterface};
67

@@ -125,7 +126,7 @@ fn build_filter(
125126
}
126127

127128
fn build_fulltext_filter_from_object(
128-
object: &BTreeMap<String, r::Value>,
129+
object: &Object,
129130
) -> Result<Option<EntityFilter>, QueryExecutionError> {
130131
object.iter().next().map_or(
131132
Err(QueryExecutionError::FulltextQueryRequiresFilter),
@@ -145,7 +146,7 @@ fn build_fulltext_filter_from_object(
145146
/// Parses a GraphQL input object into an EntityFilter, if present.
146147
fn build_filter_from_object(
147148
entity: ObjectOrInterface,
148-
object: &BTreeMap<String, r::Value>,
149+
object: &Object,
149150
) -> Result<Option<EntityFilter>, QueryExecutionError> {
150151
Ok(Some(EntityFilter::And({
151152
object
@@ -242,7 +243,7 @@ fn build_order_by(
242243
}
243244

244245
fn build_fulltext_order_by_from_object(
245-
object: &BTreeMap<String, r::Value>,
246+
object: &Object,
246247
) -> Result<Option<(String, ValueType)>, QueryExecutionError> {
247248
object.iter().next().map_or(
248249
Err(QueryExecutionError::FulltextQueryRequiresFilter),
@@ -345,6 +346,7 @@ pub fn collect_entities_from_query_field(
345346
mod tests {
346347
use graph::{
347348
components::store::EntityType,
349+
data::value::Object,
348350
prelude::s::{Directive, Field, InputValue, ObjectType, Type, Value as SchemaValue},
349351
};
350352
use graphql_parser::Pos;
@@ -724,7 +726,7 @@ mod tests {
724726
let mut args = default_arguments();
725727
args.insert(
726728
&whre,
727-
r::Value::Object(BTreeMap::from_iter(vec![(
729+
r::Value::Object(Object::from_iter(vec![(
728730
"name_ends_with".to_string(),
729731
r::Value::String("ello".to_string()),
730732
)])),

graphql/src/store/resolver.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use std::collections::{BTreeMap, HashMap};
22
use std::result;
33
use std::sync::Arc;
44

5+
use graph::data::value::Object;
56
use graph::data::{
67
graphql::{object, ObjectOrInterface},
78
schema::META_FIELD_TYPE,
@@ -220,7 +221,7 @@ impl StoreResolver {
220221
"__typename".to_string(),
221222
r::Value::String(META_FIELD_TYPE.to_string()),
222223
);
223-
return Ok((None, Some(r::Value::Object(map))));
224+
return Ok((None, Some(r::Value::object(map))));
224225
}
225226
Ok((prefetched_object, None))
226227
}
@@ -328,8 +329,9 @@ impl Resolver for StoreResolver {
328329
// or a different field queried under the response key `_meta`.
329330
ErrorPolicy::Deny => {
330331
let data = result.take_data();
331-
let meta = data.and_then(|mut d| d.remove_entry("_meta"));
332-
result.set_data(meta.map(|m| BTreeMap::from_iter(Some(m))));
332+
let meta =
333+
data.and_then(|d| d.get("_meta").map(|m| ("_meta".to_string(), m.clone())));
334+
result.set_data(meta.map(|m| Object::from_iter(Some(m))));
333335
}
334336
ErrorPolicy::Allow => (),
335337
}

graphql/src/values/coercion.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ fn coerce_to_definition<'a>(
8989
},
9090
);
9191
}
92-
Ok(r::Value::Object(coerced_object))
92+
Ok(r::Value::object(coerced_object))
9393
}
9494
_ => Err(value),
9595
},

0 commit comments

Comments
 (0)