mirror of
https://github.com/cerc-io/watcher-ts
synced 2025-01-22 19:19:05 +00:00
Handle multiple return type contract functions in codegen (#369)
* Genrate schema GQL for multiple return types * Generate indexer file for multiple return types * Fix whitespaces in generated watcher * Refactor storage mode queries after multiple return type changes
This commit is contained in:
parent
096a0081e6
commit
11cab24505
@ -9,6 +9,8 @@ import Handlebars from 'handlebars';
|
|||||||
import { Writable } from 'stream';
|
import { Writable } from 'stream';
|
||||||
import _ from 'lodash';
|
import _ from 'lodash';
|
||||||
|
|
||||||
|
import { VariableDeclaration } from '@solidity-parser/parser/dist/src/ast-types';
|
||||||
|
|
||||||
import { getGqlForSol, getTsForGql } from './utils/type-mappings';
|
import { getGqlForSol, getTsForGql } from './utils/type-mappings';
|
||||||
import { Param } from './utils/types';
|
import { Param } from './utils/types';
|
||||||
import { MODE_ETH_CALL, MODE_STORAGE } from './utils/constants';
|
import { MODE_ETH_CALL, MODE_STORAGE } from './utils/constants';
|
||||||
@ -42,12 +44,31 @@ export class Indexer {
|
|||||||
* @param returnType Return type for the query.
|
* @param returnType Return type for the query.
|
||||||
* @param stateVariableType Type of the state variable in case of state variable query.
|
* @param stateVariableType Type of the state variable in case of state variable query.
|
||||||
*/
|
*/
|
||||||
addQuery (contract: string, mode: string, name: string, params: Array<Param>, typeName: any, stateVariableType?: string): void {
|
addQuery (
|
||||||
|
contract: string,
|
||||||
|
mode: string,
|
||||||
|
name: string,
|
||||||
|
params: Array<Param>,
|
||||||
|
returnParameters: VariableDeclaration[],
|
||||||
|
stateVariableType?: string
|
||||||
|
): void {
|
||||||
// Check if the query is already added.
|
// Check if the query is already added.
|
||||||
if (this._queries.some(query => query.name === name)) {
|
if (this._queries.some(query => query.name === name)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Disable DB caching if more than 1 return params.
|
||||||
|
let disableCaching = returnParameters.length > 1;
|
||||||
|
|
||||||
|
const returnTypes = returnParameters.map(returnParameter => {
|
||||||
|
let typeName = returnParameter.typeName;
|
||||||
|
assert(typeName);
|
||||||
|
|
||||||
|
// Handle Mapping type for state variable queries
|
||||||
|
while (typeName.type === 'Mapping') {
|
||||||
|
typeName = typeName.valueType;
|
||||||
|
}
|
||||||
|
|
||||||
const baseType = getBaseType(typeName);
|
const baseType = getBaseType(typeName);
|
||||||
assert(baseType);
|
assert(baseType);
|
||||||
const gqlReturnType = getGqlForSol(baseType);
|
const gqlReturnType = getGqlForSol(baseType);
|
||||||
@ -57,20 +78,24 @@ export class Indexer {
|
|||||||
|
|
||||||
const isArray = isArrayType(typeName);
|
const isArray = isArrayType(typeName);
|
||||||
if (isArray) {
|
if (isArray) {
|
||||||
|
disableCaching = true;
|
||||||
tsReturnType = tsReturnType.concat('[]');
|
tsReturnType = tsReturnType.concat('[]');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return tsReturnType;
|
||||||
|
});
|
||||||
|
|
||||||
const queryObject = {
|
const queryObject = {
|
||||||
name,
|
name,
|
||||||
entityName: '',
|
entityName: '',
|
||||||
getQueryName: '',
|
getQueryName: '',
|
||||||
saveQueryName: '',
|
saveQueryName: '',
|
||||||
params: _.cloneDeep(params),
|
params: _.cloneDeep(params),
|
||||||
returnType: tsReturnType,
|
returnTypes,
|
||||||
mode,
|
mode,
|
||||||
stateVariableType,
|
stateVariableType,
|
||||||
contract,
|
contract,
|
||||||
disableCaching: isArray
|
disableCaching
|
||||||
};
|
};
|
||||||
|
|
||||||
if (name.charAt(0) === '_') {
|
if (name.charAt(0) === '_') {
|
||||||
|
@ -11,7 +11,6 @@ import _ from 'lodash';
|
|||||||
|
|
||||||
import { getGqlForSol, getTsForGql } from './utils/type-mappings';
|
import { getGqlForSol, getTsForGql } from './utils/type-mappings';
|
||||||
import { Param } from './utils/types';
|
import { Param } from './utils/types';
|
||||||
import { getBaseType } from './utils/helpers';
|
|
||||||
|
|
||||||
const TEMPLATE_FILE = './templates/resolvers-template.handlebars';
|
const TEMPLATE_FILE = './templates/resolvers-template.handlebars';
|
||||||
|
|
||||||
@ -30,20 +29,16 @@ export class Resolvers {
|
|||||||
* Stores the query to be passed to the template.
|
* Stores the query to be passed to the template.
|
||||||
* @param name Name of the query.
|
* @param name Name of the query.
|
||||||
* @param params Parameters to the query.
|
* @param params Parameters to the query.
|
||||||
* @param returnType Return type for the query.
|
|
||||||
*/
|
*/
|
||||||
addQuery (name: string, params: Array<Param>, typeName: any): void {
|
addQuery (name: string, params: Array<Param>): void {
|
||||||
// Check if the query is already added.
|
// Check if the query is already added.
|
||||||
if (this._queries.some(query => query.name === name)) {
|
if (this._queries.some(query => query.name === name)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
const returnType = getBaseType(typeName);
|
|
||||||
assert(returnType);
|
|
||||||
|
|
||||||
const queryObject = {
|
const queryObject = {
|
||||||
name,
|
name,
|
||||||
params: _.cloneDeep(params),
|
params: _.cloneDeep(params)
|
||||||
returnType
|
|
||||||
};
|
};
|
||||||
|
|
||||||
queryObject.params = queryObject.params.map((param) => {
|
queryObject.params = queryObject.params.map((param) => {
|
||||||
|
@ -7,6 +7,7 @@ import { GraphQLSchema, parse, printSchema, print, GraphQLDirective, GraphQLInt,
|
|||||||
import { ObjectTypeComposer, ObjectTypeComposerDefinition, ObjectTypeComposerFieldConfigMapDefinition, SchemaComposer } from 'graphql-compose';
|
import { ObjectTypeComposer, 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 { getGqlForTs, getGqlForSol } from './utils/type-mappings';
|
import { getGqlForTs, getGqlForSol } from './utils/type-mappings';
|
||||||
import { Param } from './utils/types';
|
import { Param } from './utils/types';
|
||||||
@ -30,21 +31,13 @@ export class Schema {
|
|||||||
* @param params Parameters to the query.
|
* @param params Parameters to the query.
|
||||||
* @param returnType Return type for the query.
|
* @param returnType Return type for the query.
|
||||||
*/
|
*/
|
||||||
addQuery (name: string, params: Array<Param>, typeName: any): void {
|
addQuery (name: string, params: Array<Param>, returnParameters: VariableDeclaration[]): void {
|
||||||
// Check if the query is already added.
|
// Check if the query is already added.
|
||||||
if (this._composer.Query.hasField(name)) {
|
if (this._composer.Query.hasField(name)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Handle cases where returnType/params type is an array.
|
const objectTC = this._getOrCreateResultType(name, returnParameters);
|
||||||
const isReturnTypeArray = isArrayType(typeName);
|
|
||||||
const baseTypeName = getBaseType(typeName);
|
|
||||||
assert(baseTypeName);
|
|
||||||
|
|
||||||
const gqlReturnType = getGqlForSol(baseTypeName);
|
|
||||||
assert(gqlReturnType, `gql type for sol type ${baseTypeName} for ${name} not found`);
|
|
||||||
|
|
||||||
const objectTC = this._getOrCreateResultType(gqlReturnType, isReturnTypeArray);
|
|
||||||
|
|
||||||
const queryObject: { [key: string]: any; } = {};
|
const queryObject: { [key: string]: any; } = {};
|
||||||
queryObject[name] = {
|
queryObject[name] = {
|
||||||
@ -57,6 +50,7 @@ export class Schema {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if (params.length > 0) {
|
if (params.length > 0) {
|
||||||
|
// TODO: Handle cases where params type is an array.
|
||||||
queryObject[name].args = params.reduce((acc, curr) => {
|
queryObject[name].args = params.reduce((acc, curr) => {
|
||||||
acc[curr.name] = `${getGqlForSol(curr.type)}!`;
|
acc[curr.name] = `${getGqlForSol(curr.type)}!`;
|
||||||
return acc;
|
return acc;
|
||||||
@ -242,19 +236,65 @@ export class Schema {
|
|||||||
/**
|
/**
|
||||||
* Adds Result types to the schema and typemapping.
|
* Adds Result types to the schema and typemapping.
|
||||||
*/
|
*/
|
||||||
_getOrCreateResultType (typeName: string, isArray = false): ObjectTypeComposer<any, any> {
|
_getOrCreateResultType (functionName: string, returnParameters: VariableDeclaration[]): ObjectTypeComposer<any, any> {
|
||||||
const value = `${typeName}!`;
|
const returnValueTypes = returnParameters.map((returnParameter) => {
|
||||||
|
let typeName = returnParameter.typeName;
|
||||||
|
assert(typeName);
|
||||||
|
|
||||||
|
// Handle Mapping type for state variable queries
|
||||||
|
while (typeName.type === 'Mapping') {
|
||||||
|
typeName = typeName.valueType;
|
||||||
|
}
|
||||||
|
|
||||||
|
const isReturnTypeArray = isArrayType(typeName);
|
||||||
|
const baseTypeName = getBaseType(typeName);
|
||||||
|
assert(baseTypeName);
|
||||||
|
|
||||||
|
const gqlReturnType = getGqlForSol(baseTypeName);
|
||||||
|
assert(gqlReturnType, `gql type for sol type ${baseTypeName} for ${functionName} not found`);
|
||||||
|
|
||||||
|
return {
|
||||||
|
type: gqlReturnType,
|
||||||
|
isArray: isReturnTypeArray
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
|
let objectTCName = 'Result';
|
||||||
|
let value = '';
|
||||||
|
|
||||||
|
if (returnParameters.length > 1) {
|
||||||
|
const returnValueTypesMap = returnParameters.reduce((acc: {[key: string]: string}, _, index) => {
|
||||||
|
const { type, isArray } = returnValueTypes[index];
|
||||||
|
acc[`value${index}`] = (isArray) ? `[${type}!]!` : `${type}!`;
|
||||||
|
return acc;
|
||||||
|
}, {});
|
||||||
|
|
||||||
|
const capitalizedFunctionName = `${functionName.charAt(0).toUpperCase()}${functionName.slice(1)}`;
|
||||||
|
|
||||||
|
this._composer.getOrCreateOTC(
|
||||||
|
`${capitalizedFunctionName}Type`,
|
||||||
|
(tc) => {
|
||||||
|
tc.addFields(returnValueTypesMap);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
objectTCName = objectTCName.concat(`${capitalizedFunctionName}Type`);
|
||||||
|
value = `${capitalizedFunctionName}Type!`;
|
||||||
|
} else {
|
||||||
|
const { type, isArray } = returnValueTypes[0];
|
||||||
|
value = (isArray) ? `[${type}!]!` : `${type}!`;
|
||||||
|
objectTCName = objectTCName.concat(type);
|
||||||
|
|
||||||
let objectTCName = `Result${typeName}`;
|
|
||||||
if (isArray) {
|
if (isArray) {
|
||||||
objectTCName = objectTCName.concat('Array');
|
objectTCName = objectTCName.concat('Array');
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const typeComposer = this._composer.getOrCreateOTC(
|
const typeComposer = this._composer.getOrCreateOTC(
|
||||||
objectTCName,
|
objectTCName,
|
||||||
(tc) => {
|
(tc) => {
|
||||||
tc.addFields({
|
tc.addFields({
|
||||||
value: (isArray) ? `[${value}]!` : value,
|
value,
|
||||||
proof: () => this._composer.getOTC('Proof')
|
proof: () => this._composer.getOTC('Proof')
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -37,7 +37,7 @@ export const SUBGRAPH_ENTITIES = new Set([
|
|||||||
{{~/each}}]);
|
{{~/each}}]);
|
||||||
{{/if}}
|
{{/if}}
|
||||||
export const ENTITIES = [
|
export const ENTITIES = [
|
||||||
{{~#each queries as | query |}}{{query.entityName}}{{#unless @last}}, {{/unless}}{{/each}}{{#if (subgraphPath)}}, {{/if}}
|
{{~#each queries as | query |}}{{query.entityName}}{{#if @last}}{{#if (subgraphPath)}}, {{/if}}{{else}}, {{/if}}{{/each}}
|
||||||
{{~#if (subgraphPath)}}...SUBGRAPH_ENTITIES{{/if}}];
|
{{~#if (subgraphPath)}}...SUBGRAPH_ENTITIES{{/if}}];
|
||||||
{{#if (subgraphPath)}}
|
{{#if (subgraphPath)}}
|
||||||
// Map: Entity to suitable query type.
|
// Map: Entity to suitable query type.
|
||||||
|
@ -201,22 +201,34 @@ export class Indexer implements IndexerInterface {
|
|||||||
assert(abi);
|
assert(abi);
|
||||||
|
|
||||||
const contract = new ethers.Contract(contractAddress, abi, this._ethProvider);
|
const contract = new ethers.Contract(contractAddress, abi, this._ethProvider);
|
||||||
{{#if (compare query.returnType 'bigint')}}
|
const contractResult = await contract.{{query.name}}(
|
||||||
let value = await contract.{{query.name}}(
|
|
||||||
{{~#each query.params}}{{this.name}}, {{/each}}{ blockTag: blockHash });
|
|
||||||
value = value.toString();
|
|
||||||
value = BigInt(value);
|
|
||||||
{{else}}
|
|
||||||
{{!-- Using nested if-else to avoid indentation issue --}}
|
|
||||||
{{#if (compare query.returnType 'bigint[]')}}
|
|
||||||
let value = await contract.{{query.name}}(
|
|
||||||
{{~#each query.params}}{{this.name}}, {{/each}}{ blockTag: blockHash });
|
|
||||||
value = value.map((val: ethers.BigNumber) => ethers.BigNumber.from(val).toBigInt());
|
|
||||||
{{else}}
|
|
||||||
const value = await contract.{{query.name}}(
|
|
||||||
{{~#each query.params}}{{this.name}}, {{/each}}{ blockTag: blockHash });
|
{{~#each query.params}}{{this.name}}, {{/each}}{ blockTag: blockHash });
|
||||||
|
|
||||||
|
{{#if (compare query.returnTypes.length 1 operator=">")}}
|
||||||
|
const value = {
|
||||||
|
{{#each query.returnTypes as |returnType index|}}
|
||||||
|
{{#if (compare returnType 'bigint')}}
|
||||||
|
value{{index}}: ethers.BigNumber.from(contractResult[{{index}}]).toBigInt()
|
||||||
|
{{~else}}
|
||||||
|
{{!-- https://github.com/handlebars-lang/handlebars.js/issues/1716 --}}
|
||||||
|
{{#if (compare returnType 'bigint[]')}}
|
||||||
|
value{{index}}: contractResult[{{index}}].map((val: ethers.BigNumber | number) => ethers.BigNumber.from(val).toBigInt())
|
||||||
|
{{~else}}
|
||||||
|
value{{index}}: contractResult[{{index}}]
|
||||||
|
{{~/if}}
|
||||||
{{/if}}
|
{{/if}}
|
||||||
{{/if}}
|
{{~#unless @last}},{{/unless}}
|
||||||
|
{{/each}}
|
||||||
|
};
|
||||||
|
{{else}}
|
||||||
|
{{#if (compare query.returnTypes.[0] 'bigint')}}
|
||||||
|
const value = ethers.BigNumber.from(contractResult).toBigInt();
|
||||||
|
{{else if (compare query.returnTypes.[0] 'bigint[]')}}
|
||||||
|
const value = contractResult.map((val: ethers.BigNumber | number) => ethers.BigNumber.from(val).toBigInt());
|
||||||
|
{{else}}
|
||||||
|
const value = contractResult;
|
||||||
|
{{~/if}}
|
||||||
|
{{~/if}}
|
||||||
|
|
||||||
const result: ValueResult = { value };
|
const result: ValueResult = { value };
|
||||||
{{/if}}
|
{{/if}}
|
||||||
|
@ -4,14 +4,14 @@
|
|||||||
|
|
||||||
import fs from 'fs';
|
import fs from 'fs';
|
||||||
import { Writable } from 'stream';
|
import { Writable } from 'stream';
|
||||||
|
import { TypeName } from '@solidity-parser/parser/dist/src/ast-types';
|
||||||
|
|
||||||
const isElementaryType = (typeName: any): boolean => (typeName.type === 'ElementaryTypeName');
|
export const isArrayType = (typeName: TypeName): boolean => (typeName.type === 'ArrayTypeName');
|
||||||
export const isArrayType = (typeName: any): boolean => (typeName.type === 'ArrayTypeName');
|
|
||||||
|
|
||||||
export const getBaseType = (typeName: any): string | undefined => {
|
export const getBaseType = (typeName: TypeName): string | undefined => {
|
||||||
if (isElementaryType(typeName)) {
|
if (typeName.type === 'ElementaryTypeName') {
|
||||||
return typeName.name;
|
return typeName.name;
|
||||||
} else if (isArrayType(typeName)) {
|
} else if (typeName.type === 'ArrayTypeName') {
|
||||||
return getBaseType(typeName.baseTypeName);
|
return getBaseType(typeName.baseTypeName);
|
||||||
} else {
|
} else {
|
||||||
return undefined;
|
return undefined;
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
import { Writable } from 'stream';
|
import { Writable } from 'stream';
|
||||||
import assert from 'assert';
|
import assert from 'assert';
|
||||||
import { utils } from 'ethers';
|
import { utils } from 'ethers';
|
||||||
|
import { FunctionDefinition, StateVariableDeclaration } from '@solidity-parser/parser/dist/src/ast-types';
|
||||||
|
|
||||||
import { Database } from './database';
|
import { Database } from './database';
|
||||||
import { Entity } from './entity';
|
import { Entity } from './entity';
|
||||||
@ -51,19 +52,28 @@ export class Visitor {
|
|||||||
* Visitor function for function definitions.
|
* Visitor function for function definitions.
|
||||||
* @param node ASTNode for a function definition.
|
* @param node ASTNode for a function definition.
|
||||||
*/
|
*/
|
||||||
functionDefinitionVisitor (node: any): void {
|
functionDefinitionVisitor (node: FunctionDefinition): void {
|
||||||
if (node.stateMutability === 'view' && (node.visibility === 'external' || node.visibility === 'public')) {
|
if (node.stateMutability !== 'view' || !(node.visibility === 'external' || node.visibility === 'public')) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// If function doesn't return anything skip creating watcher query
|
||||||
|
if (!node.returnParameters) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
const name = node.name;
|
const name = node.name;
|
||||||
|
assert(name);
|
||||||
|
|
||||||
const params = node.parameters.map((item: any) => {
|
const params = node.parameters.map((item: any) => {
|
||||||
return { name: item.name, type: item.typeName.name };
|
return { name: item.name, type: item.typeName.name };
|
||||||
});
|
});
|
||||||
|
|
||||||
let errorMessage = '';
|
let errorMessage = '';
|
||||||
|
|
||||||
if (node.returnParameters.length > 1) {
|
|
||||||
errorMessage = `No support in codegen for multiple returned values from method ${node.name}`;
|
|
||||||
} else {
|
|
||||||
const typeName = node.returnParameters[0].typeName;
|
const typeName = node.returnParameters[0].typeName;
|
||||||
|
assert(typeName);
|
||||||
|
|
||||||
switch (typeName.type) {
|
switch (typeName.type) {
|
||||||
case 'ElementaryTypeName':
|
case 'ElementaryTypeName':
|
||||||
this._entity.addQuery(name, params, typeName);
|
this._entity.addQuery(name, params, typeName);
|
||||||
@ -72,11 +82,11 @@ export class Visitor {
|
|||||||
// falls through
|
// falls through
|
||||||
|
|
||||||
case 'ArrayTypeName':
|
case 'ArrayTypeName':
|
||||||
this._schema.addQuery(name, params, typeName);
|
this._schema.addQuery(name, params, node.returnParameters);
|
||||||
this._resolvers.addQuery(name, params, typeName);
|
this._resolvers.addQuery(name, params);
|
||||||
|
|
||||||
assert(this._contract);
|
assert(this._contract);
|
||||||
this._indexer.addQuery(this._contract.name, MODE_ETH_CALL, name, params, typeName);
|
this._indexer.addQuery(this._contract.name, MODE_ETH_CALL, name, params, node.returnParameters);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'UserDefinedTypeName':
|
case 'UserDefinedTypeName':
|
||||||
@ -86,7 +96,6 @@ export class Visitor {
|
|||||||
default:
|
default:
|
||||||
errorMessage = `No support in codegen for return type "${typeName.type}" from method "${node.name}"`;
|
errorMessage = `No support in codegen for return type "${typeName.type}" from method "${node.name}"`;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (errorMessage !== '') {
|
if (errorMessage !== '') {
|
||||||
if (this._continueOnError) {
|
if (this._continueOnError) {
|
||||||
@ -97,18 +106,19 @@ export class Visitor {
|
|||||||
throw new Error(errorMessage);
|
throw new Error(errorMessage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visitor function for state variable declarations.
|
* Visitor function for state variable declarations.
|
||||||
* @param node ASTNode for a state variable declaration.
|
* @param node ASTNode for a state variable declaration.
|
||||||
*/
|
*/
|
||||||
stateVariableDeclarationVisitor (node: any): void {
|
stateVariableDeclarationVisitor (node: StateVariableDeclaration): void {
|
||||||
// TODO Handle multiples variables in a single line.
|
// TODO Handle multiples variables in a single line.
|
||||||
// TODO Handle array types.
|
// TODO Handle array types.
|
||||||
// TODO Handle user defined type .
|
// TODO Handle user defined type .
|
||||||
const variable = node.variables[0];
|
const variable = node.variables[0];
|
||||||
|
assert(variable.name);
|
||||||
const name: string = variable.name;
|
const name: string = variable.name;
|
||||||
|
assert(variable.typeName);
|
||||||
const stateVariableType: string = variable.typeName.type;
|
const stateVariableType: string = variable.typeName.type;
|
||||||
const params: Param[] = [];
|
const params: Param[] = [];
|
||||||
|
|
||||||
@ -118,38 +128,43 @@ export class Visitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
let typeName = variable.typeName;
|
let typeName = variable.typeName;
|
||||||
|
let errorMessage = '';
|
||||||
|
|
||||||
|
switch (typeName.type) {
|
||||||
|
case 'Mapping': {
|
||||||
let numParams = 0;
|
let numParams = 0;
|
||||||
|
|
||||||
// If the variable type is mapping, extract key as a param:
|
// If the variable type is mapping, extract key as a param:
|
||||||
// Eg. mapping(address => mapping(address => uint256)) private _allowances;
|
// Eg. mapping(address => mapping(address => uint256)) private _allowances;
|
||||||
while (typeName.type === 'Mapping') {
|
while (typeName.type === 'Mapping') {
|
||||||
|
assert(typeName.keyType.type === 'ElementaryTypeName', 'UserDefinedTypeName map keys like enum type not handled');
|
||||||
params.push({ name: `key${numParams.toString()}`, type: typeName.keyType.name });
|
params.push({ name: `key${numParams.toString()}`, type: typeName.keyType.name });
|
||||||
typeName = typeName.valueType;
|
typeName = typeName.valueType;
|
||||||
numParams++;
|
numParams++;
|
||||||
}
|
}
|
||||||
|
|
||||||
let errorMessage = '';
|
// falls through
|
||||||
|
}
|
||||||
|
|
||||||
switch (typeName.type) {
|
|
||||||
case 'ElementaryTypeName': {
|
case 'ElementaryTypeName': {
|
||||||
this._schema.addQuery(name, params, typeName);
|
this._schema.addQuery(name, params, [variable]);
|
||||||
this._resolvers.addQuery(name, params, typeName);
|
this._resolvers.addQuery(name, params);
|
||||||
this._entity.addQuery(name, params, typeName);
|
this._entity.addQuery(name, params, typeName);
|
||||||
this._database.addQuery(name, params, typeName);
|
this._database.addQuery(name, params, typeName);
|
||||||
this._client.addQuery(name, params, typeName);
|
this._client.addQuery(name, params, typeName);
|
||||||
|
|
||||||
assert(this._contract);
|
assert(this._contract);
|
||||||
this._indexer.addQuery(this._contract.name, MODE_STORAGE, name, params, typeName, stateVariableType);
|
this._indexer.addQuery(this._contract.name, MODE_STORAGE, name, params, [variable], stateVariableType);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case 'UserDefinedTypeName':
|
case 'UserDefinedTypeName':
|
||||||
errorMessage = `No support in codegen for user defined return type from method "${name}"`;
|
errorMessage = `No support in codegen for user defined type state variable "${name}"`;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'ArrayTypeName':
|
case 'ArrayTypeName':
|
||||||
errorMessage = `No support in codegen for return type "${typeName.baseTypeName.name}[]" from method "${name}"`;
|
errorMessage = `No support in codegen for array type state variable "${name}"`;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
Loading…
Reference in New Issue
Block a user