diff --git a/src/fetch/openapi.ts b/src/fetch/openapi.ts index dbdc721..2b03bcd 100644 --- a/src/fetch/openapi.ts +++ b/src/fetch/openapi.ts @@ -14,7 +14,7 @@ const TAGS = { DOCS: "Documentation", } as const; -const chains = await supportedChainsQuery(); +export const chains = await supportedChainsQuery(); const block_example = (await makeQuery(await getBlock( new URLSearchParams({limit: "2"})))).data; const timestampSchema: SchemaObject = { anyOf: [ diff --git a/src/queries.spec.ts b/src/queries.spec.ts index 07f889c..7762f3f 100644 --- a/src/queries.spec.ts +++ b/src/queries.spec.ts @@ -1,5 +1,6 @@ import { expect, test } from "bun:test"; import { getBlock, getChain } from "./queries.js"; +import { chains } from './fetch/openapi.js'; test("getBlock", () => { expect(getBlock(new URLSearchParams({ chain: "eth", block_number: "123" }))) @@ -7,6 +8,12 @@ test("getBlock", () => { expect(getBlock(new URLSearchParams({ chain: "eth", greater_or_equals_by_timestamp: '1438270048', less_or_equals_by_timestamp: '1438270083', limit: '3' }))) .toBe(`SELECT * FROM blocks WHERE (toUnixTimestamp(timestamp) >= 1438270048 AND toUnixTimestamp(timestamp) <= 1438270083 AND chain == 'eth') ORDER BY block_number DESC LIMIT 3`); + + // Check that if not chain parameter is passed, all chains are included in the selection + chains.forEach((chain) => { + expect(getBlock(new URLSearchParams({ block_number: "123" }))) + .toContain(`SELECT * FROM blocks WHERE (chain == '${chain}' AND block_number == '123') ORDER BY block_number DESC LIMIT 1`); + }); }); test("getChain", () => { diff --git a/src/queries.ts b/src/queries.ts index 1bcb53a..2456f20 100644 --- a/src/queries.ts +++ b/src/queries.ts @@ -1,5 +1,7 @@ import { DEFAULT_SORT_BY, config } from './config.js'; import { parseBlockId, parseLimit, parseTimestamp } from './utils.js'; +import { chains } from './fetch/openapi.js'; +import { create } from 'domain'; export interface Block { block_number: number; @@ -11,44 +13,60 @@ export interface Block { export function getBlock(searchParams: URLSearchParams) { // TO-DO: Modulo block number (ex: search by every 1M blocks) - // SQL Query - let query = `SELECT * FROM ${config.table}`; - const where = []; - - // Clickhouse Operators - // https://clickhouse.com/docs/en/sql-reference/operators - const operators = [ - ["greater_or_equals", ">="], - ["greater", ">"], - ["less_or_equals", "<="], - ["less", "<"], - ] - for ( const [key, operator] of operators ) { - const block_number = searchParams.get(`${key}_by_block_number`); - const timestamp = parseTimestamp(searchParams.get(`${key}_by_timestamp`)); - if (block_number) where.push(`block_number ${operator} ${block_number}`); - if (timestamp) where.push(`toUnixTimestamp(timestamp) ${operator} ${timestamp}`); - } + let createBlockQuery = (searchParams: URLSearchParams) => { + // SQL Query + let query = `SELECT * FROM ${config.table}`; + const where = []; + + // Clickhouse Operators + // https://clickhouse.com/docs/en/sql-reference/operators + const operators = [ + ["greater_or_equals", ">="], + ["greater", ">"], + ["less_or_equals", "<="], + ["less", "<"], + ] + for ( const [key, operator] of operators ) { + const block_number = searchParams.get(`${key}_by_block_number`); + const timestamp = parseTimestamp(searchParams.get(`${key}_by_timestamp`)); + if (block_number) where.push(`block_number ${operator} ${block_number}`); + if (timestamp) where.push(`toUnixTimestamp(timestamp) ${operator} ${timestamp}`); + } + + // equals + const chain = searchParams.get("chain"); + const block_id = parseBlockId(searchParams.get("block_id")); + const block_number = searchParams.get('block_number'); + const timestamp = parseTimestamp(searchParams.get('timestamp')); + if (chain) where.push(`chain == '${chain}'`); + if (block_id) where.push(`block_id == '${block_id}'`); + if (block_number) where.push(`block_number == '${block_number}'`); + if (timestamp) where.push(`toUnixTimestamp(timestamp) == ${timestamp}`); + + // Join WHERE statements with AND + if ( where.length ) query += ` WHERE (${where.join(' AND ')})`; + + // Sort and Limit + const limit = parseLimit(searchParams.get("limit")); + const sort_by = searchParams.get("sort_by"); + query += ` ORDER BY block_number ${sort_by ?? DEFAULT_SORT_BY}` + query += ` LIMIT ${limit}` + + return query; + }; - // equals const chain = searchParams.get("chain"); - const block_id = parseBlockId(searchParams.get("block_id")); - const block_number = searchParams.get('block_number'); - const timestamp = parseTimestamp(searchParams.get('timestamp')); - if (chain) where.push(`chain == '${chain}'`); - if (block_id) where.push(`block_id == '${block_id}'`); - if (block_number) where.push(`block_number == '${block_number}'`); - if (timestamp) where.push(`toUnixTimestamp(timestamp) == ${timestamp}`); - - // Join WHERE statements with AND - if ( where.length ) query += ` WHERE (${where.join(' AND ')})`; - - // Sort and Limit - const limit = parseLimit(searchParams.get("limit")); - const sort_by = searchParams.get("sort_by"); - query += ` ORDER BY block_number ${sort_by ?? DEFAULT_SORT_BY}` - query += ` LIMIT ${limit}` - return query; + + if (!chain) { + let queries = chains.map((chain) => { + searchParams.set('chain', chain); + return createBlockQuery(searchParams); + }); + + return queries.join(' UNION ALL '); + } else { + return createBlockQuery(searchParams); + } } export function getChain() {