added tx-middleware capability and schema-middleware
There are some issues we are solving for datsync to make the datomic/datascript transition smoother and I wanted to get your thoughts on the possiblity of adding tx-middleware to datascript.
This would address issues #193 and #174 We will be using something along these lines in datsync, but I think it fits better in datascript itself.
- we still need to put the actual validation in as describe in #174 but the stub for it is hooked in
- In init-db I added an options map to turn off validation when it is undesirable which would allow people affected by #193 to make their own create-conn function in user space that skips validation
- tx-middleware will allow you to use
schema-middlewareto check txs for schema changes and put them into theschemamap, but this would also open up capabilities like adding validation middleware for all the datomic :db/valueType for people who want type safety rather than speed and other things of that nature - right now i put the
schema-middlewareindatascript.dbbut it could be put in its own ns if you think that makes more sense - brings us closer to full ident support without performance hits on people who don't need that
Usage would look like
(defn test-schema-middleware []
(let [conn (ds/create-conn)]
(ds/transact!
conn
[{:db/ident :test
:db/cardinality :db.cardinality/many}]
{:datascript.db/tx-middleware datascript.db/schema-middleware})
(ds/transact!
conn
[{:db/id -1
:test :a}
{:db/id -1
:test :b}])
@conn))
FWIW @tonsky, this was the original inspiration behind #150. At the time, Datsync and Posh were both needing to override various behavior of vanilla DataScript, and thought protocols might simplify things. Upon further reflection though, much of the behavior we wanted to override could be expressed via transaction middleware. I think if we get the shape of the tx-middleware idea right, it will be a much more composable way of getting much of the desired flexibility.
@bamarco Would you please describe the signature of the tx-middleware function to clarify how it handles database, tx-data and tx-report?
@tonsky Please let us know if you have any questions or concerns.
As currently written, tx-middleware is a function which takes a transaction-fn and returns a transaction-fn. The transaction-fn has the signature of datascript.db/transact-tx-data which takes in an initial-tx-report and some txs.
(defn schema-middleware [transact]
(fn [report txs]
(let [{:as report :keys [db-after tx-data]} (transact report txs)
db-after' (transduce
(filter schema-datom?)
conj-schema-datom
db-after
tx-data)]
(if (= (:schema db-after) (:schema db-after'))
report
(assoc report
:db-after (replace-schema db-after (:schema db-after')))))))