Skip to content

Commit 8520373

Browse files
committed
edited notes: recognize dateNote label value TODAY, MONTH, YEAR
1 parent bf9b926 commit 8520373

File tree

2 files changed

+128
-1
lines changed

2 files changed

+128
-1
lines changed
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
2+
import dayjs from "dayjs";
3+
import { resolveDateParams } from "./edited-notes.js";
4+
5+
function resolveAsDate(dateStr: string) {
6+
return resolveDateParams(dateStr).date;
7+
}
8+
9+
describe("edited-notes::resolveAsDate", () => {
10+
beforeEach(() => {
11+
// Set a fixed date and time before each test
12+
vi.useFakeTimers();
13+
vi.setSystemTime(new Date('2012-11-10T23:22:21Z')); // NOTE!!: Date wrap in my timezone
14+
});
15+
16+
afterEach(() => {
17+
// Restore real timers after each test
18+
vi.useRealTimers();
19+
});
20+
21+
22+
it("resolves 'TODAY' to today's date", () => {
23+
const expectedDate = dayjs().format("YYYY-MM-DD");
24+
const resolvedDate = resolveAsDate("TODAY");
25+
expect(resolvedDate).toBe(expectedDate);
26+
});
27+
28+
it("resolves 'MONTH' to current month", () => {
29+
const expectedMonth = dayjs().format("YYYY-MM");
30+
const resolvedMonth = resolveAsDate("MONTH");
31+
expect(resolvedMonth).toBe(expectedMonth);
32+
});
33+
34+
it("resolves 'YEAR' to current year", () => {
35+
const expectedYear = dayjs().format("YYYY");
36+
const resolvedYear = resolveAsDate("YEAR");
37+
expect(resolvedYear).toBe(expectedYear);
38+
});
39+
40+
it("resolves 'TODAY-1' to yesterday's date", () => {
41+
const expectedDate = dayjs().subtract(1, "day").format("YYYY-MM-DD");
42+
const resolvedDate = resolveAsDate("TODAY-1");
43+
expect(resolvedDate).toBe(expectedDate);
44+
});
45+
46+
it("resolves 'MONTH-2' to 2 months ago", () => {
47+
const expectedMonth = dayjs().subtract(2, "month").format("YYYY-MM");
48+
const resolvedMonth = resolveAsDate("MONTH-2");
49+
expect(resolvedMonth).toBe(expectedMonth);
50+
});
51+
52+
it("resolves 'YEAR+1' to next year", () => {
53+
const expectedYear = dayjs().add(1, "year").format("YYYY");
54+
const resolvedYear = resolveAsDate("YEAR+1");
55+
expect(resolvedYear).toBe(expectedYear);
56+
});
57+
58+
it("returns original string for unrecognized keyword", () => {
59+
const unrecognizedString = "NOT_A_DYNAMIC_DATE";
60+
const resolvedString = resolveAsDate(unrecognizedString);
61+
expect(resolvedString).toBe(unrecognizedString);
62+
});
63+
64+
it("returns original string for partially recognized keyword", () => {
65+
const partialString = "TODAY-";
66+
const resolvedString = resolveAsDate(partialString);
67+
expect(resolvedString).toBe(partialString);
68+
});
69+
70+
it("resolves 'today' (lowercase) to today's date", () => {
71+
const expectedDate = dayjs().format("YYYY-MM-DD");
72+
const resolvedDate = resolveAsDate("today");
73+
expect(resolvedDate).toBe(expectedDate);
74+
});
75+
76+
});

apps/server/src/routes/api/edited-notes.ts

Lines changed: 52 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import type { Request } from "express";
66
import { NotePojo } from "../../becca/becca-interface.js";
77
import type BNote from "../../becca/entities/bnote.js";
88
import { EditedNotesResponse } from "@triliumnext/commons";
9+
import dayjs from "dayjs";
910

1011
interface NotePath {
1112
noteId: string;
@@ -20,6 +21,9 @@ interface NotePojoWithNotePath extends NotePojo {
2021
}
2122

2223
function getEditedNotesOnDate(req: Request) {
24+
const resolvedDateParams = resolveDateParams(req.params.date);
25+
26+
const sqlParams = { date: resolvedDateParams.date + "%" };
2327

2428
const noteIds = sql.getColumn<string>(/*sql*/`\
2529
SELECT notes.*
@@ -35,7 +39,7 @@ function getEditedNotesOnDate(req: Request) {
3539
)
3640
ORDER BY isDeleted
3741
LIMIT 50`,
38-
{ date: `${req.params.date}%` }
42+
sqlParams
3943
);
4044

4145
let notes = becca.getNotes(noteIds, true);
@@ -81,6 +85,53 @@ function getNotePathData(note: BNote): NotePath | undefined {
8185
}
8286
}
8387

88+
function formatDateFromKeywordAndDelta(keyword: string, delta: number): string {
89+
const formatMap = new Map<string, { format: string, addUnit: dayjs.UnitType }>([
90+
["today", { format: "YYYY-MM-DD", addUnit: "day" }],
91+
["month", { format: "YYYY-MM", addUnit: "month" }],
92+
["year", { format: "YYYY", addUnit: "year" }]
93+
]);
94+
95+
const handler = formatMap.get(keyword);
96+
97+
if (!handler) {
98+
throw new Error(`Unrecognized keyword: ${keyword}`);
99+
}
100+
101+
const date = dayjs().add(delta, handler.addUnit);
102+
return date.format(handler.format);
103+
}
104+
105+
interface DateValue {
106+
// kind: "date",
107+
date: string,
108+
}
109+
110+
type DateFilter = DateValue;
111+
112+
/**
113+
* Resolves date keyword with optional delta (e.g., "TODAY-1") to date
114+
* @param dateStr date keyword (TODAY, MONTH, YEAR) or date in format YYYY-MM-DD (or beggining)
115+
* @returns
116+
*/
117+
export function resolveDateParams(dateStr: string): DateFilter {
118+
const match = dateStr.match(/^(today|month|year)([+-]\d+)?$/i);
119+
120+
if (!match) {
121+
return {
122+
date: `${dateStr}`
123+
}
124+
}
125+
126+
const keyword = match[1].toLowerCase();
127+
const delta = match[2] ? parseInt(match[2]) : 0;
128+
129+
const date = formatDateFromKeywordAndDelta(keyword, delta);
130+
return {
131+
date: `${date}`
132+
}
133+
}
134+
84135
export default {
85136
getEditedNotesOnDate,
86137
};

0 commit comments

Comments
 (0)