diff --git a/packages/codegen/src/entity.ts b/packages/codegen/src/entity.ts index f6e37a0b..8443e93a 100644 --- a/packages/codegen/src/entity.ts +++ b/packages/codegen/src/entity.ts @@ -282,19 +282,33 @@ export class Entity { // Add subgraph entity specific columns. entityObject = this._addSubgraphColumns(subgraphTypeDefs, entityObject, def); - // Add is_pruned column. - entityObject.columns.push({ - name: 'isPruned', - pgType: 'boolean', - tsType: 'boolean', - columnType: 'Column', - columnOptions: [ - { - option: 'default', - value: false - } - ] - }); + // Add is_pruned, is_removed columns. + entityObject.columns.push( + { + name: 'isPruned', + pgType: 'boolean', + tsType: 'boolean', + columnType: 'Column', + columnOptions: [ + { + option: 'default', + value: false + } + ] + }, + { + name: 'isRemoved', + pgType: 'boolean', + tsType: 'boolean', + columnType: 'Column', + columnOptions: [ + { + option: 'default', + value: false + } + ] + } + ); // Add decimalTransformer column option if required. this._addDecimalTransformerOption(entityObject); diff --git a/packages/codegen/src/templates/indexer-template.handlebars b/packages/codegen/src/templates/indexer-template.handlebars index effe5c43..637efa97 100644 --- a/packages/codegen/src/templates/indexer-template.handlebars +++ b/packages/codegen/src/templates/indexer-template.handlebars @@ -142,8 +142,6 @@ export class Indexer implements IndexerInterface { this._storageLayoutMap = new Map(); this._contractMap = new Map(); this.eventSignaturesMap = new Map(); - let contractInterface: ethers.utils.Interface; - let eventSignatures: string[]; {{#each contracts as | contract |}} const { abi: {{contract.contractName}}ABI{{#if contract.contractStorageLayout}}, storageLayout: {{contract.contractName}}StorageLayout{{/if}} } = {{contract.contractName}}Artifacts; @@ -153,15 +151,13 @@ export class Indexer implements IndexerInterface { assert({{contract.contractName}}ABI); this._abiMap.set(KIND_{{capitalize contract.contractName}}, {{contract.contractName}}ABI); - // eslint-disable-next-line prefer-const - contractInterface = new ethers.utils.Interface({{contract.contractName}}ABI); - this._contractMap.set(KIND_{{capitalize contract.contractName}}, contractInterface); + const {{contract.contractName}}ContractInterface = new ethers.utils.Interface({{contract.contractName}}ABI); + this._contractMap.set(KIND_{{capitalize contract.contractName}}, {{contract.contractName}}ContractInterface); - // eslint-disable-next-line prefer-const - eventSignatures = Object.values(contractInterface.events).map(value => { - return contractInterface.getEventTopic(value); + const {{contract.contractName}}EventSignatures = Object.values({{contract.contractName}}ContractInterface.events).map(value => { + return {{contract.contractName}}ContractInterface.getEventTopic(value); }); - this.eventSignaturesMap.set(KIND_{{capitalize contract.contractName}}, eventSignatures); + this.eventSignaturesMap.set(KIND_{{capitalize contract.contractName}}, {{contract.contractName}}EventSignatures); {{#if contract.contractStorageLayout}} assert({{contract.contractName}}StorageLayout); diff --git a/packages/graph-node/src/loader.ts b/packages/graph-node/src/loader.ts index c44445eb..5eb038c8 100644 --- a/packages/graph-node/src/loader.ts +++ b/packages/graph-node/src/loader.ts @@ -79,7 +79,7 @@ export const instantiate = async ( assert(context.block); const entityData = await database.getEntity(entityName, entityId, context.block.blockHash); - if (!entityData) { + if (!entityData || entityData.isRemoved) { return null; } @@ -112,6 +112,25 @@ export const instantiate = async ( indexer.updateSubgraphState(context.contractAddress, diffData); } }, + 'store.remove': async (entity: number, id: number) => { + const entityName = __getString(entity); + const entityId = __getString(id); + + assert(context.block); + const entityData = await database.getEntity(entityName, entityId, context.block.blockHash); + + if (!entityData || entityData.isRemoved) { + return; + } + + // Add an additional entry at block with isRemoved set to true + entityData.blockHash = context.block.blockHash; + entityData.blockNumber = context.block.blockNumber; + entityData.isRemoved = true; + + const dbEntity = await database.saveEntity(entityName, entityData); + database.cacheUpdatedEntityByName(entityName, dbEntity); + }, 'log.log': (level: number, msg: number) => { log('log %s | %s', Level[level], __getString(msg)); diff --git a/packages/util/src/graph/database.ts b/packages/util/src/graph/database.ts index fee33dcc..f409f428 100644 --- a/packages/util/src/graph/database.ts +++ b/packages/util/src/graph/database.ts @@ -935,8 +935,8 @@ export class GraphDatabase { const entityValuePromises = entityFields.filter(field => { const { propertyName } = field; - // Filter out blockHash and blockNumber from entity fields to fill the entityInstance (wasm). - if (propertyName === 'blockHash' || propertyName === 'blockNumber') { + // Filter out custom fields from entity to fill the entityInstance (wasm). + if (['isPruned', 'isRemoved', 'blockHash', 'blockNumber'].includes(propertyName)) { return false; } @@ -1013,7 +1013,7 @@ export class GraphDatabase { const entityValuePromises = entityFields.map(async (field: any) => { const { propertyName } = field; - if (propertyName === 'isPruned') { + if (['isPruned', 'isRemoved'].includes(propertyName)) { return undefined; } diff --git a/packages/util/src/graph/utils.ts b/packages/util/src/graph/utils.ts index 13c690f9..94587315 100644 --- a/packages/util/src/graph/utils.ts +++ b/packages/util/src/graph/utils.ts @@ -638,7 +638,7 @@ export const parseEntityValue = async (instanceExports: any, valuePtr: number): } }; -export const formatEntityValue = async (instanceExports: any, type: string, value: any, isArray: boolean): Promise => { +const formatEntityValue = async (instanceExports: any, type: string, value: any, isArray: boolean): Promise => { let valueToFormat = value; let typeName = type; if (isArray) {