watcher-ts/packages/codegen/src/indexer.ts
prathamesh0 4ddb8c4af6 Auto generating state from indexer methods (#277)
* Generate default derived state for Mapping type variables

* Update IPLDBlock in storage methods instead of using a private class variable

* Default state flag for indexer storage methods

* Helper functions to update state objects

* Add checkpoint flag in Contract table and corresponding changes in existing watchers

* Update codegen docs

* Add examples to generated docs

* Turn default state off by default

* Make state parameter to indexer storage methods default to none

* Add method to get prev. state in indexer
2021-12-28 16:08:04 +05:30

125 lines
3.4 KiB
TypeScript

//
// Copyright 2021 Vulcanize, Inc.
//
import fs from 'fs';
import path from 'path';
import assert from 'assert';
import Handlebars from 'handlebars';
import { Writable } from 'stream';
import _ from 'lodash';
import { getTsForSol } from './utils/type-mappings';
import { Param } from './utils/types';
import { MODE_ETH_CALL, MODE_STORAGE } from './utils/constants';
const TEMPLATE_FILE = './templates/indexer-template.handlebars';
export class Indexer {
_queries: Array<any>;
_events: Array<any>;
_templateString: string;
constructor () {
this._queries = [];
this._events = [];
this._templateString = fs.readFileSync(path.resolve(__dirname, TEMPLATE_FILE)).toString();
}
/**
* Stores the query to be passed to the template.
* @param mode Code generation mode.
* @param name Name of the query.
* @param params Parameters to the query.
* @param returnType Return type for the query.
* @param stateVariableTypeName Type of the state variable in case of state variable query.
*/
addQuery (mode: string, name: string, params: Array<Param>, returnType: string, stateVariableType?: string): void {
// Check if the query is already added.
if (this._queries.some(query => query.name === name)) {
return;
}
const queryObject = {
name,
getQueryName: '',
saveQueryName: '',
params: _.cloneDeep(params),
returnType,
mode,
stateVariableType
};
if (name.charAt(0) === '_') {
const capitalizedName = `${name.charAt(1).toUpperCase()}${name.slice(2)}`;
queryObject.getQueryName = `_get${capitalizedName}`;
queryObject.saveQueryName = `_save${capitalizedName}`;
} else {
const capitalizedName = `${name.charAt(0).toUpperCase()}${name.slice(1)}`;
queryObject.getQueryName = `get${capitalizedName}`;
queryObject.saveQueryName = `save${capitalizedName}`;
}
queryObject.params = queryObject.params.map((param) => {
const tsParamType = getTsForSol(param.type);
assert(tsParamType);
param.type = tsParamType;
return param;
});
const tsReturnType = getTsForSol(returnType);
assert(tsReturnType);
queryObject.returnType = tsReturnType;
if (stateVariableType) {
queryObject.stateVariableType = stateVariableType;
}
this._queries.push(queryObject);
}
addEvent (name: string, params: Array<Param>): void {
// Check if the event is already added.
if (this._events.some(event => event.name === name)) {
return;
}
const eventObject = {
name,
params: _.cloneDeep(params)
};
eventObject.params = eventObject.params.map((param) => {
const tsParamType = getTsForSol(param.type);
assert(tsParamType);
param.type = tsParamType;
return param;
});
this._events.push(eventObject);
}
/**
* Writes the indexer file generated from a template to a stream.
* @param outStream A writable output stream to write the indexer file to.
* @param inputFileName Input contract file name to be passed to the template.
*/
exportIndexer (outStream: Writable, inputFileName: string, contractName: string): void {
const template = Handlebars.compile(this._templateString);
const obj = {
inputFileName,
contractName,
queries: this._queries,
constants: {
MODE_ETH_CALL,
MODE_STORAGE
},
events: this._events
};
const indexer = template(obj);
outStream.write(indexer);
}
}