| | 103 | |
| | 104 | === 2. Validate and insert story into user reading list with confirmation |
| | 105 | {{{ |
| | 106 | WITH |
| | 107 | published_story AS ( |
| | 108 | SELECT s.story_id, s.short_description |
| | 109 | FROM story s |
| | 110 | JOIN status st ON s.story_id = st.story_id |
| | 111 | WHERE s.story_id = 1 |
| | 112 | AND st.status = 'published' |
| | 113 | ), |
| | 114 | user_list AS ( |
| | 115 | SELECT list_id, list_name, is_public |
| | 116 | FROM reading_list |
| | 117 | WHERE list_id = 1 |
| | 118 | AND user_id = 4 |
| | 119 | ), |
| | 120 | already_added AS ( |
| | 121 | SELECT 1 |
| | 122 | FROM reading_list_items |
| | 123 | WHERE list_id = 1 |
| | 124 | AND story_id = 1 |
| | 125 | ), |
| | 126 | inserted AS ( |
| | 127 | INSERT INTO reading_list_items (list_id, story_id, added_at) |
| | 128 | SELECT ul.list_id, ps.story_id, CURRENT_TIMESTAMP |
| | 129 | FROM user_list ul |
| | 130 | CROSS JOIN published_story ps |
| | 131 | WHERE NOT EXISTS (SELECT 1 FROM already_added) |
| | 132 | RETURNING list_id, story_id, added_at |
| | 133 | ) |
| | 134 | SELECT |
| | 135 | rl.list_id, |
| | 136 | rl.list_name, |
| | 137 | rl.is_public, |
| | 138 | u.username AS owner, |
| | 139 | COUNT(rli.story_id) AS total_items, |
| | 140 | MAX(rli.added_at) AS last_added_at, |
| | 141 | CASE |
| | 142 | WHEN ins.story_id IS NOT NULL THEN 'Story successfully added' |
| | 143 | WHEN EXISTS (SELECT 1 FROM already_added) THEN 'Story already in list' |
| | 144 | ELSE 'Failed: story not published or list not found' |
| | 145 | END AS result_message |
| | 146 | FROM reading_list rl |
| | 147 | JOIN users u ON rl.user_id = u.user_id |
| | 148 | LEFT JOIN reading_list_items rli ON rl.list_id = rli.list_id |
| | 149 | LEFT JOIN inserted ins ON ins.list_id = rl.list_id |
| | 150 | WHERE rl.list_id = 1 |
| | 151 | GROUP BY rl.list_id, rl.list_name, rl.is_public, u.username, ins.story_id; |
| | 152 | }}} |
| | 153 | |
| | 154 | === Relational Algebra |
| | 155 | {{{ |
| | 156 | |
| | 157 | PublishedStory <- |
| | 158 | π story_id, short_description |
| | 159 | ( |
| | 160 | σ s.story_id = :story_id ∧ st.status = 'published' |
| | 161 | ( |
| | 162 | story s |
| | 163 | ⨝ (s.story_id = st.story_id) status st |
| | 164 | ) |
| | 165 | ) |
| | 166 | |
| | 167 | UserList <- |
| | 168 | σ list_id = :list_id ∧ user_id = :user_id |
| | 169 | ( |
| | 170 | reading_list |
| | 171 | ) |
| | 172 | |
| | 173 | AlreadyAdded <- |
| | 174 | σ list_id = :list_id ∧ story_id = :story_id |
| | 175 | ( |
| | 176 | reading_list_items |
| | 177 | ) |
| | 178 | |
| | 179 | NewItem <- |
| | 180 | { (list_id := :list_id, story_id := :story_id, added_at := CURRENT_TIMESTAMP) } |
| | 181 | |
| | 182 | ToInsert <- |
| | 183 | (UserList ⨯ PublishedStory) |
| | 184 | − π list_id, story_id, added_at (AlreadyAdded) |
| | 185 | |
| | 186 | reading_list_items <- reading_list_items ∪ ToInsert |
| | 187 | |
| | 188 | UpdatedCount <- |
| | 189 | γ list_id; |
| | 190 | total_items := COUNT(story_id), |
| | 191 | last_added := MAX(added_at) |
| | 192 | ( |
| | 193 | σ list_id = :list_id (reading_list_items) |
| | 194 | ) |
| | 195 | |
| | 196 | Result <- |
| | 197 | π |
| | 198 | rl.list_id, |
| | 199 | rl.list_name, |
| | 200 | rl.is_public, |
| | 201 | u.username → owner, |
| | 202 | uc.total_items, |
| | 203 | uc.last_added, |
| | 204 | CASE |
| | 205 | WHEN ins.story_id IS NOT NULL → 'Story successfully added' |
| | 206 | WHEN AlreadyAdded ≠ ∅ → 'Story already in list' |
| | 207 | ELSE 'Failed: story not published or list not found' |
| | 208 | END → result_message |
| | 209 | ( |
| | 210 | ( |
| | 211 | reading_list rl |
| | 212 | ⨝ (rl.user_id = u.user_id) users u |
| | 213 | ) |
| | 214 | ⨝ (rl.list_id = uc.list_id) UpdatedCount uc |
| | 215 | ⟕ (rl.list_id = ins.list_id) ToInsert ins |
| | 216 | ) |
| | 217 | }}} |