Skip to content

Commit

Permalink
Add __token metafield to schema definition
Browse files Browse the repository at this point in the history
Reviewed By: kassens

Differential Revision: D24509450

fbshipit-source-id: fc5c173e784690e7b753a4f811cc44a0108da06f
  • Loading branch information
Inanc Sevinc authored and facebook-github-bot committed Nov 9, 2020
1 parent 0b1a756 commit 018af6d
Show file tree
Hide file tree
Showing 9 changed files with 124 additions and 1 deletion.
29 changes: 29 additions & 0 deletions compiler/crates/graphql-ir/src/build.rs
Expand Up @@ -24,6 +24,7 @@ use schema::{

lazy_static! {
static ref TYPENAME_FIELD_NAME: StringKey = "__typename".intern();
static ref FETCH_TOKEN_FIELD_NAME: StringKey = "__token".intern();

/// Relay extension field that's available on all types.
static ref CLIENT_ID_FIELD_NAME: StringKey = "__id".intern();
Expand Down Expand Up @@ -813,6 +814,8 @@ impl<'schema, 'signatures> Builder<'schema, 'signatures> {
return self.build_typename_field(field);
} else if self.options.relay_mode && field_name == *CLIENT_ID_FIELD_NAME {
return self.build_clientid_field(field);
} else if field_name == *FETCH_TOKEN_FIELD_NAME {
return self.build_fetch_token_field(field);
};
let span = field.name.span;
let field_id = match self.lookup_field(
Expand Down Expand Up @@ -911,6 +914,32 @@ impl<'schema, 'signatures> Builder<'schema, 'signatures> {
})
}

fn build_fetch_token_field(
&mut self,
field: &graphql_syntax::ScalarField,
) -> DiagnosticsResult<ScalarField> {
let field_id = self.schema.fetch_token_field();
let alias = self.build_alias(&field.alias);
if let Some(arguments) = &field.arguments {
return Err(Diagnostic::error(
ValidationMessage::InvalidArgumentsOnFetchTokenField(),
self.location.with_span(arguments.span),
)
.into());
}
let directives = self.build_directives(&field.directives, DirectiveLocation::Field)?;
Ok(ScalarField {
alias,
definition: WithLocation::from_span(
self.location.source_location(),
field.name.span,
field_id,
),
arguments: Default::default(),
directives,
})
}

fn build_alias(
&mut self,
alias: &Option<graphql_syntax::Alias>,
Expand Down
3 changes: 3 additions & 0 deletions compiler/crates/graphql-ir/src/errors.rs
Expand Up @@ -145,6 +145,9 @@ pub enum ValidationMessage {
#[error("Unexpected arguments on `__typename` field")]
InvalidArgumentsOnTypenameField(),

#[error("Unexpected arguments on '__token' field")]
InvalidArgumentsOnFetchTokenField(),

#[error(
"Relay does not allow aliasing fields to `id`. This name is reserved for the globally unique `id` field on `Node`."
)]
Expand Down
@@ -0,0 +1,13 @@
==================================== INPUT ====================================
# expected-to-throw
fragment Foo on User {
__token(arg: 1)
}
==================================== ERROR ====================================
✖︎ Unexpected arguments on '__token' field

fetch_token_with_arguments.invalid.graphql:3:10
2 │ fragment Foo on User {
3 │ __token(arg: 1)
│ ^^^^^^^^
4 │ }
@@ -0,0 +1,4 @@
# expected-to-throw
fragment Foo on User {
__token(arg: 1)
}
9 changes: 8 additions & 1 deletion compiler/crates/graphql-ir/tests/parse_test.rs
@@ -1,4 +1,4 @@
// @generated SignedSource<<c93e294a1c594f65125929d1762d8cdc>>
// @generated SignedSource<<bf32c3c7a7794c71e6c06d78154eed03>>
// Generated by $ cargo run -p fixture-tests -- oss/crates/graphql-ir/tests/parse

mod parse;
Expand Down Expand Up @@ -97,6 +97,13 @@ fn enum_values_invalid() {
test_fixture(transform_fixture, "enum-values.invalid.graphql", "parse/fixtures/enum-values.invalid.expected", input, expected);
}

#[test]
fn fetch_token_with_arguments_invalid() {
let input = include_str!("parse/fixtures/fetch_token_with_arguments.invalid.graphql");
let expected = include_str!("parse/fixtures/fetch_token_with_arguments.invalid.expected");
test_fixture(transform_fixture, "fetch_token_with_arguments.invalid.graphql", "parse/fixtures/fetch_token_with_arguments.invalid.expected", input, expected);
}

#[test]
fn field_argument_missing_required_invalid() {
let input = include_str!("parse/fixtures/field_argument_missing_required.invalid.graphql");
Expand Down
31 changes: 31 additions & 0 deletions compiler/crates/schema/src/definitions.rs
Expand Up @@ -31,9 +31,11 @@ pub struct Schema {

clientid_field: FieldID,
typename_field: FieldID,
fetch_token_field: FieldID,

clientid_field_name: StringKey,
typename_field_name: StringKey,
fetch_token_field_name: StringKey,

string_type: Option<Type>,
id_type: Option<Type>,
Expand Down Expand Up @@ -72,6 +74,10 @@ impl Schema {
self.typename_field
}

pub fn fetch_token_field(&self) -> FieldID {
self.fetch_token_field
}

pub fn get_type(&self, type_name: StringKey) -> Option<Type> {
self.type_map.get(&type_name).cloned()
}
Expand Down Expand Up @@ -259,6 +265,10 @@ impl Schema {
if name == self.typename_field_name {
return Some(self.typename_field);
}
// TODO(inanc): Also check if the parent type is fetchable?
if name == self.fetch_token_field_name {
return Some(self.fetch_token_field);
}
if name == self.clientid_field_name {
return Some(self.clientid_field);
}
Expand Down Expand Up @@ -631,8 +641,10 @@ impl Schema {
type_map: HashMap::new(),
clientid_field: FieldID(0),
typename_field: FieldID(0),
fetch_token_field: FieldID(0),
clientid_field_name: "__id".intern(),
typename_field_name: "__typename".intern(),
fetch_token_field_name: "__token".intern(),
string_type: None,
id_type: None,
unchecked_argument_type_sentinel: None,
Expand Down Expand Up @@ -737,8 +749,10 @@ impl Schema {
type_map,
clientid_field: FieldID(0), // dummy value, overwritten later
typename_field: FieldID(0), // dummy value, overwritten later
fetch_token_field: FieldID(0), // dummy value, overwritten later
clientid_field_name: "__id".intern(),
typename_field_name: "__typename".intern(),
fetch_token_field_name: "__token".intern(),
string_type: Some(string_type),
id_type: Some(id_type),
unchecked_argument_type_sentinel,
Expand Down Expand Up @@ -792,6 +806,7 @@ impl Schema {
pub fn load_defaults(&mut self) {
self.load_default_root_types();
self.load_default_typename_field();
self.load_default_fetch_token_field();
self.load_default_clientid_field();
}

Expand Down Expand Up @@ -832,6 +847,20 @@ impl Schema {
});
}

fn load_default_fetch_token_field(&mut self) {
let id_type = *self.type_map.get(&"ID".intern()).unwrap();
let fetch_token_field_id = self.fields.len();
self.fetch_token_field = FieldID(fetch_token_field_id.try_into().unwrap());
self.fields.push(Field {
name: self.fetch_token_field_name,
is_extension: false,
arguments: ArgumentDefinitions::new(Default::default()),
type_: TypeReference::NonNull(Box::new(TypeReference::Named(id_type))),
directives: Vec::new(),
parent_type: None,
});
}

fn load_default_clientid_field(&mut self) {
let id_type = *self.type_map.get(&"ID".intern()).unwrap();
let clientid_field_id = self.fields.len();
Expand Down Expand Up @@ -1296,8 +1325,10 @@ impl Schema {
directives,
clientid_field: _clientid_field,
typename_field: _typename_field,
fetch_token_field: _fetch_token_field,
clientid_field_name: _clientid_field_name,
typename_field_name: _typename_field_name,
fetch_token_field_name: _fetch_token_field_name,
string_type: _string_type,
id_type: _id_type,
unchecked_argument_type_sentinel: _unchecked_argument_type_sentinel,
Expand Down
Expand Up @@ -400,6 +400,18 @@ Schema {
directives: [],
parent_type: None,
},
Field {
name: "__token",
is_extension: false,
arguments: [],
type_: NonNull(
Named(
Scalar(5),
),
),
directives: [],
parent_type: None,
},
Field {
name: "__id",
is_extension: true,
Expand Down
Expand Up @@ -198,6 +198,18 @@ Schema {
directives: [],
parent_type: None,
},
Field {
name: "__token",
is_extension: false,
arguments: [],
type_: NonNull(
Named(
Scalar(4),
),
),
directives: [],
parent_type: None,
},
Field {
name: "__id",
is_extension: true,
Expand Down
Expand Up @@ -312,6 +312,18 @@ Schema {
directives: [],
parent_type: None,
},
Field {
name: "__token",
is_extension: false,
arguments: [],
type_: NonNull(
Named(
Scalar(4),
),
),
directives: [],
parent_type: None,
},
Field {
name: "__id",
is_extension: true,
Expand Down

0 comments on commit 018af6d

Please sign in to comment.