mentat/tx/fixtures/test_upsert_vector.edn
Nick Alexander dcd9bcb1ce Extract partial storage abstraction; use error-chain throughout. Fixes #328. r=rnewman (#341)
* Pre: Drop unneeded tx0 from search results.

* Pre: Don't require a schema in some of the DB code.

The idea is to separate the transaction applying code, which is
schema-aware, from the concrete storage code, which is just concerned
with getting bits onto disk.

* Pre: Only reference Schema, not DB, in debug module.

This is part of a larger separation of the volatile PartitionMap,
which is modified every transaction, from the stable Schema, which is
infrequently modified.

* Pre: Fix indentation.

* Extract part of DB to new SchemaTypeChecking trait.

* Extract part of DB to new PartitionMapping trait.

* Pre: Don't expect :db.part/tx partition to advance when tx fails.

This fails right now, because we allocate tx IDs even when we shouldn't.

* Sketch a db interface without DB.

* Add ValueParseError; use error-chain in tx-parser.

This can be simplified when
https://github.com/Marwes/combine/issues/86 makes it to a published
release, but this unblocks us for now.  This converts the `combine`
error type `ParseError<&'a [edn::Value]>` to a type with owned
`Vec<edn::Value>` collections, re-using `edn::Value::Vector` for
making them `Display`.

* Pre: Accept Borrow<Schema> instead of just &Schema in debug module.

This makes it easy to use Rc<Schema> or Arc<Schema> without inserting
&* sigils throughout the code.

* Use error-chain in query-parser.

There are a few things to point out here:

- the fine grained error types have been flattened into one crate-wide
  error type; it's pretty easy to regain the granularity as needed.

- edn::ParseError is automatically lifted to
  mentat_query_parser::errors::Error;

- we use mentat_parser_utils::ValueParser to maintain parsing error
  information from `combine`.

* Patch up top-level.

* Review comment: Only `borrow()` once.
2017-02-24 15:33:48 -08:00

122 lines
3.7 KiB
Clojure

[{:test/label ":db.cardinality/one, insert"
:test/assertions
[[:db/add 100 :db/ident :name/Ivan]
[:db/add 101 :db/ident :name/Petr]]
:test/expected-transaction
#{[100 :db/ident :name/Ivan ?tx1 true]
[101 :db/ident :name/Petr ?tx1 true]
[?tx1 :db/txInstant ?ms1 ?tx1 true]}
:test/expected-datoms
#{[100 :db/ident :name/Ivan]
[101 :db/ident :name/Petr]}}
{:test/label "upsert two tempids to same entid"
:test/assertions
[[:db/add "t1" :db/ident :name/Ivan]
[:db/add "t1" :db.schema/attribute 100]
[:db/add "t2" :db/ident :name/Petr]
[:db/add "t2" :db.schema/attribute 101]]
:test/expected-transaction
#{[100 :db.schema/attribute 100 ?tx2 true]
[101 :db.schema/attribute 101 ?tx2 true]
[?tx2 :db/txInstant ?ms2 ?tx2 true]}
:test/expected-datoms
#{[100 :db/ident :name/Ivan]
[101 :db/ident :name/Petr]
[100 :db.schema/attribute 100]
[101 :db.schema/attribute 101]}
:test/expected-tempids
{"t1" 100
"t2" 101}}
{:test/label "upsert with tempid"
:test/assertions
[[:db/add "t1" :db/ident :name/Ivan]
;; Ref doesn't have to exist (at this time). Can't reuse due to :db/unique :db.unique/value.
[:db/add "t1" :db.schema/attribute 102]]
:test/expected-transaction
#{[100 :db.schema/attribute 102 ?tx3 true]
[?tx3 :db/txInstant ?ms3 ?tx3 true]}
:test/expected-datoms
#{[100 :db/ident :name/Ivan]
[101 :db/ident :name/Petr]
[100 :db.schema/attribute 100]
[100 :db.schema/attribute 102]
[101 :db.schema/attribute 101]}
:test/expected-tempids
{"t1" 100}}
;; TODO: don't hard-code allocated entids.
{:test/label "single complex upsert allocates new entid"
:test/assertions
[[:db/add "t1" :db.schema/attribute "t2"]]
:test/expected-transaction
#{[65536 :db.schema/attribute 65537 ?tx4 true]
[?tx4 :db/txInstant ?ms4 ?tx4 true]}
:test/expected-tempids
{"t1" 65536
"t2" 65537}}
{:test/label "conflicting upserts fail"
:test/assertions
[[:db/add "t1" :db/ident :name/Ivan]
[:db/add "t1" :db/ident :name/Petr]]
:test/expected-transaction
nil
:test/expected-error-message
"Conflicting upsert"
;; nil
}
{:test/label "tempids in :db/retract that do upsert are fine"
:test/assertions
[[:db/add "t1" :db/ident :name/Ivan]
;; This ref doesn't exist, so the assertion will be ignored.
[:db/retract "t1" :db.schema/attribute 103]]
:test/expected-transaction
#{[?tx5 :db/txInstant ?ms5 ?tx5 true]}
:test/expected-error-message
""
:test/expected-tempids
{}}
{:test/label "tempids in :db/retract that don't upsert fail"
:test/assertions
[[:db/retract "t1" :db/ident :name/Anonymous]]
:test/expected-transaction
nil
:test/expected-error-message
""}
;; The upsert algorithm will first try to resolve "t1", fail, and then allocate both "t1" and "t2".
{:test/label "multistep, both allocated"
:test/assertions
[[:db/add "t1" :db/ident :name/Josef]
[:db/add "t2" :db.schema/attribute "t1"]]
:test/expected-transaction
#{[65538 :db/ident :name/Josef ?tx6 true]
[65539 :db.schema/attribute 65538 ?tx6 true]
[?tx6 :db/txInstant ?ms6 ?tx6 true]}
:test/expected-error-message
""
:test/expected-tempids
{"t1" 65538
"t2" 65539}}
;; Can't quite test this without more schema elements.
;; ;; This time, we can resolve both, but we have to try "t1", succeed, and then resolve "t2".
;; {:test/label "multistep, upserted allocated"
;; :test/assertions
;; [[:db/add "t1" :db/ident :name/Josef]
;; [:db/add "t2" :db/ident "t1"]]
;; :test/expected-transaction
;; #{[65538 :db/ident :name/Josef]
;; [65538 :db/ident :name/Karl]
;; [?tx8 :db/txInstant ?ms8 ?tx8 true]}
;; :test/expected-error-message
;; ""
;; :test/expected-tempids
;; {"t1" 65538
;; "t2" 65539}}
]