mirror of
https://github.com/purrgrammer/grimoire.git
synced 2026-04-14 09:26:52 +02:00
feat: since and until
This commit is contained in:
@@ -391,26 +391,266 @@ describe("parseReqCommand", () => {
|
||||
});
|
||||
|
||||
describe("time flags (--since, --until)", () => {
|
||||
it("should parse unix timestamp for --since", () => {
|
||||
const result = parseReqCommand(["--since", "1234567890"]);
|
||||
expect(result.filter.since).toBe(1234567890);
|
||||
describe("unix timestamps", () => {
|
||||
it("should parse unix timestamp for --since", () => {
|
||||
const result = parseReqCommand(["--since", "1234567890"]);
|
||||
expect(result.filter.since).toBe(1234567890);
|
||||
});
|
||||
|
||||
it("should parse unix timestamp for --until", () => {
|
||||
const result = parseReqCommand(["--until", "1234567890"]);
|
||||
expect(result.filter.until).toBe(1234567890);
|
||||
});
|
||||
});
|
||||
|
||||
it("should parse relative time for --since (hours)", () => {
|
||||
const result = parseReqCommand(["--since", "2h"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
expect(result.filter.since).toBeGreaterThan(0);
|
||||
describe("relative time - seconds (s)", () => {
|
||||
it("should parse seconds for --since", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "30s"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
expect(result.filter.since).toBeGreaterThan(now - 35);
|
||||
expect(result.filter.since).toBeLessThan(now - 25);
|
||||
});
|
||||
|
||||
it("should parse 1 second for --since", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "1s"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
expect(result.filter.since).toBeGreaterThan(now - 5);
|
||||
expect(result.filter.since).toBeLessThan(now + 1);
|
||||
});
|
||||
|
||||
it("should parse seconds for --until", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--until", "30s"]);
|
||||
expect(result.filter.until).toBeDefined();
|
||||
expect(result.filter.until).toBeGreaterThan(now - 35);
|
||||
expect(result.filter.until).toBeLessThan(now - 25);
|
||||
});
|
||||
});
|
||||
|
||||
it("should parse relative time for --since (days)", () => {
|
||||
const result = parseReqCommand(["--since", "7d"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
expect(result.filter.since).toBeGreaterThan(0);
|
||||
describe("relative time - minutes (m)", () => {
|
||||
it("should parse minutes for --since", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "30m"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
const diff = now - result.filter.since!;
|
||||
expect(diff).toBeGreaterThan(1795); // 30m - 5s
|
||||
expect(diff).toBeLessThan(1805); // 30m + 5s
|
||||
});
|
||||
|
||||
it("should parse 1 minute for --since", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "1m"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
const diff = now - result.filter.since!;
|
||||
expect(diff).toBeGreaterThan(55); // 1m - 5s
|
||||
expect(diff).toBeLessThan(65); // 1m + 5s
|
||||
});
|
||||
});
|
||||
|
||||
it("should parse unix timestamp for --until", () => {
|
||||
const result = parseReqCommand(["--until", "1234567890"]);
|
||||
expect(result.filter.until).toBe(1234567890);
|
||||
describe("relative time - hours (h)", () => {
|
||||
it("should parse hours for --since", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "2h"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
const diff = now - result.filter.since!;
|
||||
expect(diff).toBeGreaterThan(7195); // 2h - 5s
|
||||
expect(diff).toBeLessThan(7205); // 2h + 5s
|
||||
});
|
||||
|
||||
it("should parse 24 hours for --since", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "24h"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
const diff = now - result.filter.since!;
|
||||
expect(diff).toBeGreaterThan(86395); // 24h - 5s
|
||||
expect(diff).toBeLessThan(86405); // 24h + 5s
|
||||
});
|
||||
});
|
||||
|
||||
describe("relative time - days (d)", () => {
|
||||
it("should parse days for --since", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "7d"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
const diff = now - result.filter.since!;
|
||||
expect(diff).toBeGreaterThan(604795); // 7d - 5s
|
||||
expect(diff).toBeLessThan(604805); // 7d + 5s
|
||||
});
|
||||
|
||||
it("should parse 1 day for --since", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "1d"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
const diff = now - result.filter.since!;
|
||||
expect(diff).toBeGreaterThan(86395); // 1d - 5s
|
||||
expect(diff).toBeLessThan(86405); // 1d + 5s
|
||||
});
|
||||
});
|
||||
|
||||
describe("relative time - weeks (w)", () => {
|
||||
it("should parse weeks for --since", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "2w"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
const diff = now - result.filter.since!;
|
||||
expect(diff).toBeGreaterThan(1209595); // 2w - 5s
|
||||
expect(diff).toBeLessThan(1209605); // 2w + 5s
|
||||
});
|
||||
|
||||
it("should parse 1 week for --since", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "1w"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
const diff = now - result.filter.since!;
|
||||
expect(diff).toBeGreaterThan(604795); // 1w - 5s
|
||||
expect(diff).toBeLessThan(604805); // 1w + 5s
|
||||
});
|
||||
});
|
||||
|
||||
describe("relative time - months (mo)", () => {
|
||||
it("should parse months for --since", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "3mo"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
const diff = now - result.filter.since!;
|
||||
// 3 months = 7776000 seconds (90 days)
|
||||
expect(diff).toBeGreaterThan(7775995); // 3mo - 5s
|
||||
expect(diff).toBeLessThan(7776005); // 3mo + 5s
|
||||
});
|
||||
|
||||
it("should parse 1 month for --since", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "1mo"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
const diff = now - result.filter.since!;
|
||||
// 1 month = 2592000 seconds (30 days)
|
||||
expect(diff).toBeGreaterThan(2591995); // 1mo - 5s
|
||||
expect(diff).toBeLessThan(2592005); // 1mo + 5s
|
||||
});
|
||||
});
|
||||
|
||||
describe("relative time - years (y)", () => {
|
||||
it("should parse years for --since", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "4y"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
const diff = now - result.filter.since!;
|
||||
// 4 years = 126144000 seconds (1460 days)
|
||||
expect(diff).toBeGreaterThan(126143995); // 4y - 5s
|
||||
expect(diff).toBeLessThan(126144005); // 4y + 5s
|
||||
});
|
||||
|
||||
it("should parse 1 year for --since", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "1y"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
const diff = now - result.filter.since!;
|
||||
// 1 year = 31536000 seconds (365 days)
|
||||
expect(diff).toBeGreaterThan(31535995); // 1y - 5s
|
||||
expect(diff).toBeLessThan(31536005); // 1y + 5s
|
||||
});
|
||||
});
|
||||
|
||||
describe("special keyword - now", () => {
|
||||
it("should parse 'now' for --since", () => {
|
||||
const before = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "now"]);
|
||||
const after = Math.floor(Date.now() / 1000);
|
||||
|
||||
expect(result.filter.since).toBeDefined();
|
||||
expect(result.filter.since).toBeGreaterThanOrEqual(before);
|
||||
expect(result.filter.since).toBeLessThanOrEqual(after);
|
||||
});
|
||||
|
||||
it("should parse 'now' for --until", () => {
|
||||
const before = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--until", "now"]);
|
||||
const after = Math.floor(Date.now() / 1000);
|
||||
|
||||
expect(result.filter.until).toBeDefined();
|
||||
expect(result.filter.until).toBeGreaterThanOrEqual(before);
|
||||
expect(result.filter.until).toBeLessThanOrEqual(after);
|
||||
});
|
||||
|
||||
it("should be case-insensitive for 'now'", () => {
|
||||
const result1 = parseReqCommand(["--since", "NOW"]);
|
||||
const result2 = parseReqCommand(["--since", "Now"]);
|
||||
const result3 = parseReqCommand(["--since", "now"]);
|
||||
|
||||
expect(result1.filter.since).toBeDefined();
|
||||
expect(result2.filter.since).toBeDefined();
|
||||
expect(result3.filter.since).toBeDefined();
|
||||
});
|
||||
|
||||
it("should work with other filters", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["-k", "1", "--since", "7d", "--until", "now"]);
|
||||
|
||||
expect(result.filter.kinds).toEqual([1]);
|
||||
expect(result.filter.since).toBeLessThan(now);
|
||||
expect(result.filter.until).toBeGreaterThanOrEqual(now - 1);
|
||||
expect(result.filter.until).toBeLessThanOrEqual(now + 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe("invalid time formats", () => {
|
||||
it("should return undefined for invalid time format", () => {
|
||||
const result = parseReqCommand(["--since", "invalid"]);
|
||||
expect(result.filter.since).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return undefined for time unit without number", () => {
|
||||
const result = parseReqCommand(["--since", "h"]);
|
||||
expect(result.filter.since).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return undefined for unsupported unit", () => {
|
||||
const result = parseReqCommand(["--since", "5x"]);
|
||||
expect(result.filter.since).toBeUndefined();
|
||||
});
|
||||
|
||||
it("should return undefined for negative time", () => {
|
||||
const result = parseReqCommand(["--since", "-5h"]);
|
||||
expect(result.filter.since).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
describe("combined time flags", () => {
|
||||
it("should parse both --since and --until", () => {
|
||||
const result = parseReqCommand([
|
||||
"--since",
|
||||
"7d",
|
||||
"--until",
|
||||
"1d",
|
||||
"-k",
|
||||
"1",
|
||||
]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
expect(result.filter.until).toBeDefined();
|
||||
expect(result.filter.since).toBeLessThan(result.filter.until!);
|
||||
expect(result.filter.kinds).toEqual([1]);
|
||||
});
|
||||
|
||||
it("should work with unix timestamps for time range", () => {
|
||||
const result = parseReqCommand([
|
||||
"--since",
|
||||
"1600000000",
|
||||
"--until",
|
||||
"1700000000",
|
||||
]);
|
||||
expect(result.filter.since).toBe(1600000000);
|
||||
expect(result.filter.until).toBe(1700000000);
|
||||
});
|
||||
|
||||
it("should work with mixed relative and unix timestamps", () => {
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const result = parseReqCommand(["--since", "7d", "--until", "1234567890"]);
|
||||
expect(result.filter.since).toBeDefined();
|
||||
expect(result.filter.since).toBeLessThan(now);
|
||||
expect(result.filter.until).toBe(1234567890);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -410,18 +410,24 @@ function isRelayDomain(value: string): boolean {
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse timestamp - supports unix timestamp, relative time (1h, 30m, 7d)
|
||||
* Parse timestamp - supports unix timestamp, relative time (1s, 30m, 2h, 7d, 2w, 3mo, 1y), or "now"
|
||||
*/
|
||||
function parseTimestamp(value: string): number | null {
|
||||
if (!value) return null;
|
||||
|
||||
// Special keyword: "now" - current timestamp
|
||||
if (value.toLowerCase() === "now") {
|
||||
return Math.floor(Date.now() / 1000);
|
||||
}
|
||||
|
||||
// Unix timestamp (10 digits)
|
||||
if (/^\d{10}$/.test(value)) {
|
||||
return parseInt(value, 10);
|
||||
}
|
||||
|
||||
// Relative time: 1h, 30m, 7d, 2w
|
||||
const relativeMatch = value.match(/^(\d+)([smhdw])$/);
|
||||
// Relative time: 30s, 1m, 2h, 7d, 2w, 3mo, 1y
|
||||
// Note: Using alternation to support multi-character units like "mo"
|
||||
const relativeMatch = value.match(/^(\d+)(s|m|h|d|w|mo|y)$/);
|
||||
if (relativeMatch) {
|
||||
const amount = parseInt(relativeMatch[1], 10);
|
||||
const unit = relativeMatch[2];
|
||||
@@ -433,6 +439,8 @@ function parseTimestamp(value: string): number | null {
|
||||
h: 3600,
|
||||
d: 86400,
|
||||
w: 604800,
|
||||
mo: 2592000, // 30 days (approximate month)
|
||||
y: 31536000, // 365 days (approximate year)
|
||||
};
|
||||
|
||||
return now - amount * multipliers[unit];
|
||||
|
||||
@@ -200,12 +200,12 @@ export const manPages: Record<string, ManPageEntry> = {
|
||||
{
|
||||
flag: "--since <time>",
|
||||
description:
|
||||
"Events after timestamp (unix timestamp or relative: 1h, 30m, 7d)",
|
||||
"Events after timestamp (unix timestamp, relative: 30s, 1m, 2h, 7d, 2w, 3mo, 1y, or 'now')",
|
||||
},
|
||||
{
|
||||
flag: "--until <time>",
|
||||
description:
|
||||
"Events before timestamp (unix timestamp or relative: 1h, 30m, 7d)",
|
||||
"Events before timestamp (unix timestamp, relative: 30s, 1m, 2h, 7d, 2w, 3mo, 1y, or 'now')",
|
||||
},
|
||||
{
|
||||
flag: "--search <text>",
|
||||
@@ -231,6 +231,9 @@ export const manPages: Record<string, ManPageEntry> = {
|
||||
"req -k 1 -a npub1...,npub2... Get notes from multiple authors (balances across outbox relays)",
|
||||
"req -a $me Get all your events (queries your outbox relays)",
|
||||
"req -k 1 -a $contacts --since 24h Get notes from contacts (queries their outbox relays)",
|
||||
"req -k 1 -a $contacts --since 7d Get notes from contacts in last week",
|
||||
"req -k 1 -a $contacts --since 3mo Get notes from contacts in last 3 months",
|
||||
"req -k 1 -a $contacts --since 1y Get notes from contacts in last year",
|
||||
"req -p $me -k 1,7 Get replies and reactions to you (queries your inbox relays)",
|
||||
"req -k 1 -a $me -a $contacts Get notes from you and contacts",
|
||||
"req -k 9735 -p $me --since 7d Get zaps you received (queries your inbox)",
|
||||
@@ -238,6 +241,7 @@ export const manPages: Record<string, ManPageEntry> = {
|
||||
"req -k 9735 -P $contacts Get zaps sent by your contacts",
|
||||
"req -k 1 -p verbiricha@habla.news Get notes mentioning user (queries their inbox)",
|
||||
"req -k 1 --since 1h relay.damus.io Get notes from last hour (manual relay override)",
|
||||
"req -k 1 --since 7d --until now Get notes from last week up to now",
|
||||
"req -k 1 --close-on-eose Get recent notes and close after EOSE",
|
||||
"req -t nostr,bitcoin -l 50 Get 50 events tagged #nostr or #bitcoin",
|
||||
"req --tag a 30023:abc...:article Get events referencing addressable event (#a tag)",
|
||||
|
||||
Reference in New Issue
Block a user