Skip to content

Commit c28381e

Browse files
committed
all: Thread the spec version into InputSchema validation
1 parent 28cc721 commit c28381e

File tree

28 files changed

+95
-55
lines changed

28 files changed

+95
-55
lines changed

graph/examples/validate.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ use clap::Parser;
3232
use graph::data::graphql::ext::DirectiveFinder;
3333
use graph::data::graphql::DirectiveExt;
3434
use graph::data::graphql::DocumentExt;
35+
use graph::data::subgraph::SPEC_VERSION_1_1_0;
3536
use graph::prelude::s;
3637
use graph::prelude::DeploymentHash;
3738
use graph::schema::InputSchema;
@@ -105,7 +106,7 @@ fn parse(raw: &str, name: &str, api: bool) {
105106
&format!("Failed to parse schema sgd{}", name),
106107
);
107108
let id = subgraph_id(&schema);
108-
let input_schema = match InputSchema::parse(raw, id.clone()) {
109+
let input_schema = match InputSchema::parse(&SPEC_VERSION_1_1_0, raw, id.clone()) {
109110
Ok(schema) => schema,
110111
Err(e) => {
111112
println!("InputSchema: {}[{}]: {}", name, id, e);

graph/src/components/store/write.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -979,7 +979,8 @@ mod test {
979979
"#;
980980
lazy_static! {
981981
static ref DEPLOYMENT: DeploymentHash = DeploymentHash::new("batchAppend").unwrap();
982-
static ref SCHEMA: InputSchema = InputSchema::parse(GQL, DEPLOYMENT.clone()).unwrap();
982+
static ref SCHEMA: InputSchema =
983+
InputSchema::parse_latest(GQL, DEPLOYMENT.clone()).unwrap();
983984
static ref THING_TYPE: EntityType = SCHEMA.entity_type("Thing").unwrap();
984985
static ref ROW_GROUP_TYPE: EntityType = SCHEMA.entity_type("RowGroup").unwrap();
985986
static ref ENTRY_TYPE: EntityType = SCHEMA.entity_type("Entry").unwrap();

graph/src/components/subgraph/proof_of_indexing/mod.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,8 @@ mod tests {
137137
let id = DeploymentHash::new("Qm123").unwrap();
138138

139139
let data_schema =
140-
InputSchema::parse("type User @entity { id: String!, val: Int }", id.clone()).unwrap();
140+
InputSchema::parse_latest("type User @entity { id: String!, val: Int }", id.clone())
141+
.unwrap();
141142
let data = data_schema
142143
.make_entity(hashmap! {
143144
"id".into() => Value::String("id".to_owned()),
@@ -146,12 +147,12 @@ mod tests {
146147
.unwrap();
147148

148149
let empty_schema =
149-
InputSchema::parse("type User @entity { id: String! }", id.clone()).unwrap();
150+
InputSchema::parse_latest("type User @entity { id: String! }", id.clone()).unwrap();
150151
let data_empty = empty_schema
151152
.make_entity(hashmap! { "id".into() => Value::String("id".into())})
152153
.unwrap();
153154

154-
let data2_schema = InputSchema::parse(
155+
let data2_schema = InputSchema::parse_latest(
155156
"type User @entity { id: String!, key: String!, null: String }",
156157
id,
157158
)

graph/src/data/store/mod.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -776,10 +776,10 @@ pub enum EntityValidationError {
776776
/// ```
777777
/// use graph::entity;
778778
/// use graph::schema::InputSchema;
779-
/// use graph::data::subgraph::DeploymentHash;
779+
/// use graph::data::subgraph::{LATEST_VERSION, DeploymentHash};
780780
///
781781
/// let id = DeploymentHash::new("Qm123").unwrap();
782-
/// let schema = InputSchema::parse("type User @entity { id: String!, name: String! }", id).unwrap();
782+
/// let schema = InputSchema::parse(LATEST_VERSION, "type User @entity { id: String!, name: String! }", id).unwrap();
783783
///
784784
/// let entity = entity! { schema => id: "1", name: "John Doe" };
785785
/// ```
@@ -1107,8 +1107,8 @@ fn entity_validation() {
11071107

11081108
lazy_static! {
11091109
static ref SUBGRAPH: DeploymentHash = DeploymentHash::new("doesntmatter").unwrap();
1110-
static ref SCHEMA: InputSchema =
1111-
InputSchema::parse(DOCUMENT, SUBGRAPH.clone()).expect("Failed to parse test schema");
1110+
static ref SCHEMA: InputSchema = InputSchema::parse_latest(DOCUMENT, SUBGRAPH.clone())
1111+
.expect("Failed to parse test schema");
11121112
static ref THING_TYPE: EntityType = SCHEMA.entity_type("Thing").unwrap();
11131113
}
11141114

graph/src/data/subgraph/api_version.rs

+7
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@ pub const SPEC_VERSION_0_0_9: Version = Version::new(0, 0, 9);
4444
// Enables `indexerHints` feature.
4545
pub const SPEC_VERSION_1_0_0: Version = Version::new(1, 0, 0);
4646

47+
// Enables @aggregation entities
48+
// Enables `id: Int8`
49+
pub const SPEC_VERSION_1_1_0: Version = Version::new(1, 1, 0);
50+
51+
// The latest spec version available
52+
pub const LATEST_VERSION: &Version = &SPEC_VERSION_1_1_0;
53+
4754
pub const MIN_SPEC_VERSION: Version = Version::new(0, 0, 2);
4855

4956
#[derive(Clone, PartialEq, Debug)]

graph/src/data/subgraph/mod.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,7 @@ pub struct UnresolvedSchema {
409409
impl UnresolvedSchema {
410410
pub async fn resolve(
411411
self,
412+
spec_version: &Version,
412413
id: DeploymentHash,
413414
resolver: &Arc<dyn LinkResolver>,
414415
logger: &Logger,
@@ -417,7 +418,7 @@ impl UnresolvedSchema {
417418
.cat(logger, &self.file)
418419
.await
419420
.with_context(|| format!("failed to resolve schema {}", &self.file.link))?;
420-
InputSchema::parse(&String::from_utf8(schema_bytes)?, id)
421+
InputSchema::parse(spec_version, &String::from_utf8(schema_bytes)?, id)
421422
}
422423
}
423424

@@ -901,7 +902,9 @@ impl<C: Blockchain> UnresolvedSubgraphManifest<C> {
901902
);
902903
}
903904

904-
let schema = schema.resolve(id.clone(), resolver, logger).await?;
905+
let schema = schema
906+
.resolve(&spec_version, id.clone(), resolver, logger)
907+
.await?;
905908

906909
let (data_sources, templates) = try_join(
907910
data_sources

graph/src/schema/api.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1179,7 +1179,7 @@ fn add_field_arguments(
11791179

11801180
#[cfg(test)]
11811181
mod tests {
1182-
use crate::{prelude::DeploymentHash, schema::InputSchema};
1182+
use crate::{data::subgraph::LATEST_VERSION, prelude::DeploymentHash, schema::InputSchema};
11831183
use graphql_parser::schema::*;
11841184
use lazy_static::lazy_static;
11851185

@@ -1192,8 +1192,8 @@ mod tests {
11921192

11931193
#[track_caller]
11941194
fn parse(raw: &str) -> ApiSchema {
1195-
let input_schema =
1196-
InputSchema::parse(raw, ID.clone()).expect("Failed to parse input schema");
1195+
let input_schema = InputSchema::parse(LATEST_VERSION, raw, ID.clone())
1196+
.expect("Failed to parse input schema");
11971197
input_schema
11981198
.api_schema()
11991199
.expect("Failed to derive API schema")

graph/src/schema/input_schema.rs

+33-14
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ use std::sync::Arc;
55
use std::time::Duration;
66

77
use anyhow::{anyhow, Error};
8+
use semver::Version;
89
use store::Entity;
910

1011
use crate::bail;
@@ -774,7 +775,7 @@ impl InputSchema {
774775
/// A convenience function for creating an `InputSchema` from the string
775776
/// representation of the subgraph's GraphQL schema `raw` and its
776777
/// deployment hash `id`. The returned schema is fully validated.
777-
pub fn parse(raw: &str, id: DeploymentHash) -> Result<Self, Error> {
778+
pub fn parse(spec_version: &Version, raw: &str, id: DeploymentHash) -> Result<Self, Error> {
778779
fn agg_mappings(ts_types: &[TypeInfo]) -> Box<[AggregationMapping]> {
779780
let mut mappings: Vec<_> = ts_types
780781
.iter()
@@ -798,7 +799,7 @@ impl InputSchema {
798799
}
799800

800801
let schema = Schema::parse(raw, id.clone())?;
801-
validations::validate(&schema).map_err(|errors| {
802+
validations::validate(spec_version, &schema).map_err(|errors| {
802803
anyhow!(
803804
"Validation errors in subgraph `{}`:\n{}",
804805
id,
@@ -859,6 +860,13 @@ impl InputSchema {
859860
})
860861
}
861862

863+
/// Parse with the latest spec version
864+
pub fn parse_latest(raw: &str, id: DeploymentHash) -> Result<Self, Error> {
865+
use crate::data::subgraph::LATEST_VERSION;
866+
867+
Self::parse(LATEST_VERSION, raw, id)
868+
}
869+
862870
/// Convenience for tests to construct an `InputSchema`
863871
///
864872
/// # Panics
@@ -868,7 +876,7 @@ impl InputSchema {
868876
#[track_caller]
869877
pub fn raw(document: &str, hash: &str) -> Self {
870878
let hash = DeploymentHash::new(hash).unwrap();
871-
Self::parse(document, hash).unwrap()
879+
Self::parse_latest(document, hash).unwrap()
872880
}
873881

874882
pub fn schema(&self) -> &Schema {
@@ -1324,6 +1332,7 @@ mod validations {
13241332

13251333
use inflector::Inflector;
13261334
use itertools::Itertools;
1335+
use semver::Version;
13271336

13281337
use crate::{
13291338
data::{
@@ -1343,15 +1352,20 @@ mod validations {
13431352

13441353
/// Helper struct for validations
13451354
struct Schema<'a> {
1355+
#[allow(dead_code)]
1356+
spec_version: &'a Version,
13461357
schema: &'a BaseSchema,
13471358
subgraph_schema_type: Option<&'a s::ObjectType>,
13481359
// All entity types, excluding the subgraph schema type
13491360
entity_types: Vec<&'a s::ObjectType>,
13501361
aggregations: Vec<&'a s::ObjectType>,
13511362
}
13521363

1353-
pub(super) fn validate(schema: &BaseSchema) -> Result<(), Vec<SchemaValidationError>> {
1354-
let schema = Schema::new(schema);
1364+
pub(super) fn validate(
1365+
spec_version: &Version,
1366+
schema: &BaseSchema,
1367+
) -> Result<(), Vec<SchemaValidationError>> {
1368+
let schema = Schema::new(spec_version, schema);
13551369

13561370
let mut errors: Vec<SchemaValidationError> = [
13571371
schema.validate_no_extra_types(),
@@ -1380,14 +1394,15 @@ mod validations {
13801394
}
13811395

13821396
impl<'a> Schema<'a> {
1383-
fn new(schema: &'a BaseSchema) -> Self {
1397+
fn new(spec_version: &'a Version, schema: &'a BaseSchema) -> Self {
13841398
let subgraph_schema_type = schema.subgraph_schema_object_type();
13851399
let mut entity_types = schema.document.get_object_type_definitions();
13861400
entity_types.retain(|obj_type| obj_type.find_directive(kw::ENTITY).is_some());
13871401
let mut aggregations = schema.document.get_object_type_definitions();
13881402
aggregations.retain(|obj_type| obj_type.find_directive(kw::AGGREGATION).is_some());
13891403

13901404
Schema {
1405+
spec_version,
13911406
schema,
13921407
subgraph_schema_type,
13931408
entity_types,
@@ -2276,7 +2291,7 @@ mod validations {
22762291
mod tests {
22772292
use std::ffi::OsString;
22782293

2279-
use crate::prelude::DeploymentHash;
2294+
use crate::{data::subgraph::LATEST_VERSION, prelude::DeploymentHash};
22802295

22812296
use super::*;
22822297

@@ -2285,6 +2300,10 @@ mod validations {
22852300
BaseSchema::parse(schema, hash).unwrap()
22862301
}
22872302

2303+
fn validate(schema: &BaseSchema) -> Result<(), Vec<SchemaValidationError>> {
2304+
super::validate(LATEST_VERSION, schema)
2305+
}
2306+
22882307
#[test]
22892308
fn object_types_have_id() {
22902309
const NO_ID: &str = "type User @entity { name: String! }";
@@ -2369,7 +2388,7 @@ type Account implements Address @entity { id: ID!, txn: Transaction! @derivedFro
23692388
.expect("Failed to parse raw schema")
23702389
.into_static();
23712390
let schema = BaseSchema::new(DeploymentHash::new("id").unwrap(), document).unwrap();
2372-
let schema = Schema::new(&schema);
2391+
let schema = Schema::new(LATEST_VERSION, &schema);
23732392
match schema.validate_derived_from() {
23742393
Err(ref e) => match e {
23752394
SchemaValidationError::InvalidDerivedFrom(_, _, msg) => {
@@ -2425,7 +2444,7 @@ type _Schema_ { id: ID! }";
24252444
let document =
24262445
graphql_parser::parse_schema(ROOT_SCHEMA).expect("Failed to parse root schema");
24272446
let schema = BaseSchema::new(DeploymentHash::new("id").unwrap(), document).unwrap();
2428-
let schema = Schema::new(&schema);
2447+
let schema = Schema::new(LATEST_VERSION, &schema);
24292448
assert_eq!(
24302449
schema.validate_schema_type_has_no_fields().expect_err(
24312450
"Expected validation to fail due to fields defined on the reserved type"
@@ -2442,7 +2461,7 @@ type _Schema_ @illegal";
24422461
let document =
24432462
graphql_parser::parse_schema(ROOT_SCHEMA).expect("Failed to parse root schema");
24442463
let schema = BaseSchema::new(DeploymentHash::new("id").unwrap(), document).unwrap();
2445-
let schema = Schema::new(&schema);
2464+
let schema = Schema::new(LATEST_VERSION, &schema);
24462465
assert_eq!(
24472466
schema.validate_directives_on_schema_type().expect_err(
24482467
"Expected validation to fail due to extra imports defined on the reserved type"
@@ -2467,7 +2486,7 @@ type A @entity {
24672486
let document =
24682487
graphql_parser::parse_schema(ROOT_SCHEMA).expect("Failed to parse root schema");
24692488
let schema = BaseSchema::new(DeploymentHash::new("id").unwrap(), document).unwrap();
2470-
let schema = Schema::new(&schema);
2489+
let schema = Schema::new(LATEST_VERSION, &schema);
24712490
assert_eq!(schema.validate_fields().len(), 0);
24722491
}
24732492

@@ -2575,7 +2594,7 @@ type Gravatar @entity {
25752594

25762595
let document = graphql_parser::parse_schema(SCHEMA).expect("Failed to parse schema");
25772596
let schema = BaseSchema::new(DeploymentHash::new("id1").unwrap(), document).unwrap();
2578-
let schema = Schema::new(&schema);
2597+
let schema = Schema::new(LATEST_VERSION, &schema);
25792598
assert_eq!(schema.validate_fulltext_directives(), vec![]);
25802599
}
25812600

@@ -2706,7 +2725,7 @@ mod tests {
27062725

27072726
fn make_schema() -> InputSchema {
27082727
let id = DeploymentHash::new("test").unwrap();
2709-
InputSchema::parse(SCHEMA, id).unwrap()
2728+
InputSchema::parse_latest(SCHEMA, id).unwrap()
27102729
}
27112730

27122731
#[test]
@@ -2748,7 +2767,7 @@ mod tests {
27482767
"#;
27492768

27502769
let id = DeploymentHash::new("test").unwrap();
2751-
let schema = InputSchema::parse(SCHEMA, id).unwrap();
2770+
let schema = InputSchema::parse_latest(SCHEMA, id).unwrap();
27522771

27532772
let dog = schema.entity_type("Dog").unwrap();
27542773
let cat = schema.entity_type("Cat").unwrap();

graphql/examples/schema.rs

+4-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,10 @@ pub fn main() {
3030
};
3131
let schema = ensure(fs::read_to_string(schema), "Can not read schema file");
3232
let id = DeploymentHash::new("unknown").unwrap();
33-
let schema = ensure(InputSchema::parse(&schema, id), "Failed to parse schema");
33+
let schema = ensure(
34+
InputSchema::parse_latest(&schema, id),
35+
"Failed to parse schema",
36+
);
3437
let schema = ensure(schema.api_schema(), "Failed to convert to API schema");
3538

3639
println!("{}", schema.schema().document);

graphql/src/store/query.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -911,7 +911,7 @@ mod tests {
911911
"#;
912912

913913
let id = DeploymentHash::new("id").unwrap();
914-
let input_schema = InputSchema::parse(INPUT_SCHEMA, id.clone()).unwrap();
914+
let input_schema = InputSchema::parse_latest(INPUT_SCHEMA, id.clone()).unwrap();
915915
let api_schema = input_schema.api_schema().unwrap();
916916

917917
SchemaPair {

node/src/manager/commands/listen.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ pub async fn entities(
7474
writeln!(buf, "type {entity_type} @entity {{ id: ID! }}").unwrap();
7575
buf
7676
});
77-
let schema = InputSchema::parse(&schema, id.clone()).unwrap();
77+
let schema = InputSchema::parse_latest(&schema, id.clone()).unwrap();
7878
entity_types
7979
.iter()
8080
.map(|et| schema.entity_type(et))

store/postgres/examples/layout.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -140,7 +140,7 @@ pub fn main() {
140140
let subgraph = DeploymentHash::new("Qmasubgraph").unwrap();
141141
let schema = ensure(fs::read_to_string(schema), "Can not read schema file");
142142
let schema = ensure(
143-
InputSchema::parse(&schema, subgraph.clone()),
143+
InputSchema::parse_latest(&schema, subgraph.clone()),
144144
"Failed to parse schema",
145145
);
146146
let namespace = ensure(

store/postgres/src/deployment.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ pub fn schema(conn: &PgConnection, site: &Site) -> Result<(InputSchema, bool), S
303303
.select((sm::schema, sm::use_bytea_prefix))
304304
.filter(sm::id.eq(site.id))
305305
.first::<(String, bool)>(conn)?;
306-
InputSchema::parse(s.as_str(), site.deployment.clone())
306+
InputSchema::parse_latest(s.as_str(), site.deployment.clone())
307307
.map_err(StoreError::Unknown)
308308
.map(|schema| (schema, use_bytea_prefix))
309309
}
@@ -335,7 +335,7 @@ impl ManifestInfo {
335335
))
336336
.filter(sm::id.eq(site.id))
337337
.first(conn)?;
338-
let input_schema = InputSchema::parse(s.as_str(), site.deployment.clone())?;
338+
let input_schema = InputSchema::parse_latest(s.as_str(), site.deployment.clone())?;
339339

340340
// Using the features field to store the instrument flag is a bit
341341
// backhanded, but since this will be used very rarely, should not

store/postgres/src/fork.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -240,7 +240,7 @@ mod tests {
240240
}
241241

242242
fn test_schema() -> InputSchema {
243-
InputSchema::parse(
243+
InputSchema::parse_latest(
244244
r#"type Gravatar @entity {
245245
id: ID!
246246
owner: Bytes!

store/postgres/src/relational/ddl_tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ const ID_TYPE: ColumnType = ColumnType::String;
99

1010
fn test_layout(gql: &str) -> Layout {
1111
let subgraph = DeploymentHash::new("subgraph").unwrap();
12-
let schema = InputSchema::parse(gql, subgraph.clone()).expect("Test schema invalid");
12+
let schema = InputSchema::parse_latest(gql, subgraph.clone()).expect("Test schema invalid");
1313
let namespace = Namespace::new("sgd0815".to_owned()).unwrap();
1414
let site = Arc::new(make_dummy_site(subgraph, namespace, "anet".to_string()));
1515
let ents = {

0 commit comments

Comments
 (0)