Skip to content

Commit c46ef9e

Browse files
aiskleeyeh
authored andcommitted
feat(Object): add bit related operations (#510)
1 parent 0d585bb commit c46ef9e

File tree

4 files changed

+205
-0
lines changed

4 files changed

+205
-0
lines changed

src/object.js

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -789,6 +789,39 @@ module.exports = function(AV) {
789789
return this.set(attr, new AV.Op.Remove(ensureArray(item)));
790790
},
791791

792+
/**
793+
* Atomically apply a "bit and" operation on the value associated with a
794+
* given key.
795+
*
796+
* @param attr {String} The key.
797+
* @param value {Number} The value to apply.
798+
*/
799+
bitAnd(attr, value) {
800+
return this.set(attr, new AV.Op.BitAnd(value));
801+
},
802+
803+
/**
804+
* Atomically apply a "bit or" operation on the value associated with a
805+
* given key.
806+
*
807+
* @param attr {String} The key.
808+
* @param value {Number} The value to apply.
809+
*/
810+
bitOr(attr, value) {
811+
return this.set(attr, new AV.Op.BitOr(value));
812+
},
813+
814+
/**
815+
* Atomically apply a "bit xor" operation on the value associated with a
816+
* given key.
817+
*
818+
* @param attr {String} The key.
819+
* @param value {Number} The value to apply.
820+
*/
821+
bitXor(attr, value) {
822+
return this.set(attr, new AV.Op.BitXor(value));
823+
},
824+
792825
/**
793826
* Returns an instance of a subclass of AV.Op describing what kind of
794827
* modification has been performed on this field since the last time it was

src/op.js

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,138 @@ module.exports = function(AV) {
194194
return new AV.Op.Increment(json.amount);
195195
});
196196

197+
/**
198+
* @private
199+
* @class
200+
* BitAnd is an atomic operation where the given value will be bit and to the
201+
* value than is stored in this field.
202+
*/
203+
AV.Op.BitAnd = AV.Op._extend(/** @lends AV.Op.BitAnd.prototype */ {
204+
_initialize(value) {
205+
this._value = value;
206+
},
207+
208+
value() {
209+
return this._value;
210+
},
211+
212+
/**
213+
* Returns a JSON version of the operation suitable for sending to AV.
214+
* @return {Object}
215+
*/
216+
toJSON() {
217+
return { __op: 'BitAnd', value: this.value() };
218+
},
219+
220+
_mergeWithPrevious(previous) {
221+
if (!previous) {
222+
return this;
223+
} else if (previous instanceof AV.Op.Unset) {
224+
return new AV.Op.Set(0);
225+
} else if (previous instanceof AV.Op.Set) {
226+
return new AV.Op.Set(previous.value() & this.value());
227+
} else {
228+
throw new Error('Op is invalid after previous op.');
229+
}
230+
},
231+
232+
_estimate(oldValue) {
233+
return oldValue & this.value();
234+
},
235+
});
236+
237+
AV.Op._registerDecoder('BitAnd', function (json) {
238+
return new AV.Op.BitAnd(json.value);
239+
});
240+
241+
/**
242+
* @private
243+
* @class
244+
* BitOr is an atomic operation where the given value will be bit and to the
245+
* value than is stored in this field.
246+
*/
247+
AV.Op.BitOr = AV.Op._extend(/** @lends AV.Op.BitOr.prototype */ {
248+
_initialize(value) {
249+
this._value = value;
250+
},
251+
252+
value() {
253+
return this._value;
254+
},
255+
256+
/**
257+
* Returns a JSON version of the operation suitable for sending to AV.
258+
* @return {Object}
259+
*/
260+
toJSON() {
261+
return { __op: 'BitOr', value: this.value() };
262+
},
263+
264+
_mergeWithPrevious(previous) {
265+
if (!previous) {
266+
return this;
267+
} else if (previous instanceof AV.Op.Unset) {
268+
return new AV.Op.Set(this.value());
269+
} else if (previous instanceof AV.Op.Set) {
270+
return new AV.Op.Set(previous.value() | this.value());
271+
} else {
272+
throw new Error('Op is invalid after previous op.');
273+
}
274+
},
275+
276+
_estimate(oldValue) {
277+
return oldValue | this.value();
278+
},
279+
});
280+
281+
AV.Op._registerDecoder('BitOr', function (json) {
282+
return new AV.Op.BitOr(json.value);
283+
});
284+
285+
/**
286+
* @private
287+
* @class
288+
* BitXor is an atomic operation where the given value will be bit and to the
289+
* value than is stored in this field.
290+
*/
291+
AV.Op.BitXor = AV.Op._extend(/** @lends AV.Op.BitXor.prototype */ {
292+
_initialize(value) {
293+
this._value = value;
294+
},
295+
296+
value() {
297+
return this._value;
298+
},
299+
300+
/**
301+
* Returns a JSON version of the operation suitable for sending to AV.
302+
* @return {Object}
303+
*/
304+
toJSON() {
305+
return { __op: 'BitXor', value: this.value() };
306+
},
307+
308+
_mergeWithPrevious(previous) {
309+
if (!previous) {
310+
return this;
311+
} else if (previous instanceof AV.Op.Unset) {
312+
return new AV.Op.Set(this.value());
313+
} else if (previous instanceof AV.Op.Set) {
314+
return new AV.Op.Set(previous.value() ^ this.value());
315+
} else {
316+
throw new Error('Op is invalid after previous op.');
317+
}
318+
},
319+
320+
_estimate(oldValue) {
321+
return oldValue ^ this.value();
322+
},
323+
});
324+
325+
AV.Op._registerDecoder('BitXor', function (json) {
326+
return new AV.Op.BitXor(json.value);
327+
});
328+
197329
/**
198330
* @private
199331
* @class

storage.d.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,9 @@ declare namespace AV {
281281
initialize(): void;
282282
add(attributeName: string, item: any): Object;
283283
addUnique(attributeName: string, item: any): any;
284+
bitAnd(attributeName: string, item: number): Object;
285+
bitOr(attributeName: string, item: number): Object;
286+
bitXor(attributeName: string, item: number): Object;
284287
change(options: any): Object;
285288
changedAttributes(diff: any): boolean;
286289
clear(options: any): any;

test/object.js

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -605,5 +605,42 @@ describe('Objects', function(){
605605

606606
});
607607

608+
describe('Bit operations', function() {
609+
it('bit and', function() {
610+
var score = new GameScore();
611+
score.bitAnd('flags', 0b1);
612+
expect(score.get('flags')).to.be(0);
613+
return score.save().then(() => {
614+
expect(score.get('flags')).to.be(0);
615+
return GameScore.query.get(score.id);
616+
}).then((savedScore) => {
617+
expect(savedScore.get('flags')).to.be(0);
618+
});
619+
});
620+
621+
it('bit or', function() {
622+
var score = new GameScore();
623+
score.bitOr('flags', 0b1);
624+
expect(score.get('flags')).to.be(0b1);
625+
return score.save().then(() => {
626+
expect(score.get('flags')).to.be(0b1);
627+
return GameScore.query.get(score.id);
628+
}).then((savedScore) => {
629+
expect(savedScore.get('flags')).to.be(0b1);
630+
});
631+
});
632+
633+
it('bit xor', function() {
634+
var score = new GameScore();
635+
score.bitXor('flags', 0b1);
636+
expect(score.get('flags')).to.be(0b1);
637+
return score.save().then(() => {
638+
expect(score.get('flags')).to.be(0b1);
639+
return GameScore.query.get(score.id);
640+
}).then((savedScore) => {
641+
expect(savedScore.get('flags')).to.be(0b1);
642+
});
643+
});
644+
});
608645

609646
});//END RETRIEVING

0 commit comments

Comments
 (0)