// // Copyright 2021 Vulcanize, Inc. // import assert from 'assert'; import { Connection, ConnectionOptions, DeepPartial, FindConditions, QueryRunner, FindManyOptions } from 'typeorm'; import path from 'path'; import { IPLDDatabase as BaseDatabase, IPLDDatabaseInterface, QueryOptions, StateKind, Where } from '@cerc-io/util'; import { Contract } from './entity/Contract'; import { Event } from './entity/Event'; import { SyncStatus } from './entity/SyncStatus'; import { IpldStatus } from './entity/IpldStatus'; import { BlockProgress } from './entity/BlockProgress'; import { IPLDBlock } from './entity/IPLDBlock'; import { GetMethod } from './entity/GetMethod'; import { _Test } from './entity/_Test'; export class Database implements IPLDDatabaseInterface { _config: ConnectionOptions; _conn!: Connection; _baseDatabase: BaseDatabase; _propColMaps: { [key: string]: Map; } constructor (config: ConnectionOptions) { assert(config); this._config = { ...config, entities: [path.join(__dirname, 'entity/*')] }; this._baseDatabase = new BaseDatabase(this._config); this._propColMaps = {}; } async init (): Promise { this._conn = await this._baseDatabase.init(); this._setPropColMaps(); } async close (): Promise { return this._baseDatabase.close(); } async getGetMethod ({ blockHash, contractAddress }: { blockHash: string, contractAddress: string }): Promise { return this._conn.getRepository(GetMethod) .findOne({ blockHash, contractAddress }); } async _getTest ({ blockHash, contractAddress }: { blockHash: string, contractAddress: string }): Promise<_Test | undefined> { return this._conn.getRepository(_Test) .findOne({ blockHash, contractAddress }); } async saveGetMethod ({ blockHash, blockNumber, contractAddress, value, proof }: DeepPartial): Promise { const repo = this._conn.getRepository(GetMethod); const entity = repo.create({ blockHash, blockNumber, contractAddress, value, proof }); return repo.save(entity); } async _saveTest ({ blockHash, blockNumber, contractAddress, value, proof }: DeepPartial<_Test>): Promise<_Test> { const repo = this._conn.getRepository(_Test); const entity = repo.create({ blockHash, blockNumber, contractAddress, value, proof }); return repo.save(entity); } getNewIPLDBlock (): IPLDBlock { return new IPLDBlock(); } async getIPLDBlocks (where: FindConditions): Promise { const repo = this._conn.getRepository(IPLDBlock); return this._baseDatabase.getIPLDBlocks(repo, where); } async getLatestIPLDBlock (contractAddress: string, kind: StateKind | null, blockNumber?: number): Promise { const repo = this._conn.getRepository(IPLDBlock); return this._baseDatabase.getLatestIPLDBlock(repo, contractAddress, kind, blockNumber); } async getPrevIPLDBlock (blockHash: string, contractAddress: string, kind?: string): Promise { const repo = this._conn.getRepository(IPLDBlock); return this._baseDatabase.getPrevIPLDBlock(repo, blockHash, contractAddress, kind); } // Fetch all diff IPLDBlocks after the specified block number. async getDiffIPLDBlocksInRange (contractAddress: string, startBlock: number, endBlock: number): Promise { const repo = this._conn.getRepository(IPLDBlock); return this._baseDatabase.getDiffIPLDBlocksInRange(repo, contractAddress, startBlock, endBlock); } async saveOrUpdateIPLDBlock (dbTx: QueryRunner, ipldBlock: IPLDBlock): Promise { const repo = dbTx.manager.getRepository(IPLDBlock); return this._baseDatabase.saveOrUpdateIPLDBlock(repo, ipldBlock); } async removeIPLDBlocks (dbTx: QueryRunner, blockNumber: number, kind: string): Promise { const repo = dbTx.manager.getRepository(IPLDBlock); await this._baseDatabase.removeIPLDBlocks(repo, blockNumber, kind); } async getIPLDStatus (): Promise { const repo = this._conn.getRepository(IpldStatus); return this._baseDatabase.getIPLDStatus(repo); } async updateIPLDStatusHooksBlock (queryRunner: QueryRunner, blockNumber: number, force?: boolean): Promise { const repo = queryRunner.manager.getRepository(IpldStatus); return this._baseDatabase.updateIPLDStatusHooksBlock(repo, blockNumber, force); } async updateIPLDStatusCheckpointBlock (queryRunner: QueryRunner, blockNumber: number, force?: boolean): Promise { const repo = queryRunner.manager.getRepository(IpldStatus); return this._baseDatabase.updateIPLDStatusCheckpointBlock(repo, blockNumber, force); } async updateIPLDStatusIPFSBlock (queryRunner: QueryRunner, blockNumber: number, force?: boolean): Promise { const repo = queryRunner.manager.getRepository(IpldStatus); return this._baseDatabase.updateIPLDStatusIPFSBlock(repo, blockNumber, force); } async getContracts (): Promise { const repo = this._conn.getRepository(Contract); return this._baseDatabase.getContracts(repo); } async createTransactionRunner (): Promise { return this._baseDatabase.createTransactionRunner(); } async getProcessedBlockCountForRange (fromBlockNumber: number, toBlockNumber: number): Promise<{ expected: number, actual: number }> { const repo = this._conn.getRepository(BlockProgress); return this._baseDatabase.getProcessedBlockCountForRange(repo, fromBlockNumber, toBlockNumber); } async getEventsInRange (fromBlockNumber: number, toBlockNumber: number): Promise> { const repo = this._conn.getRepository(Event); return this._baseDatabase.getEventsInRange(repo, fromBlockNumber, toBlockNumber); } async saveEventEntity (queryRunner: QueryRunner, entity: Event): Promise { const repo = queryRunner.manager.getRepository(Event); return this._baseDatabase.saveEventEntity(repo, entity); } async getBlockEvents (blockHash: string, where: Where, queryOptions: QueryOptions): Promise { const repo = this._conn.getRepository(Event); return this._baseDatabase.getBlockEvents(repo, blockHash, where, queryOptions); } async saveEvents (queryRunner: QueryRunner, block: DeepPartial, events: DeepPartial[]): Promise { const blockRepo = queryRunner.manager.getRepository(BlockProgress); const eventRepo = queryRunner.manager.getRepository(Event); return this._baseDatabase.saveEvents(blockRepo, eventRepo, block, events); } async saveContract (queryRunner: QueryRunner, address: string, kind: string, checkpoint: boolean, startingBlock: number): Promise { const repo = queryRunner.manager.getRepository(Contract); return this._baseDatabase.saveContract(repo, address, kind, checkpoint, startingBlock); } async updateSyncStatusIndexedBlock (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise { const repo = queryRunner.manager.getRepository(SyncStatus); return this._baseDatabase.updateSyncStatusIndexedBlock(repo, blockHash, blockNumber, force); } async updateSyncStatusCanonicalBlock (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise { const repo = queryRunner.manager.getRepository(SyncStatus); return this._baseDatabase.updateSyncStatusCanonicalBlock(repo, blockHash, blockNumber, force); } async updateSyncStatusChainHead (queryRunner: QueryRunner, blockHash: string, blockNumber: number, force = false): Promise { const repo = queryRunner.manager.getRepository(SyncStatus); return this._baseDatabase.updateSyncStatusChainHead(repo, blockHash, blockNumber, force); } async getSyncStatus (queryRunner: QueryRunner): Promise { const repo = queryRunner.manager.getRepository(SyncStatus); return this._baseDatabase.getSyncStatus(repo); } async getEvent (id: string): Promise { const repo = this._conn.getRepository(Event); return this._baseDatabase.getEvent(repo, id); } async getBlocksAtHeight (height: number, isPruned: boolean): Promise { const repo = this._conn.getRepository(BlockProgress); return this._baseDatabase.getBlocksAtHeight(repo, height, isPruned); } async markBlocksAsPruned (queryRunner: QueryRunner, blocks: BlockProgress[]): Promise { const repo = queryRunner.manager.getRepository(BlockProgress); return this._baseDatabase.markBlocksAsPruned(repo, blocks); } async getBlockProgress (blockHash: string): Promise { const repo = this._conn.getRepository(BlockProgress); return this._baseDatabase.getBlockProgress(repo, blockHash); } async getBlockProgressEntities (where: FindConditions, options: FindManyOptions): Promise { const repo = this._conn.getRepository(BlockProgress); return this._baseDatabase.getBlockProgressEntities(repo, where, options); } async updateBlockProgress (queryRunner: QueryRunner, block: BlockProgress, lastProcessedEventIndex: number): Promise { const repo = queryRunner.manager.getRepository(BlockProgress); return this._baseDatabase.updateBlockProgress(repo, block, lastProcessedEventIndex); } async removeEntities (queryRunner: QueryRunner, entity: new () => Entity, findConditions?: FindManyOptions | FindConditions): Promise { return this._baseDatabase.removeEntities(queryRunner, entity, findConditions); } async deleteEntitiesByConditions (queryRunner: QueryRunner, entity: new () => Entity, findConditions: FindConditions): Promise { await this._baseDatabase.deleteEntitiesByConditions(queryRunner, entity, findConditions); } async getAncestorAtDepth (blockHash: string, depth: number): Promise { return this._baseDatabase.getAncestorAtDepth(blockHash, depth); } _getPropertyColumnMapForEntity (entityName: string): Map { return this._conn.getMetadata(entityName).ownColumns.reduce((acc, curr) => { return acc.set(curr.propertyName, curr.databaseName); }, new Map()); } _setPropColMaps (): void { this._propColMaps.GetMethod = this._getPropertyColumnMapForEntity('GetMethod'); this._propColMaps._Test = this._getPropertyColumnMapForEntity('_Test'); } }