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 {
[key: string]: {
[key: string]: [{
value: any;
not: boolean;
operator: keyof typeof OPERATOR_MAP;
}
}]
}
export class Database {
@ -479,40 +479,43 @@ export class Database {
selectQueryBuilder = selectQueryBuilder.leftJoinAndSelect(`${repo.metadata.tableName}.${relation}`, relation);
});
Object.entries(where).forEach(([field, filter]) => {
// Form the where clause.
const { not, operator, value } = filter;
const columnMetadata = repo.metadata.findColumnWithPropertyName(field);
assert(columnMetadata);
let whereClause = `${tableName}.${columnMetadata.propertyAliasName} `;
Object.entries(where).forEach(([field, filters]) => {
filters.forEach((filter, index) => {
// Form the where clause.
const { not, operator, value } = filter;
const columnMetadata = repo.metadata.findColumnWithPropertyName(field);
assert(columnMetadata);
let whereClause = `${tableName}.${columnMetadata.propertyAliasName} `;
if (not) {
if (operator === 'equals') {
whereClause += '!';
} else {
whereClause += 'NOT ';
if (not) {
if (operator === 'equals') {
whereClause += '!';
} else {
whereClause += 'NOT ';
}
}
}
whereClause += `${OPERATOR_MAP[operator]} `;
whereClause += `${OPERATOR_MAP[operator]} `;
if (['contains', 'starts'].some(el => el === operator)) {
whereClause += '%:';
} else if (operator === 'in') {
whereClause += '(:...';
} else {
whereClause += ':';
}
if (['contains', 'starts'].some(el => el === operator)) {
whereClause += '%:';
} else if (operator === 'in') {
whereClause += '(:...';
} else {
whereClause += ':';
}
whereClause += 'value';
const variableName = `${field}${index}`;
whereClause += variableName;
if (['contains', 'ends'].some(el => el === operator)) {
whereClause += '%';
} else if (operator === 'in') {
whereClause += ')';
}
if (['contains', 'ends'].some(el => el === operator)) {
whereClause += '%';
} else if (operator === 'in') {
whereClause += ')';
}
selectQueryBuilder = selectQueryBuilder.andWhere(whereClause, { value });
selectQueryBuilder = selectQueryBuilder.andWhere(whereClause, { [variableName]: value });
});
});
const { limit = DEFAULT_LIMIT, orderBy, orderDirection, skip = DEFAULT_SKIP } = queryOptions;

View File

@ -206,6 +206,30 @@ export class Indexer {
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> {
return this._db.getEvent(id);
}
@ -290,7 +314,11 @@ export class Indexer {
where = Object.entries(where).reduce((acc: { [key: string]: any }, [fieldWithSuffix, value]) => {
const [field, ...suffix] = fieldWithSuffix.split('_');
acc[field] = {
if (!acc[field]) {
acc[field] = [];
}
const filter = {
value,
not: false,
operator: 'equals'
@ -299,14 +327,16 @@ export class Indexer {
let operator = suffix.shift();
if (operator === 'not') {
acc[field].not = true;
filter.not = true;
operator = suffix.shift();
}
if (operator) {
acc[field].operator = operator;
filter.operator = operator;
}
acc[field].push(filter);
return acc;
}, {});

View File

@ -133,6 +133,12 @@ export const createResolvers = async (indexer: Indexer): Promise<any> => {
log('positions', first, where);
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!
}
type Block {
number: Int!
hash: Bytes!
timestamp: Int!
}
enum OrderDirection {
asc
desc
@ -268,6 +274,15 @@ input Position_filter {
id: ID
}
input Block_filter {
timestamp_gt: Int
timestamp_lt: Int
}
enum Block_orderBy {
timestamp
}
type Query {
bundle(
id: ID!
@ -413,5 +428,12 @@ type Query {
first: Int = 100
where: Position_filter
): [Position!]!
blocks(
first: Int = 100
orderBy: Block_orderBy
orderDirection: OrderDirection
where: Block_filter
): [Block!]!
}
`;