We require three new handles:
- InsertHandler: binds to
add
. - DeleteHandler: binds to
delete
. - UpdateHandler (optional): binds to
set
andreplace
.
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.
Agree except for
addPendingPromise
. To be discussed.