mirror of
https://github.com/cerc-io/watcher-ts
synced 2026-09-09 17:24:07 +00:00
Implement gql queries for relation entities similar to subgraph (#53)
* Add implementation for one to one relation * Implement one to many relation in gql queries * Make changes for gql relation queries in eden-watcher * Implement subgraph gql relation queries with joins
This commit is contained in:
@@ -73,6 +73,65 @@ export class Database {
|
||||
}
|
||||
}
|
||||
|
||||
async getEntityWithRelations<Entity> (entity: (new () => Entity) | string, id: string, blockHash: string, relations: { [key: string]: any }): Promise<Entity | undefined> {
|
||||
const queryRunner = this._conn.createQueryRunner();
|
||||
|
||||
try {
|
||||
const repo = queryRunner.manager.getRepository(entity);
|
||||
|
||||
// Fetching blockHash for previous entity in frothy region.
|
||||
const { blockHash: entityblockHash, blockNumber, id: frothyId } = await this._baseDatabase.getFrothyEntity(queryRunner, repo, { blockHash, id });
|
||||
|
||||
let selectQueryBuilder = repo.createQueryBuilder('entity');
|
||||
|
||||
if (frothyId) {
|
||||
// If entity found in frothy region.
|
||||
selectQueryBuilder = selectQueryBuilder.where('entity.block_hash = :entityblockHash', { entityblockHash });
|
||||
} else {
|
||||
// If entity not in frothy region.
|
||||
const canonicalBlockNumber = blockNumber + 1;
|
||||
|
||||
selectQueryBuilder = selectQueryBuilder.innerJoinAndSelect('block_progress', 'block', 'block.block_hash = entity.block_hash')
|
||||
.where('block.is_pruned = false')
|
||||
.andWhere('entity.block_number <= :canonicalBlockNumber', { canonicalBlockNumber })
|
||||
.orderBy('entity.block_number', 'DESC')
|
||||
.limit(1);
|
||||
}
|
||||
|
||||
selectQueryBuilder = selectQueryBuilder.andWhere('entity.id = :id', { id });
|
||||
|
||||
// TODO: Implement query for nested relations.
|
||||
Object.entries(relations).forEach(([field, data], index) => {
|
||||
const { entity: relatedEntity, isArray } = data;
|
||||
const alias = `relatedEntity${index}`;
|
||||
|
||||
if (isArray) {
|
||||
// For one to many relational field.
|
||||
selectQueryBuilder = selectQueryBuilder.leftJoinAndMapMany(
|
||||
`entity.${field}`,
|
||||
relatedEntity,
|
||||
alias,
|
||||
`${alias}.id IN (SELECT unnest(entity.${field})) AND ${alias}.block_number <= entity.block_number`
|
||||
)
|
||||
.addOrderBy(`${alias}.block_number`, 'DESC');
|
||||
} else {
|
||||
// For one to one relational field.
|
||||
selectQueryBuilder = selectQueryBuilder.leftJoinAndMapOne(
|
||||
`entity.${field}`,
|
||||
relatedEntity,
|
||||
alias,
|
||||
`entity.${field} = ${alias}.id AND ${alias}.block_number <= entity.block_number`
|
||||
)
|
||||
.addOrderBy(`${alias}.block_number`, 'DESC');
|
||||
}
|
||||
});
|
||||
|
||||
return selectQueryBuilder.getOne();
|
||||
} finally {
|
||||
await queryRunner.release();
|
||||
}
|
||||
}
|
||||
|
||||
async saveEntity (entity: string, data: any): Promise<void> {
|
||||
const repo = this._conn.getRepository(entity);
|
||||
|
||||
|
||||
@@ -184,9 +184,9 @@ export class GraphWatcher {
|
||||
this._indexer = indexer;
|
||||
}
|
||||
|
||||
async getEntity<Entity> (entity: new () => Entity, id: string, blockHash: string): Promise<any> {
|
||||
async getEntity<Entity> (entity: new () => Entity, id: string, blockHash: string, relations: { [key: string]: any }): Promise<any> {
|
||||
// Get entity from the database.
|
||||
const result = await this._database.getEntity(entity, id, blockHash) as any;
|
||||
const result = await this._database.getEntityWithRelations(entity, id, blockHash, relations) as any;
|
||||
|
||||
// Resolve any field name conflicts in the entity result.
|
||||
return resolveEntityFieldConflicts(result);
|
||||
|
||||
Reference in New Issue
Block a user