delete support for Array & Map
This commit is contained in:
parent
66a7d2720d
commit
6b153896dd
@ -130,8 +130,8 @@ gulp.task("build_jasmine_browser", function(){
|
|||||||
gulp.task("develop", ["build_jasmine_browser", "build"], function(){
|
gulp.task("develop", ["build_jasmine_browser", "build"], function(){
|
||||||
|
|
||||||
gulp.watch(files.test, ["build_jasmine_browser"]);
|
gulp.watch(files.test, ["build_jasmine_browser"]);
|
||||||
gulp.watch(files.test, ["test"]);
|
//gulp.watch(files.test, ["test"]);
|
||||||
gulp.watch(files.test, ["build"]);
|
//gulp.watch(files.test, ["build"]);
|
||||||
|
|
||||||
return gulp.src("build/jasmine_browser.js")
|
return gulp.src("build/jasmine_browser.js")
|
||||||
.pipe(watch("build/jasmine_browser.js"))
|
.pipe(watch("build/jasmine_browser.js"))
|
||||||
|
@ -2,7 +2,6 @@ var globalRoom = {
|
|||||||
users: {},
|
users: {},
|
||||||
buffers: {},
|
buffers: {},
|
||||||
removeUser: function(user : AbstractConnector){
|
removeUser: function(user : AbstractConnector){
|
||||||
|
|
||||||
for (var i in this.users) {
|
for (var i in this.users) {
|
||||||
this.users[i].userLeft(user);
|
this.users[i].userLeft(user);
|
||||||
}
|
}
|
||||||
|
@ -73,10 +73,9 @@ function compareAllUsers(users){//eslint-disable-line
|
|||||||
}
|
}
|
||||||
|
|
||||||
function createUsers(self, numberOfUsers, done) {//eslint-disable-line
|
function createUsers(self, numberOfUsers, done) {//eslint-disable-line
|
||||||
if (self.users != null) {
|
//destroy old users
|
||||||
for (var y of self.users) {
|
for (var u in globalRoom.users) {//eslint-disable-line
|
||||||
y.destroy();
|
globalRoom.users[u].y.destroy()//eslint-disable-line
|
||||||
}
|
|
||||||
}
|
}
|
||||||
self.users = [];
|
self.users = [];
|
||||||
|
|
@ -9,7 +9,7 @@ class AbstractTransaction { //eslint-disable-line no-unused-vars
|
|||||||
if (t == null) {
|
if (t == null) {
|
||||||
var op = yield* this.getOperation(id);
|
var op = yield* this.getOperation(id);
|
||||||
if (op != null) {
|
if (op != null) {
|
||||||
t = yield* Y[op.type].create(this.store, op);
|
t = yield* Y[op.type].create.call(this, this.store, op);
|
||||||
this.store.initializedTypes[sid] = t;
|
this.store.initializedTypes[sid] = t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -28,7 +28,7 @@ class AbstractTransaction { //eslint-disable-line no-unused-vars
|
|||||||
state.clock++;
|
state.clock++;
|
||||||
yield* this.setState(state);
|
yield* this.setState(state);
|
||||||
this.os.add(op);
|
this.os.add(op);
|
||||||
this.store.operationAdded(op);
|
yield* this.store.operationAdded(this, op);
|
||||||
return true;
|
return true;
|
||||||
} else if (op.id[1] < state.clock) {
|
} else if (op.id[1] < state.clock) {
|
||||||
return false;
|
return false;
|
||||||
@ -41,7 +41,7 @@ class AbstractTransaction { //eslint-disable-line no-unused-vars
|
|||||||
for (var i = 0; i < ops.length; i++) {
|
for (var i = 0; i < ops.length; i++) {
|
||||||
var op = ops[i];
|
var op = ops[i];
|
||||||
yield* Struct[op.struct].execute.call(this, op);
|
yield* Struct[op.struct].execute.call(this, op);
|
||||||
send.push(Struct[op.struct].encode(op));
|
send.push(copyObject(Struct[op.struct].encode(op)));
|
||||||
}
|
}
|
||||||
this.store.y.connector.broadcast({
|
this.store.y.connector.broadcast({
|
||||||
type: "update",
|
type: "update",
|
||||||
@ -161,7 +161,7 @@ class AbstractOperationStore { //eslint-disable-line no-unused-vars
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
// called by a transaction when an operation is added
|
// called by a transaction when an operation is added
|
||||||
operationAdded (op) {
|
*operationAdded (transaction, op) {
|
||||||
var sid = JSON.stringify(op.id);
|
var sid = JSON.stringify(op.id);
|
||||||
var l = this.listenersById[sid];
|
var l = this.listenersById[sid];
|
||||||
delete this.listenersById[sid];
|
delete this.listenersById[sid];
|
||||||
@ -178,7 +178,7 @@ class AbstractOperationStore { //eslint-disable-line no-unused-vars
|
|||||||
// notify parent, if it has been initialized as a custom type
|
// notify parent, if it has been initialized as a custom type
|
||||||
var t = this.initializedTypes[JSON.stringify(op.parent)];
|
var t = this.initializedTypes[JSON.stringify(op.parent)];
|
||||||
if (t != null) {
|
if (t != null) {
|
||||||
t._changed(op);
|
yield* t._changed(transaction, copyObject(op));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
removeParentListener (id, f) {
|
removeParentListener (id, f) {
|
||||||
|
@ -120,7 +120,7 @@ Y.Memory = (function(){ //eslint-disable-line no-unused-vars
|
|||||||
}
|
}
|
||||||
requestTransaction (makeGen : Function) {
|
requestTransaction (makeGen : Function) {
|
||||||
var t = new Transaction(this);
|
var t = new Transaction(this);
|
||||||
var gen = makeGen.call(t, t.getType(["_", 0]).next().value);
|
var gen = makeGen.call(t);
|
||||||
var res = gen.next();
|
var res = gen.next();
|
||||||
while(!res.done){
|
while(!res.done){
|
||||||
if (res.value === "transaction") {
|
if (res.value === "transaction") {
|
||||||
|
@ -35,7 +35,7 @@ function compareIds(id1, id2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var Struct = {
|
var Struct = {
|
||||||
/*
|
/* This Operations does _not_ have an id!
|
||||||
{
|
{
|
||||||
target: Id
|
target: Id
|
||||||
}
|
}
|
||||||
@ -48,12 +48,16 @@ var Struct = {
|
|||||||
return [op.target];
|
return [op.target];
|
||||||
},
|
},
|
||||||
execute: function* (op) {
|
execute: function* (op) {
|
||||||
if ((yield* this.addOperation(op)) === false) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
var target = yield* this.getOperation(op.target);
|
var target = yield* this.getOperation(op.target);
|
||||||
target.deleted = true;
|
if (!target.deleted) {
|
||||||
yield* this.setOperation(target);
|
target.deleted = true;
|
||||||
|
yield* this.setOperation(target);
|
||||||
|
var t = this.store.initializedTypes[JSON.stringify(target.parent)];
|
||||||
|
if (t != null) {
|
||||||
|
yield* t._changed(this, copyObject(op));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Insert: {
|
Insert: {
|
||||||
@ -280,14 +284,6 @@ var Struct = {
|
|||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
},
|
},
|
||||||
delete: function* (op, pos) {
|
|
||||||
var ref = yield* Struct.List.ref.call(this, op, pos);
|
|
||||||
if (ref != null) {
|
|
||||||
yield* Struct.Delete.create.call(this, {
|
|
||||||
target: ref.id
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
map: function* (o : Op, f : Function) : Array<any> {
|
map: function* (o : Op, f : Function) : Array<any> {
|
||||||
o = o.start;
|
o = o.start;
|
||||||
var res = [];
|
var res = [];
|
||||||
@ -299,31 +295,6 @@ var Struct = {
|
|||||||
o = operation.right;
|
o = operation.right;
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
},
|
|
||||||
insert: function* (op, pos : number, contents : Array<any>) {
|
|
||||||
var left, right;
|
|
||||||
if (pos === 0) {
|
|
||||||
left = null;
|
|
||||||
right = op.start;
|
|
||||||
} else {
|
|
||||||
var ref = yield* Struct.List.ref.call(this, op, pos - 1);
|
|
||||||
if (ref === null) {
|
|
||||||
left = op.end;
|
|
||||||
right = null;
|
|
||||||
} else {
|
|
||||||
left = ref.id;
|
|
||||||
right = ref.right;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (var key in contents) {
|
|
||||||
var insert = {
|
|
||||||
left: left,
|
|
||||||
right: right,
|
|
||||||
content: contents[key],
|
|
||||||
parent: op.id
|
|
||||||
};
|
|
||||||
left = (yield* Struct.Insert.create.call(this, insert)).id;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
Map: {
|
Map: {
|
||||||
|
@ -12,18 +12,28 @@
|
|||||||
this.eventHandler = new EventHandler( ops =>{
|
this.eventHandler = new EventHandler( ops =>{
|
||||||
for (var i in ops) {
|
for (var i in ops) {
|
||||||
var op = ops[i];
|
var op = ops[i];
|
||||||
var pos;
|
if (op.struct === "Insert") {
|
||||||
if (op.right === null) {
|
let pos;
|
||||||
pos = this.idArray.length;
|
// we check op.left only!,
|
||||||
|
// because op.right might not be defined when this is called
|
||||||
|
if (op.left === null) {
|
||||||
|
pos = 0;
|
||||||
|
} else {
|
||||||
|
var sid = JSON.stringify(op.left);
|
||||||
|
pos = this.idArray.indexOf(sid) + 1;
|
||||||
|
if (pos <= 0) {
|
||||||
|
throw new Error("Unexpected operation!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.idArray.splice(pos, 0, JSON.stringify(op.id));
|
||||||
|
this.valArray.splice(pos, 0, op.content);
|
||||||
|
} else if (op.struct === "Delete") {
|
||||||
|
let pos = this.idArray.indexOf(JSON.stringify(op.target));
|
||||||
|
this.idArray.splice(pos, 1);
|
||||||
|
this.valArray.splice(pos, 1);
|
||||||
} else {
|
} else {
|
||||||
var sid = JSON.stringify(op.right);
|
throw new Error("Unexpected struct!");
|
||||||
pos = this.idArray.indexOf(sid);
|
|
||||||
}
|
}
|
||||||
if (pos < 0) {
|
|
||||||
throw new Error("Unexpected operation!");
|
|
||||||
}
|
|
||||||
this.idArray.splice(pos, 0, JSON.stringify(op.id));
|
|
||||||
this.valArray.splice(pos, 0, op.content);
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -50,7 +60,6 @@
|
|||||||
throw new Error("This position exceeds the range of the array!");
|
throw new Error("This position exceeds the range of the array!");
|
||||||
}
|
}
|
||||||
var mostLeft = pos === 0 ? null : JSON.parse(this.idArray[pos - 1]);
|
var mostLeft = pos === 0 ? null : JSON.parse(this.idArray[pos - 1]);
|
||||||
var mostRight = pos === this.idArray.length ? null : JSON.parse(this.idArray[pos]);
|
|
||||||
|
|
||||||
var ops = [];
|
var ops = [];
|
||||||
var prevId = mostLeft;
|
var prevId = mostLeft;
|
||||||
@ -58,7 +67,9 @@
|
|||||||
var op = {
|
var op = {
|
||||||
left: prevId,
|
left: prevId,
|
||||||
origin: prevId,
|
origin: prevId,
|
||||||
right: mostRight,
|
// right: mostRight,
|
||||||
|
// NOTE: I intentionally do not define right here, because it could be deleted
|
||||||
|
// at the time of creating this operation, and is therefore not defined in idArray
|
||||||
parent: this._model,
|
parent: this._model,
|
||||||
content: contents[i],
|
content: contents[i],
|
||||||
struct: "Insert",
|
struct: "Insert",
|
||||||
@ -70,19 +81,58 @@
|
|||||||
var eventHandler = this.eventHandler;
|
var eventHandler = this.eventHandler;
|
||||||
eventHandler.awaitAndPrematurelyCall(ops);
|
eventHandler.awaitAndPrematurelyCall(ops);
|
||||||
this.os.requestTransaction(function*(){
|
this.os.requestTransaction(function*(){
|
||||||
|
// now we can set the right reference.
|
||||||
|
var mostRight;
|
||||||
|
if (mostLeft != null) {
|
||||||
|
mostRight = (yield* this.getOperation(mostLeft)).right;
|
||||||
|
} else {
|
||||||
|
mostRight = (yield* this.getOperation(ops[0].parent)).start;
|
||||||
|
}
|
||||||
|
for (var j in ops) {
|
||||||
|
ops[j].right = mostRight;
|
||||||
|
}
|
||||||
yield* this.applyCreatedOperations(ops);
|
yield* this.applyCreatedOperations(ops);
|
||||||
eventHandler.awaitedLastOp(ops.length);
|
eventHandler.awaitedLastInserts(ops.length);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
*delete (pos) {
|
delete (pos, length = 1) {
|
||||||
|
if (typeof length !== "number") {
|
||||||
|
throw new Error("pos must be a number!");
|
||||||
|
}
|
||||||
if (typeof pos !== "number") {
|
if (typeof pos !== "number") {
|
||||||
throw new Error("pos must be a number!");
|
throw new Error("pos must be a number!");
|
||||||
}
|
}
|
||||||
var t = yield "transaction";
|
if (pos + length > this.idArray.length || pos < 0 || length < 0) {
|
||||||
var model = yield* t.getOperation(this._model);
|
throw new Error("The deletion range exceeds the range of the array!");
|
||||||
yield* Y.Struct.Array.delete.call(t, model, pos);
|
}
|
||||||
|
var eventHandler = this.eventHandler;
|
||||||
|
var newLeft = pos > 0 ? JSON.parse(this.idArray[pos - 1]) : null;
|
||||||
|
var dels = [];
|
||||||
|
for (var i = 0; i < length; i++) {
|
||||||
|
dels.push({
|
||||||
|
target: JSON.parse(this.idArray[pos + i]),
|
||||||
|
struct: "Delete"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
eventHandler.awaitAndPrematurelyCall(dels);
|
||||||
|
this.os.requestTransaction(function*(){
|
||||||
|
yield* this.applyCreatedOperations(dels);
|
||||||
|
eventHandler.awaitedLastDeletes(dels.length, newLeft);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
_changed (op) {
|
*_changed (transaction, op) {
|
||||||
|
if (op.struct === "Insert") {
|
||||||
|
var l = op.left;
|
||||||
|
var left;
|
||||||
|
while (l != null) {
|
||||||
|
left = yield* transaction.getOperation(l);
|
||||||
|
if (!left.deleted) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
l = left.left;
|
||||||
|
}
|
||||||
|
op.left = l;
|
||||||
|
}
|
||||||
this.eventHandler.receivedOp(op);
|
this.eventHandler.receivedOp(op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
/*eslint-env browser,jasmine */
|
/*eslint-env browser,jasmine */
|
||||||
|
|
||||||
var numberOfYArrayTests = 10;
|
var numberOfYArrayTests = 20;
|
||||||
|
|
||||||
describe("Array Type", function(){
|
describe("Array Type", function(){
|
||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 3000;
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000;
|
||||||
beforeEach(function(done){
|
beforeEach(function(done){
|
||||||
createUsers(this, 5, done);
|
createUsers(this, 5, done);
|
||||||
});
|
});
|
||||||
@ -42,11 +42,64 @@ describe("Array Type", function(){
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it("Basic insert&delete in array (handle three conflicts)", function(done){
|
||||||
|
var y = this.users[0];
|
||||||
|
var l1, l2, l3;
|
||||||
|
y.root.set("Array", Y.Array).then((array)=>{
|
||||||
|
l1 = array;
|
||||||
|
l1.insert(0, ["x", "y", "z"]);
|
||||||
|
y.connector.flushAll();
|
||||||
|
l1.insert(1, [0]);
|
||||||
|
return this.users[1].root.get("Array");
|
||||||
|
}).then((array)=>{
|
||||||
|
l2 = array;
|
||||||
|
l2.delete(0);
|
||||||
|
l2.delete(1);
|
||||||
|
return this.users[2].root.get("Array");
|
||||||
|
}).then((array)=>{
|
||||||
|
l3 = array;
|
||||||
|
l3.insert(1, [2]);
|
||||||
|
y.connector.flushAll();
|
||||||
|
expect(l1.toArray()).toEqual(l2.toArray());
|
||||||
|
expect(l2.toArray()).toEqual(l3.toArray());
|
||||||
|
expect(l2.toArray()).toEqual([0, 2, "y"]);
|
||||||
|
compareAllUsers(this.users);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
it("Basic insert. Then delete the whole array", function(done){
|
||||||
|
var y = this.users[0];
|
||||||
|
var l1, l2, l3;
|
||||||
|
y.root.set("Array", Y.Array).then((array)=>{
|
||||||
|
l1 = array;
|
||||||
|
l1.insert(0, ["x", "y", "z"]);
|
||||||
|
y.connector.flushAll();
|
||||||
|
l1.delete(0, 3);
|
||||||
|
return this.users[1].root.get("Array");
|
||||||
|
}).then((array)=>{
|
||||||
|
l2 = array;
|
||||||
|
return this.users[2].root.get("Array");
|
||||||
|
}).then((array)=>{
|
||||||
|
l3 = array;
|
||||||
|
y.connector.flushAll();
|
||||||
|
expect(l1.toArray()).toEqual(l2.toArray());
|
||||||
|
expect(l2.toArray()).toEqual(l3.toArray());
|
||||||
|
expect(l2.toArray()).toEqual([]);
|
||||||
|
compareAllUsers(this.users);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe("Random tests", function(){
|
describe(`${numberOfYArrayTests} Random tests`, function(){
|
||||||
var randomMapTransactions = [
|
var randomArrayTransactions = [
|
||||||
function insert (array) {
|
function insert (array) {
|
||||||
array.insert(getRandomNumber(array.toArray().length), [getRandomNumber()]);
|
array.insert(getRandomNumber(array.toArray().length), [getRandomNumber()]);
|
||||||
|
},
|
||||||
|
function _delete (array) {
|
||||||
|
var length = array.toArray().length;
|
||||||
|
if (length > 0) {
|
||||||
|
array.delete(getRandomNumber(length - 1));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
function compareArrayValues(arrays){
|
function compareArrayValues(arrays){
|
||||||
@ -82,7 +135,7 @@ describe("Array Type", function(){
|
|||||||
expect(this.arrays.length).toEqual(this.users.length);
|
expect(this.arrays.length).toEqual(this.users.length);
|
||||||
});
|
});
|
||||||
it(`succeed after ${numberOfYArrayTests} actions`, function(done){
|
it(`succeed after ${numberOfYArrayTests} actions`, function(done){
|
||||||
applyRandomTransactions(this.users, this.arrays, randomMapTransactions, numberOfYArrayTests);
|
applyRandomTransactions(this.users, this.arrays, randomArrayTransactions, numberOfYArrayTests);
|
||||||
setTimeout(()=>{
|
setTimeout(()=>{
|
||||||
compareAllUsers(this.users);
|
compareAllUsers(this.users);
|
||||||
compareArrayValues(this.arrays);
|
compareArrayValues(this.arrays);
|
||||||
|
@ -18,12 +18,12 @@ class EventHandler {
|
|||||||
this.awaiting++;
|
this.awaiting++;
|
||||||
this.onevent(ops);
|
this.onevent(ops);
|
||||||
}
|
}
|
||||||
awaitedLastOp (n) {
|
awaitedLastInserts (n) {
|
||||||
var ops = this.waiting.splice(this.waiting.length - n);
|
var ops = this.waiting.splice(this.waiting.length - n);
|
||||||
for (var oid = 0; oid < ops.length; oid++) {
|
for (var oid = 0; oid < ops.length; oid++) {
|
||||||
var op = ops[oid];
|
var op = ops[oid];
|
||||||
for (var i = this.waiting.length - 1; i >= 0; i--) {
|
for (var i = this.waiting.length - 1; i >= 0; i--) {
|
||||||
var w = this.waiting[i];
|
let w = this.waiting[i];
|
||||||
if (compareIds(op.left, w.id)) {
|
if (compareIds(op.left, w.id)) {
|
||||||
// include the effect of op in w
|
// include the effect of op in w
|
||||||
w.right = op.id;
|
w.right = op.id;
|
||||||
@ -36,7 +36,25 @@ class EventHandler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
this.tryCallEvents();
|
||||||
|
}
|
||||||
|
awaitedLastDeletes (n, newLeft) {
|
||||||
|
var ops = this.waiting.splice(this.waiting.length - n);
|
||||||
|
for (var j in ops) {
|
||||||
|
var del = ops[j];
|
||||||
|
if (newLeft != null) {
|
||||||
|
for (var i in this.waiting) {
|
||||||
|
let w = this.waiting[i];
|
||||||
|
// We will just care about w.left
|
||||||
|
if (compareIds(del.target, w.left)) {
|
||||||
|
del.left = newLeft;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.tryCallEvents();
|
||||||
|
}
|
||||||
|
tryCallEvents () {
|
||||||
this.awaiting--;
|
this.awaiting--;
|
||||||
if (this.awaiting <= 0) {
|
if (this.awaiting <= 0) {
|
||||||
var events = this.waiting;
|
var events = this.waiting;
|
||||||
@ -44,25 +62,39 @@ class EventHandler {
|
|||||||
this.onevent(events);
|
this.onevent(events);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
|
}
|
||||||
(function(){
|
(function(){
|
||||||
class Map {
|
class Map {
|
||||||
constructor (os, model) {
|
constructor (os, model) {
|
||||||
this._model = model.id;
|
this._model = model.id;
|
||||||
this.os = os;
|
this.os = os;
|
||||||
this.map = model.map;
|
this.map = copyObject(model.map);
|
||||||
this.contents = {};
|
this.contents = {};
|
||||||
this.opContents = {};
|
this.opContents = {};
|
||||||
this.eventHandler = new EventHandler( ops =>{
|
this.eventHandler = new EventHandler( ops =>{
|
||||||
for (var i in ops) {
|
for (var i in ops) {
|
||||||
var op = ops[i];
|
var op = ops[i];
|
||||||
if (op.left === null) {
|
if (op.struct === "Insert"){
|
||||||
if (op.opContent != null) {
|
if (op.left === null) {
|
||||||
this.opContents[op.parentSub] = op.opContent;
|
if (op.opContent != null) {
|
||||||
} else {
|
this.opContents[op.parentSub] = op.opContent;
|
||||||
this.contents[op.parentSub] = op.content;
|
} else {
|
||||||
|
this.contents[op.parentSub] = op.content;
|
||||||
|
}
|
||||||
|
this.map[op.parentSub] = op.id;
|
||||||
}
|
}
|
||||||
|
} else if (op.struct === "Delete") {
|
||||||
|
var key = op.key;
|
||||||
|
if (compareIds(this.map[key], op.target)) {
|
||||||
|
if (this.contents[key] != null) {
|
||||||
|
delete this.contents[key];
|
||||||
|
} else {
|
||||||
|
delete this.opContents[key];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
throw new Error("Unexpected Operation!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -82,6 +114,23 @@ class EventHandler {
|
|||||||
return def.promise;
|
return def.promise;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
delete (key) {
|
||||||
|
var right = this.map[key];
|
||||||
|
if (right != null) {
|
||||||
|
var del = {
|
||||||
|
target: right,
|
||||||
|
struct: "Delete"
|
||||||
|
};
|
||||||
|
var eventHandler = this.eventHandler;
|
||||||
|
var modDel = copyObject(del);
|
||||||
|
modDel.key = key;
|
||||||
|
eventHandler.awaitAndPrematurelyCall([modDel]);
|
||||||
|
this.os.requestTransaction(function*(){
|
||||||
|
yield* this.applyCreatedOperations([del]);
|
||||||
|
eventHandler.awaitedLastDeletes(1);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
set (key, value) {
|
set (key, value) {
|
||||||
// set property.
|
// set property.
|
||||||
// if property is a type, return a promise
|
// if property is a type, return a promise
|
||||||
@ -114,7 +163,7 @@ class EventHandler {
|
|||||||
|
|
||||||
this.os.requestTransaction(function*(){
|
this.os.requestTransaction(function*(){
|
||||||
yield* this.applyCreatedOperations([insert]);
|
yield* this.applyCreatedOperations([insert]);
|
||||||
eventHandler.awaitedLastOp(1);
|
eventHandler.awaitedLastInserts(1);
|
||||||
});
|
});
|
||||||
def.resolve(value);
|
def.resolve(value);
|
||||||
}
|
}
|
||||||
@ -126,7 +175,10 @@ class EventHandler {
|
|||||||
var model = yield* t.getOperation(this._model);
|
var model = yield* t.getOperation(this._model);
|
||||||
yield* Y.Struct.Map.delete.call(t, model, key);
|
yield* Y.Struct.Map.delete.call(t, model, key);
|
||||||
}*/
|
}*/
|
||||||
_changed (op) {
|
*_changed (transaction, op) {
|
||||||
|
if (op.struct === "Delete") {
|
||||||
|
op.key = (yield* transaction.getOperation(op.target)).parentSub;
|
||||||
|
}
|
||||||
this.eventHandler.receivedOp(op);
|
this.eventHandler.receivedOp(op);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
/*eslint-env browser,jasmine */
|
/*eslint-env browser,jasmine */
|
||||||
|
|
||||||
var numberOfYMapTests = 5;
|
var numberOfYMapTests = 70;
|
||||||
|
|
||||||
describe("Map Type", function(){
|
describe("Map Type", function(){
|
||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 3000;
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 3000;
|
||||||
@ -77,6 +77,25 @@ describe("Map Type", function(){
|
|||||||
done();
|
done();
|
||||||
}, 50);
|
}, 50);
|
||||||
});
|
});
|
||||||
|
it("Basic get&set&delete of Map property (handle conflict)", function(done){
|
||||||
|
var y = this.users[0];
|
||||||
|
y.connector.flushAll();
|
||||||
|
y.root.set("stuff", "c0");
|
||||||
|
y.root.delete("stuff");
|
||||||
|
|
||||||
|
this.users[1].root.set("stuff", "c1");
|
||||||
|
|
||||||
|
y.connector.flushAll();
|
||||||
|
|
||||||
|
setTimeout( () => {
|
||||||
|
for (var key in this.users) {
|
||||||
|
var u = this.users[key];
|
||||||
|
expect(u.root.get("stuff")).toBeUndefined();
|
||||||
|
compareAllUsers(this.users);
|
||||||
|
}
|
||||||
|
done();
|
||||||
|
}, 50);
|
||||||
|
});
|
||||||
it("Basic get&set of Map property (handle three conflicts)", function(done){
|
it("Basic get&set of Map property (handle three conflicts)", function(done){
|
||||||
var y = this.users[0];
|
var y = this.users[0];
|
||||||
this.users[0].root.set("stuff", "c0");
|
this.users[0].root.set("stuff", "c0");
|
||||||
@ -94,13 +113,36 @@ describe("Map Type", function(){
|
|||||||
done();
|
done();
|
||||||
}, 50);
|
}, 50);
|
||||||
});
|
});
|
||||||
|
it("Basic get&set&delete of Map property (handle three conflicts)", function(done){
|
||||||
|
var y = this.users[0];
|
||||||
|
this.users[0].root.set("stuff", "c0");
|
||||||
|
this.users[1].root.set("stuff", "c1");
|
||||||
|
this.users[2].root.set("stuff", "c2");
|
||||||
|
this.users[3].root.set("stuff", "c3");
|
||||||
|
y.connector.flushAll();
|
||||||
|
this.users[0].root.set("stuff", "deleteme");
|
||||||
|
this.users[0].root.delete("stuff");
|
||||||
|
this.users[1].root.set("stuff", "c1");
|
||||||
|
this.users[2].root.set("stuff", "c2");
|
||||||
|
this.users[3].root.set("stuff", "c3");
|
||||||
|
y.connector.flushAll();
|
||||||
|
|
||||||
|
setTimeout( () => {
|
||||||
|
for (var key in this.users) {
|
||||||
|
var u = this.users[key];
|
||||||
|
expect(u.root.get("stuff")).toBeUndefined();
|
||||||
|
}
|
||||||
|
compareAllUsers(this.users);
|
||||||
|
done();
|
||||||
|
}, 50);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe("Random tests", function(){
|
describe(`${numberOfYMapTests} Random tests`, function(){
|
||||||
var randomMapTransactions = [
|
var randomMapTransactions = [
|
||||||
function set (map) {
|
function set (map) {
|
||||||
map.set("somekey", getRandomNumber());
|
map.set("somekey", getRandomNumber());
|
||||||
},
|
},
|
||||||
function* delete_ (map) {
|
function delete_ (map) {
|
||||||
map.delete("somekey");
|
map.delete("somekey");
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
|
Loading…
x
Reference in New Issue
Block a user