add models, migrations, and CRUD
Schema mirrors the webapp tasks module's ScheduledEvent + EventCompletion shape: - tasks.tasks (NIP-52 kind 31922 cache): (pubkey, d_tag) is the parameterized-replaceable key. JSON-encoded participants / categories / recurrence columns are decoded on read via _parse_task_row so each model can keep clean field validators. - tasks.completions (kind 31925 cache): unique on (task_address, pubkey, occurrence). occurrence is NULL for one-shot tasks; create_completion deletes any prior claim for the same triple so the latest event wins. - tasks.settings: singleton row with public_listing toggle. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
bc88b421b6
commit
6fbb6d4a42
3 changed files with 521 additions and 3 deletions
|
|
@ -1 +1,76 @@
|
|||
# Migrations are filled in by the next commit.
|
||||
async def m001_initial(db):
|
||||
"""
|
||||
Tasks table (NIP-52 kind 31922 cache) and completions table (kind 31925
|
||||
cache). The (pubkey, d_tag) pair is the parameterized-replaceable key.
|
||||
"""
|
||||
await db.execute(
|
||||
f"""
|
||||
CREATE TABLE tasks.tasks (
|
||||
id TEXT PRIMARY KEY,
|
||||
wallet TEXT NOT NULL,
|
||||
pubkey TEXT NOT NULL,
|
||||
d_tag TEXT NOT NULL,
|
||||
title TEXT NOT NULL,
|
||||
start_date TEXT NOT NULL,
|
||||
end_date TEXT,
|
||||
description TEXT NOT NULL DEFAULT '',
|
||||
location TEXT,
|
||||
status TEXT NOT NULL DEFAULT 'pending',
|
||||
event_type TEXT NOT NULL DEFAULT 'task',
|
||||
participants TEXT,
|
||||
categories TEXT,
|
||||
recurrence TEXT,
|
||||
nostr_event_id TEXT,
|
||||
nostr_event_created_at INTEGER,
|
||||
time TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}
|
||||
);
|
||||
"""
|
||||
)
|
||||
await db.execute(
|
||||
"CREATE UNIQUE INDEX tasks_pubkey_dtag_idx "
|
||||
"ON tasks.tasks (pubkey, d_tag)"
|
||||
)
|
||||
|
||||
await db.execute(
|
||||
f"""
|
||||
CREATE TABLE tasks.completions (
|
||||
id TEXT PRIMARY KEY,
|
||||
task_address TEXT NOT NULL,
|
||||
pubkey TEXT NOT NULL,
|
||||
occurrence TEXT,
|
||||
task_status TEXT NOT NULL DEFAULT 'claimed',
|
||||
completed_at INTEGER,
|
||||
notes TEXT NOT NULL DEFAULT '',
|
||||
nostr_created_at INTEGER NOT NULL,
|
||||
time TIMESTAMP NOT NULL DEFAULT {db.timestamp_now}
|
||||
);
|
||||
"""
|
||||
)
|
||||
# occurrence is NULL for one-shot tasks; the (task_address, pubkey,
|
||||
# occurrence) tuple identifies "the latest claim by this user for this
|
||||
# specific occurrence".
|
||||
await db.execute(
|
||||
"CREATE INDEX tasks_completions_address_idx "
|
||||
"ON tasks.completions (task_address)"
|
||||
)
|
||||
await db.execute(
|
||||
"CREATE INDEX tasks_completions_pubkey_idx "
|
||||
"ON tasks.completions (pubkey)"
|
||||
)
|
||||
|
||||
|
||||
async def m002_settings(db):
|
||||
"""Singleton settings row for the admin UI."""
|
||||
await db.execute(
|
||||
"""
|
||||
CREATE TABLE IF NOT EXISTS tasks.settings (
|
||||
id INTEGER PRIMARY KEY DEFAULT 1,
|
||||
public_listing BOOLEAN NOT NULL DEFAULT FALSE
|
||||
)
|
||||
"""
|
||||
)
|
||||
await db.execute(
|
||||
"INSERT INTO tasks.settings (id, public_listing) "
|
||||
"SELECT 1, FALSE WHERE NOT EXISTS "
|
||||
"(SELECT 1 FROM tasks.settings WHERE id = 1)"
|
||||
)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue