diff --git a/packages/codegen/package.json b/packages/codegen/package.json index 26fabd83..895626d4 100644 --- a/packages/codegen/package.json +++ b/packages/codegen/package.json @@ -28,6 +28,7 @@ "gql-generator": "https://github.com/vulcanize/gql-generator.git", "graphql": "^15.5.0", "graphql-compose": "^9.0.3", + "pluralize": "^8.0.0", "handlebars": "^4.7.7", "js-yaml": "^4.0.0", "lodash": "^4.17.21", @@ -40,6 +41,7 @@ "devDependencies": { "@openzeppelin/contracts": "^4.3.2", "@types/js-yaml": "^4.0.3", + "@types/pluralize": "^0.0.29", "@types/lodash": "^4.14.168", "@types/node": "^16.9.0", "@types/yargs": "^17.0.0", diff --git a/packages/codegen/src/resolvers.ts b/packages/codegen/src/resolvers.ts index 502fd040..a4a9ea16 100644 --- a/packages/codegen/src/resolvers.ts +++ b/packages/codegen/src/resolvers.ts @@ -68,6 +68,7 @@ export class Resolvers { queryName }; + // TODO: Generate plural query resolvers this._subgraphQueries.push(queryObject); } } diff --git a/packages/codegen/src/schema.ts b/packages/codegen/src/schema.ts index fa5f9cf8..2237b233 100644 --- a/packages/codegen/src/schema.ts +++ b/packages/codegen/src/schema.ts @@ -3,16 +3,20 @@ // 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 { Writable } from 'stream'; import { utils } from 'ethers'; import { VariableDeclaration } from '@solidity-parser/parser/dist/src/ast-types'; +import pluralize from 'pluralize'; import { getGqlForSol } from './utils/type-mappings'; import { Param } from './utils/types'; import { getBaseType, isArrayType } from './utils/helpers'; +const OrderDirection = 'OrderDirection'; +const BlockHeight = 'Block_height'; + export class Schema { _composer: SchemaComposer; _events: Array; @@ -147,8 +151,8 @@ export class Schema { this._composer.addTypeDefs(subgraphTypeDefsString); // Create the Block_height input needed in subgraph queries. - const typeComposer = this._composer.createInputTC({ - name: 'Block_height', + let typeComposer: any = this._composer.createInputTC({ + name: BlockHeight, fields: { hash: 'Bytes', number: 'Int' @@ -156,11 +160,22 @@ export class Schema { }); 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. this._addSubgraphSchemaQueries(subgraphTypeDefs); } - _addSubgraphSchemaQueries (subgraphTypeDefs: any): void { + _addSubgraphSchemaQueries (subgraphTypeDefs: ReadonlyArray): void { for (const subgraphTypeDef of subgraphTypeDefs) { // Filtering out enums. if (subgraphTypeDef.kind !== 'ObjectTypeDefinition') { @@ -178,7 +193,38 @@ export class Schema { type: this._composer.getAnyTC(subgraphType).NonNull, args: { 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 { this._composer.Query.addFields({ events: { - type: [this._composer.getOTC('ResultEvent').NonNull], + type: this._composer.getOTC('ResultEvent').NonNull.List, args: { blockHash: 'String!', contractAddress: 'String!', @@ -381,7 +427,7 @@ export class Schema { this._composer.Query.addFields({ eventsInRange: { - type: [this._composer.getOTC('ResultEvent').NonNull], + type: this._composer.getOTC('ResultEvent').NonNull.List, args: { fromBlockNumber: 'Int!', toBlockNumber: 'Int!' diff --git a/packages/codegen/src/templates/config-template.handlebars b/packages/codegen/src/templates/config-template.handlebars index bf50e7e2..d2618709 100644 --- a/packages/codegen/src/templates/config-template.handlebars +++ b/packages/codegen/src/templates/config-template.handlebars @@ -83,6 +83,7 @@ maxCompletionLagInSecs = 300 jobDelayInMilliSecs = 100 eventsInBatch = 50 + subgraphEventsOrder = true blockDelayInMilliSecs = 2000 prefetchBlocksInMem = true prefetchBlockCount = 10 diff --git a/packages/util/src/database.ts b/packages/util/src/database.ts index 25c31741..bfc6ac8a 100644 --- a/packages/util/src/database.ts +++ b/packages/util/src/database.ts @@ -829,12 +829,10 @@ export class Database { whereClause += `${OPERATOR_MAP[operator]} `; + value = this._transformBigIntValues(value); if (operator === 'in') { whereClause += '(:...'; } else { - // Convert to string type value as bigint type throws error in query. - value = value.toString(); - whereClause += ':'; } @@ -900,4 +898,20 @@ export class Database { 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(); + } + } }