fixing types.

This commit is contained in:
Kevin Jahns 2015-07-09 15:50:59 +02:00
parent f862fae473
commit 9b45a78e58
9 changed files with 76 additions and 61 deletions

View File

@ -4,8 +4,22 @@ class AbstractTransaction { //eslint-disable-line no-unused-vars
this.store = store;
}
*getType (id) {
var op = yield* this.getOperation(id);
return new Y[op.type].Create(op);
var sid = JSON.stringify(id);
var t = this.store.initializedTypes[sid];
if (t == null) {
var op = yield* this.getOperation(id);
if (op != null) {
t = new Y[op.type].Create(op.id);
this.store.initializedTypes[sid] = t;
}
}
return t;
}
createType (model) {
var sid = JSON.stringify(model.id);
var t = new Y[model.type].Create(model.id);
this.store.initializedTypes[sid] = t;
return t;
}
// returns false if operation is not expected.
*addOperation (op) {
@ -34,9 +48,6 @@ type Id = [string, number];
class AbstractOperationStore { //eslint-disable-line no-unused-vars
constructor (y) {
this.y = y;
this.parentListeners = {};
this.parentListenersRequestPending = false;
this.parentListenersActivated = {};
// E.g. this.listenersById[id] : Array<Listener>
this.listenersById = {};
// Execute the next time a transaction is requested
@ -53,6 +64,9 @@ class AbstractOperationStore { //eslint-disable-line no-unused-vars
Always remember to first overwrite
a property before you iterate over it!
*/
// TODO: Use ES7 Weak Maps. This way types that are no longer user,
// wont be kept in memory.
this.initializedTypes = {};
}
setUserId (userId) {
this.userId = userId;
@ -142,32 +156,11 @@ class AbstractOperationStore { //eslint-disable-line no-unused-vars
}
}
}
// notify parent listeners, if possible
var listeners = this.parentListeners[op.parent];
if ( this.parentListenersRequestPending
|| ( listeners == null )
|| ( listeners.length === 0 )) {
return;
// notify parent, if it has been initialized as a custom type
var t = this.initializedTypes[JSON.stringify(op.parent)];
if (t != null) {
t._changed(op);
}
var al = this.parentListenersActivated[JSON.stringify(op.parent)];
if ( al == null ){
al = [];
this.parentListenersActivated[JSON.stringify(op.parent)] = al;
}
al.push(op);
this.parentListenersRequestPending = true;
var store = this;
this.requestTransaction(function*(){
store.parentListenersRequestPending = false;
var activatedOperations = store.parentListenersActivated;
store.parentListenersActivated = {};
for (var parentId in activatedOperations){
var parent = yield* this.getOperation(parentId);
Struct[parent.struct].notifyObservers(activatedOperations[parentId]);
}
});
}
removeParentListener (id, f) {
var ls = this.parentListeners[id];

View File

@ -35,12 +35,10 @@ Y.Memory = (function(){ //eslint-disable-line no-unused-vars
return op;
}
*getOperation (id) {
var op = this.os.find(id);
if (op == null) {
throw new Error("Op does not exist..");
} else {
return op;
if (id == null) {
throw new Error("You must define id!");
}
return this.os.find(id);
}
*removeOperation (id) {
this.os.delete(id);
@ -123,13 +121,13 @@ Y.Memory = (function(){ //eslint-disable-line no-unused-vars
}
requestTransaction (makeGen : Function) {
var t = new Transaction(this);
var gen = makeGen.call(t, new Y.Map.Create(["_", 0]));
var gen = makeGen.call(t, t.getType(["_", 0]).next().value);
var res = gen.next();
while(!res.done){
if (res.value === "transaction") {
res = gen.next(t);
} else {
throw new Error("You may not yield this type. (Maybe you meant to use 'yield*'?)");
throw new Error("You must not yield this type. (Maybe you meant to use 'yield*'?)");
}
}
}

View File

@ -417,9 +417,12 @@ var Struct = {
}
},
get: function* (op, name) {
var res = yield* this.getOperation(op.map[name]);
return (res == null || res.deleted) ? void 0 : (res.opContent == null
? res.content : yield* this.getType(res.opContent));
var oid = op.map[name];
if (oid != null) {
var res = yield* this.getOperation(oid);
return (res == null || res.deleted) ? void 0 : (res.opContent == null
? res.content : yield* this.getType(res.opContent));
}
},
set: function* (op, name, value) {
var right = op.map[name] || null;
@ -429,19 +432,13 @@ var Struct = {
parent: op.id,
parentSub: name
};
var oid;
if ( value != null && value._model != null
&& (oid = value._model.id) != null && oid.length === 2) {
insert.opContent = oid;
&& value._model.length === 2) {
insert.opContent = value._model;
} else {
insert.content = value;
}
yield* Struct.Insert.create.call(this, insert);
if (right != null) {
yield* Struct.Delete.create.call(this, {
target: right
});
}
},
delete: function* (op, name) {
var v = op.map[name] || null;

View File

@ -8,11 +8,12 @@
}
*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, this._model, pos);
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, this._model, function(c){return c; });
return yield* Y.Struct.List.map.call(t, model, function(c){return c; });
}
}
*insert (pos, contents) {
@ -23,21 +24,25 @@
throw new Error("contents must be an Array of objects!");
}
var t = yield "transaction";
yield* Y.Struct.List.insert.call(t, this._model, pos, contents);
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";
yield* Y.Struct.List.delete.call(t, this._model, pos);
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 new List(model);
return t.createType(model);
};
Y.List.Create = List;
})();

View File

@ -29,13 +29,15 @@
var model = yield* t.getOperation(this._model);
yield* Y.Struct.Map.delete.call(t, model, key);
}
_changed () {
}
}
Y.Map = function* YMap(){
var t = yield "transaction";
if (this instanceof Y.AbstractOperationStore) {
var model = yield* Y.Struct.map.create.call(t, {type: "Map"});
return new Map(model);
return t.createType(model);
} else {
throw new Error("Don't use `new` to create this type!");
}

View File

@ -8,11 +8,14 @@ class Y { //eslint-disable-line no-unused-vars
this.connector = new Y[opts.connector.name](this, opts.connector);
this.db.requestTransaction(function*(){
// create initial Map type
yield* this.addOperation({
var model = {
id: ["_", 0],
struct: "Map",
type: "Map",
map: {}
});
};
yield* this.addOperation(model);
this.createType(model);
});
}
transact (generator) {

View File

@ -21,7 +21,6 @@ function getRandomNumber(n) {
return Math.floor(Math.random() * n);
}
var numberOfYMapTests = 30;
function applyRandomTransactions (users, transactions, numberOfTransactions) {
@ -94,12 +93,30 @@ describe("Yjs", function(){
});
describe("Basic tests", function(){
it("There is an initial Map type", function(){
it("There is an initial Map type & it is created only once", function(){
var y = this.users[0];
var root1;
y.transact(function*(root){
expect(root).not.toBeUndefined();
root1 = root;
});
y.transact(function*(root2){
expect(root1).toBe(root2);
});
});
it("Custom Types are created only once", function(){
var y = this.users[0];
var l1;
y.transact(function*(root){
var l = yield* Y.List();
yield* root.val("list", l);
l1 = l;
});
y.transact(function*(root){
expect(l1).toBe(yield* root.val("list"));
});
});
it("Basic get&set of Map property (converge via sync)", function(){
var y = this.users[0];
y.transact(function*(root){

4
y.js

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long