Fix "fetch more" button

This sent a lot of unnecessary requests, because the `min_id` / `max_id`
parameters that were fetched from the database were way off. No idea why
exactly that happened, but aggregating the result manually seems to work
fine.
This commit is contained in:
arne 2025-11-20 19:36:32 +01:00
commit a06ec7ceae
2 changed files with 109 additions and 63 deletions

View file

@ -27,7 +27,6 @@
; TODO: Handle other lists
:section/posts posts-init-state}))
; TODO Ensure that cached data is up to date
; TODO Handle 429
; TODO Search for tags (`#foo`) and handles (`@bar`)
; TODO Explain which kind of search currently is possible
@ -156,7 +155,7 @@
(declare debounced-refresh!)
(defn- fetch-application-settings []
(->> (db/open-cursor! ::db/application db/all)
(->> (db/open-cursor! ::db/application ::db/all)
(db/first-result (map #(js->clj % :keywordize-keys true)))))
(defn setup-application!
@ -253,7 +252,8 @@
(swap! state update-in [:section/posts :loading] conj req-id)
(-> (mastodon-request! {:url url :bearer-token bearer-token})
(.then (fn [response]
(let [next-url (link-header "next" (:raw response))]
(let [url-params (url->search-params (.-url (:raw response)))
next-url (link-header (if (.get url-params "min_id") "prev" "next") (:raw response))]
(swap! state update-in [:section/posts :loading] disj req-id)
(on-response response)
(when (and (continue? response) next-url)
@ -381,7 +381,9 @@
refresh-id (js/Date.now)]
(swap! state update-in [:section/posts :loading] conj refresh-id)
(. (promise-all [(db/count! ::db/posts)
(->> (db/open-cursor! ::db/posts ::db/post-created-at db/all "prev")
(->> (db/open-cursor! ::db/posts ::db/all
{:index ::db/post-created-at
:direction :desc})
(db/transduce-cursor xform))])
(then (fn [[total displayed-posts]]
(swap! state update :section/posts #(-> (assoc % :total total)
@ -395,6 +397,7 @@
:on-response (fn [response]
(let [url-params (url->search-params (.-url (:raw response)))]
(doseq [post (:body response)]
; this returns a promise, but we don't care if these updates happen in sequence
(db/put! ::db/posts (cond-> post
; these IDs are internal server ids and it looks like
; they are not returned in any response; they are
@ -403,28 +406,41 @@
; if outer circumstances decide so (for example if the
; tab is closed)
(.get url-params "max_id")
(assoc :internal_id (.get url-params "max_id"))
(assoc :internal_id (parse-long (.get url-params "max_id")))
(.get url-params "min_id")
(assoc :internal_id (.get url-params "min_id"))))))
(assoc :internal_id (parse-long (.get url-params "min_id")))))))
(debounced-refresh! (:section/posts @state)))}]
(paginate-posts! (merge defaults opts))))
(defn- internal-post-id [max-or-min]
(->> (db/open-cursor! ::db/posts ::db/post-created-at db/all (if (= max-or-min :min)
"next"
"prev"))
(db/first-result (keep (j/get :internal_id)))))
(defn- internal-post-id
"Returns a promise which resolves to the smallest or largest internal post id.
This is useful to continue interrupted paginated requests."
[max-or-min]
; this may look like a horribly inefficient way to get these numbers, and it is!
; there was an earlier version that simply used an index on :internal_id and
; retrieved the first result in ascending or descending order; however, the
; result that was returned was unexpected and unreliable. this may very well
; have been my fault, because i'm only learning how the indexeddb api works as
; i implement all of this here.
(let [xform (comp (keep (j/get :internal_id)))
rf (if (= max-or-min :min) min max)
init (if (= max-or-min :min) js/Number.POSITIVE_INFINITY js/Number.NEGATIVE_INFINITY)]
(. (->> (db/open-cursor! ::db/posts ::db/all)
(db/transduce-cursor xform rf init))
(then (fn [result]
(when-not (infinite? result)
result))))))
(defn fetch-more-posts! [e]
(.preventDefault e)
(. (promise-all [(fetch-application-settings) (internal-post-id :min) (internal-post-id :max)])
(then (fn [[application min-id max-id]]
(when min-id
(when max-id
(fetch-posts! {:instance-url (:instance_url application)
:bearer-token (:bearer_token application)
:min-id max-id}))
(when max-id
(when min-id
(fetch-posts! {:instance-url (:instance_url application)
:bearer-token (:bearer_token application)
:max-id min-id}))
@ -513,6 +529,14 @@
(-> (db/open-store txn ::db/posts "readwrite")
(db/create-index! ::db/post-internal-id "internal_id" {:unique false})))})
(defn- convert-internal-ids! []
; TODO figure out when we can remove this again
(. (->> (db/open-cursor! ::db/posts ::db/all)
(db/transduce-cursor (filter (comp string? (j/get :internal_id)))))
(then (fn [rows]
(doseq [row rows]
(db/put! ::db/posts (j/update! row :internal_id parse-long)))))))
;; go go go
(defn ^:dev/after-load render []
@ -523,5 +547,6 @@
(render)
(-> (db/setup! ::database db-version migrations)
(.then #(setup-application!))
(.then #(convert-internal-ids!))
(.catch (fn [err]
(js/console.log ::db/setup! err)))))
(js/console.error ::db/setup! err)))))