Closed aaj3f closed 1 year ago
This should implement the syntax reference in the other ticket - details in the link above, but in summary was:
'{:delete [?s :schema/name "William"]
:insert [?s :schema/name "Bill"]
:where [[?s :schema/name "William"]]}
The main item not addressed in the above example is that :insert
and :delete
as well should support multiple values as per the example below.
If this addition to this ticket makes it take any longer than only supporting the single-value example above, it should be split into two tickets and the multi-value syntax supported separately.
'{:delete [[?s :schema/name "William"]
[?s :schema/age ?age]]
:insert [[?s :schema/name "Bill"]
[?s :schema/age 42]]
:where [[?s :schema/name "William"]
{:optional [?s :schema/age ?age]}]}
Which would mean for anyone named "William", rename them to "Bill", delete their age(s) if they exist, and insert a single new age of 42.
In the example from the ticket description to update an @id from x to y, the syntax would be:
'{:delete ["ex:person123" ?p ?o]
:insert ["ex:personABC" ?p ?o]
:where [["ex:person123" ?p ?o]]}
As a general reference to this feature, note https://www.w3.org/TR/sparql11-update/#deleteInsert - which we'll ultimately need to parse SPARQL in this format into our format specified above.
Sample test for consideration:
(deftest ^:integration deleting-data
(let [conn (test-utils/create-conn)
ledger @(fluree/create conn "tx/delete" {:defaultContext ["" {:ex "http://example.org/ns/"}]})
db @(fluree/stage
(fluree/db ledger)
{:graph [{:id :ex/alice,
:type :ex/User,
:schema/name "Alice"
:schema/email "alice@flur.ee"
:schema/age 42}
{:id :ex/bob,
:type :ex/User,
:schema/name "Bob"
:schema/age 22}
{:id :ex/jane,
:type :ex/User,
:schema/name "Jane"
:schema/email "jane@flur.ee"
:schema/age 30}]})
;; Change Bob's age - but only if his age is still 22
db-update-bob @(fluree/stage db
'{:delete [:ex/bob :schema/age 22]
:insert [:ex/bob :schema/age 23]
:where [[:ex/bob :schema/age 22]]})
;; Shouldn't change Bob's age as the current age is not a match
db-update-bob2 @(fluree/stage db
'{:delete [:ex/bob :schema/age 99]
:insert [:ex/bob :schema/age 23]
:where [[:ex/bob :schema/age 99]]})
;; change Jane's age regardless of its current value
db-update-jane @(fluree/stage db
'{:delete [:ex/jane :schema/age ?current-age]
:insert [:ex/jane :schema/age 31]
:where [[:ex/jane :schema/age ?current-age]]})]
(testing "Updating property value only if it's current value is a match."
(is (= {:id :ex/bob,
:type :ex/User,
:schema/name "Bob"
:schema/age 23}
@(fluree/query db-update-bob
'{:select {?s [:*]}
:where [[?s :id :ex/bob]]}))
"Bob's age should now be updated to 23 (from 22)."))
(testing "No update should happen if there is no match."
(is (= {:id :ex/bob,
:type :ex/User,
:schema/name "Bob"
:schema/age 22}
@(fluree/query db-update-bob2
'{:select {?s [:*]}
:where [[?s :id :ex/bob]]}))
"Bob's age should have not been changed and still be 22."))
(testing "Replacing existing property value with new property value."
(is (= {:id :ex/jane,
:type :ex/User,
:schema/name "Jane"
:schema/email "jane@flur.ee"
:schema/age 31}
@(fluree/query db-update-jane
'{:select {?s [:*]}
:where [[?s :id :ex/jane]]}))
"Jane's age should now be updated to 31 (from 30)."))))
In the example from the ticket description to update an @id from x to y, the syntax would be:
'{:delete ["ex:person123" ?p ?o] :insert ["ex:personABC" ?p ?o] :where [["ex:person123" ?p ?o]]}
I'm a little worried about this usage because of the interplay between subject ids and subject iris. The naive implementation would delete all the flakes related to the subject with iri ex:person123 and create a new subject with the a different iri and the same predicate-object mappings. The problem here is that we wouldn't update any references to that subject.
We could special case this specific operation to update the "@id" predicate on the subject, but I think the parsing code to support this would be a bit cumbersome.
Could we instead support the following syntax for updating a subject's id?
'{:delete [?s :id "ex:person123"]
:insert [?s :id "ex:personABC"]
:where [[?s :id "ex:person123"]]}
Description
Currently the only supported "update" syntax is either (1) a limited retract-and-replace pattern or (2) a "delete"+"where" pattern. Other required update patterns have been described that would allow...
_:f...
IRI but the user wants to update this to an explicitly described IRI)X
values on that property and re-inserting[...X, y, z]
)sh:name: "UserClassShape"
)Technical Details
If the current "delete"+"where" capability pattern is standards-based, then this work might want to comply with that standard. And even if not, it would be desirable for the above use cases to conform to a generally consistent pattern, such as the one already laid out by the "delete"+"where" syntax
A previous draft ticket (but an old one, possibly worth closing) suggested an extension to "delete"+"where" that singularly allowed multi-cardinality insertions. @dpetran @bplatz you may want to weigh in on this if you had previous discussion around that ticket.