o-development / ldo-legacy

Linked Data Objects
Other
19 stars 2 forks source link

$toSparqlUpdate behaves unexpectedly when using relative paths #14

Closed mrkvon closed 1 year ago

mrkvon commented 1 year ago

Let's say we try to save a ldo repeatedly with the same predicate and object.

Then, the second time, the sparql query looks approximately:

INSERT DATA { <https://subject#foo> <https://predicate#bar> <#example>. };
DELETE DATA { <https://subject#foo> <https://predicate#bar> <https://example.com#example>. }

As far as https://example.com is concerned, both INSERT DATA and DELETE DATA contain the same triple. And after executing the query, we end up with the triple disappearing.

Expected behavior

The triple doesn't change after running the query second time

Actual behavior

The triple disappears

Issue

If the order of INSERT DATA and DELETE DATA was reverse, the behavior would be as expected.

Also see

https://matrix.to/#/!ogHmAuzhszmxlGQrVp:gitter.im/$W_kvL7Ht0blpLAcbfmYuFaxBzQGB2Q1JgkxcbLAYJTQ?via=gitter.im&via=matrix.org&via=chat.semantic.works

jaxoncreed commented 1 year ago

At the moment, LDO isn't designed to work with relative IRIs. I will add this to a features list.

mrkvon commented 1 year ago

At the moment, LDO isn't designed to work with relative IRIs. I will add this to a features list.

That would be fine. The issue i try to point out is the order of INSERT DATA and DELETE DATA in $toSparqlUpdate, which leads to inconsistent results. In the linked discussion, people mention that typically DELETE should be executed before INSERT.

Well, that would be another kind of query, i.e. INSERT {} DELETE {} WHERE {}. In it, DELETE should be applied before INSERT. It's not the same, but it points out the direction to resolving this issue, i.e. put DELETE DATA {}; before INSERT DATA {};.

jaxoncreed commented 1 year ago

The order should only matter if you are inserting and deleting identical triples. This should never happen because LDO keeps track of the changed triples internally.

Nonetheless, I'll swap the order for a future update.

jaxoncreed commented 1 year ago

Hi @mrkvon. The Insert and Delete data have been swapped in the generation. Could you confirm that it works for you.

Also, could you paste some more in-depth example code of the problem you've encountered (how are you fetching data, what modifications are you making to that data using LDO, etc). I was to determine if the lack of support for relative IRIs is something that needs to be addressed.

mrkvon commented 1 year ago

@jaxoncreed

Could you confirm that it works for you.

Yes, this should fix the main issue described. Thank you!

could you paste some more in-depth example code of the problem you've encountered

The full logic how we use LDO is here. It's how we use LDO in connection with rtk-query... it might be a bit obscure if you're not used to that library.

Then, we call the particular api function here.

I might provide more details later. Right now it's late in Europe...

I was to determine if the lack of support for relative IRIs is something that needs to be addressed.

In these examples - i.e. saving .acl, the only difference was that we had to write

'@id': fileOrFolder + '.acl#Read',

instead of simpler

'@id': '#Read',

which is not a big deal. The main confusing thing was the seemingly unpredictable behavior of updates with the older version of $toSparqlUpdate, which should be fixed now.


If something is unclear, let me know what i could elaborate or specify, and i'll try. 🙂

mrkvon commented 1 year ago

I just learned in Solid specification chatroom that application/sparql-update is not in the Solid protocol. While sparql-update works with NSS and CSS, it seems text/n3 should be the standard way to apply patches in Solid.

It means that Solid apps may actually have to move away from using this method. That's too bad, i liked it... 😕

edit:

I use the following method to generate Solid n3 patches now:

import { Dataset } from '@rdfjs/types'
import { transactionChanges } from 'ldo'
import { datasetToString } from 'ldo/dist/datasetConverters'
import { LdoBase } from 'ldo/dist/util'
import { solid } from 'rdf-namespaces'

export async function toN3Patch(ldo: LdoBase): Promise<string> {
  const changes = transactionChanges(ldo)
  const patch = `
      _:patch a <${solid.InsertDeletePatch}>;
        <${solid.inserts}> { ${
    changes.added
      ? await datasetToString(changes.added as Dataset, { format: 'N3' })
      : ''
  } };
        <${solid.deletes}> { ${
    changes.removed
      ? await datasetToString(changes.removed as Dataset, { format: 'N3' })
      : ''
  } }.`
  return patch
}
jaxoncreed commented 1 year ago

@mrkvon Got it. For now, I'm going to say that LDO will not support BaseIRIs/Relative IRIs as it is essentially a pointer to an RDF JS dataset and RDF JS datasets also don't have a concept of a BaseIRI. Let me know if this feature becomes more important in the future.