Handle subgraph schema field with derivedFrom directive (#60)

* Handle subgraph schema field with derivedFrom directive

* Handle derivedFrom directive in eden-watcher

* Fix 1 to N relation error by removing limit from query

* Order by id for derivedFrom relations to match graph-node

* Refactor example subgraph schema entities

* Fix watcher queries to return correct relation field values

* Fix hierarchical query for getting two entities at same block
This commit is contained in:
2021-12-28 16:08:05 +05:30
committed by nabarun
parent b04f6f2fba
commit 238ad21189
26 changed files with 482 additions and 376 deletions
@@ -12,30 +12,33 @@ import {
BigDecimal
} from "@graphprotocol/graph-ts";
export class RelatedEntity extends Entity {
export class Blog extends Entity {
constructor(id: string) {
super();
this.set("id", Value.fromString(id));
this.set("paramBigInt", Value.fromBigInt(BigInt.zero()));
this.set("bigIntArray", Value.fromBigIntArray(new Array(0)));
this.set("kind", Value.fromString(""));
this.set("isActive", Value.fromBoolean(false));
this.set("reviews", Value.fromBigIntArray(new Array(0)));
this.set("author", Value.fromString(""));
this.set("categories", Value.fromStringArray(new Array(0)));
}
save(): void {
let id = this.get("id");
assert(id != null, "Cannot save RelatedEntity entity without an ID");
assert(id != null, "Cannot save Blog entity without an ID");
if (id) {
assert(
id.kind == ValueKind.STRING,
"Cannot save RelatedEntity entity with non-string ID. " +
"Cannot save Blog entity with non-string ID. " +
'Considering using .toHex() to convert the "id" to a string.'
);
store.set("RelatedEntity", id.toString(), this);
store.set("Blog", id.toString(), this);
}
}
static load(id: string): RelatedEntity | null {
return changetype<RelatedEntity | null>(store.get("RelatedEntity", id));
static load(id: string): Blog | null {
return changetype<Blog | null>(store.get("Blog", id));
}
get id(): string {
@@ -47,56 +50,79 @@ export class RelatedEntity extends Entity {
this.set("id", Value.fromString(value));
}
get paramBigInt(): BigInt {
let value = this.get("paramBigInt");
return value!.toBigInt();
get kind(): string {
let value = this.get("kind");
return value!.toString();
}
set paramBigInt(value: BigInt) {
this.set("paramBigInt", Value.fromBigInt(value));
set kind(value: string) {
this.set("kind", Value.fromString(value));
}
get bigIntArray(): Array<BigInt> {
let value = this.get("bigIntArray");
get isActive(): boolean {
let value = this.get("isActive");
return value!.toBoolean();
}
set isActive(value: boolean) {
this.set("isActive", Value.fromBoolean(value));
}
get reviews(): Array<BigInt> {
let value = this.get("reviews");
return value!.toBigIntArray();
}
set bigIntArray(value: Array<BigInt>) {
this.set("bigIntArray", Value.fromBigIntArray(value));
set reviews(value: Array<BigInt>) {
this.set("reviews", Value.fromBigIntArray(value));
}
get author(): string {
let value = this.get("author");
return value!.toString();
}
set author(value: string) {
this.set("author", Value.fromString(value));
}
get categories(): Array<string> {
let value = this.get("categories");
return value!.toStringArray();
}
set categories(value: Array<string>) {
this.set("categories", Value.fromStringArray(value));
}
}
export class ExampleEntity extends Entity {
export class Author extends Entity {
constructor(id: string) {
super();
this.set("id", Value.fromString(id));
this.set("count", Value.fromBigInt(BigInt.zero()));
this.set("paramString", Value.fromString(""));
this.set("blogCount", Value.fromBigInt(BigInt.zero()));
this.set("name", Value.fromString(""));
this.set("rating", Value.fromBigDecimal(BigDecimal.zero()));
this.set("paramInt", Value.fromI32(0));
this.set("paramBoolean", Value.fromBoolean(false));
this.set("paramBytes", Value.fromBytes(Bytes.empty()));
this.set("paramEnum", Value.fromString(""));
this.set("paramBigDecimal", Value.fromBigDecimal(BigDecimal.zero()));
this.set("related", Value.fromString(""));
this.set("manyRelated", Value.fromStringArray(new Array(0)));
}
save(): void {
let id = this.get("id");
assert(id != null, "Cannot save ExampleEntity entity without an ID");
assert(id != null, "Cannot save Author entity without an ID");
if (id) {
assert(
id.kind == ValueKind.STRING,
"Cannot save ExampleEntity entity with non-string ID. " +
"Cannot save Author entity with non-string ID. " +
'Considering using .toHex() to convert the "id" to a string.'
);
store.set("ExampleEntity", id.toString(), this);
store.set("Author", id.toString(), this);
}
}
static load(id: string): ExampleEntity | null {
return changetype<ExampleEntity | null>(store.get("ExampleEntity", id));
static load(id: string): Author | null {
return changetype<Author | null>(store.get("Author", id));
}
get id(): string {
@@ -108,22 +134,31 @@ export class ExampleEntity extends Entity {
this.set("id", Value.fromString(value));
}
get count(): BigInt {
let value = this.get("count");
get blogCount(): BigInt {
let value = this.get("blogCount");
return value!.toBigInt();
}
set count(value: BigInt) {
this.set("count", Value.fromBigInt(value));
set blogCount(value: BigInt) {
this.set("blogCount", Value.fromBigInt(value));
}
get paramString(): string {
let value = this.get("paramString");
get name(): string {
let value = this.get("name");
return value!.toString();
}
set paramString(value: string) {
this.set("paramString", Value.fromString(value));
set name(value: string) {
this.set("name", Value.fromString(value));
}
get rating(): BigDecimal {
let value = this.get("rating");
return value!.toBigDecimal();
}
set rating(value: BigDecimal) {
this.set("rating", Value.fromBigDecimal(value));
}
get paramInt(): i32 {
@@ -135,15 +170,6 @@ export class ExampleEntity extends Entity {
this.set("paramInt", Value.fromI32(value));
}
get paramBoolean(): boolean {
let value = this.get("paramBoolean");
return value!.toBoolean();
}
set paramBoolean(value: boolean) {
this.set("paramBoolean", Value.fromBoolean(value));
}
get paramBytes(): Bytes {
let value = this.get("paramBytes");
return value!.toBytes();
@@ -153,68 +179,40 @@ export class ExampleEntity extends Entity {
this.set("paramBytes", Value.fromBytes(value));
}
get paramEnum(): string {
let value = this.get("paramEnum");
return value!.toString();
}
set paramEnum(value: string) {
this.set("paramEnum", Value.fromString(value));
}
get paramBigDecimal(): BigDecimal {
let value = this.get("paramBigDecimal");
return value!.toBigDecimal();
}
set paramBigDecimal(value: BigDecimal) {
this.set("paramBigDecimal", Value.fromBigDecimal(value));
}
get related(): string {
let value = this.get("related");
return value!.toString();
}
set related(value: string) {
this.set("related", Value.fromString(value));
}
get manyRelated(): Array<string> {
let value = this.get("manyRelated");
get blogs(): Array<string> {
let value = this.get("blogs");
return value!.toStringArray();
}
set manyRelated(value: Array<string>) {
this.set("manyRelated", Value.fromStringArray(value));
set blogs(value: Array<string>) {
this.set("blogs", Value.fromStringArray(value));
}
}
export class ManyRelatedEntity extends Entity {
export class Category extends Entity {
constructor(id: string) {
super();
this.set("id", Value.fromString(id));
this.set("name", Value.fromString(""));
this.set("count", Value.fromBigInt(BigInt.zero()));
}
save(): void {
let id = this.get("id");
assert(id != null, "Cannot save ManyRelatedEntity entity without an ID");
assert(id != null, "Cannot save Category entity without an ID");
if (id) {
assert(
id.kind == ValueKind.STRING,
"Cannot save ManyRelatedEntity entity with non-string ID. " +
"Cannot save Category entity with non-string ID. " +
'Considering using .toHex() to convert the "id" to a string.'
);
store.set("ManyRelatedEntity", id.toString(), this);
store.set("Category", id.toString(), this);
}
}
static load(id: string): ManyRelatedEntity | null {
return changetype<ManyRelatedEntity | null>(
store.get("ManyRelatedEntity", id)
);
static load(id: string): Category | null {
return changetype<Category | null>(store.get("Category", id));
}
get id(): string {
@@ -226,6 +224,15 @@ export class ManyRelatedEntity extends Entity {
this.set("id", Value.fromString(value));
}
get name(): string {
let value = this.get("name");
return value!.toString();
}
set name(value: string) {
this.set("name", Value.fromString(value));
}
get count(): BigInt {
let value = this.get("count");
return value!.toBigInt();
@@ -1,28 +1,29 @@
enum EnumType {
choice1
choice2
enum BlogKind {
short
long
}
type RelatedEntity @entity {
type Blog @entity {
id: ID!
paramBigInt: BigInt!
bigIntArray: [BigInt!]!
kind: BlogKind!
isActive: Boolean!
reviews: [BigInt!]!
author: Author!
categories: [Category!]!
}
type ExampleEntity @entity {
type Author @entity {
id: ID!
count: BigInt!
paramString: String! # string
blogCount: BigInt!
name: String! # string
rating: BigDecimal!
paramInt: Int! # uint8
paramBoolean: Boolean!
paramBytes: Bytes!
paramEnum: EnumType!
paramBigDecimal: BigDecimal!
related: RelatedEntity!
manyRelated: [ManyRelatedEntity!]!
blogs: [Blog!]! @derivedFrom(field: "author")
}
type ManyRelatedEntity @entity {
type Category @entity {
id: ID!
name: String!
count: BigInt!
}
@@ -4,7 +4,7 @@ import {
Example1,
Test
} from '../generated/Example1/Example1';
import { ExampleEntity, ManyRelatedEntity, RelatedEntity } from '../generated/schema';
import { Author, Blog, Category } from '../generated/schema';
export function handleTest (event: Test): void {
log.debug('event.address: {}', [event.address.toHexString()]);
@@ -15,52 +15,54 @@ export function handleTest (event: Test): void {
// Entities can be loaded from the store using a string ID; this ID
// needs to be unique across all entities of the same type
let entity = ExampleEntity.load(event.transaction.from.toHex());
let author = Author.load(event.transaction.from.toHex());
// Entities only exist after they have been saved to the store;
// `null` checks allow to create entities on demand
if (!entity) {
entity = new ExampleEntity(event.transaction.from.toHex());
if (!author) {
author = new Author(event.transaction.from.toHex());
// Entity fields can be set using simple assignments
entity.count = BigInt.fromString('0');
author.blogCount = BigInt.fromString('0');
}
// BigInt and BigDecimal math are supported
entity.count = entity.count + BigInt.fromString('1');
author.blogCount = author.blogCount + BigInt.fromString('1');
// Entity fields can be set based on event parameters
entity.paramString = event.params.param1;
entity.paramInt = event.params.param2;
entity.paramBoolean = true;
entity.paramBytes = event.address;
entity.paramEnum = 'choice1';
entity.paramBigDecimal = BigDecimal.fromString('123');
let relatedEntity = RelatedEntity.load(event.params.param1);
if (!relatedEntity) {
relatedEntity = new RelatedEntity(event.params.param1);
relatedEntity.paramBigInt = BigInt.fromString('123');
}
const bigIntArray = relatedEntity.bigIntArray;
bigIntArray.push(entity.count);
relatedEntity.bigIntArray = bigIntArray;
relatedEntity.save();
entity.related = relatedEntity.id;
const manyRelatedEntity = new ManyRelatedEntity(event.transaction.hash.toHexString());
manyRelatedEntity.count = entity.count;
manyRelatedEntity.save();
const manyRelated = entity.manyRelated;
manyRelated.push(manyRelatedEntity.id);
entity.manyRelated = manyRelated;
author.name = event.params.param1;
author.paramInt = event.params.param2;
author.paramBytes = event.address;
author.rating = BigDecimal.fromString('4');
// Entities can be written to the store with `.save()`
entity.save();
author.save();
let category = Category.load(author.blogCount.toString());
if (!category) {
category = new Category(author.blogCount.toString());
category.name = event.params.param1;
}
category.count = category.count + BigInt.fromString('1');
category.save();
const blog = new Blog(event.transaction.hash.toHexString());
blog.kind = 'long';
blog.isActive = true;
const blogReviews = blog.reviews;
blogReviews.push(BigInt.fromString('4'));
blog.reviews = blogReviews;
blog.author = author.id;
const categories = blog.categories;
categories.push(category.id);
blog.categories = categories;
blog.save();
const contractAddress = dataSource.address();
const contract = Example1.bind(contractAddress);