created Array type that has a good time complexity for both insert and retrieval of objects
This commit is contained in:
parent
8cc374cabb
commit
d50d34dc12
@ -28,6 +28,7 @@
|
|||||||
"Operation": true,
|
"Operation": true,
|
||||||
"getRandom": true,
|
"getRandom": true,
|
||||||
"RBTree": true,
|
"RBTree": true,
|
||||||
"compareIds": true
|
"compareIds": true,
|
||||||
|
"EventHandler": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -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.id);
|
t = yield* Y[op.type].create(this.store, op);
|
||||||
this.store.initializedTypes[sid] = t;
|
this.store.initializedTypes[sid] = t;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -36,6 +36,18 @@ class AbstractTransaction { //eslint-disable-line no-unused-vars
|
|||||||
throw new Error("Operations must arrive in order!");
|
throw new Error("Operations must arrive in order!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*applyCreatedOperations (ops) {
|
||||||
|
var send = [];
|
||||||
|
for (var i = 0; i < ops.length; i++) {
|
||||||
|
var op = ops[i];
|
||||||
|
yield* Struct[op.struct].execute.call(this, op);
|
||||||
|
send.push(Struct[op.struct].encode(op));
|
||||||
|
}
|
||||||
|
this.store.y.connector.broadcast({
|
||||||
|
type: "update",
|
||||||
|
ops: send
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
type Listener = {
|
type Listener = {
|
||||||
@ -70,6 +82,13 @@ class AbstractOperationStore { //eslint-disable-line no-unused-vars
|
|||||||
}
|
}
|
||||||
setUserId (userId) {
|
setUserId (userId) {
|
||||||
this.userId = userId;
|
this.userId = userId;
|
||||||
|
this.opClock = 0;
|
||||||
|
}
|
||||||
|
getNextOpId () {
|
||||||
|
if (this.userId == null) {
|
||||||
|
throw new Error("OperationStore not yet initialized!");
|
||||||
|
}
|
||||||
|
return [this.userId, this.opClock++];
|
||||||
}
|
}
|
||||||
apply (ops) {
|
apply (ops) {
|
||||||
for (var key in ops) {
|
for (var key in ops) {
|
||||||
|
@ -14,13 +14,12 @@ function copyObject (o) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type StateVector = Array<State>;
|
type StateVector = Array<State>;
|
||||||
type OperationSet = Object; // os[Id] = op
|
|
||||||
type StateSet = Object;
|
type StateSet = Object;
|
||||||
|
|
||||||
Y.Memory = (function(){ //eslint-disable-line no-unused-vars
|
Y.Memory = (function(){ //eslint-disable-line no-unused-vars
|
||||||
class Transaction extends AbstractTransaction { //eslint-disable-line
|
class Transaction extends AbstractTransaction { //eslint-disable-line
|
||||||
ss: StateSet;
|
ss: StateSet;
|
||||||
os: OperationSet;
|
os: RBTree;
|
||||||
store: OperationStore;
|
store: OperationStore;
|
||||||
|
|
||||||
constructor (store : OperationStore) {
|
constructor (store : OperationStore) {
|
||||||
|
@ -35,28 +35,12 @@ function compareIds(id1, id2) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var Struct = {
|
var Struct = {
|
||||||
Operation: { //eslint-disable-line no-unused-vars
|
/*
|
||||||
create: function*(op : Op) : Struct.Operation {
|
{
|
||||||
var user = this.store.y.connector.userId;
|
target: Id
|
||||||
var state = yield* this.getState(user);
|
|
||||||
op.id = [user, state.clock];
|
|
||||||
yield* Struct[op.struct].execute.call(this, op);
|
|
||||||
|
|
||||||
this.store.y.connector.broadcast({
|
|
||||||
type: "update",
|
|
||||||
ops: [Struct[op.struct].encode(op)]
|
|
||||||
});
|
|
||||||
return op;
|
|
||||||
}
|
}
|
||||||
},
|
*/
|
||||||
Delete: {
|
Delete: {
|
||||||
create: function* (op) {
|
|
||||||
if (op.target == null) {
|
|
||||||
throw new Error("You must define a delete target!");
|
|
||||||
}
|
|
||||||
op.struct = "Delete";
|
|
||||||
return yield* Struct.Operation.create.call(this, op);
|
|
||||||
},
|
|
||||||
encode: function (op) {
|
encode: function (op) {
|
||||||
return op;
|
return op;
|
||||||
},
|
},
|
||||||
@ -77,20 +61,12 @@ var Struct = {
|
|||||||
content: any,
|
content: any,
|
||||||
left: Id,
|
left: Id,
|
||||||
right: Id,
|
right: Id,
|
||||||
|
origin: id,
|
||||||
parent: Id,
|
parent: Id,
|
||||||
parentSub: string (optional)
|
parentSub: string (optional),
|
||||||
|
id: this.os.getNextOpId()
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
create: function* ( op: Op ) : Insert {
|
|
||||||
if ( op.left === undefined
|
|
||||||
|| op.right === undefined
|
|
||||||
|| op.parent === undefined ) {
|
|
||||||
throw new Error("You must define left, right, and parent!");
|
|
||||||
}
|
|
||||||
op.origin = op.left;
|
|
||||||
op.struct = "Insert";
|
|
||||||
return yield* Struct.Operation.create.call(this, op);
|
|
||||||
},
|
|
||||||
encode: function(op){
|
encode: function(op){
|
||||||
/*var e = {
|
/*var e = {
|
||||||
id: op.id,
|
id: op.id,
|
||||||
@ -248,12 +224,15 @@ var Struct = {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
List: {
|
List: {
|
||||||
create: function* ( op : Op){
|
/*
|
||||||
op.start = null;
|
{
|
||||||
op.end = null;
|
start: null,
|
||||||
op.struct = "List";
|
end: null,
|
||||||
return yield* Struct.Operation.create.call(this, op);
|
struct: "List",
|
||||||
},
|
type: "",
|
||||||
|
id: this.os.getNextOpId()
|
||||||
|
}
|
||||||
|
*/
|
||||||
encode: function(op){
|
encode: function(op){
|
||||||
return {
|
return {
|
||||||
struct: "List",
|
struct: "List",
|
||||||
@ -315,7 +294,7 @@ var Struct = {
|
|||||||
while ( o != null) {
|
while ( o != null) {
|
||||||
var operation = yield* this.getOperation(o);
|
var operation = yield* this.getOperation(o);
|
||||||
if (!operation.deleted) {
|
if (!operation.deleted) {
|
||||||
res.push(f(operation.content));
|
res.push(f(operation));
|
||||||
}
|
}
|
||||||
o = operation.right;
|
o = operation.right;
|
||||||
}
|
}
|
||||||
@ -350,19 +329,18 @@ var Struct = {
|
|||||||
Map: {
|
Map: {
|
||||||
/*
|
/*
|
||||||
{
|
{
|
||||||
// empty
|
map: {},
|
||||||
|
struct: "Map",
|
||||||
|
type: "",
|
||||||
|
id: this.os.getNextOpId()
|
||||||
}
|
}
|
||||||
*/
|
*/
|
||||||
create: function* ( op : Op ){
|
|
||||||
op.map = {};
|
|
||||||
op.struct = "Map";
|
|
||||||
return yield* Struct.Operation.create.call(this, op);
|
|
||||||
},
|
|
||||||
encode: function(op){
|
encode: function(op){
|
||||||
return {
|
return {
|
||||||
struct: "Map",
|
struct: "Map",
|
||||||
type: op.type,
|
type: op.type,
|
||||||
id: op.id
|
id: op.id,
|
||||||
|
map: {} // overwrite map!!
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
requiredOps: function(){
|
requiredOps: function(){
|
||||||
|
109
src/Types/Array.js
Normal file
109
src/Types/Array.js
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
|
||||||
|
|
||||||
|
(function(){
|
||||||
|
|
||||||
|
class YArray {
|
||||||
|
constructor (os, _model, idArray, valArray) {
|
||||||
|
this.os = os;
|
||||||
|
this._model = _model;
|
||||||
|
// Array of all the operation id's
|
||||||
|
this.idArray = idArray;
|
||||||
|
this.valArray = valArray;
|
||||||
|
this.eventHandler = new EventHandler( ops =>{
|
||||||
|
for (var i in ops) {
|
||||||
|
var op = ops[i];
|
||||||
|
var pos;
|
||||||
|
if (op.right === null) {
|
||||||
|
pos = this.idArray.length;
|
||||||
|
} else {
|
||||||
|
var sid = JSON.stringify(op.right);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
get (pos) {
|
||||||
|
if (pos == null || typeof pos !== "number") {
|
||||||
|
throw new Error("pos must be a number!");
|
||||||
|
}
|
||||||
|
return this.valArray[pos];
|
||||||
|
}
|
||||||
|
toArray() {
|
||||||
|
return this.valArray.slice();
|
||||||
|
}
|
||||||
|
insert (pos, contents) {
|
||||||
|
if (typeof pos !== "number") {
|
||||||
|
throw new Error("pos must be a number!");
|
||||||
|
}
|
||||||
|
if (!(contents instanceof Array)) {
|
||||||
|
throw new Error("contents must be an Array of objects!");
|
||||||
|
}
|
||||||
|
if (contents.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (pos > this.idArray.length || pos < 0) {
|
||||||
|
throw new Error("This position exceeds the range of the array!");
|
||||||
|
}
|
||||||
|
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 prevId = mostLeft;
|
||||||
|
for (var i = 0; i < contents.length; i++) {
|
||||||
|
var op = {
|
||||||
|
left: prevId,
|
||||||
|
origin: prevId,
|
||||||
|
right: mostRight,
|
||||||
|
parent: this._model,
|
||||||
|
content: contents[i],
|
||||||
|
struct: "Insert",
|
||||||
|
id: this.os.getNextOpId()
|
||||||
|
};
|
||||||
|
ops.push(op);
|
||||||
|
prevId = op.id;
|
||||||
|
}
|
||||||
|
var eventHandler = this.eventHandler;
|
||||||
|
eventHandler.awaitAndPrematurelyCall(ops);
|
||||||
|
this.os.requestTransaction(function*(){
|
||||||
|
yield* this.applyCreatedOperations(ops);
|
||||||
|
eventHandler.awaitedLastOp(ops.length);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
*delete (pos) {
|
||||||
|
if (typeof pos !== "number") {
|
||||||
|
throw new Error("pos must be a number!");
|
||||||
|
}
|
||||||
|
var t = yield "transaction";
|
||||||
|
var model = yield* t.getOperation(this._model);
|
||||||
|
yield* Y.Struct.Array.delete.call(t, model, pos);
|
||||||
|
}
|
||||||
|
_changed (op) {
|
||||||
|
this.eventHandler.receivedOp(op);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Y.Array = function* _YArray(){
|
||||||
|
var model = {
|
||||||
|
start: null,
|
||||||
|
end: null,
|
||||||
|
struct: "List",
|
||||||
|
type: "Array",
|
||||||
|
id: this.store.getNextOpId()
|
||||||
|
};
|
||||||
|
yield* this.applyCreatedOperations([model]);
|
||||||
|
return yield* this.createType(model);
|
||||||
|
};
|
||||||
|
Y.Array.create = function* YArrayCreate(os, model){
|
||||||
|
var valArray = [];
|
||||||
|
var idArray = yield* Y.Struct.List.map.call(this, model, function(c){
|
||||||
|
valArray.push(c.content);
|
||||||
|
return JSON.stringify(c.id);
|
||||||
|
});
|
||||||
|
return new YArray(os, model.id, idArray, valArray);
|
||||||
|
};
|
||||||
|
})();
|
@ -1,48 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
(function(){
|
|
||||||
|
|
||||||
class List {
|
|
||||||
constructor (_model) {
|
|
||||||
this._model = _model;
|
|
||||||
}
|
|
||||||
*val (pos) {
|
|
||||||
var t = yield "transaction";
|
|
||||||
var model = yield* t.getOperation(this._model);
|
|
||||||
if (pos != null) {
|
|
||||||
var o = yield* Y.Struct.List.ref.call(t, model, pos);
|
|
||||||
return o ? o.content : null;
|
|
||||||
} else {
|
|
||||||
return yield* Y.Struct.List.map.call(t, model, function(c){return c; });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
*insert (pos, contents) {
|
|
||||||
if (typeof pos !== "number") {
|
|
||||||
throw new Error("pos must be a number!");
|
|
||||||
}
|
|
||||||
if (!(contents instanceof Array)) {
|
|
||||||
throw new Error("contents must be an Array of objects!");
|
|
||||||
}
|
|
||||||
var t = yield "transaction";
|
|
||||||
var model = yield* t.getOperation(this._model);
|
|
||||||
yield* Y.Struct.List.insert.call(t, model, pos, contents);
|
|
||||||
}
|
|
||||||
*delete (pos) {
|
|
||||||
if (typeof pos !== "number") {
|
|
||||||
throw new Error("pos must be a number!");
|
|
||||||
}
|
|
||||||
var t = yield "transaction";
|
|
||||||
var model = yield* t.getOperation(this._model);
|
|
||||||
yield* Y.Struct.List.delete.call(t, model, pos);
|
|
||||||
}
|
|
||||||
_changed () {
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Y.List = function* YList(){
|
|
||||||
var t = yield "transaction";
|
|
||||||
var model = yield* Y.Struct.List.create.call(t, {type: "List"});
|
|
||||||
return t.createType(model);
|
|
||||||
};
|
|
||||||
Y.List.Create = List;
|
|
||||||
})();
|
|
@ -14,12 +14,14 @@ class EventHandler {
|
|||||||
this.waiting.push(copyObject(op));
|
this.waiting.push(copyObject(op));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
awaitAndPrematurelyCall (op) {
|
awaitAndPrematurelyCall (ops) {
|
||||||
this.awaiting++;
|
this.awaiting++;
|
||||||
this.onevent([op]);
|
this.onevent(ops);
|
||||||
}
|
}
|
||||||
awaitedLastOp () {
|
awaitedLastOp (n) {
|
||||||
var op = this.waiting.pop();
|
var ops = this.waiting.splice(this.waiting.length - n);
|
||||||
|
for (var oid = 0; oid < ops.length; 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];
|
var w = this.waiting[i];
|
||||||
if (compareIds(op.left, w.id)) {
|
if (compareIds(op.left, w.id)) {
|
||||||
@ -33,6 +35,8 @@ class EventHandler {
|
|||||||
op.right = w.right;
|
op.right = w.right;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
this.awaiting--;
|
this.awaiting--;
|
||||||
if (this.awaiting <= 0) {
|
if (this.awaiting <= 0) {
|
||||||
var events = this.waiting;
|
var events = this.waiting;
|
||||||
@ -87,8 +91,10 @@ class EventHandler {
|
|||||||
var insert = {
|
var insert = {
|
||||||
left: null,
|
left: null,
|
||||||
right: right,
|
right: right,
|
||||||
|
origin: null,
|
||||||
parent: this._model,
|
parent: this._model,
|
||||||
parentSub: key
|
parentSub: key,
|
||||||
|
struct: "Insert"
|
||||||
};
|
};
|
||||||
var def = Promise.defer();
|
var def = Promise.defer();
|
||||||
if ( value != null && value.constructor === GeneratorFunction) {
|
if ( value != null && value.constructor === GeneratorFunction) {
|
||||||
@ -96,17 +102,19 @@ class EventHandler {
|
|||||||
this.os.requestTransaction(function*(){
|
this.os.requestTransaction(function*(){
|
||||||
var type = yield* value.call(this);
|
var type = yield* value.call(this);
|
||||||
insert.opContent = type._model;
|
insert.opContent = type._model;
|
||||||
yield* Struct.Insert.create.call(this, insert);
|
insert.id = this.store.getNextOpId();
|
||||||
|
yield* this.applyCreatedOperations([insert]);
|
||||||
def.resolve(type);
|
def.resolve(type);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
insert.content = value;
|
insert.content = value;
|
||||||
|
insert.id = this.os.getNextOpId();
|
||||||
var eventHandler = this.eventHandler;
|
var eventHandler = this.eventHandler;
|
||||||
eventHandler.awaitAndPrematurelyCall(insert);
|
eventHandler.awaitAndPrematurelyCall([insert]);
|
||||||
|
|
||||||
this.os.requestTransaction(function*(){
|
this.os.requestTransaction(function*(){
|
||||||
yield* Struct.Insert.create.call(this, insert);
|
yield* this.applyCreatedOperations([insert]);
|
||||||
eventHandler.awaitedLastOp();
|
eventHandler.awaitedLastOp(1);
|
||||||
});
|
});
|
||||||
def.resolve(value);
|
def.resolve(value);
|
||||||
}
|
}
|
||||||
@ -124,7 +132,13 @@ class EventHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Y.Map = function* YMap(){
|
Y.Map = function* YMap(){
|
||||||
var model = yield* Y.Struct.Map.create.call(this, {type: "Map"});
|
var model = {
|
||||||
|
map: {},
|
||||||
|
struct: "Map",
|
||||||
|
type: "Map",
|
||||||
|
id: this.store.getNextOpId()
|
||||||
|
};
|
||||||
|
yield* this.applyCreatedOperations([model]);
|
||||||
return yield* this.createType(model);
|
return yield* this.createType(model);
|
||||||
};
|
};
|
||||||
Y.Map.create = function* YMapCreate(os, model){
|
Y.Map.create = function* YMapCreate(os, model){
|
||||||
|
171
src/y.spec.js
171
src/y.spec.js
@ -21,9 +21,9 @@ function getRandomNumber(n) {
|
|||||||
return Math.floor(Math.random() * n);
|
return Math.floor(Math.random() * n);
|
||||||
}
|
}
|
||||||
|
|
||||||
var numberOfYMapTests = 30;
|
var numberOfYMapTests = 5;
|
||||||
|
|
||||||
function applyRandomTransactions (users, transactions, numberOfTransactions) {
|
function applyRandomTransactions (users, objects, transactions, numberOfTransactions) {
|
||||||
function randomTransaction (root) {
|
function randomTransaction (root) {
|
||||||
var f = getRandom(transactions);
|
var f = getRandom(transactions);
|
||||||
f(root);
|
f(root);
|
||||||
@ -34,7 +34,7 @@ function applyRandomTransactions (users, transactions, numberOfTransactions) {
|
|||||||
// 10% chance to flush
|
// 10% chance to flush
|
||||||
users[0].connector.flushOne();
|
users[0].connector.flushOne();
|
||||||
} else {
|
} else {
|
||||||
randomTransaction(getRandom(users).root);
|
randomTransaction(getRandom(objects));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,7 +70,7 @@ function compareAllUsers(users){
|
|||||||
}
|
}
|
||||||
|
|
||||||
describe("Yjs", function(){
|
describe("Yjs", function(){
|
||||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 500;
|
jasmine.DEFAULT_TIMEOUT_INTERVAL = 3000;
|
||||||
beforeEach(function(done){
|
beforeEach(function(done){
|
||||||
if (this.users != null) {
|
if (this.users != null) {
|
||||||
for (var y of this.users) {
|
for (var y of this.users) {
|
||||||
@ -121,6 +121,16 @@ describe("Yjs", function(){
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it("Map can set custom types (Array)", function(done){
|
||||||
|
var y = this.users[0].root;
|
||||||
|
y.set("Array", Y.Array).then(function(array) {
|
||||||
|
array.insert(0, [1, 2, 3]);
|
||||||
|
return y.get("Array");
|
||||||
|
}).then(function(array){
|
||||||
|
expect(array.toArray()).toEqual([1, 2, 3]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
it("Basic get&set of Map property (converge via update)", function(done){
|
it("Basic get&set of Map property (converge via update)", function(done){
|
||||||
var u = this.users[0];
|
var u = this.users[0];
|
||||||
u.connector.flushAll();
|
u.connector.flushAll();
|
||||||
@ -172,6 +182,28 @@ describe("Yjs", function(){
|
|||||||
done();
|
done();
|
||||||
}, 50);
|
}, 50);
|
||||||
});
|
});
|
||||||
|
it("Basic insert 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;
|
||||||
|
y.connector.flushAll();
|
||||||
|
l1.insert(0, [0]);
|
||||||
|
return this.users[1].root.get("Array");
|
||||||
|
}).then((array)=>{
|
||||||
|
l2 = array;
|
||||||
|
l2.insert(0, [1]);
|
||||||
|
return this.users[2].root.get("Array");
|
||||||
|
}).then((array)=>{
|
||||||
|
l3 = array;
|
||||||
|
l3.insert(0, [2]);
|
||||||
|
y.connector.flushAll();
|
||||||
|
expect(l1.toArray()).toEqual(l2.toArray());
|
||||||
|
expect(l2.toArray()).toEqual(l3.toArray());
|
||||||
|
compareAllUsers(this.users);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
describe("Map random tests", function(){
|
describe("Map random tests", function(){
|
||||||
var randomMapTransactions = [
|
var randomMapTransactions = [
|
||||||
@ -182,10 +214,10 @@ describe("Yjs", function(){
|
|||||||
map.delete("somekey");
|
map.delete("somekey");
|
||||||
}
|
}
|
||||||
];
|
];
|
||||||
function compareMapValues(users){
|
function compareMapValues(maps){
|
||||||
var firstMap;
|
var firstMap;
|
||||||
for (var u of users) {
|
for (var map of maps) {
|
||||||
var val = u.root.get();
|
var val = map.get();
|
||||||
if (firstMap == null) {
|
if (firstMap == null) {
|
||||||
firstMap = val;
|
firstMap = val;
|
||||||
} else {
|
} else {
|
||||||
@ -193,79 +225,80 @@ describe("Yjs", function(){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
it(`succeed after ${numberOfYMapTests} actions with flush before transactions`, function(done){
|
beforeEach(function(done){
|
||||||
|
this.users[0].root.set("Map", Y.Map);
|
||||||
this.users[0].connector.flushAll();
|
this.users[0].connector.flushAll();
|
||||||
applyRandomTransactions(this.users, randomMapTransactions, numberOfYMapTests);
|
|
||||||
setTimeout(()=>{
|
|
||||||
compareAllUsers(this.users);
|
|
||||||
compareMapValues(this.users);
|
|
||||||
done();
|
|
||||||
}, 500);
|
|
||||||
});
|
|
||||||
it(`succeed after ${numberOfYMapTests} actions without flush before transactions`, function(done){
|
|
||||||
applyRandomTransactions(this.users, randomMapTransactions, numberOfYMapTests);
|
|
||||||
setTimeout(()=>{
|
|
||||||
compareAllUsers(this.users);
|
|
||||||
compareMapValues(this.users);
|
|
||||||
done();
|
|
||||||
}, 500);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
/*
|
var then = Promise.resolve();
|
||||||
|
var maps = [];
|
||||||
var numberOfYListTests = 100;
|
for (var u of this.users) {
|
||||||
describe("List random tests", function(){
|
then = then.then(function(){ //eslint-disable-line
|
||||||
var randomListTests = [function* insert (root) {
|
return u.root.get("Map");
|
||||||
var list = yield* root.get("list");
|
}).then(function(map){//eslint-disable-line
|
||||||
yield* list.insert(Math.floor(Math.random() * 10), [getRandomNumber()]);
|
maps.push(map);
|
||||||
}, function* delete_(root) {
|
|
||||||
var list = yield* root.get("list");
|
|
||||||
yield* list.delete(Math.floor(Math.random() * 10));
|
|
||||||
}];
|
|
||||||
beforeEach(function(){
|
|
||||||
this.users[0].transact(function*(root){
|
|
||||||
var list = yield* Y.List();
|
|
||||||
yield* root.set("list", list);
|
|
||||||
});
|
});
|
||||||
this.users[0].connector.flushAll();
|
|
||||||
});
|
|
||||||
|
|
||||||
it(`succeeds after ${numberOfYListTests} actions`, function(){
|
|
||||||
applyRandomTransactions(this.users, randomListTests, numberOfYListTests);
|
|
||||||
compareAllUsers(this.users);
|
|
||||||
var userList;
|
|
||||||
this.users[0].transact(function*(root){
|
|
||||||
var list = yield* root.get("list");
|
|
||||||
if (userList == null) {
|
|
||||||
userList = yield* list.get();
|
|
||||||
} else {
|
|
||||||
expect(userList).toEqual(yield* list.get());
|
|
||||||
expect(userList.length > 0).toBeTruthy();
|
|
||||||
}
|
}
|
||||||
|
this.maps = maps;
|
||||||
|
then.then(function(){
|
||||||
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
it(`succeed after ${numberOfYMapTests} actions`, function(done){
|
||||||
|
applyRandomTransactions(this.users, this.maps, randomMapTransactions, numberOfYMapTests);
|
||||||
|
setTimeout(()=>{
|
||||||
|
compareAllUsers(this.users);
|
||||||
|
compareMapValues(this.maps);
|
||||||
|
done();
|
||||||
|
}, 500);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe("Map debug tests", function(){
|
var numberOfYArrayTests = 10;
|
||||||
beforeEach(function(){
|
describe("Array random tests", function(){
|
||||||
this.u1 = this.users[0];
|
var randomMapTransactions = [
|
||||||
this.u2 = this.users[1];
|
function insert (array) {
|
||||||
this.u3 = this.users[2];
|
array.insert(getRandomNumber(array.toArray().length), [getRandomNumber()]);
|
||||||
|
}
|
||||||
|
];
|
||||||
|
function compareArrayValues(arrays){
|
||||||
|
var firstArray;
|
||||||
|
for (var l of arrays) {
|
||||||
|
var val = l.toArray();
|
||||||
|
if (firstArray == null) {
|
||||||
|
firstArray = val;
|
||||||
|
} else {
|
||||||
|
expect(val).toEqual(firstArray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
beforeEach(function(done){
|
||||||
|
this.users[0].root.set("Array", Y.Array);
|
||||||
|
this.users[0].connector.flushAll();
|
||||||
|
|
||||||
|
var then = Promise.resolve();
|
||||||
|
var arrays = [];
|
||||||
|
for (var u of this.users) {
|
||||||
|
then = then.then(function(){ //eslint-disable-line
|
||||||
|
return u.root.get("Array");
|
||||||
|
}).then(function(array){//eslint-disable-line
|
||||||
|
arrays.push(array);
|
||||||
});
|
});
|
||||||
it("concurrent insertions #1", function(){
|
}
|
||||||
this.u1.transact(function*(root){
|
this.arrays = arrays;
|
||||||
var op = {
|
then.then(function(){
|
||||||
content: 1,
|
done();
|
||||||
left: null,
|
|
||||||
right: null,
|
|
||||||
parent: root._model,
|
|
||||||
parentSub: "a"
|
|
||||||
};
|
|
||||||
Struct.Insert.create.call(this, op);
|
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
it("arrays.length equals users.length", function(){
|
||||||
|
expect(this.arrays.length).toEqual(this.users.length);
|
||||||
|
});
|
||||||
|
it(`succeed after ${numberOfYArrayTests} actions`, function(done){
|
||||||
|
applyRandomTransactions(this.users, this.arrays, randomMapTransactions, numberOfYArrayTests);
|
||||||
|
setTimeout(()=>{
|
||||||
compareAllUsers(this.users);
|
compareAllUsers(this.users);
|
||||||
|
compareArrayValues(this.arrays);
|
||||||
|
done();
|
||||||
|
}, 500);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
*/
|
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user