From b31800a7db735d2909f87bedbe8dc018d5ed56e5 Mon Sep 17 00:00:00 2001 From: Glenn Thompson Date: Sat, 4 Oct 2025 17:40:25 +0300 Subject: [PATCH] Fix playlist schema mismatch - use track-ids field consistently - Fixed field name mismatch: schema uses 'track-ids' not 'tracks' - Handle Radiance DB storing text fields as lists - Parse/format comma-separated track IDs properly - Code is now correct but db:update still doesn't persist (i-lambdalite limitation) - Requires PostgreSQL for full functionality --- asteroid.lisp | 22 +++++++--- playlist-management.lisp | 86 ++++++++++++++++++++++++---------------- 2 files changed, 68 insertions(+), 40 deletions(-) diff --git a/asteroid.lisp b/asteroid.lisp index e9f65f3..e8e7611 100644 --- a/asteroid.lisp +++ b/asteroid.lisp @@ -77,15 +77,25 @@ ("playlists" . ,(mapcar (lambda (playlist) (let ((name-val (gethash "name" playlist)) (desc-val (gethash "description" playlist)) - (tracks-val (gethash "tracks" playlist)) + (track-ids-val (gethash "track-ids" playlist)) (created-val (gethash "created-date" playlist)) (id-val (gethash "_id" playlist))) (format t "Playlist ID: ~a (type: ~a)~%" id-val (type-of id-val)) - `(("id" . ,(if (listp id-val) (first id-val) id-val)) - ("name" . ,(if (listp name-val) (first name-val) name-val)) - ("description" . ,(if (listp desc-val) (first desc-val) desc-val)) - ("track-count" . ,(if tracks-val (length tracks-val) 0)) - ("created-date" . ,(if (listp created-val) (first created-val) created-val))))) + ;; Calculate track count from comma-separated string + ;; Handle nil, empty string, or list containing empty string + (let* ((track-ids-str (if (listp track-ids-val) + (first track-ids-val) + track-ids-val)) + (track-count (if (and track-ids-str + (stringp track-ids-str) + (not (string= track-ids-str ""))) + (length (cl-ppcre:split "," track-ids-str)) + 0))) + `(("id" . ,(if (listp id-val) (first id-val) id-val)) + ("name" . ,(if (listp name-val) (first name-val) name-val)) + ("description" . ,(if (listp desc-val) (first desc-val) desc-val)) + ("track-count" . ,track-count) + ("created-date" . ,(if (listp created-val) (first created-val) created-val)))))) playlists))))) (error (e) (cl-json:encode-json-to-string diff --git a/playlist-management.lisp b/playlist-management.lisp index bc1f363..1012fe6 100644 --- a/playlist-management.lisp +++ b/playlist-management.lisp @@ -13,9 +13,8 @@ (let ((playlist-data `(("user-id" ,user-id) ("name" ,name) ("description" ,(or description "")) - ("tracks" ()) - ("created-date" ,(local-time:timestamp-to-unix (local-time:now))) - ("modified-date" ,(local-time:timestamp-to-unix (local-time:now)))))) + ("track-ids" "") ; Empty string for text field + ("created-date" ,(local-time:timestamp-to-unix (local-time:now)))))) (format t "Creating playlist with user-id: ~a (type: ~a)~%" user-id (type-of user-id)) (format t "Playlist data: ~a~%" playlist-data) (db:insert "playlists" playlist-data) @@ -62,47 +61,56 @@ "Add a track to a playlist" (let ((playlist (get-playlist-by-id playlist-id))) (when playlist - (let* ((current-tracks (gethash "tracks" playlist)) - (tracks-list (if (and current-tracks (listp current-tracks)) - current-tracks - (if current-tracks (list current-tracks) nil))) - (new-tracks (append tracks-list (list track-id)))) + (let* ((current-track-ids-raw (gethash "track-ids" playlist)) + ;; Handle database storing as list - extract string + (current-track-ids (if (listp current-track-ids-raw) + (first current-track-ids-raw) + current-track-ids-raw)) + ;; Parse comma-separated string into list + (tracks-list (if (and current-track-ids + (stringp current-track-ids) + (not (string= current-track-ids ""))) + (mapcar #'parse-integer + (cl-ppcre:split "," current-track-ids)) + nil)) + (new-tracks (append tracks-list (list track-id))) + ;; Convert back to comma-separated string + (track-ids-str (format nil "~{~a~^,~}" new-tracks))) (format t "Adding track ~a to playlist ~a~%" track-id playlist-id) - (format t "Current tracks: ~a~%" current-tracks) + (format t "Current track-ids raw: ~a (type: ~a)~%" current-track-ids-raw (type-of current-track-ids-raw)) + (format t "Current track-ids: ~a~%" current-track-ids) (format t "Tracks list: ~a~%" tracks-list) (format t "New tracks: ~a~%" new-tracks) - - ;; Update using db:update with all fields - (let ((stored-id (gethash "_id" playlist)) - (user-id (gethash "user-id" playlist)) - (name (gethash "name" playlist)) - (description (gethash "description" playlist)) - (created-date (gethash "created-date" playlist))) - (format t "Updating playlist with stored ID: ~a~%" stored-id) - (format t "New tracks to save: ~a~%" new-tracks) - ;; Update all fields including tracks - (db:update "playlists" - (db:query :all) ; Update all, then filter in Lisp - `(("user-id" ,user-id) - ("name" ,name) - ("description" ,description) - ("tracks" ,new-tracks) - ("created-date" ,created-date) - ("modified-date" ,(local-time:timestamp-to-unix (local-time:now))))) - (format t "Update complete~%")) + (format t "Track IDs string: ~a~%" track-ids-str) + ;; Update using track-ids field (defined in schema) + (db:update "playlists" + (db:query (:= "_id" playlist-id)) + `(("track-ids" ,track-ids-str))) + (format t "Update complete~%") t)))) (defun remove-track-from-playlist (playlist-id track-id) "Remove a track from a playlist" (let ((playlist (get-playlist-by-id playlist-id))) (when playlist - (let* ((current-tracks (gethash "tracks" playlist)) - (tracks-list (if (listp current-tracks) current-tracks (list current-tracks))) - (new-tracks (remove track-id tracks-list :test #'equal))) + (let* ((current-track-ids-raw (gethash "track-ids" playlist)) + ;; Handle database storing as list - extract string + (current-track-ids (if (listp current-track-ids-raw) + (first current-track-ids-raw) + current-track-ids-raw)) + ;; Parse comma-separated string into list + (tracks-list (if (and current-track-ids + (stringp current-track-ids) + (not (string= current-track-ids ""))) + (mapcar #'parse-integer + (cl-ppcre:split "," current-track-ids)) + nil)) + (new-tracks (remove track-id tracks-list :test #'equal)) + ;; Convert back to comma-separated string + (track-ids-str (format nil "~{~a~^,~}" new-tracks))) (db:update "playlists" (db:query (:= "_id" playlist-id)) - `(("tracks" ,new-tracks) - ("modified-date" ,(local-time:timestamp-to-unix (local-time:now))))) + `(("track-ids" ,track-ids-str))) t)))) (defun delete-playlist (playlist-id) @@ -114,4 +122,14 @@ "Ensure playlists collection exists in database" (unless (db:collection-exists-p "playlists") (format t "Creating playlists collection...~%") - (db:create "playlists"))) + (db:create "playlists")) + + ;; Debug: Print the actual structure + (format t "~%=== PLAYLISTS COLLECTION STRUCTURE ===~%") + (format t "Structure: ~a~%~%" (db:structure "playlists")) + + ;; Debug: Check existing playlists + (let ((playlists (db:select "playlists" (db:query :all)))) + (when playlists + (format t "Sample playlist fields: ~{~a~^, ~}~%~%" + (alexandria:hash-table-keys (first playlists))))))