Skip to content

Commit

Permalink
enum time range filter and results split by chain
Browse files Browse the repository at this point in the history
  • Loading branch information
Pelotfr committed Nov 16, 2023
1 parent 98aef4f commit faccf5d
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 30 deletions.
2 changes: 1 addition & 1 deletion src/fetch/history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ export default async function (req: Request) {
return toJSON(formatted);
} catch (e: any) {
logger.error(e);
prometheus.request_error.inc({pathname: "/uaw/history/", status: 400});
prometheus.request_error.inc({pathname: "/uaw/history", status: 400});
return BadRequest
}
}
6 changes: 3 additions & 3 deletions src/fetch/openapi.ts
Original file line number Diff line number Diff line change
Expand Up @@ -304,7 +304,7 @@ export default new OpenApiBuilder()
get: {
tags: [TAGS.USAGE],
summary: "Get daily unique active wallets",
description: "Get daily unique active wallets for previous given number of days filtered by `chain`",
description: "Get daily unique active wallets for given time range filtered by `chain`",
parameters: [
{
name: "chain",
Expand All @@ -316,9 +316,9 @@ export default new OpenApiBuilder()
{
name: "range",
in: "query",
description: "Number of days to go back",
description: "Time range to query (ex: 7d)",
required: false,
schema: { type: "number" },
schema: { enum: ["24h", "7d", "30d", "90d", "1y", "all"] },
}
],
responses: {
Expand Down
28 changes: 21 additions & 7 deletions src/queries.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { expect, jest, mock, test } from "bun:test";
import { createBlockQuery, getBlock, getAggregate, getDAW } from "./queries.js";
import { createBlockQuery, getBlock, getAggregate, getUAWFromDate, getUAWHistory } from "./queries.js";
import { store } from "./clickhouse/stores.js";

// Mock supported chains data to prevent DB query
Expand Down Expand Up @@ -37,11 +37,25 @@ test("getAggregate", async () => {
.toBe(`SELECT chain, count(transaction_traces) FROM BlockStats GROUP BY chain`);
});

test("getDAW", async () => {
const singleChainQuery = new URLSearchParams({ chain: "wax"});
expect(getDAW(singleChainQuery))
.toBe(`SELECT chain, count(distinct uaw) FROM BlockStats ARRAY JOIN uaw WHERE (chain == 'wax') GROUP BY chain`);
test("getUAWFromDate", async () => {
const singleChainQuery = new URLSearchParams({ chain: "wax", date: "2023-09-06" });
expect(getUAWFromDate(singleChainQuery))
.toBe(`SELECT chain, count(distinct uaw) FROM BlockStats ARRAY JOIN uaw WHERE (toUnixTimestamp(DATE(timestamp)) == toUnixTimestamp(DATE(1693958400)) AND chain == 'wax') GROUP BY chain`);

expect(getUAWFromDate(new URLSearchParams({ date: "2023-09-06" })))
.toBe(`SELECT chain, count(distinct uaw) FROM BlockStats ARRAY JOIN uaw WHERE (toUnixTimestamp(DATE(timestamp)) == toUnixTimestamp(DATE(1693958400))) GROUP BY chain`);
});

test("getUAWHistory", async () => {
const date_of_query = Math.floor(Number(new Date().setHours(0,0,0,0)) / 1000);
const datetime_of_query = Math.floor(Number(new Date()) / 1000);

expect(getUAWHistory(new URLSearchParams({ chain: "eos", range: "7d" })))
.toBe(`SELECT chain, toUnixTimestamp(DATE(timestamp)) as day, count(distinct uaw) as UAW FROM BlockStats ARRAY JOIN uaw WHERE (timestamp BETWEEN ${date_of_query} - 86400 * 7 AND ${date_of_query} AND chain == 'eos') GROUP BY chain, day ORDER BY day ASC`);

expect(getUAWHistory(new URLSearchParams({ range: "24h" })))
.toBe(`SELECT chain, toUnixTimestamp(DATE(timestamp)) as day, count(distinct uaw) as UAW FROM BlockStats ARRAY JOIN uaw WHERE (timestamp BETWEEN ${datetime_of_query} - 3600 * 24 AND ${datetime_of_query}) GROUP BY chain, day ORDER BY day ASC`);

expect(getDAW(new URLSearchParams({ date: "2023-09-06" })))
.toBe(`SELECT chain, count(distinct uaw) FROM BlockStats ARRAY JOIN uaw WHERE (DATE(timestamp) == '2023-09-06') GROUP BY chain`);
expect(getUAWHistory(new URLSearchParams({ range: "1y" })))
.toBe(`SELECT chain, toUnixTimestamp(DATE(timestamp)) as day, count(distinct uaw) as UAW FROM BlockStats ARRAY JOIN uaw WHERE (timestamp BETWEEN ${date_of_query} - 31536000 * 1 AND ${date_of_query}) GROUP BY chain, day ORDER BY day ASC`);
});
24 changes: 20 additions & 4 deletions src/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ export interface Block {
}

export interface UAWHistory {
chain: string;
UAW: string;
day: number;
}
Expand Down Expand Up @@ -147,24 +148,39 @@ export function getUAWFromDate(searchParams: URLSearchParams) {

export function getUAWHistory(searchParams: URLSearchParams) {
// SQL Query
let query = `SELECT count(distinct uaw) as UAW, toUnixTimestamp(DATE(timestamp)) as day FROM BlockStats ARRAY JOIN uaw`;
let query = `SELECT chain, toUnixTimestamp(DATE(timestamp)) as day, count(distinct uaw) as UAW FROM BlockStats ARRAY JOIN uaw`;

const where = [];

const datetime_of_query = Math.floor(Number(new Date()) / 1000);
const date_of_query = Math.floor(Number(new Date().setHours(0,0,0,0)) / 1000);

//const test = 1694296800;

const range = parseHistoryRange(searchParams.get('range'));
where.push(`timestamp BETWEEN ${date_of_query} - 86400 * ${range} AND ${date_of_query}`);

if (range?.includes('h')) {
const hours = parseInt(range);
if (hours) where.push(`timestamp BETWEEN ${datetime_of_query} - 3600 * ${hours} AND ${datetime_of_query}`);
}

if (range?.includes('d')) {
const days = parseInt(range);
if (days) where.push(`timestamp BETWEEN ${date_of_query} - 86400 * ${days} AND ${date_of_query}`);
}

if(range?.includes('y')) {
const years = parseInt(range);
if (years) where.push(`timestamp BETWEEN ${date_of_query} - 31536000 * ${years} AND ${date_of_query}`);
}

const chain = parseChain(searchParams.get('chain'));
if (chain) where.push(`chain == '${chain}'`);

// Join WHERE statements with AND
if ( where.length ) query += ` WHERE (${where.join(' AND ')})`;

// Group by timestamp
query += ` GROUP BY day`;
query += ` GROUP BY chain, day ORDER BY day ASC`;

return query;
}
14 changes: 13 additions & 1 deletion src/utils.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { expect, test } from "bun:test";
import { parseBlockId, parseBlockNumber, parseChain, parseLimit, parseSortBy, parseTimestamp, parseAggregateColumn, parseAggregateFunction } from "./utils.js";
import { parseBlockId, parseBlockNumber, parseChain, parseLimit, parseSortBy,
parseTimestamp, parseAggregateColumn, parseAggregateFunction, parseHistoryRange } from "./utils.js";
import { DEFAULT_MAX_LIMIT, DEFAULT_SORT_BY } from "./config.js";
import { parse } from "querystring";

test("parseBlockId", () => {
expect(parseBlockId()).toBeUndefined();
Expand Down Expand Up @@ -84,4 +86,14 @@ test("parseAggregateColumn", () => {
expect(parseAggregateColumn("transaction_traces")).toBe("transaction_traces");
expect(parseAggregateColumn("trace_calls")).toBe("trace_calls");
expect(parseAggregateColumn("total_uaw")).toBe("total_uaw");
});

test("parseHistoryRange", () => {
expect(parseHistoryRange()).toBe("7d");
expect(parseHistoryRange(null)).toBe("7d");
expect(parseHistoryRange("invalid")).toBe("7d");
expect(parseHistoryRange("24h")).toBe("24h");
expect(parseHistoryRange("7d")).toBe("7d");
expect(parseHistoryRange("1y")).toBe("1y");
expect(parseHistoryRange("all")).toBe("all");
});
36 changes: 22 additions & 14 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,15 @@ import { DEFAULT_SORT_BY, DEFAULT_AGGREGATE_FUNCTION, config } from "./config.js
import { logger } from './logger.js';
import { store } from "./clickhouse/stores.js";
import { toText } from './fetch/cors.js';
import { Query } from './clickhouse/makeQuery.js';
import { UAWHistory } from './queries.js';

export interface FormattedUAWHistory {
[chain: string]: {
UAW: number[];
day: number[];
};
}

export function parseBlockId(block_id?: string|null) {
// Match against hexadecimal string (with or without '0x' prefix)
if (!z.string().regex(/^(0x)?[a-fA-F0-9]+$/).safeParse(block_id).success) {
Expand Down Expand Up @@ -103,20 +109,22 @@ export async function verifyParameters(req: Request) {
}

export function parseUAWResponse(data: UAWHistory[]) {
const formattedData = {
'UAW' : data.map(item => parseInt(item.UAW)),
'day' : data.map(item => item.day)
}
return formattedData;
return data.reduce((formattedData, item) => {
const { chain, UAW, day } = item;

formattedData[chain] = formattedData[chain] || { UAW: [], day: [] };

formattedData[chain].UAW.push(parseInt(UAW, 10));
formattedData[chain].day.push(day);

return formattedData;
}, {} as FormattedUAWHistory);
}

export function parseHistoryRange(range: string|null|number) {
let value = 7;
if (range) {
if (typeof range === "string") value = parseInt(range);
if (typeof range === "number") value = range;
export function parseHistoryRange(range?: string|null) {
if (!z.enum(["24h", "7d", "30d", "90d", "1y", "all"]).safeParse(range).success) {
return "7d";
}
// Must be non-negative number
if ( value && value <= 0 ) value = 7;
return value;

return range;
}

0 comments on commit faccf5d

Please sign in to comment.