Skip to content

Commit 1b732e1

Browse files
committed
Channel no longer overrides bucket methods
A bucket instance is given a channel instance and it uses the appropriate methods to communicate with the channel
1 parent 8141af2 commit 1b732e1

3 files changed

Lines changed: 174 additions & 108 deletions

File tree

src/simperium/bucket.js

Lines changed: 120 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,60 +1,164 @@
11
import { EventEmitter } from 'events'
22
import { inherits } from 'util'
3-
import uuid from 'node-uuid';
3+
import { v4 as uuid } from 'uuid';
44

5-
export default function Bucket( name, storeProvider ) {
5+
const callbackAsPromise = ( callback, task ) => new Promise( ( resolve, reject ) => {
6+
task( ( error, result ) => {
7+
if ( error ) {
8+
reject( error );
9+
return;
10+
}
11+
resolve( result );
12+
} );
13+
} );
14+
15+
const deprecateCallback = ( callback, promise ) => {
16+
if ( typeof callback === 'function' ) {
17+
// TODO: warn about deprecating callback API
18+
// and convert to promises
19+
return promise.then(
20+
result => {
21+
callback( null, result );
22+
return result;
23+
},
24+
error => {
25+
callback( error );
26+
return error;
27+
}
28+
);
29+
}
30+
return promise;
31+
};
32+
33+
const promiseAPI = store => ( {
34+
get: ( id, callback ) =>
35+
callbackAsPromise( callback, store.get.bind( store, id ) ),
36+
update: ( id, object, isIndexing, callback ) =>
37+
callbackAsPromise( callback, store.update.bind( store, id, object, isIndexing ) ),
38+
remove: ( id, callback ) =>
39+
callbackAsPromise( callback, store.remove.bind( store, id ) ),
40+
find: ( query, callback ) =>
41+
callbackAsPromise( callback, store.find.bind( store, query ) )
42+
} );
43+
44+
export default function Bucket( name, storeProvider, channel ) {
645
EventEmitter.call( this );
746
this.name = name;
847
this.store = storeProvider( this );
48+
this.storeAPI = promiseAPI( this.store );
949
this.isIndexing = false;
50+
this.channel = channel;
51+
52+
channel
53+
// forward the index and error events from the channel
54+
.on( 'index', ( ... args ) => this.emit( 'index', ... args ) )
55+
.on( 'error', ( ... args ) => this.emit( 'error', ... args ) )
56+
// when the channel updates or removes data, the bucket should apply
57+
// the same updates
58+
.on( 'update', ( id, data ) => {
59+
this.update( id, data, { sync: false } );
60+
} )
61+
.on( 'indexingStateChange', ( isIndexing ) => {
62+
this.isIndexing = isIndexing;
63+
if ( isIndexing ) {
64+
this.emit( 'indexing' );
65+
}
66+
} )
67+
.on( 'remove', ( id ) => {
68+
// TODO, there needs te be a way to remove without telling the
69+
// channel to do it
70+
this.remove( id );
71+
} );
1072
}
1173

1274
inherits( Bucket, EventEmitter );
1375

1476
Bucket.prototype.reload = function() {
15-
this.emit( 'reload' );
77+
this.channel.reload();
1678
};
1779

80+
/**
81+
* Stores an object in the bucket and syncs it to simperium. Generates an
82+
* object ID to represent the object in simperium.
83+
*
84+
* @param {Object} object - plain js object literal to be saved/synced
85+
* @param {Function} callback - runs when object has been saved
86+
* @return {Promise<Object>} data stored in the bucket
87+
*/
1888
Bucket.prototype.add = function( object, callback ) {
19-
var id = uuid.v4();
89+
var id = uuid();
2090
return this.update( id, object, callback );
2191
};
2292

93+
/**
94+
* Requests the object data stored in the bucket for the given id.
95+
*
96+
* @param {String} id - bucket object id
97+
* @param {Function} callback - with the data stored in the bucket
98+
* @return {Promise<Object>} the object data for the given id
99+
*/
23100
Bucket.prototype.get = function( id, callback ) {
24-
return this.store.get( id, callback );
101+
return deprecateCallback( callback, this.storeAPI.get( id ) );
25102
};
26103

104+
/**
105+
* Update the bucket object of `id` with the given data.
106+
*
107+
* @param {String} id - the bucket id for the object to update
108+
* @param {Object} data - object literal to replace the object data with
109+
* @param {Object} [options] - optional settings
110+
* @param {Boolean} [options.sync=true] - false if object should not be synced with this update
111+
* @param {Function} callback - executed when object is updated localy
112+
* @returns {Promise<Object>} - update data
113+
*/
27114
Bucket.prototype.update = function( id, data, options, callback ) {
28115
if ( typeof options === 'function' ) {
29116
callback = options;
117+
options = { sync: true };
118+
}
119+
120+
if ( !! options === false ) {
121+
options = { sync: true };
30122
}
31-
return this.store.update( id, data, this.isIndexing, callback );
123+
124+
const task = this.storeAPI.update( id, data, this.isIndexing )
125+
.then( bucketObject => {
126+
this.emit( 'update', id, bucketObject.data );
127+
this.channel.update( bucketObject, options.sync );
128+
return bucketObject;
129+
} );
130+
return deprecateCallback( callback, task );
32131
};
33132

34133
Bucket.prototype.hasLocalChanges = function( callback ) {
35-
callback( null, false );
134+
return deprecateCallback( callback, this.channel.hasLocalChanges() );
36135
};
37136

38137
Bucket.prototype.getVersion = function( id, callback ) {
39-
callback( null, 0 );
138+
return deprecateCallback( callback, this.channel.getVersion( id ) );
40139
};
41140

42141
Bucket.prototype.touch = function( id, callback ) {
43-
return this.store.get( id, ( e, object ) => {
44-
if ( e ) return callback( e );
45-
this.update( object.id, object.data, callback );
46-
} );
142+
const task = this.storeAPI.get( id )
143+
.then( object => this.update( object.id, object.data ) );
144+
145+
return deprecateCallback( callback, task );
47146
};
48147

49148
Bucket.prototype.remove = function( id, callback ) {
50-
return this.store.remove( id, callback );
149+
const task = this.storeAPI.remove( id )
150+
.then( ( result ) => {
151+
this.emit( 'remove', id );
152+
this.channel.remove( id );
153+
return result;
154+
} )
155+
return deprecateCallback( callback, task );
51156
};
52157

53158
Bucket.prototype.find = function( query, callback ) {
54-
return this.store.find( query, callback );
159+
return deprecateCallback( callback, this.storeAPI.find( query ) );
55160
};
56161

57162
Bucket.prototype.getRevisions = function( id, callback ) {
58-
// Overridden in Channel
59-
callback( new Error( 'Failed to fetch revisions for' + id ) );
163+
return deprecateCallback( callback, this.channel.getRevisions( id ) );
60164
}

0 commit comments

Comments
 (0)