mirror of
https://github.com/cerc-io/watcher-ts
synced 2025-05-10 22:31:15 +00:00
Generate plural GQL query schema for subgraph entities (#443)
* Generate plural GQL queries for subgraph entities * Use pluralize for plural query names * Handle bigint values for filters in db query
This commit is contained in:
parent
a8e59eb6b9
commit
15ee523e71
@ -28,6 +28,7 @@
|
|||||||
"gql-generator": "https://github.com/vulcanize/gql-generator.git",
|
"gql-generator": "https://github.com/vulcanize/gql-generator.git",
|
||||||
"graphql": "^15.5.0",
|
"graphql": "^15.5.0",
|
||||||
"graphql-compose": "^9.0.3",
|
"graphql-compose": "^9.0.3",
|
||||||
|
"pluralize": "^8.0.0",
|
||||||
"handlebars": "^4.7.7",
|
"handlebars": "^4.7.7",
|
||||||
"js-yaml": "^4.0.0",
|
"js-yaml": "^4.0.0",
|
||||||
"lodash": "^4.17.21",
|
"lodash": "^4.17.21",
|
||||||
@ -40,6 +41,7 @@
|
|||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@openzeppelin/contracts": "^4.3.2",
|
"@openzeppelin/contracts": "^4.3.2",
|
||||||
"@types/js-yaml": "^4.0.3",
|
"@types/js-yaml": "^4.0.3",
|
||||||
|
"@types/pluralize": "^0.0.29",
|
||||||
"@types/lodash": "^4.14.168",
|
"@types/lodash": "^4.14.168",
|
||||||
"@types/node": "^16.9.0",
|
"@types/node": "^16.9.0",
|
||||||
"@types/yargs": "^17.0.0",
|
"@types/yargs": "^17.0.0",
|
||||||
|
@ -68,6 +68,7 @@ export class Resolvers {
|
|||||||
queryName
|
queryName
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// TODO: Generate plural query resolvers
|
||||||
this._subgraphQueries.push(queryObject);
|
this._subgraphQueries.push(queryObject);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -3,16 +3,20 @@
|
|||||||
//
|
//
|
||||||
|
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
import { GraphQLSchema, parse, printSchema, print, GraphQLDirective, GraphQLInt, GraphQLBoolean } from 'graphql';
|
import { GraphQLSchema, parse, printSchema, print, GraphQLDirective, GraphQLInt, GraphQLBoolean, GraphQLEnumType, DefinitionNode } from 'graphql';
|
||||||
import { ObjectTypeComposer, NonNullComposer, ObjectTypeComposerDefinition, ObjectTypeComposerFieldConfigMapDefinition, SchemaComposer } from 'graphql-compose';
|
import { ObjectTypeComposer, NonNullComposer, ObjectTypeComposerDefinition, ObjectTypeComposerFieldConfigMapDefinition, SchemaComposer } from 'graphql-compose';
|
||||||
import { Writable } from 'stream';
|
import { Writable } from 'stream';
|
||||||
import { utils } from 'ethers';
|
import { utils } from 'ethers';
|
||||||
import { VariableDeclaration } from '@solidity-parser/parser/dist/src/ast-types';
|
import { VariableDeclaration } from '@solidity-parser/parser/dist/src/ast-types';
|
||||||
|
import pluralize from 'pluralize';
|
||||||
|
|
||||||
import { getGqlForSol } from './utils/type-mappings';
|
import { getGqlForSol } from './utils/type-mappings';
|
||||||
import { Param } from './utils/types';
|
import { Param } from './utils/types';
|
||||||
import { getBaseType, isArrayType } from './utils/helpers';
|
import { getBaseType, isArrayType } from './utils/helpers';
|
||||||
|
|
||||||
|
const OrderDirection = 'OrderDirection';
|
||||||
|
const BlockHeight = 'Block_height';
|
||||||
|
|
||||||
export class Schema {
|
export class Schema {
|
||||||
_composer: SchemaComposer;
|
_composer: SchemaComposer;
|
||||||
_events: Array<string>;
|
_events: Array<string>;
|
||||||
@ -147,8 +151,8 @@ export class Schema {
|
|||||||
this._composer.addTypeDefs(subgraphTypeDefsString);
|
this._composer.addTypeDefs(subgraphTypeDefsString);
|
||||||
|
|
||||||
// Create the Block_height input needed in subgraph queries.
|
// Create the Block_height input needed in subgraph queries.
|
||||||
const typeComposer = this._composer.createInputTC({
|
let typeComposer: any = this._composer.createInputTC({
|
||||||
name: 'Block_height',
|
name: BlockHeight,
|
||||||
fields: {
|
fields: {
|
||||||
hash: 'Bytes',
|
hash: 'Bytes',
|
||||||
number: 'Int'
|
number: 'Int'
|
||||||
@ -156,11 +160,22 @@ export class Schema {
|
|||||||
});
|
});
|
||||||
this._composer.addSchemaMustHaveType(typeComposer);
|
this._composer.addSchemaMustHaveType(typeComposer);
|
||||||
|
|
||||||
|
// Add the OrderDirection enum needed in subgraph plural queries.
|
||||||
|
const orderDirectionEnum = new GraphQLEnumType({
|
||||||
|
name: OrderDirection,
|
||||||
|
values: {
|
||||||
|
asc: {},
|
||||||
|
desc: {}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
typeComposer = this._composer.createEnumTC(orderDirectionEnum);
|
||||||
|
this._composer.addSchemaMustHaveType(typeComposer);
|
||||||
|
|
||||||
// Add subgraph-schema entity queries to the schema composer.
|
// Add subgraph-schema entity queries to the schema composer.
|
||||||
this._addSubgraphSchemaQueries(subgraphTypeDefs);
|
this._addSubgraphSchemaQueries(subgraphTypeDefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
_addSubgraphSchemaQueries (subgraphTypeDefs: any): void {
|
_addSubgraphSchemaQueries (subgraphTypeDefs: ReadonlyArray<DefinitionNode>): void {
|
||||||
for (const subgraphTypeDef of subgraphTypeDefs) {
|
for (const subgraphTypeDef of subgraphTypeDefs) {
|
||||||
// Filtering out enums.
|
// Filtering out enums.
|
||||||
if (subgraphTypeDef.kind !== 'ObjectTypeDefinition') {
|
if (subgraphTypeDef.kind !== 'ObjectTypeDefinition') {
|
||||||
@ -178,7 +193,38 @@ export class Schema {
|
|||||||
type: this._composer.getAnyTC(subgraphType).NonNull,
|
type: this._composer.getAnyTC(subgraphType).NonNull,
|
||||||
args: {
|
args: {
|
||||||
id: 'ID!',
|
id: 'ID!',
|
||||||
block: 'Block_height'
|
block: BlockHeight
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Add plural query
|
||||||
|
|
||||||
|
// Create the subgraphType_orderBy enum type
|
||||||
|
const subgraphTypeOrderByEnum = new GraphQLEnumType({
|
||||||
|
name: `${subgraphType}_orderBy`,
|
||||||
|
values: (subgraphTypeDef.fields || []).reduce((acc: any, field) => {
|
||||||
|
acc[field.name.value] = {};
|
||||||
|
return acc;
|
||||||
|
}, {})
|
||||||
|
});
|
||||||
|
this._composer.addSchemaMustHaveType(subgraphTypeOrderByEnum);
|
||||||
|
|
||||||
|
// Create plural query name
|
||||||
|
// Append suffix 's' if pluralized name is the same as singular name (eg. PoolDayData)
|
||||||
|
let pluralQueryName = pluralize(queryName);
|
||||||
|
pluralQueryName = (pluralQueryName === queryName) ? `${pluralQueryName}s` : pluralQueryName;
|
||||||
|
|
||||||
|
queryObject[pluralQueryName] = {
|
||||||
|
// Get type composer object for return type from the schema composer.
|
||||||
|
type: this._composer.getAnyTC(subgraphType).NonNull.List.NonNull,
|
||||||
|
args: {
|
||||||
|
block: BlockHeight,
|
||||||
|
// TODO: Create input type for where clause
|
||||||
|
// where: subgraphType_filter,
|
||||||
|
orderBy: subgraphTypeOrderByEnum,
|
||||||
|
orderDirection: OrderDirection,
|
||||||
|
first: { type: GraphQLInt, defaultValue: 100 },
|
||||||
|
skip: { type: GraphQLInt, defaultValue: 0 }
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -370,7 +416,7 @@ export class Schema {
|
|||||||
_addEventsQuery (): void {
|
_addEventsQuery (): void {
|
||||||
this._composer.Query.addFields({
|
this._composer.Query.addFields({
|
||||||
events: {
|
events: {
|
||||||
type: [this._composer.getOTC('ResultEvent').NonNull],
|
type: this._composer.getOTC('ResultEvent').NonNull.List,
|
||||||
args: {
|
args: {
|
||||||
blockHash: 'String!',
|
blockHash: 'String!',
|
||||||
contractAddress: 'String!',
|
contractAddress: 'String!',
|
||||||
@ -381,7 +427,7 @@ export class Schema {
|
|||||||
|
|
||||||
this._composer.Query.addFields({
|
this._composer.Query.addFields({
|
||||||
eventsInRange: {
|
eventsInRange: {
|
||||||
type: [this._composer.getOTC('ResultEvent').NonNull],
|
type: this._composer.getOTC('ResultEvent').NonNull.List,
|
||||||
args: {
|
args: {
|
||||||
fromBlockNumber: 'Int!',
|
fromBlockNumber: 'Int!',
|
||||||
toBlockNumber: 'Int!'
|
toBlockNumber: 'Int!'
|
||||||
|
@ -83,6 +83,7 @@
|
|||||||
maxCompletionLagInSecs = 300
|
maxCompletionLagInSecs = 300
|
||||||
jobDelayInMilliSecs = 100
|
jobDelayInMilliSecs = 100
|
||||||
eventsInBatch = 50
|
eventsInBatch = 50
|
||||||
|
subgraphEventsOrder = true
|
||||||
blockDelayInMilliSecs = 2000
|
blockDelayInMilliSecs = 2000
|
||||||
prefetchBlocksInMem = true
|
prefetchBlocksInMem = true
|
||||||
prefetchBlockCount = 10
|
prefetchBlockCount = 10
|
||||||
|
@ -829,12 +829,10 @@ export class Database {
|
|||||||
|
|
||||||
whereClause += `${OPERATOR_MAP[operator]} `;
|
whereClause += `${OPERATOR_MAP[operator]} `;
|
||||||
|
|
||||||
|
value = this._transformBigIntValues(value);
|
||||||
if (operator === 'in') {
|
if (operator === 'in') {
|
||||||
whereClause += '(:...';
|
whereClause += '(:...';
|
||||||
} else {
|
} else {
|
||||||
// Convert to string type value as bigint type throws error in query.
|
|
||||||
value = value.toString();
|
|
||||||
|
|
||||||
whereClause += ':';
|
whereClause += ':';
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -900,4 +898,20 @@ export class Database {
|
|||||||
|
|
||||||
eventCount.set(res);
|
eventCount.set(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_transformBigIntValues (value: any): any {
|
||||||
|
if (Array.isArray(value)) {
|
||||||
|
if (value.length > 0 && typeof value[0] === 'bigint') {
|
||||||
|
return value.map(val => {
|
||||||
|
return val.toString();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (typeof value === 'bigint') {
|
||||||
|
return value.toString();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user