Skip to content

Instantly share code, notes, and snippets.

@rubensworks
Last active January 8, 2019 03:38
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rubensworks/1123742b048bd2e82624c713a024dcab to your computer and use it in GitHub Desktop.
Save rubensworks/1123742b048bd2e82624c713a024dcab to your computer and use it in GitHub Desktop.

We require three new handles:

  • InsertHandler: binds to add.
  • DeleteHandler: binds to delete.
  • UpdateHandler (optional): binds to set and replace.

Getting random values

await user.friends.friends.random // returns a random friend

Addition

This requires a straightforward handler that intercepts the add and addAll functions that take one mandatory argument.

Adding a single value:

await user.friends.add('https://rubensworks.solid.community/profile/card#me')
await user.friends.add(await user.friends.friends) // Add a random friends friend.

SPARQL:

INSERT DATA
{ 
  <https://rubensworks.solid.community/profile/card#me> foaf:knows <https://rubensworks.solid.community/profile/card#me>.
}

Adding multiple values:

1. Adding friend of friends to as your friends
await user.friends.add(user.friends.friends)
INSERT
{
  <https://rubensworks.solid.community/profile/card#me> foaf:knows ?friendOfFriend.
}
WHERE
{
  <https://rubensworks.solid.community/profile/card#me> foaf:knows ?friend.
  ?friend foaf:knows ?friendOfFriend.
}
2. Adding yourself as friend to your friends friends
await user.friends.friends.add(user)
INSERT
{
  ?friendOfFriend foaf:knows <https://rubensworks.solid.community/profile/card#me>.
}
WHERE
{
  <https://rubensworks.solid.community/profile/card#me> foaf:knows ?friend.
  ?friend foaf:knows ?friendOfFriend.
}
3. Adding your mother as friend to your friends friends
await user.friends.friends.add(user.mother)
INSERT
{
  ?friendOfFriend foaf:knows ?mother.
}
WHERE
{
  <https://rubensworks.solid.community/profile/card#me> foaf:knows ?friend.
  ?friend foaf:knows ?friendOfFriend.

  <https://rubensworks.solid.community/profile/card#me> :hasMother ?mother.
}

Note: We can not trap = via the proxy (set), as this requires a synchronous operation, and you can not play around with return values.

Adding multiple raw values:

await user.friends.add('uri-a', 'uri-b')

Deletion

This requires a handler that intercepts the delete and deleteAll functions that take one optional argument.

Deleting a single value:

await user.friends.delete('https://rubensworks.solid.community/profile/card#me')
await user.friends.delete(await user.friends.friends) // Delete a random friends friend.
await user.friends.random.delete() // Delete a random friend
await user.friends.delete() // Delete all friends

SPARQL:

DELETE DATA
{ 
  <https://rubensworks.solid.community/profile/card#me> foaf:knows <https://rubensworks.solid.community/profile/card#me>.
}

Deleting multiple values:

await user.friends.delete(user.friends.friends)

SPARQL:

DELETE
{
  <https://rubensworks.solid.community/profile/card#me> foaf:knows ?friendOfFriend.
}
WHERE
{
  <https://rubensworks.solid.community/profile/card#me> foaf:knows ?friend.
  ?friend foaf:knows ?friendOfFriend.
}

Note: We can not trap the delete operator via the proxy (deleteProperty), as this requires a synchronous operation, and you can not play around with return values.

Deleting multiple raw values:

await user.friends.delete('uri-a', 'uri-b')

Update

This corresponds to a delete followed by an insert. This is merely convenience functionality that combines deletion and addition (optimizable with a combined SPARQL query: https://www.w3.org/TR/2013/REC-sparql11-update-20130321/#deleteInsert). This requires a handler for set and setAll that take one mandatory argument.

Updating a single value:

await user.name.set('Ruben')

Translation:

await user.name.delete() // Delete all existing values
await user.name.add('Ruben') // Add a single value

Updating with a random value:

await user.name.set(user.friends.name.random)

Translation:

await user.name.delete()
await user.name.add(user.friends.name.random)

Updating with multiple values:

await user.name.set(user.friends.name)

Translation:

await user.name.delete()
await user.name.add(user.friends.name)

Replacing values:

await user.name.replace('ruben', 'Ruben')

Translation:

await user.name.delete('ruben')
await user.name.add('Ruben')

Syntactical sugar

Some syntactical sugar for updates and deletes.

Update

data.user.name = 'Ruben';

Translation:

data.addPendingPromise(user.name.delete()) // This will have no effect if no previous value existed.
data.addPendingPromise(user.name.add('Ruben'))

data.pending is an awaitable over all pending promises.

Delete

delete data.user.daughter;

Translation:

data.addPendingPromise(data.user.daughter.delete())

Batching

Batching allows multiple operations to be grouped together in a single SPARQL query, for improved efficiency. (We probably don't need this in the first stage)

Option 1

// Do data things batched
data.batch((batch) -> {
  batch.user.name = 'Ruben';
  batch.user.brother.name = 'Niels';
  batch.user.sister.name = 'Muriel';
  delete batch.user.daughter;
});

Option 2

// Do data things batched
const batch = data.batch();
batch.user.name = 'Ruben';
batch.user.brother.name = 'Niels';
batch.user.sister.name = 'Muriel';
delete batch.user.daughter;

More complex to implement, but may be doable using WeakMap.

@RubenVerborgh
Copy link

Agree except for addPendingPromise. To be discussed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment