Skip to content

Commit 9d7ac65

Browse files
committed
validation/schema: Allow deriving from interface-typed fields
The source of a derived field used to be restricted to just the type that contained the derived field. With this change, it is also permissible to use an interface that is implemented by the type containing the derived field. This mirrors the fix from this PR in graph-node: graphprotocol/graph-node#1278
1 parent 8908bc8 commit 9d7ac65

File tree

7 files changed

+81
-3
lines changed

7 files changed

+81
-3
lines changed

src/validation/schema.js

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -339,7 +339,9 @@ does not exist on type '${targetEntity.name.value}'`,
339339
let backrefTypeName = unwrapType(derivedFromField.type)
340340
let backRefEntity = entityTypeByName(defs, backrefTypeName.name.value)
341341

342-
if (!backRefEntity || backRefEntity.name.value !== def.name.value) {
342+
// The field we are deriving from must either have type 'def' or one of the
343+
// interface types that 'def' is implementing
344+
if (!backRefEntity || (backRefEntity.name.value !== def.name.value && !def.interfaces.find(intf => intf.name.value === backRefEntity.name.value))) {
343345
return immutable.fromJS([
344346
{
345347
loc: directive.loc,
@@ -348,7 +350,8 @@ does not exist on type '${targetEntity.name.value}'`,
348350
Field '${field.name.value}': \
349351
@derivedFrom field '${directive.arguments[0].value.value}' \
350352
on type '${targetEntity.name.value}' must have the type \
351-
'${def.name.value}', '${def.name.value}!' or '[${def.name.value}!]!'`,
353+
'${def.name.value}', '${def.name.value}!', '[${def.name.value}!]!', \
354+
or one of the interface types that '${def.name.value}' implements`,
352355
},
353356
])
354357
}

tests/cli/validation.test.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,6 +120,14 @@ describe('Validation', () => {
120120
exitCode: 1,
121121
},
122122
)
123+
cliTest(
124+
'Deriving from interface-typed fields is allowed',
125+
['codegen', '--skip-migrations'],
126+
'validation/derived-from-with-interface',
127+
{
128+
exitCode: 0,
129+
},
130+
)
123131
cliTest(
124132
'@derivedFrom target type missing',
125133
['codegen', '--skip-migrations'],
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
[{"constant":false,"inputs":[{"name":"_imageUrl","type":"string"}],"name":"updateGravatarImage","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[],"name":"setMythicalGravatar","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"owner","type":"address"}],"name":"getGravatar","outputs":[{"name":"","type":"string"},{"name":"","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"gravatarToOwner","outputs":[{"name":"","type":"address"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":true,"inputs":[{"name":"","type":"address"}],"name":"ownerToGravatar","outputs":[{"name":"","type":"uint256"}],"payable":false,"stateMutability":"view","type":"function"},{"constant":false,"inputs":[{"name":"_displayName","type":"string"}],"name":"updateGravatarName","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":false,"inputs":[{"name":"_displayName","type":"string"},{"name":"_imageUrl","type":"string"}],"name":"createGravatar","outputs":[],"payable":false,"stateMutability":"nonpayable","type":"function"},{"constant":true,"inputs":[{"name":"","type":"uint256"}],"name":"gravatars","outputs":[{"name":"owner","type":"address"},{"name":"displayName","type":"string"},{"name":"imageUrl","type":"string"}],"payable":false,"stateMutability":"view","type":"function"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"displayName","type":"string"},{"indexed":false,"name":"imageUrl","type":"string"}],"name":"NewGravatar","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"name":"id","type":"uint256"},{"indexed":false,"name":"owner","type":"address"},{"indexed":false,"name":"displayName","type":"string"},{"indexed":false,"name":"imageUrl","type":"string"}],"name":"UpdatedGravatar","type":"event"}]
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
import { NewGravatar, UpdatedGravatar } from '../generated/Gravity/Gravity'
2+
import { Gravatar } from '../generated/schema'
3+
4+
export function handleNewGravatar(event: NewGravatar): void {
5+
let gravatar = new Gravatar(event.params.id.toHex())
6+
gravatar.owner = event.params.owner
7+
gravatar.displayName = event.params.displayName
8+
gravatar.imageUrl = event.params.imageUrl
9+
gravatar.save()
10+
}
11+
12+
export function handleUpdatedGravatar(event: UpdatedGravatar): void {
13+
let id = event.params.id.toHex()
14+
let gravatar = Gravatar.load(id)
15+
if (gravatar == null) {
16+
gravatar = new Gravatar(id)
17+
}
18+
gravatar.owner = event.params.owner
19+
gravatar.displayName = event.params.displayName
20+
gravatar.imageUrl = event.params.imageUrl
21+
gravatar.save()
22+
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
type Gravatar @entity {
2+
id: ID!
3+
# This field points at an interface; we allow that a derived field
4+
# in a type that implements the interface derives from this field
5+
# The test checks that this construct is accepted
6+
owner: Account!
7+
imageUrl: String!
8+
}
9+
10+
interface Account {
11+
id: ID!
12+
gravatars: [Gravatar!]! @derivedFrom(field: "owner")
13+
}
14+
15+
type UserAccount implements Account @entity {
16+
id: ID!
17+
name: String!
18+
gravatars: [Gravatar!]! @derivedFrom(field: "owner")
19+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
specVersion: 0.0.2
2+
schema:
3+
file: ./schema.graphql
4+
dataSources:
5+
- kind: ethereum/contract
6+
name: Gravity
7+
network: mainnet
8+
source:
9+
address: '0x2E645469f354BB4F5c8a05B3b30A929361cf77eC'
10+
abi: Gravity
11+
mapping:
12+
kind: ethereum/events
13+
apiVersion: 0.0.4
14+
language: wasm/assemblyscript
15+
entities:
16+
- Gravatar
17+
abis:
18+
- name: Gravity
19+
file: ./Gravity.json
20+
eventHandlers:
21+
- event: NewGravatar(uint256,address,string,string)
22+
handler: handleNewGravatar
23+
- event: UpdatedGravatar(uint256,address,string,string)
24+
handler: handleUpdatedGravatar
25+
file: ./mapping.ts

tests/cli/validation/missing-or-invalid-derived-from-fields.stderr

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,4 +7,4 @@
77
- Field 'd': @derivedFrom directive must have a 'field' argument
88
- Field 'e': @derivedFrom directive must have a 'field' argument
99
- Field 'f': Value of the @derivedFrom 'field' argument must be a string
10-
- Field 'g': @derivedFrom field 'a' on type 'G' must have the type 'A', 'A!' or '[A!]!'
10+
- Field 'g': @derivedFrom field 'a' on type 'G' must have the type 'A', 'A!', '[A!]!', or one of the interface types that 'A' implements

0 commit comments

Comments
 (0)