-
Notifications
You must be signed in to change notification settings - Fork 0
Open
Description
Just using GH for communication, this isn't a specific issue.
Working on simple invariant query examples - the one below is intended to ensure that all writes to user/points are >= the preceding value - but written in such a way that a transaction would be rejected if any of its points values are decreasing.
(ns invariant.datahike-scratch
(:require [invariant.datahike]
[invariant.test.util
:refer [read-resource]]
[datahike.api :as d]
[datahike.core :as dc]))
(def schema
[#:db{:ident :user/points
:valueType :db.type/bigint
:cardinality :db.cardinality/one}])
(defn query [q db tx]
(d/q q
db
(dc/db-with db tx)
(dc/db-with (dc/empty-db) (concat schema tx))
tx))
(let [uri "datahike:mem:///invariant-test-2"]
(d/delete-database uri)
(d/create-database uri)
(let [conn (d/connect uri)]
(d/transact conn schema)
(d/transact conn [{:db/id 1 :user/points 1}
{:db/id 2 :user/points 1}])
(let [tx [[:db/add 1 :user/points 2]
[:db/add 2 :user/points 0]]]
(query '[:find ?all-valid .
:in $before $after $empty+tx $tx
:where
[(subquery
[:find (count ?entity) .
:where
[?entity :user/points _]]
$empty+tx) ?n-total]
[(subquery
[:find (count ?entity) .
:in $before $after $empty+tx
:where
[$after ?entity :user/points ?points-after]
[(get-else $before ?entity :user/points 0) ?points-before]
[(<= ?points-before ?points-after)]]
$before $after $empty+tx) ?n-valid]
[(= ?n-total ?n-valid) ?all-valid]]
@conn tx))))This works, but it's long. I'm sure I'm doing something dumb here, and that it'd be possible to write a short, single query which returns something falsy if any of the points are invalid (i.e. lifting the second subquery and flipping the :where to contain (> ?points-before ?points-after)) - and then doing something else that isn't clear to me.
Metadata
Metadata
Assignees
Labels
No labels