snapshot
This commit is contained in:
+35
-9
@@ -18,6 +18,7 @@ export type SnippetRow = {
|
||||
sort_order: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
deadline_at: string | null;
|
||||
tags: string[];
|
||||
/** Anzeige-Label pro Tag (Prefix + Name), gleiche Reihenfolge wie `tags`. */
|
||||
tag_display: string[];
|
||||
@@ -25,6 +26,17 @@ export type SnippetRow = {
|
||||
tag_colors: Record<string, string | null>;
|
||||
};
|
||||
|
||||
/** PATCH/POST: `undefined` = nicht ändern, `null` = entfernen. */
|
||||
export function normalizeDeadlineAtInput(raw: unknown): string | null | undefined {
|
||||
if (raw === undefined) return undefined;
|
||||
if (raw === null) return null;
|
||||
if (typeof raw !== "string") throw new Error("deadline_at muss ein String (YYYY-MM-DD) sein");
|
||||
const t = raw.trim();
|
||||
if (t === "") return null;
|
||||
if (!/^\d{4}-\d{2}-\d{2}$/.test(t)) throw new Error("deadline_at muss YYYY-MM-DD sein");
|
||||
return t;
|
||||
}
|
||||
|
||||
/** `tag:x`, `title:y`, `content:z` (case-insensitive); remainder = default (title OR tag names, LIKE). All parts AND. */
|
||||
function parseSearchQuery(raw: string): {
|
||||
defaultText: string | null;
|
||||
@@ -69,6 +81,10 @@ function orderClause(sort: string): string {
|
||||
return "ORDER BY s.title COLLATE NOCASE ASC NULLS LAST, s.updated_at DESC";
|
||||
case "title_desc":
|
||||
return "ORDER BY s.title COLLATE NOCASE DESC NULLS LAST, s.updated_at DESC";
|
||||
case "deadline_asc":
|
||||
return "ORDER BY s.deadline_at ASC NULLS LAST, s.updated_at DESC";
|
||||
case "deadline_desc":
|
||||
return "ORDER BY s.deadline_at DESC NULLS LAST, s.updated_at DESC";
|
||||
case "manual":
|
||||
return "ORDER BY s.sort_order ASC, s.updated_at DESC";
|
||||
case "updated_desc":
|
||||
@@ -107,6 +123,7 @@ function rowToPublic(
|
||||
sort_order: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
deadline_at: string | null;
|
||||
},
|
||||
tagsRaw: string[],
|
||||
): SnippetRow {
|
||||
@@ -124,6 +141,7 @@ function rowToPublic(
|
||||
sort_order: row.sort_order,
|
||||
created_at: row.created_at,
|
||||
updated_at: row.updated_at,
|
||||
deadline_at: row.deadline_at,
|
||||
tags,
|
||||
tag_display,
|
||||
tag_colors,
|
||||
@@ -142,12 +160,13 @@ export function listSnippets(q: string | null, sort: string | null): SnippetRow[
|
||||
sort_order: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
deadline_at: string | null;
|
||||
}[];
|
||||
|
||||
if (trimmed === "") {
|
||||
rows = database
|
||||
.query(
|
||||
`SELECT s.id, s.title, s.body, s.sort_order, s.created_at, s.updated_at
|
||||
`SELECT s.id, s.title, s.body, s.sort_order, s.created_at, s.updated_at, s.deadline_at
|
||||
FROM snippets s
|
||||
${order}`,
|
||||
)
|
||||
@@ -229,7 +248,7 @@ export function listSnippets(q: string | null, sort: string | null): SnippetRow[
|
||||
if (conditions.length === 0) {
|
||||
rows = database
|
||||
.query(
|
||||
`SELECT s.id, s.title, s.body, s.sort_order, s.created_at, s.updated_at
|
||||
`SELECT s.id, s.title, s.body, s.sort_order, s.created_at, s.updated_at, s.deadline_at
|
||||
FROM snippets s
|
||||
${order}`,
|
||||
)
|
||||
@@ -238,7 +257,7 @@ export function listSnippets(q: string | null, sort: string | null): SnippetRow[
|
||||
const where = conditions.join(" AND ");
|
||||
rows = database
|
||||
.query(
|
||||
`SELECT s.id, s.title, s.body, s.sort_order, s.created_at, s.updated_at
|
||||
`SELECT s.id, s.title, s.body, s.sort_order, s.created_at, s.updated_at, s.deadline_at
|
||||
FROM snippets s
|
||||
WHERE ${where}
|
||||
${order}`,
|
||||
@@ -256,7 +275,7 @@ export function getSnippetById(id: number): SnippetRow | null {
|
||||
const database = getDb();
|
||||
const row = database
|
||||
.query(
|
||||
`SELECT id, title, body, sort_order, created_at, updated_at FROM snippets WHERE id = ?`,
|
||||
`SELECT id, title, body, sort_order, created_at, updated_at, deadline_at FROM snippets WHERE id = ?`,
|
||||
)
|
||||
.get(id) as
|
||||
| {
|
||||
@@ -266,6 +285,7 @@ export function getSnippetById(id: number): SnippetRow | null {
|
||||
sort_order: number;
|
||||
created_at: string;
|
||||
updated_at: string;
|
||||
deadline_at: string | null;
|
||||
}
|
||||
| undefined;
|
||||
if (!row) return null;
|
||||
@@ -300,6 +320,7 @@ export function createSnippet(input: {
|
||||
body?: string;
|
||||
tags?: string[];
|
||||
sort_order?: number;
|
||||
deadline_at?: string | null;
|
||||
}): SnippetRow {
|
||||
const database = getDb();
|
||||
const t = nowIso();
|
||||
@@ -311,10 +332,12 @@ export function createSnippet(input: {
|
||||
: String(input.title).trim();
|
||||
const body = input.body ?? "";
|
||||
const sortOrder = typeof input.sort_order === "number" ? input.sort_order : Date.now();
|
||||
const deadlineAt =
|
||||
input.deadline_at === undefined ? null : input.deadline_at === null ? null : String(input.deadline_at).trim() || null;
|
||||
|
||||
database.run(
|
||||
`INSERT INTO snippets (title, body, sort_order, created_at, updated_at) VALUES (?, ?, ?, ?, ?)`,
|
||||
[title, body, sortOrder, t, t],
|
||||
`INSERT INTO snippets (title, body, sort_order, created_at, updated_at, deadline_at) VALUES (?, ?, ?, ?, ?, ?)`,
|
||||
[title, body, sortOrder, t, t, deadlineAt],
|
||||
);
|
||||
const idRow = database.query(`SELECT last_insert_rowid() AS id`).get() as { id: number };
|
||||
const newId = Number(idRow.id);
|
||||
@@ -329,6 +352,7 @@ export function updateSnippet(
|
||||
body?: string;
|
||||
tags?: string[];
|
||||
sort_order?: number;
|
||||
deadline_at?: string | null;
|
||||
},
|
||||
): SnippetRow | null {
|
||||
const database = getDb();
|
||||
@@ -336,11 +360,12 @@ export function updateSnippet(
|
||||
if (!existing) return null;
|
||||
|
||||
const current = database
|
||||
.query(`SELECT title, body, sort_order FROM snippets WHERE id = ?`)
|
||||
.query(`SELECT title, body, sort_order, deadline_at FROM snippets WHERE id = ?`)
|
||||
.get(id) as {
|
||||
title: string | null;
|
||||
body: string;
|
||||
sort_order: number;
|
||||
deadline_at: string | null;
|
||||
};
|
||||
|
||||
const title =
|
||||
@@ -351,11 +376,12 @@ export function updateSnippet(
|
||||
: String(input.title).trim();
|
||||
const body = input.body === undefined ? current.body : String(input.body);
|
||||
const sort_order = input.sort_order === undefined ? current.sort_order : input.sort_order;
|
||||
const deadline_at = input.deadline_at === undefined ? current.deadline_at : input.deadline_at;
|
||||
const t = nowIso();
|
||||
|
||||
database.run(
|
||||
`UPDATE snippets SET title = ?, body = ?, sort_order = ?, updated_at = ? WHERE id = ?`,
|
||||
[title, body, sort_order, t, id],
|
||||
`UPDATE snippets SET title = ?, body = ?, sort_order = ?, deadline_at = ?, updated_at = ? WHERE id = ?`,
|
||||
[title, body, sort_order, deadline_at, t, id],
|
||||
);
|
||||
|
||||
if (input.tags !== undefined) {
|
||||
|
||||
Reference in New Issue
Block a user