Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

## [Unreleased]

### Fixed
- Cancelling an in-flight initial query now leaves its cache entry stale so a
later `ensure-query` can retry it.
- Cancelling a query that never received a successful response now reverts the
status to `:idle` instead of leaving it at `:loading`.
### Changed
- **Breaking:** executing a query or mutation with no effect adapter (per-query/mutation `:effect-fn` or global default) now throws instead of passing the raw effects map through. The undocumented legacy form — `query-fn` returning a full effects map with hand-written callbacks — is removed; it let stale responses overwrite fresh data ([#6](https://github.com/shipclojure/re-frame-query/issues/6)).

Expand Down
1 change: 1 addition & 0 deletions src/re_frame/query.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@
and `:refetch-state`. Responses from the superseded requests are dropped
on arrival — `:data`, `:status` and `:error` are left as they are. No-op
when the query is not cached.
An in-flight entry is marked stale so `ensure-query` can retry it.

Use it when you write the cache yourself and do not want an older fetch to
win the race:
Expand Down
16 changes: 16 additions & 0 deletions src/re_frame/query/db.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,17 @@
(update db :re-frame.query/queries dissoc qid)
db)))

(defn compute-cancelled-status
"Return the :status a query should have after cancellation.

If the query never received a successful response (`:loading`), revert to
`:idle`. Otherwise keep the last finished status (`:success` or `:error`)."
[query-data]
(let [status (:status query-data)]
(if (= :loading status)
:idle
status)))

(defn cancel-query
"Cancel any pending request attempts by setting `request-id` on the query data.
Works by setting a new request-id on the query data, which will trigger the
Expand All @@ -107,6 +118,9 @@
[db k params query-config request-id]
(let [qid (util/query-id k params)
query-data (get-in db [:re-frame.query/queries qid])
in-flight? (or (:fetching? query-data)
(:fetching-next? query-data)
(:fetching-prev? query-data))
Comment thread
jramosg marked this conversation as resolved.
infinite? (util/infinite-query? query-config)]
(when (and request-id
(= (:request-id query-data) request-id))
Expand All @@ -121,7 +135,9 @@
(update-in db [:re-frame.query/queries qid]
util/merge-with-default
(cond-> {:request-id request-id
:status (compute-cancelled-status query-data)
:fetching? false}
in-flight? (assoc :stale? true)
infinite? (assoc :fetching-next? false
:fetching-prev? false
:refetch-state nil)))
Expand Down
25 changes: 25 additions & 0 deletions test/re_frame/query/supersession_test.cljc
Original file line number Diff line number Diff line change
Expand Up @@ -271,6 +271,31 @@
(is (nil? (query-entry qid))
"cancelling an uncached query does not create an entry"))))

(deftest cancel-query-allows-an-initial-request-to-retry
(testing "cancelling the initial load leaves the query stale"
(let [calls (reg-patients!)
qid (util/query-id :patients/page {:page 1})]
(h/process-event [:re-frame.query/ensure-query
:patients/page {:page 1}])
(h/process-event [:re-frame.query/cancel-query
:patients/page {:page 1}])
(let [query (query-entry qid)]
(is (= :idle (:status query))
"cancel reverts to :idle when there was no previous success")
(is (false? (:fetching? query)))
(is (true? (:stale? query))
"a cancelled initial request must remain retryable"))

(h/process-event [:re-frame.query/ensure-query
:patients/page {:page 1}])
(is (= 2 (count @calls))
"ensure-query retries after the initial request is cancelled")
(deliver! (:on-success (attempt calls 0)) [{:id :cancelled}])
(is (nil? (:data (query-entry qid)))
"the cancelled initial response is still dropped")
(deliver! (:on-success (attempt calls 1)) [{:id :fresh}])
(is (= [{:id :fresh}] (:data (query-entry qid)))))))

(deftest cancel-query-only-clears-paging-flags-for-infinite-queries
(testing "a cancelled regular query gains no infinite-only keys"
(reg-patients!)
Expand Down