Skip to content

Commit

Permalink
Initial WIP on adding new Int8 scalar
Browse files Browse the repository at this point in the history
  • Loading branch information
dotansimha committed Apr 3, 2023
1 parent 5fa50f9 commit 7000fc3
Show file tree
Hide file tree
Showing 13 changed files with 98 additions and 11 deletions.
18 changes: 18 additions & 0 deletions graph/src/data/store/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ pub const ID: &str = "ID";
pub const BYTES_SCALAR: &str = "Bytes";
pub const BIG_INT_SCALAR: &str = "BigInt";
pub const BIG_DECIMAL_SCALAR: &str = "BigDecimal";
pub const INT8_SCALAR: &str = "Int8";

#[derive(Clone, Debug, PartialEq)]
pub enum ValueType {
Expand All @@ -138,6 +139,7 @@ pub enum ValueType {
Bytes,
BigDecimal,
Int,
Int8,
String,
}

Expand All @@ -151,6 +153,7 @@ impl FromStr for ValueType {
"Bytes" => Ok(ValueType::Bytes),
"BigDecimal" => Ok(ValueType::BigDecimal),
"Int" => Ok(ValueType::Int),
"Int8" => Ok(ValueType::Int8),
"String" | "ID" => Ok(ValueType::String),
s => Err(anyhow!("Type not available in this context: {}", s)),
}
Expand All @@ -172,6 +175,7 @@ impl ValueType {
pub enum Value {
String(String),
Int(i32),
Int8(i64),
BigDecimal(scalar::BigDecimal),
Bool(bool),
List(Vec<Value>),
Expand Down Expand Up @@ -207,6 +211,9 @@ impl stable_hash_legacy::StableHash for Value {
Int(inner) => {
stable_hash_legacy::StableHash::stable_hash(inner, sequence_number, state)
}
Int8(inner) => {
stable_hash_legacy::StableHash::stable_hash(inner, sequence_number, state)
}
BigDecimal(inner) => {
stable_hash_legacy::StableHash::stable_hash(inner, sequence_number, state)
}
Expand Down Expand Up @@ -264,6 +271,10 @@ impl StableHash for Value {
BigInt(inner) => {
inner.stable_hash(field_address.child(0), state);
7
},
Int8(inner) => {
inner.stable_hash(field_address.child(0), state);
8
}
};

Expand Down Expand Up @@ -300,6 +311,7 @@ impl Value {
BYTES_SCALAR => Value::Bytes(scalar::Bytes::from_str(s)?),
BIG_INT_SCALAR => Value::BigInt(scalar::BigInt::from_str(s)?),
BIG_DECIMAL_SCALAR => Value::BigDecimal(scalar::BigDecimal::from_str(s)?),
INT8_SCALAR => Value::Int8(s.parse::<i64>().map_err(|_| QueryExecutionError::ValueParseError("Int8".to_string(), format!("{}", s)))?),
_ => Value::String(s.clone()),
}
}
Expand Down Expand Up @@ -391,6 +403,7 @@ impl Value {
Value::Bool(_) => "Boolean".to_owned(),
Value::Bytes(_) => "Bytes".to_owned(),
Value::Int(_) => "Int".to_owned(),
Value::Int8(_) => "Int8".to_owned(),
Value::List(values) => {
if let Some(v) = values.first() {
format!("[{}]", v.type_name())
Expand All @@ -411,6 +424,7 @@ impl Value {
| (Value::Bool(_), ValueType::Boolean)
| (Value::Bytes(_), ValueType::Bytes)
| (Value::Int(_), ValueType::Int)
| (Value::Int8(_), ValueType::Int8)
| (Value::Null, _) => true,
(Value::List(values), _) if is_list => values
.iter()
Expand All @@ -428,6 +442,7 @@ impl fmt::Display for Value {
match self {
Value::String(s) => s.to_string(),
Value::Int(i) => i.to_string(),
Value::Int8(i) => i.to_string(),
Value::BigDecimal(d) => d.to_string(),
Value::Bool(b) => b.to_string(),
Value::Null => "null".to_string(),
Expand All @@ -445,6 +460,7 @@ impl fmt::Debug for Value {
match self {
Self::String(s) => f.debug_tuple("String").field(s).finish(),
Self::Int(i) => f.debug_tuple("Int").field(i).finish(),
Self::Int8(i) => f.debug_tuple("Int8").field(i).finish(),
Self::BigDecimal(d) => d.fmt(f),
Self::Bool(arg0) => f.debug_tuple("Bool").field(arg0).finish(),
Self::List(arg0) => f.debug_tuple("List").field(arg0).finish(),
Expand All @@ -460,6 +476,7 @@ impl From<Value> for q::Value {
match value {
Value::String(s) => q::Value::String(s),
Value::Int(i) => q::Value::Int(q::Number::from(i)),
Value::Int8(i) => q::Value::String(i.to_string()),
Value::BigDecimal(d) => q::Value::String(d.to_string()),
Value::Bool(b) => q::Value::Boolean(b),
Value::Null => q::Value::Null,
Expand All @@ -477,6 +494,7 @@ impl From<Value> for r::Value {
match value {
Value::String(s) => r::Value::String(s),
Value::Int(i) => r::Value::Int(i as i64),
Value::Int8(i) => r::Value::String(i.to_string()),
Value::BigDecimal(d) => r::Value::String(d.to_string()),
Value::Bool(b) => r::Value::Boolean(b),
Value::Null => r::Value::Null,
Expand Down
1 change: 1 addition & 0 deletions graph/src/data/value.rs
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ impl Value {
Err(Value::Int(num))
}
}
("Int8", Value::Int(num)) => Ok(Value::Int(num)),
("String", Value::String(s)) => Ok(Value::String(s)),
("ID", Value::String(s)) => Ok(Value::String(s)),
("ID", Value::Int(n)) => Ok(Value::String(n.to_string())),
Expand Down
1 change: 1 addition & 0 deletions graph/src/runtime/gas/size_of.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ impl GasSizeOf for Value {
Value::Null => Gas(1),
Value::List(list) => list.gas_size_of(),
Value::Int(int) => int.gas_size_of(),
Value::Int8(int) => int.gas_size_of(),
Value::Bytes(bytes) => bytes.gas_size_of(),
Value::Bool(bool) => bool.gas_size_of(),
Value::BigInt(big_int) => big_int.gas_size_of(),
Expand Down
2 changes: 1 addition & 1 deletion graph/src/util/cache_weight.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ impl CacheWeight for Value {
Value::List(values) => values.indirect_weight(),
Value::Bytes(bytes) => bytes.indirect_weight(),
Value::BigInt(n) => n.indirect_weight(),
Value::Int(_) | Value::Bool(_) | Value::Null => 0,
Value::Int8(_) | Value::Int(_) | Value::Bool(_) | Value::Null => 0,
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions graphql/src/schema/api.rs
Original file line number Diff line number Diff line change
Expand Up @@ -367,6 +367,7 @@ fn field_scalar_filter_input_values(
"BigDecimal" => vec!["", "not", "gt", "lt", "gte", "lte", "in", "not_in"],
"ID" => vec!["", "not", "gt", "lt", "gte", "lte", "in", "not_in"],
"Int" => vec!["", "not", "gt", "lt", "gte", "lte", "in", "not_in"],
"Int8" => vec!["", "not", "gt", "lt", "gte", "lte", "in", "not_in"],
"String" => vec![
"",
"not",
Expand Down Expand Up @@ -894,6 +895,9 @@ mod tests {
schema
.get_named_type("String")
.expect("String type is missing in API schema");
schema
.get_named_type("Int8")
.expect("Int8 type is missing in API schema");
}

#[test]
Expand Down
2 changes: 2 additions & 0 deletions graphql/src/schema/meta.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,11 @@ directive @subgraphId(id: String!) on OBJECT
"creates a virtual field on the entity that may be queried but cannot be set manually through the mappings API."
directive @derivedFrom(field: String!) on FIELD_DEFINITION

# Additional scalar types
scalar BigDecimal
scalar Bytes
scalar BigInt
scalar Int8

# The type names are purposely awkward to minimize the risk of them
# colliding with user-supplied types
Expand Down
19 changes: 19 additions & 0 deletions graphql/src/values/coercion.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ impl MaybeCoercible<ScalarType> for q::Value {
Err(q::Value::Int(num))
}
}
("Int8", q::Value::Int(num)) => {
let n = num.as_i64().ok_or_else(|| q::Value::Int(num.clone()))?;
Ok(r::Value::Int(n))
}
("String", q::Value::String(s)) => Ok(r::Value::String(s)),
("ID", q::Value::String(s)) => Ok(r::Value::String(s)),
("ID", q::Value::Int(n)) => Ok(r::Value::String(
Expand Down Expand Up @@ -395,6 +399,21 @@ mod tests {
);
}

#[test]
fn coerce_int8_scalar() {
let int8_type = TypeDefinition::Scalar(ScalarType::new("Int8".to_string()));
let resolver = |_: &str| Some(&int8_type);

assert_eq!(
coerce_to_definition(Value::Int(1234.into()), "", &resolver),
Ok(Value::Int(1234_i64))
);
assert_eq!(
coerce_to_definition(Value::Int((-1234_i32).into()), "", &resolver,),
Ok(Value::Int(-1234_i64))
);
}

#[test]
fn coerce_bytes_scalar() {
let bytes_type = TypeDefinition::Scalar(ScalarType::new("Bytes".to_string()));
Expand Down
18 changes: 10 additions & 8 deletions graphql/tests/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ fn test_schema(id: DeploymentHash, id_type: IdType) -> Schema {
mainBand: Band
bands: [Band!]!
writtenSongs: [Song!]! @derivedFrom(field: \"writtenBy\")
favoriteCount: Int8!
}
type Band @entity {
Expand Down Expand Up @@ -316,8 +317,8 @@ async fn insert_test_entities(
let s = id_type.songs();
let md = id_type.medias();
let entities0 = vec![
entity! { __typename: "Musician", id: "m1", name: "John", mainBand: "b1", bands: vec!["b1", "b2"] },
entity! { __typename: "Musician", id: "m2", name: "Lisa", mainBand: "b1", bands: vec!["b1"] },
entity! { __typename: "Musician", id: "m1", name: "John", mainBand: "b1", bands: vec!["b1", "b2"], favoriteCount: 2 },
entity! { __typename: "Musician", id: "m2", name: "Lisa", mainBand: "b1", bands: vec!["b1"], favoriteCount: 100 },
entity! { __typename: "Publisher", id: "0xb1" },
entity! { __typename: "Band", id: "b1", name: "The Musicians", originalSongs: vec![s[1], s[2]] },
entity! { __typename: "Band", id: "b2", name: "The Amateurs", originalSongs: vec![s[1], s[3], s[4]] },
Expand Down Expand Up @@ -348,8 +349,8 @@ async fn insert_test_entities(
];

let entities1 = vec![
entity! { __typename: "Musician", id: "m3", name: "Tom", mainBand: "b2", bands: vec!["b1", "b2"] },
entity! { __typename: "Musician", id: "m4", name: "Valerie", bands: Vec::<String>::new() },
entity! { __typename: "Musician", id: "m3", name: "Tom", mainBand: "b2", bands: vec!["b1", "b2"], favoriteCount: 5 },
entity! { __typename: "Musician", id: "m4", name: "Valerie", bands: Vec::<String>::new(), favoriteCount: 10 },
];

async fn insert_at(entities: Vec<Entity>, deployment: &DeploymentLocator, block_ptr: BlockPtr) {
Expand Down Expand Up @@ -570,6 +571,7 @@ fn can_query_one_to_one_relationship() {
mainBand {
name
}
favoriteCount
}
songStats(first: 100, orderBy: id) {
id
Expand All @@ -586,10 +588,10 @@ fn can_query_one_to_one_relationship() {
let s = id_type.songs();
let exp = object! {
musicians: vec![
object! { name: "John", mainBand: object! { name: "The Musicians" } },
object! { name: "Lisa", mainBand: object! { name: "The Musicians" } },
object! { name: "Tom", mainBand: object! { name: "The Amateurs"} },
object! { name: "Valerie", mainBand: r::Value::Null }
object! { name: "John", mainBand: object! { name: "The Musicians" }, favoriteCount: 2 },
object! { name: "Lisa", mainBand: object! { name: "The Musicians" }, favoriteCount: 100 },
object! { name: "Tom", mainBand: object! { name: "The Amateurs" }, favoriteCount: 5 },
object! { name: "Valerie", mainBand: r::Value::Null, favoriteCount: 10 }
],
songStats: vec![
object! {
Expand Down
8 changes: 8 additions & 0 deletions runtime/wasm/src/asc_abi/class.rs
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,12 @@ impl From<EnumPayload> for f64 {
}
}

impl From<EnumPayload> for i64 {
fn from(payload: EnumPayload) -> i64 {
payload.0 as i64
}
}

impl From<EnumPayload> for bool {
fn from(payload: EnumPayload) -> bool {
payload.0 != 0
Expand Down Expand Up @@ -540,6 +546,7 @@ impl AscValue for EthereumValueKind {}
pub enum StoreValueKind {
String,
Int,
Int8,
BigDecimal,
Bool,
Array,
Expand All @@ -555,6 +562,7 @@ impl StoreValueKind {
match value {
Value::String(_) => StoreValueKind::String,
Value::Int(_) => StoreValueKind::Int,
Value::Int8(_) => StoreValueKind::Int8,
Value::BigDecimal(_) => StoreValueKind::BigDecimal,
Value::Bool(_) => StoreValueKind::Bool,
Value::List(_) => StoreValueKind::Array,
Expand Down
2 changes: 2 additions & 0 deletions runtime/wasm/src/to_from/external.rs
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@ impl FromAscObj<AscEnum<StoreValueKind>> for store::Value {
Value::String(asc_get(heap, ptr, gas)?)
}
StoreValueKind::Int => Value::Int(i32::from(payload)),
StoreValueKind::Int8 => Value::Int8(i64::from(payload)),
StoreValueKind::BigDecimal => {
let ptr: AscPtr<AscBigDecimal> = AscPtr::from(payload);
Value::BigDecimal(asc_get(heap, ptr, gas)?)
Expand Down Expand Up @@ -285,6 +286,7 @@ impl ToAscObj<AscEnum<StoreValueKind>> for store::Value {
let payload = match self {
Value::String(string) => asc_new(heap, string.as_str(), gas)?.into(),
Value::Int(n) => EnumPayload::from(*n),
Value::Int8(n) => EnumPayload::from(*n),
Value::BigDecimal(n) => asc_new(heap, n, gas)?.into(),
Value::Bool(b) => EnumPayload::from(*b),
Value::List(array) => asc_new(heap, array.as_slice(), gas)?.into(),
Expand Down
3 changes: 3 additions & 0 deletions store/postgres/src/relational.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1010,6 +1010,7 @@ pub enum ColumnType {
BigInt,
Bytes,
Int,
Int8,
String,
TSVector(FulltextConfig),
Enum(EnumType),
Expand Down Expand Up @@ -1067,6 +1068,7 @@ impl ColumnType {
ValueType::BigInt => Ok(ColumnType::BigInt),
ValueType::Bytes => Ok(ColumnType::Bytes),
ValueType::Int => Ok(ColumnType::Int),
ValueType::Int8 => Ok(ColumnType::Int8),
ValueType::String => Ok(ColumnType::String),
}
}
Expand All @@ -1078,6 +1080,7 @@ impl ColumnType {
ColumnType::BigInt => "numeric",
ColumnType::Bytes => "bytea",
ColumnType::Int => "integer",
ColumnType::Int8 => "int8",
ColumnType::String => "text",
ColumnType::TSVector(_) => "tsvector",
ColumnType::Enum(enum_type) => enum_type.name.as_str(),
Expand Down
16 changes: 15 additions & 1 deletion store/postgres/src/relational_queries.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use diesel::pg::{Pg, PgConnection};
use diesel::query_builder::{AstPass, QueryFragment, QueryId};
use diesel::query_dsl::{LoadQuery, RunQueryDsl};
use diesel::result::{Error as DieselError, QueryResult};
use diesel::sql_types::{Array, BigInt, Binary, Bool, Integer, Jsonb, Text};
use diesel::sql_types::{Array, BigInt, Binary, Bool, Integer, Jsonb, Text, Int8};
use diesel::Connection;

use graph::components::store::{DerivedEntityQuery, EntityKey};
Expand Down Expand Up @@ -314,6 +314,15 @@ pub trait FromColumnValue: Sized + std::fmt::Debug {
number
))),
},
(j::Number(number), ColumnType::Int8) => match number.as_i64() {
Some(i) => i32::try_from(i).map(Self::from_i32).map_err(|e| {
StoreError::Unknown(anyhow!("failed to convert {} to Int8: {}", number, e))
}),
None => Err(StoreError::Unknown(anyhow!(
"failed to convert {} to Int8",
number
))),
},
(j::Number(number), ColumnType::BigDecimal) => {
let s = number.to_string();
scalar::BigDecimal::from_str(s.as_str())
Expand Down Expand Up @@ -572,6 +581,7 @@ impl<'a> QueryFragment<Pg> for QueryValue<'a> {
),
},
Value::Int(i) => out.push_bind_param::<Integer, _>(i),
Value::Int8(i) => out.push_bind_param::<Int8, _>(i),
Value::BigDecimal(d) => {
out.push_bind_param::<Text, _>(&d.to_string())?;
out.push_sql("::numeric");
Expand All @@ -590,6 +600,7 @@ impl<'a> QueryFragment<Pg> for QueryValue<'a> {
ColumnType::Boolean => out.push_bind_param::<Array<Bool>, _>(&sql_values),
ColumnType::Bytes => out.push_bind_param::<Array<Binary>, _>(&sql_values),
ColumnType::Int => out.push_bind_param::<Array<Integer>, _>(&sql_values),
ColumnType::Int8 => out.push_bind_param::<Array<Int8>, _>(&sql_values),
ColumnType::String => out.push_bind_param::<Array<Text>, _>(&sql_values),
ColumnType::Enum(enum_type) => {
out.push_bind_param::<Array<Text>, _>(&sql_values)?;
Expand Down Expand Up @@ -1168,6 +1179,7 @@ impl<'a> QueryFilter<'a> {
Value::Null
| Value::BigDecimal(_)
| Value::Int(_)
| Value::Int8(_)
| Value::Bool(_)
| Value::BigInt(_) => {
let filter = match negated {
Expand Down Expand Up @@ -1238,6 +1250,7 @@ impl<'a> QueryFilter<'a> {
| Value::Bytes(_)
| Value::BigDecimal(_)
| Value::Int(_)
| Value::Int8(_)
| Value::String(_) => QueryValue(value, &column.column_type).walk_ast(out)?,
Value::Bool(_) | Value::List(_) | Value::Null => {
return Err(UnsupportedFilter {
Expand Down Expand Up @@ -1377,6 +1390,7 @@ impl<'a> QueryFilter<'a> {
| Value::Bytes(_)
| Value::BigDecimal(_)
| Value::Int(_)
| Value::Int8(_)
| Value::List(_)
| Value::Null => {
return Err(UnsupportedFilter {
Expand Down
Loading

0 comments on commit 7000fc3

Please sign in to comment.