Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Datastore + Transactional semantics

33 views
Skip to first unread message

Dale Harvey

unread,
Jan 22, 2014, 9:03:38 AM1/22/14
to dev-webapi
So my last question about the Datastore API was a simple misunderstanding
so apologies if this is too.

It seems like the canonical way to update an object would look like

.get(id).then(function() {
... do stuff
.put(object)

however this is obviously broken, you try to do 2 writes within a similiar
time and you will lose data

Is there an alternative approach to this? in PouchDB each object is given a
revision so on the .put you will be notified that data is outdated and the
save will be rejected.

Otherwise it seems like every user of datastore will need to write some
transactional wrapper around the datastore api

Cheers
Dale

Andrea Marchesini

unread,
Jan 22, 2014, 11:21:14 AM1/22/14
to Dale Harvey, dev-webapi
Good point.

Here 2 proposals:

dStore.get(1).then(function(data) {
/* where data is:
{ id: 1,
value: {the Object},
revisionId: {the revision for this object }} */

data.value.foobar = 42;

dStore.puts(data.value, data.id, data.revisionId).catch(function(e) {
if (e.name == "RevisionError") {
/* this is not the last revision any more! ... */
}
});
});

Another approach can have some "magic" properties in any object:

dStore.get(1).then(function(obj) {

obj.foobar = 42;
// obj._id is 1
// obj._revisionId is the last revision of this object.

dStore.puts(obj, obj._id, obj._revisionId).catch(function(e) {
if (e.name == 'RevisionError') {
/* this is not the last revision any more! ... */
}
});
});

Of course revisionId is an optional param for dStore.puts().

Feedback?
b
> _______________________________________________
> dev-webapi mailing list
> dev-w...@lists.mozilla.org
> https://lists.mozilla.org/listinfo/dev-webapi
>

Dale Harvey

unread,
Jan 22, 2014, 11:37:30 AM1/22/14
to Andrea Marchesini, dev-webapi
I dont think theres a need to use extra parameters when using 'special'
objects, they can just be picked up from the object

dStore.get(1).then(function(obj) {

obj.foobar = 42;
// obj._id is 1
// obj._revisionId is the last revision of this object.

dStore.puts(obj).catch(function(e) {
if (e.name == 'RevisionError') {
/* this is not the last revision any more! ... */
}
});
});

The question about revisionId being optional, I am not so sure, as it
currently stands I suspect everyone is going to use this API incorrectly
and introduce data loss, I suspect it should use revisions by default, with
a possible option to 'stomp', this also leads into other questions of how
datastore handles multiple writers (apps) + conflicts, I dont know what the
plan / implementation for that looks like though.

Ehsan Akhgari

unread,
Jan 22, 2014, 2:52:20 PM1/22/14
to Andrea Marchesini, Dale Harvey, dev-webapi
On 1/22/2014, 11:21 AM, Andrea Marchesini wrote:
> Good point.
>
> Here 2 proposals:
>
> dStore.get(1).then(function(data) {
> /* where data is:
> { id: 1,
> value: {the Object},
> revisionId: {the revision for this object }} */
>
> data.value.foobar = 42;
>
> dStore.puts(data.value, data.id, data.revisionId).catch(function(e) {
> if (e.name == "RevisionError") {
> /* this is not the last revision any more! ... */
> }
> });
> });

I think this proposal makes more sense to me than the other one, given
that it doesn't require magic properties. It does mean that we're going
to have to break the existing get() method which is unfortunate. I
think the ID arguments to put/add/remove should be optional and we
should not perform any checking unless those are passed in, which means
we won't need to break those methods.

Other feedback is much appreciated too!

Cheers,
Ehsan

Andrea Marchesini

unread,
Jan 22, 2014, 3:04:00 PM1/22/14
to Ehsan Akhgari, Dale Harvey, dev-webapi
Here a full proposal for DataStore + transaction semantics:

interface DataStore : EventTarget {
...

// Get returns a single DataStoreRecord object or an array of them.
// Promise<any>
Promise get(DataStoreKey... id);

// Promise<void>
Promise put(any obj, DataStoreKey id, optional DOMString revisionId);

// Promise<DataStoreKey>
Promise add(any obj, optional DataStoreKey id,
optional DOMString revisionId);

// Promise<boolean>
Promise remove(DataStoreKey id, optional DOMString revisionId);

...
};

// This dictionary is the return value of the get() method.
dictionary DataStoreRecord {
DOMString revisionId;
DataStoreKey id;
any value;
};

put(), add() and remove() have an optional param for the revisionId.
If it's not null, the operation is completed only if the current revision of the object is equal to what has been passed as argument.

b

----- Original Message -----

Dale Harvey

unread,
Jan 22, 2014, 4:47:09 PM1/22/14
to Andrea Marchesini, dev-webapi, Ehsan Akhgari
its awkward that the .put and .get arent symetrical, however people have
found the magic properties slightly confusing in couch / pouchdb, this is
more explicit, but works for me

Thanks
Dale

Jonas Sicking

unread,
Mar 4, 2014, 4:16:48 PM3/4/14
to Andrea Marchesini, Dale Harvey, Ehsan Akhgari, dev-webapi
On Wed, Jan 22, 2014 at 12:04 PM, Andrea Marchesini <ba...@mozilla.com> wrote:
> Here a full proposal for DataStore + transaction semantics:
>
> interface DataStore : EventTarget {
> ...
>
> // Get returns a single DataStoreRecord object or an array of them.
> // Promise<any>
> Promise get(DataStoreKey... id);
>
> // Promise<void>
> Promise put(any obj, DataStoreKey id, optional DOMString revisionId);
>
> // Promise<DataStoreKey>
> Promise add(any obj, optional DataStoreKey id,
> optional DOMString revisionId);
>
> // Promise<boolean>
> Promise remove(DataStoreKey id, optional DOMString revisionId);
>
> ...
> };
>
> // This dictionary is the return value of the get() method.
> dictionary DataStoreRecord {
> DOMString revisionId;
> DataStoreKey id;
> any value;
> };
>
> put(), add() and remove() have an optional param for the revisionId.
> If it's not null, the operation is completed only if the current revision of the object is equal to what has been passed as argument.

Sounds good to me.

/ Jonas
0 new messages