Blocks GQL API (#213)

* Add schema for blocks query.

* Implement resolver for blocks query.

* Fix issue with multiple query filters for one entity field.

Co-authored-by: nabarun <nabarun@deepstacksoft.com>
This commit is contained in:
Ashwin Phatak 2021-08-13 15:06:58 +05:30 committed by GitHub
parent a7ec3d8da8
commit eb912b7f68
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 93 additions and 32 deletions

View File

@ -62,11 +62,11 @@ export interface QueryOptions {
} }
interface Where { interface Where {
[key: string]: { [key: string]: [{
value: any; value: any;
not: boolean; not: boolean;
operator: keyof typeof OPERATOR_MAP; operator: keyof typeof OPERATOR_MAP;
} }]
} }
export class Database { export class Database {
@ -479,7 +479,8 @@ export class Database {
selectQueryBuilder = selectQueryBuilder.leftJoinAndSelect(`${repo.metadata.tableName}.${relation}`, relation); selectQueryBuilder = selectQueryBuilder.leftJoinAndSelect(`${repo.metadata.tableName}.${relation}`, relation);
}); });
Object.entries(where).forEach(([field, filter]) => { Object.entries(where).forEach(([field, filters]) => {
filters.forEach((filter, index) => {
// Form the where clause. // Form the where clause.
const { not, operator, value } = filter; const { not, operator, value } = filter;
const columnMetadata = repo.metadata.findColumnWithPropertyName(field); const columnMetadata = repo.metadata.findColumnWithPropertyName(field);
@ -504,7 +505,8 @@ export class Database {
whereClause += ':'; whereClause += ':';
} }
whereClause += 'value'; const variableName = `${field}${index}`;
whereClause += variableName;
if (['contains', 'ends'].some(el => el === operator)) { if (['contains', 'ends'].some(el => el === operator)) {
whereClause += '%'; whereClause += '%';
@ -512,7 +514,8 @@ export class Database {
whereClause += ')'; whereClause += ')';
} }
selectQueryBuilder = selectQueryBuilder.andWhere(whereClause, { value }); selectQueryBuilder = selectQueryBuilder.andWhere(whereClause, { [variableName]: value });
});
}); });
const { limit = DEFAULT_LIMIT, orderBy, orderDirection, skip = DEFAULT_SKIP } = queryOptions; const { limit = DEFAULT_LIMIT, orderBy, orderDirection, skip = DEFAULT_SKIP } = queryOptions;

View File

@ -206,6 +206,30 @@ export class Indexer {
return block; return block;
} }
async getBlocks (where: { [key: string]: any } = {}, queryOptions: QueryOptions): Promise<any> {
if (where.timestamp_gt) {
where.blockTimestamp_gt = where.timestamp_gt;
delete where.timestamp_gt;
}
if (where.timestamp_lt) {
where.blockTimestamp_lt = where.timestamp_lt;
delete where.timestamp_lt;
}
if (queryOptions.orderBy === 'timestamp') {
queryOptions.orderBy = 'blockTimestamp';
}
const blocks = await this.getEntities(BlockProgress, {}, where, queryOptions);
return blocks.map(block => ({
timestamp: block.blockTimestamp,
number: block.blockNumber,
hash: block.blockHash
}));
}
async getEvent (id: string): Promise<Event | undefined> { async getEvent (id: string): Promise<Event | undefined> {
return this._db.getEvent(id); return this._db.getEvent(id);
} }
@ -290,7 +314,11 @@ export class Indexer {
where = Object.entries(where).reduce((acc: { [key: string]: any }, [fieldWithSuffix, value]) => { where = Object.entries(where).reduce((acc: { [key: string]: any }, [fieldWithSuffix, value]) => {
const [field, ...suffix] = fieldWithSuffix.split('_'); const [field, ...suffix] = fieldWithSuffix.split('_');
acc[field] = { if (!acc[field]) {
acc[field] = [];
}
const filter = {
value, value,
not: false, not: false,
operator: 'equals' operator: 'equals'
@ -299,14 +327,16 @@ export class Indexer {
let operator = suffix.shift(); let operator = suffix.shift();
if (operator === 'not') { if (operator === 'not') {
acc[field].not = true; filter.not = true;
operator = suffix.shift(); operator = suffix.shift();
} }
if (operator) { if (operator) {
acc[field].operator = operator; filter.operator = operator;
} }
acc[field].push(filter);
return acc; return acc;
}, {}); }, {});

View File

@ -133,6 +133,12 @@ export const createResolvers = async (indexer: Indexer): Promise<any> => {
log('positions', first, where); log('positions', first, where);
return indexer.getEntities(Position, {}, where, { limit: first }, ['pool', 'token0', 'token1', 'tickLower', 'tickUpper', 'transaction']); return indexer.getEntities(Position, {}, where, { limit: first }, ['pool', 'token0', 'token1', 'tickLower', 'tickUpper', 'transaction']);
},
blocks: async (_: any, { first, orderBy, orderDirection, where }: { first: number, orderBy: string, orderDirection: OrderDirection, where: { [key: string]: any } }) => {
log('blocks', first, orderBy, orderDirection, where);
return indexer.getBlocks(where, { limit: first, orderBy, orderDirection });
} }
} }
}; };

View File

@ -160,6 +160,12 @@ type Position {
feeGrowthInside1LastX128: BigInt! feeGrowthInside1LastX128: BigInt!
} }
type Block {
number: Int!
hash: Bytes!
timestamp: Int!
}
enum OrderDirection { enum OrderDirection {
asc asc
desc desc
@ -268,6 +274,15 @@ input Position_filter {
id: ID id: ID
} }
input Block_filter {
timestamp_gt: Int
timestamp_lt: Int
}
enum Block_orderBy {
timestamp
}
type Query { type Query {
bundle( bundle(
id: ID! id: ID!
@ -413,5 +428,12 @@ type Query {
first: Int = 100 first: Int = 100
where: Position_filter where: Position_filter
): [Position!]! ): [Position!]!
blocks(
first: Int = 100
orderBy: Block_orderBy
orderDirection: OrderDirection
where: Block_filter
): [Block!]!
} }
`; `;