WebAPI/DataStore: Difference between revisions

no edit summary
No edit summary
 
(18 intermediate revisions by 3 users not shown)
Line 63: Line 63:
== Interface ==
== Interface ==


  typedef (DOMString or unsigned long) DataStoreKey;
 
   interface DataStore : EventTarget {
   interface DataStore : EventTarget {
     // Returns the label of the DataSource.
     // Returns the label of the DataSource.
Line 75: Line 77:
    
    
     // Promise<any>
     // Promise<any>
     Promise get(unsigned long id);
     Promise get(DataStoreKey... id);
 
     
    // Promise<any>
    Promise get(sequence<unsigned long> id);
 
     // Promise<void>
     // Promise<void>
     Promise update(unsigned long id, any obj);
     Promise put(any obj, DataStoreKey id, optional DOMString revisionId = "");
 
 
     // Promise<unsigned long>
     // Promise<DataStoreKey>
     Promise add(any obj);
     Promise add(any obj, optional DataStoreKey id, optional DOMString revisionId = "");
    
    
     // Promise<boolean>
     // Promise<boolean>
     Promise remove(unsigned long id);
     Promise remove(DataStoreKey id, optional DOMString revisionId = "");
    
    
     // Promise<void>
     // Promise<void>
     Promise clear();
     Promise clear(optional DOMString revisionId = "");
    
    
     readonly attribute DOMString revisionId;
     readonly attribute DOMString revisionId;
 
   
     attribute EventHandler onchange;
     attribute EventHandler onchange;
 
      
     // Promise<DataStoreChanges>
    Promise getChanges(DOMString revisionId);
 
     // Promise<unsigned long>
     // Promise<unsigned long>
     Promise getLength();
     Promise getLength();
Line 127: Line 123:
     DOMString revisionId;   
     DOMString revisionId;   
    
    
     IDBCursorDirection operation;
     DataStoreOperation operation;
     unsigned long id;
     DataStoreKey id;
     any data;
     any data;
  };
 
  dictionary DataStoreChanges {
    DOMString revisionId;
    sequence<unsigned long> addedIds;
    sequence<unsigned long> updatedIds;
    sequence<unsigned long> removedIds;
   };
   };
    
    
   dictionary DataStoreChangeEventInit : EventInit {
   dictionary DataStoreChangeEventInit : EventInit {
     DOMString revisionId = "";
     DOMString revisionId = "";
     unsigned long id = 0;
     DataStoreKey id = 0;
     DOMString operation = "";
     DOMString operation = "";
    DOMStirng owner = "";
   };
   };
    
    
Line 148: Line 138:
   interface DataStoreChangeEvent : Event {
   interface DataStoreChangeEvent : Event {
     readonly attribute DOMString revisionId;
     readonly attribute DOMString revisionId;
     readonly attribute unsigned long id;
     readonly attribute DataStoreKey id;
     readonly attribute DOMString operation;
     readonly attribute DOMString operation;
    readonly attribute DOMString owner;
   };
   };


Line 159: Line 150:
     datastores-owned: {
     datastores-owned: {
       "contacts": {
       "contacts": {
         "readonly": true,
         "access": "readonly",
         "description": "Facebook contacts",
         "description": ...
       }
       }
     },
     },
Line 171: Line 162:
     datastores-access: {
     datastores-access: {
       "contacts": {
       "contacts": {
         "access": "readonly",
         "readonly": true,
         "description": ...
         "description": "Facebook contacts",
       }
       }
     },
     },
Line 180: Line 171:
== Revisions and changes ==
== Revisions and changes ==


The revisionId is a UUID and it can be used to retrieve the delta between a particular revisionId and the current one. This operation is done using |Promise<DataStoreChanges> getChanges(DOMString revisionId);|. Note that the object DataStoreChanges contains only useful operations: for example, the ID of record that has been updated and removed only shows up in the |removedIds| array.
The revisionId is a UUID and it can be used to retrieve the delta between a particular revisionId and the current one using |sync()|


== Examples ==
== Examples ==
Line 200: Line 191:
       // Update an object
       // Update an object
       obj.nick = 'baku';
       obj.nick = 'baku';
       stores[0].update(42, obj).then(function(id) {
       stores[0].put(obj, 42).then(function(id) {
         // id == 42
         // id == 42
         // ...
         // ...
Line 223: Line 214:
   });
   });


=== Revisions ===
=== Sync ===


  // Let's assume that I have a revisionId stored somewhere (IndexedDb? LocalStorage?)
The synchronization of  a DataStore with a 'private' app storage can be done using the 'sync' method. Calling this method, DataStore creates a DataStoreCursor that helps the app with the synchronization starting from scratch or for a valid revisionId. The sync operation can be terminated calling cursor.close(). If something changes in the DataStore when the cursor is synchronize the app, all the changes will be managed by the cursor as additional operation: this means that when the cursor completes its tasks, the app will be always in sync with the current revisionId of the DataStore.
   var revisionId = 'b66e9248-5990-4ac3-9f5d-3cdeb02b337f';
 
The basic usage of the cursor is this:
 
  navigator.getDataStores('contacts').then(functions(stores) {
    if (!stores.length) return;
    
    let cursor = stores[0].sync(/* a revisionId can be used here. If it's invalid it'll be ignored */);
    
    
  navigator.getDataStores('contacts').then(function(stores) {
    function cursorResolve(task) {
    if (!stores.length) return;
      // task.operation describes what the app has to do in order to be in sync with the current revision of this datastore.
   
      switch (task.operation) {
    stores[0].getChanges(revisionId).then(function(delta) {
        case 'done':
      if (revisionId == delta.revisionId) {
          // No additional operation has to be done.
         // Nothing changed
          dump("The current revision ID is: " + task.revisionId + "\n");
      } else {
          return;
        dump("We lost: " + delta.removedIds + " contacts, but " + delta.addedIds + " have been added!\n");
 
         revisionId = delta.revisionId; // To store, somewhere.
        case 'clear':
          // All the data you have are out-of-sync. Delete all of them.
          break;
 
        case 'add':
          // A new object has to be inserted
          dump("Adding id: " + task.id + " data: " + task.data + "\n");
          break;
 
         case 'update':
          // Something has to be updated
          dump("Updating id: " + task.id + " data: " + task.data + "\n");
          break;
 
         case 'remove':
          dump("Record: " + task.id + " must be removed\n");
          break;
       }
       }
     });
 
      cursor.next().then(cursorResolve);
     }
 
    // Cursor.next() always returns a promise.
    cursor.next().then(cursorResolve);
   });
   });


Line 244: Line 262:
  * {name, owner, value} is a complicated key.
  * {name, owner, value} is a complicated key.
  * UI: what to do when we have multiple access requests?
  * UI: what to do when we have multiple access requests?
* What's happening if the central gets changes during the process of local updates?
  * Should all data stores with the same name share a schema?
  * Should all data stores with the same name share a schema?
  * Enforcing types can be a footgun. What should a data provider do if it decides some key should have a different type?
  * Enforcing types can be a footgun. What should a data provider do if it decides some key should have a different type?
[[Category:Web APIs]]
Confirmed users
1,340

edits