Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

'Surprising' behaviour of @delete with variables #76

Closed
gsvarovsky opened this issue Sep 21, 2021 · 4 comments
Closed

'Surprising' behaviour of @delete with variables #76

gsvarovsky opened this issue Sep 21, 2021 · 4 comments
Labels
investigate Extra attention is needed

Comments

@gsvarovsky
Copy link
Member

gsvarovsky commented Sep 21, 2021

See https://gitter.im/m-ld/community?at=6149e78a8065e87a8ef6167a

Violation of principle of least surprise.

You can always delete any old property value using a variable, like this:

{ "@delete": { "@id": "<id>", "<property>": "?value" } }

However there's a little subtlety to deletes with variables, which should probably be addressed with docs or maybe an improved semantic.

The subtlety is that the presence of a variable in the delete clause creates an implicit @where clause with the same content as the @delete, with the effective procedure:

  1. match graph triples against the (implicit) @where clause
  2. capture values for the variable ?value
  3. for each value found, substitute it into the @delete clause and delete those triples

So far this is the same behaviour as SPARQL DELETE WHERE.

The catch happens when you include a @insert clause as well, which you definitely want to do, if you are atomically updating a single-value property. Step 3 also applies to the insert; so if no value is matched, nothing gets inserted (even if the variable does not appear in the insert clause).

So, if you know there was definitely a value before (e.g. it's a mandatory property), you can just use a variable in the delete. But if you don't know that, then the only sane thing to do is to read the old value first, which is ungainly.

See also #31

@gsvarovsky
Copy link
Member Author

gsvarovsky commented Sep 21, 2021

https://www.w3.org/TR/2013/REC-sparql11-update-20130321/#updateLanguage

A request is a sequence of operations and is terminated by EOF (End of File). Multiple operations are separated by a ';' (semicolon) character. A semicolon after the last operation in a request is optional. Implementations must ensure that the operations of a single request are executed in a fashion that guarantees the same effects as executing them sequentially in the order they appear in the request.

A top-level array of Patterns would be a way to break out of the shared @where and so do an @insert without the @where applied to it, in the same atomic transaction:

[
  { "@delete": { "@id": "<id>", "<property>": "?anyOldValue" } },
  { "@insert": { "@id": "<id>", "<property>": "<newValue>" } }
]

Concerns:

  • Does not address the surprise when done in the same Pattern (per ticket).
  • The top-level array looks like a procedure, with sequential operations. Does each pattern apply:
    • to the resulting state of the previous pattern? This would require intermediate commits, which are not currently possible in the Javascript engine. (There's nothing wrong with the JS engine not fully implementing json-rql, but that would leave the motivating use-case unanswered.)
    • to the starting state? This would be a divergence between json-rql and SPARQL.
  • The top-level array cannot bear a @context, making a shared context awkward

@gsvarovsky
Copy link
Member Author

This pattern works for updating a property, even if it does not already exist:

{
  "@delete": { "@id": "1", "a": "?a" },
  "@insert": { "@id": "1", "a": 5 },
  "@where": {
    "@union": [
      { "@id": "1", "a": "?a" },
      { "@values": {} }
    ]
  }
}

Playground link

The empty @values ensures that there is always at least a single binding for the @insert to be applied to.

This is not at all intuitive.

@gsvarovsky
Copy link
Member Author

gsvarovsky commented Sep 26, 2021

Experimenting with changing the behaviour to make the original use-case more intuitive, I propose the following (as documentation for the Update.'@insert' member):


Subjects with properties to be inserted into the domain. Variables may be used, values for which will be established as follows:

  • If a @where clause exists, then values matched in the @where clause will be used.
  • If there is no @where, but a @delete clause exists, then values matched in the @delete clause will be used.
  • If a variable value is not matched by the @where or @delete clause as above, no insertion happens (i.e. there must exist a complete solution to all variables in the @insert).

Note that in the case that the @insert contains no variables, there is a difference between matching with a @where and @delete. If a @where clause is provided, it must match some existing data for the inserts to happen. However, if no @where clauses is provided, then the insertion will happen even if nothing is matched by the @delete.

For example, assume this data exists:

{ "@id": "fred", "name": "Fred" }`

Compare the following update patterns:

{
  "@delete": { "@id": "fred", "height": "?height" },
  "@insert": { "@id": "fred", "height": "6" }
}

The pattern above updates Fred's height to 6, even though no prior height value exists.

{
  "@delete": { "@id": "fred", "height": "?height" },
  "@insert": { "@id": "fred", "height": "6" },
  "@where": { "@id": "fred", "height": "?height" }
}

The pattern above does nothing, because no prior height value is matched by the @where.

@gsvarovsky
Copy link
Member Author

gsvarovsky commented Sep 29, 2021

Suggested pattern #76 (comment) is now available on the edge:

  • Documentation
  • npm install @m-ld/m-ld@edge
  • Playground example (note that applying the update works even on an empty domain – i.e. no existing matched value)

@gsvarovsky gsvarovsky added this to To do in m-ld backlog via automation Oct 3, 2021
@gsvarovsky gsvarovsky moved this from To do to On edge in m-ld backlog Oct 3, 2021
m-ld backlog automation moved this from On edge to Done Jan 16, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
investigate Extra attention is needed
Projects
None yet
Development

No branches or pull requests

1 participant