breadcrumps, todos, etc.
This commit is contained in:
+31
-1
@@ -11,7 +11,7 @@
|
||||
database-schema-version
|
||||
migrate-database!)
|
||||
|
||||
(define current-schema-version 3)
|
||||
(define current-schema-version 5)
|
||||
|
||||
(define schema-1-statements
|
||||
(list
|
||||
@@ -215,6 +215,30 @@ SQL
|
||||
(replace-page-todos! db (vector-ref row 0) (vector-ref row 1)))
|
||||
(record-schema-version! db 3))
|
||||
|
||||
|
||||
(define (migrate-3->4! db)
|
||||
(query-exec db
|
||||
#<<SQL
|
||||
CREATE TABLE IF NOT EXISTS bookmarks (
|
||||
user_id BIGINT NOT NULL REFERENCES users(id) ON DELETE CASCADE,
|
||||
page_id BIGINT NOT NULL REFERENCES pages(id) ON DELETE CASCADE,
|
||||
section TEXT NOT NULL DEFAULT '',
|
||||
position INTEGER NOT NULL DEFAULT 0,
|
||||
created_at BIGINT NOT NULL,
|
||||
PRIMARY KEY(user_id, page_id)
|
||||
)
|
||||
SQL
|
||||
)
|
||||
(query-exec db
|
||||
"CREATE INDEX IF NOT EXISTS bookmarks_user_idx ON bookmarks(user_id, section, position, created_at)")
|
||||
(record-schema-version! db 4))
|
||||
|
||||
(define (migrate-4->5! db)
|
||||
(for ((row (in-list (query-rows db "SELECT id, markdown FROM pages WHERE archived = FALSE"))))
|
||||
(replace-page-todos! db (vector-ref row 0) (vector-ref row 1)))
|
||||
(record-schema-version! db 5))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; goal : Bring a racket-wiki PostgreSQL database to the current schema.
|
||||
; pre : db is a writable PostgreSQL connection and config identifies the
|
||||
@@ -235,6 +259,12 @@ SQL
|
||||
(define after-attachments (database-schema-version db))
|
||||
(when (= after-attachments 2)
|
||||
(migrate-2->3! db))
|
||||
(define after-todos (database-schema-version db))
|
||||
(when (= after-todos 3)
|
||||
(migrate-3->4! db))
|
||||
(define after-bookmarks (database-schema-version db))
|
||||
(when (= after-bookmarks 4)
|
||||
(migrate-4->5! db))
|
||||
(define resulting-version (database-schema-version db))
|
||||
(when (> resulting-version current-schema-version)
|
||||
(error 'migrate-database!
|
||||
|
||||
@@ -22,6 +22,10 @@
|
||||
read-version
|
||||
search-pages
|
||||
list-todos
|
||||
list-recent-pages
|
||||
list-bookmarks
|
||||
set-bookmark!
|
||||
delete-bookmark!
|
||||
save-upload!
|
||||
uploaded-file)
|
||||
|
||||
@@ -390,6 +394,112 @@ SQL
|
||||
'line (vector-ref row 3)
|
||||
'text (vector-ref row 4))))))
|
||||
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; goal : List recently edited current wiki pages.
|
||||
; pre : PostgreSQL schema 1 or newer is initialized.
|
||||
; post : Page rows have only been read.
|
||||
; result : At most limit page metadata hashes, newest first.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define (list-recent-pages config [limit 50])
|
||||
(call-with-wiki-database
|
||||
config
|
||||
(λ (db)
|
||||
(for/list ((row (in-list
|
||||
(query-rows db
|
||||
(string-append "SELECT " page-columns
|
||||
" FROM pages WHERE archived = FALSE"
|
||||
" ORDER BY updated_at DESC, lower(title), title"
|
||||
" LIMIT $1")
|
||||
limit))))
|
||||
(row->page row #f)))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; goal : List bookmarks for one wiki user.
|
||||
; pre : PostgreSQL schema 4 or newer is initialized and user-id identifies a user.
|
||||
; post : Bookmark and page rows have only been read.
|
||||
; result : Bookmarks ordered by section and position.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define (list-bookmarks config user-id)
|
||||
(call-with-wiki-database
|
||||
config
|
||||
(λ (db)
|
||||
(for/list ((row (in-list
|
||||
(query-rows db
|
||||
#<<SQL
|
||||
SELECT p.slug, p.title, b.section, b.position, b.created_at, p.updated_at
|
||||
FROM bookmarks b
|
||||
JOIN pages p ON p.id = b.page_id
|
||||
WHERE b.user_id = $1
|
||||
AND p.archived = FALSE
|
||||
ORDER BY lower(b.section), b.section, b.position, b.created_at, lower(p.title), p.title
|
||||
SQL
|
||||
user-id))))
|
||||
(hash 'slug (vector-ref row 0)
|
||||
'title (vector-ref row 1)
|
||||
'section (vector-ref row 2)
|
||||
'position (vector-ref row 3)
|
||||
'createdAt (vector-ref row 4)
|
||||
'updatedAt (vector-ref row 5))))))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; goal : Add a page to a user's bookmarks or move it to another section.
|
||||
; pre : PostgreSQL schema 4 or newer is initialized and slug identifies a current page.
|
||||
; post : Exactly one bookmark exists for user-id and the page.
|
||||
; result : void.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define (set-bookmark! config user-id slug section)
|
||||
(call-with-wiki-database
|
||||
config
|
||||
(λ (db)
|
||||
(call-with-transaction
|
||||
db
|
||||
(λ ()
|
||||
(define page-id
|
||||
(query-maybe-value db
|
||||
"SELECT id FROM pages WHERE slug = $1 AND archived = FALSE"
|
||||
slug))
|
||||
(unless page-id
|
||||
(error 'set-bookmark! "unknown page: ~a" slug))
|
||||
(define clean-section (string-trim section))
|
||||
(define position
|
||||
(query-value db
|
||||
#<<SQL
|
||||
SELECT COALESCE(MAX(position), -1) + 1
|
||||
FROM bookmarks
|
||||
WHERE user_id = $1 AND section = $2
|
||||
SQL
|
||||
user-id
|
||||
clean-section))
|
||||
(query-exec db
|
||||
#<<SQL
|
||||
INSERT INTO bookmarks(user_id, page_id, section, position, created_at)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
ON CONFLICT (user_id, page_id)
|
||||
DO UPDATE SET section = EXCLUDED.section, position = EXCLUDED.position
|
||||
SQL
|
||||
user-id page-id clean-section position (current-seconds))))))
|
||||
(void))
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
; goal : Remove one page from a user's bookmarks.
|
||||
; pre : PostgreSQL schema 4 or newer is initialized.
|
||||
; post : The bookmark no longer exists; other bookmarks are unchanged.
|
||||
; result : void.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
(define (delete-bookmark! config user-id slug)
|
||||
(call-with-wiki-database
|
||||
config
|
||||
(λ (db)
|
||||
(query-exec db
|
||||
#<<SQL
|
||||
DELETE FROM bookmarks
|
||||
WHERE user_id = $1
|
||||
AND page_id = (SELECT id FROM pages WHERE slug = $2)
|
||||
SQL
|
||||
user-id slug)))
|
||||
(void))
|
||||
|
||||
(define (safe-file-name name)
|
||||
(define clean
|
||||
(regexp-replace* #px"[^A-Za-z0-9._ -]" name "_"))
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@
|
||||
((regexp-match? #px"^(```|~~~)" trimmed)
|
||||
(set! in-fence? (not in-fence?)))
|
||||
((not in-fence?)
|
||||
(for ((match (in-list (regexp-match* #px"todo\\([^()]+\\)" line))))
|
||||
(for ((match (in-list (regexp-match* #px"[Tt][Oo][Dd][Oo]\\([^()]+\\)" line))))
|
||||
(define text (string-trim (substring match 5 (- (string-length match) 1))))
|
||||
(when (not (string=? text ""))
|
||||
(set! item-number (+ item-number 1))
|
||||
|
||||
Reference in New Issue
Block a user