Dre*_*lee 7 database transactions clojure datomic
详细说来,大多数关系数据库都有数据库约束的概念.这是关于约束的Postgres 文档.Datomic提供哪些工具来约束数据或维护存储数据的一些不变量?
编辑 2019-06-28:自0.9.5927(Datomic On-Prem) / (Datomic Cloud) 以来,Datomic 通过Attribute Predicates、Entity Specs和Entity Predicates480-8770支持更精细的写入时验证。这使得大部分最初的答案无效或无关紧要。
特别是,观察实体谓词接受数据库值作为参数,因此它们实际上可以强制跨越多个实体的不变量。
默认情况下,Datomic 仅对可写入的数据强制执行一组非常有限的约束,其中主要包括:
:db.type/string[:db/add [:my.app/id "fjdsklfjsl"] :my.app/content 42]将失败[:my.app/id "fjdsklfjsl"]:db/add同一实体属性对有 2 个不同的值。(可能忘记了一些,如有请评论。)
特别是在撰写本文时,没有内置方法可以向给定属性添加自定义验证或“外键”约束。
然而,结合事务函数和推测写入(又名db.with())为您提供了一种强制执行任意不变量的强大方法。例如,您可以将事务包装在事务函数中,该函数使用 推测性地应用事务db.with(),然后在推测结果中搜索不变违规,如果发现某些违规则抛出异常。您甚至可以通过在 Datalog 中实现“搜索不变违规”部分来使此事务函数变得非常通用。
以下是 API 的示例:
[:myapp.fns/checking-invariants
;; a description of the invariant
{:query
[:find ?message ?user-id
:in $db-before $db-after ?tx-data ?tempids ?user-id
:where
[$db-before ?user :myapp.user/id ?user-id]
[$db-before ?user :myapp.user/email ?email-before]
[$db-after ?user :myapp.user/email ?email-after]
[(not= ?email-before ?email-after)]
[(ground "A user may not change her email") ?message]]
:inputs ["user-id-12342141"]}
;; the wrapped transaction
[[:db/add 125315815291 :myapp.user/email "hello.world@yopmail.com"]
[:db/add 125315815291 :myapp.user/name "Foo Bar"]]]
Run Code Online (Sandbox Code Playgroud)
这是(未经测试的)实现:myapp.fns/checking-invariants:
{:db/ident :myapp.fns/checking-invariants,
:db/fn #db/fn{:lang :clojure,
:imports [],
:requires [[datomic.api :as d]],
:params [db invariant-q tx],
:code
(let [{:keys [query inputs]} invariants-q
{:keys [db-before db-after tx-data tempids]}
(d/with db tx)]
(when-some [violations (apply d/q query
db-before db-after tx-data tempids
inputs)]
(throw (ex-info
"Transaction would violate invariants."
{:tx tx
:violations violations
:t (d/basis-t db-before)})))
tx)}}
Run Code Online (Sandbox Code Playgroud)
限制:
db.invoke()