basic get&set of Map properties works
This commit is contained in:
parent
8f63147dbc
commit
bffbb6ca27
@ -53,9 +53,9 @@ var polyfills = [
|
||||
];
|
||||
|
||||
var files = {
|
||||
y: polyfills.concat(["src/**/*.js", "!src/**/*.spec.js"]),
|
||||
y: polyfills.concat(["src/y.js", "src/**/*.js", "!src/**/*.spec.js"]),
|
||||
lint: ["src/**/*.js", "gulpfile.js"],
|
||||
test: polyfills.concat(["src/**/*.js"]),
|
||||
test: polyfills.concat(["src/y.js", "src/**/*.js"]),
|
||||
build_test: ["build_test/y.js"]
|
||||
};
|
||||
|
||||
@ -119,7 +119,7 @@ gulp.task("build_jasmine_browser", function(){
|
||||
});
|
||||
|
||||
|
||||
gulp.task("develop", ["build_jasmine_browser", "test", "build"], function(){
|
||||
gulp.task("develop", ["build_jasmine_browser", "build"], function(){
|
||||
|
||||
gulp.watch(files.test, ["build_jasmine_browser"]);
|
||||
gulp.watch(files.test, ["test"]);
|
||||
|
@ -5,7 +5,8 @@ class AbstractConnector { //eslint-disable-line no-unused-vars
|
||||
.role : String Role of this client ("master" or "slave")
|
||||
.userId : String that uniquely defines the user.
|
||||
*/
|
||||
constructor (opts) {
|
||||
constructor (y, opts) {
|
||||
this.y = y;
|
||||
if (opts == null){
|
||||
opts = {};
|
||||
}
|
||||
@ -23,7 +24,8 @@ class AbstractConnector { //eslint-disable-line no-unused-vars
|
||||
this.currentSyncTarget = null;
|
||||
}
|
||||
setUserId (userId) {
|
||||
this.os.setUserId(userId);
|
||||
this.userId = userId;
|
||||
this.y.db.setUserId(userId);
|
||||
}
|
||||
onUserEvent (f) {
|
||||
this.userEventListeners.push(f);
|
||||
|
@ -16,8 +16,9 @@ var globalRoom = {
|
||||
users: {},
|
||||
buffers: {},
|
||||
removeUser: function(user){
|
||||
for (var u of this.users) {
|
||||
u.userLeft(user);
|
||||
|
||||
for (var i in this.users) {
|
||||
this.users[i].userLeft(user);
|
||||
}
|
||||
delete this.users[user];
|
||||
delete this.buffers[user];
|
||||
@ -49,11 +50,11 @@ setInterval(function(){
|
||||
var userIdCounter = 0;
|
||||
|
||||
class Test extends AbstractConnector {
|
||||
constructor (options) {
|
||||
constructor (y, options) {
|
||||
if(options === undefined){
|
||||
throw new Error("Options must not be undefined!");
|
||||
}
|
||||
super({
|
||||
super(y, {
|
||||
role: "master"
|
||||
});
|
||||
|
||||
|
@ -5,10 +5,11 @@ class AbstractTransaction { //eslint-disable-line no-unused-vars
|
||||
}
|
||||
// returns false if operation is not expected.
|
||||
*addOperation (op) {
|
||||
var state = this.getState(op.id[0]);
|
||||
var state = yield* this.getState(op.id[0]);
|
||||
if (op.id[1] === state.clock){
|
||||
state.clock++;
|
||||
yield* this.setState(state);
|
||||
yield* this.setOperation(op);
|
||||
this.store.operationAdded(op);
|
||||
return true;
|
||||
} else {
|
||||
@ -16,6 +17,7 @@ class AbstractTransaction { //eslint-disable-line no-unused-vars
|
||||
}
|
||||
}
|
||||
}
|
||||
Y.AbstractTransaction = AbstractTransaction;
|
||||
|
||||
type Listener = {
|
||||
f : GeneratorFunction, // is called when all operations are available
|
||||
@ -47,6 +49,9 @@ class AbstractOperationStore { //eslint-disable-line no-unused-vars
|
||||
a property before you iterate over it!
|
||||
*/
|
||||
}
|
||||
setUserId (userId) {
|
||||
this.userId = userId;
|
||||
}
|
||||
apply (ops) {
|
||||
for (var o of ops) {
|
||||
var required = Y.Struct[o.type].requiredOps(o);
|
||||
@ -169,3 +174,4 @@ class AbstractOperationStore { //eslint-disable-line no-unused-vars
|
||||
ls.push(f);
|
||||
}
|
||||
}
|
||||
Y.AbstractOperationStore = AbstractOperationStore;
|
||||
|
@ -113,11 +113,16 @@ Y.IndexedDB = (function(){ //eslint-disable-line no-unused-vars
|
||||
if (opts == null) {
|
||||
opts = {};
|
||||
}
|
||||
if (opts.namespace != null || typeof opts.namespace !== "string") {
|
||||
if (opts.namespace == null || typeof opts.namespace !== "string") {
|
||||
throw new Error("IndexedDB: expect a string (opts.namespace)!");
|
||||
} else {
|
||||
this.namespace = opts.namespace;
|
||||
}
|
||||
if (opts.idbVersion != null) {
|
||||
this.idbVersion = opts.idbVersion;
|
||||
} else {
|
||||
this.idbVersion = 5;
|
||||
}
|
||||
|
||||
this.transactionQueue = {
|
||||
queue: [],
|
||||
@ -127,7 +132,7 @@ Y.IndexedDB = (function(){ //eslint-disable-line no-unused-vars
|
||||
var store = this;
|
||||
|
||||
var tGen = (function *transactionGen(){
|
||||
store.db = yield indexedDB.open(opts.namespace, 3);
|
||||
store.db = yield indexedDB.open(opts.namespace, store.idbVersion);
|
||||
var transactionQueue = store.transactionQueue;
|
||||
|
||||
var transaction = null;
|
||||
@ -174,8 +179,12 @@ Y.IndexedDB = (function(){ //eslint-disable-line no-unused-vars
|
||||
};
|
||||
request.onupgradeneeded = function(event){
|
||||
var db = event.target.result;
|
||||
db.createObjectStore("OperationStore", {keyPath: "id"});
|
||||
db.createObjectStore("StateVector", {keyPath: "user"});
|
||||
try {
|
||||
db.createObjectStore("OperationStore", {keyPath: "id"});
|
||||
db.createObjectStore("StateVector", {keyPath: "user"});
|
||||
} catch (e) {
|
||||
// console.log("Store already exists!");
|
||||
}
|
||||
};
|
||||
} else {
|
||||
tGen.throw("You can not yield this type!");
|
||||
|
@ -4,7 +4,7 @@
|
||||
if(typeof window !== "undefined"){
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 1000;
|
||||
describe("IndexedDB", function() {
|
||||
var ob = new IndexedDB("Test");
|
||||
var ob = new Y.IndexedDB(null, {namespace: "Test"});
|
||||
|
||||
it("can add and get operation", function(done) {
|
||||
ob.requestTransaction(function*(){
|
||||
|
@ -16,7 +16,7 @@ Y.Memory = (function(){ //eslint-disable-line no-unused-vars
|
||||
|
||||
constructor (store : OperationStore) {
|
||||
super(store);
|
||||
this.sv = store.ss;
|
||||
this.ss = store.ss;
|
||||
this.os = store.os;
|
||||
}
|
||||
*setOperation (op) {
|
||||
@ -30,7 +30,7 @@ Y.Memory = (function(){ //eslint-disable-line no-unused-vars
|
||||
delete this.os[JSON.stringify(id)];
|
||||
}
|
||||
*setState (state : State) : State {
|
||||
this.sv[state.user] = state.clock;
|
||||
this.ss[state.user] = state.clock;
|
||||
}
|
||||
*getState (user : string) : State {
|
||||
var clock = this.ss[user];
|
||||
@ -80,18 +80,21 @@ Y.Memory = (function(){ //eslint-disable-line no-unused-vars
|
||||
}
|
||||
}
|
||||
class OperationStore extends AbstractOperationStore { //eslint-disable-line no-undef
|
||||
namespace: string;
|
||||
ready: Promise;
|
||||
whenReadyListeners: Array<Function>;
|
||||
constructor (y) {
|
||||
super(y);
|
||||
this.os = {};
|
||||
this.ss = {};
|
||||
}
|
||||
requestTransaction (makeGen : Function) {
|
||||
var t = new Transaction(this);
|
||||
var gen = makeGen.call(t);
|
||||
gen.next();
|
||||
if (gen.done !== true) {
|
||||
throw new Error("transaction is supposed to be done. Note: you may not yield with this transaction! (yield* is allowed though)");
|
||||
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*'?)");
|
||||
}
|
||||
}
|
||||
}
|
||||
*removeDatabase () {
|
||||
|
@ -19,6 +19,21 @@ type Insert = {
|
||||
content: any
|
||||
};
|
||||
|
||||
function compareIds(id1, id2) {
|
||||
if (id1 == null) {
|
||||
if (id2 == null) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (id1[0] === id2[0] && id1[1] === id2[1]) {
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var Struct = {
|
||||
Operation: { //eslint-disable-line no-unused-vars
|
||||
create: function*(op : Op) : Struct.Operation {
|
||||
@ -55,6 +70,25 @@ var Struct = {
|
||||
op.right.left = op.id;
|
||||
yield* this.setOperation(op.right);
|
||||
}
|
||||
var parent = yield* this.getOperation(op.parent);
|
||||
if (op.parentSub != null){
|
||||
if (compareIds(parent.map[op.parentSub], op.left)) {
|
||||
parent.map[op.parentSub] = op.id;
|
||||
yield* this.setOperation(parent);
|
||||
}
|
||||
} else {
|
||||
var start = compareIds(parent.start, op.right);
|
||||
var end = compareIds(parent.end, op.left);
|
||||
if (start || end) {
|
||||
if (start) {
|
||||
parent.start = op.id;
|
||||
}
|
||||
if (end) {
|
||||
parent.end = op.id;
|
||||
}
|
||||
yield* this.setOperation(parent);
|
||||
}
|
||||
}
|
||||
return op;
|
||||
},
|
||||
requiredOps: function(op, ids){
|
||||
@ -209,6 +243,11 @@ var Struct = {
|
||||
}
|
||||
},
|
||||
Map: {
|
||||
/*
|
||||
{
|
||||
// empty
|
||||
}
|
||||
*/
|
||||
create: function*( op : Op ){
|
||||
op.map = {};
|
||||
op.struct = "Map";
|
||||
@ -224,7 +263,7 @@ var Struct = {
|
||||
// nop
|
||||
},
|
||||
get: function* (op, name) {
|
||||
return yield* this.getOperation(op.map[name].end);
|
||||
return (yield* this.getOperation(op.map[name])).content;
|
||||
},
|
||||
set: function* (op, name, value) {
|
||||
var end = op.map[name];
|
||||
@ -243,3 +282,5 @@ var Struct = {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Y.Struct = Struct;
|
||||
|
29
src/Types/Map.js
Normal file
29
src/Types/Map.js
Normal file
@ -0,0 +1,29 @@
|
||||
|
||||
(function(){
|
||||
class Map {
|
||||
constructor (_model) {
|
||||
this._model = _model;
|
||||
}
|
||||
*val () {
|
||||
var transaction = yield "transaction";
|
||||
var model = yield* transaction.getOperation(this._model);
|
||||
if (arguments.length === 0) {
|
||||
throw new Error("Implement this case!");
|
||||
} else if (arguments.length === 1) {
|
||||
return yield* Y.Struct.Map.get.call(transaction, model, arguments[0]);
|
||||
} else {
|
||||
return yield* Y.Struct.Map.set.call(transaction, model, arguments[0], arguments[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Y.Map = function* YMap(){
|
||||
if (this instanceof Y.AbstractOperationStore) {
|
||||
var model = yield* Y.Struct.map.create.call(this);
|
||||
return new Map(model);
|
||||
} else {
|
||||
throw new Error("Don't use `new` to create this type!");
|
||||
}
|
||||
};
|
||||
Y.Map.Create = Map;
|
||||
})();
|
@ -1,25 +0,0 @@
|
||||
|
||||
(function(){
|
||||
class Map {
|
||||
constructor (_model) {
|
||||
this._model = _model;
|
||||
}
|
||||
*val () {
|
||||
var transaction = yield "transaction";
|
||||
var model = transaction.getOperation(this._model);
|
||||
if (arguments.length === 0) {
|
||||
throw new Error("Implement this case!");
|
||||
} else if (arguments.length === 1) {
|
||||
return yield* this.Struct.Map.get.call(transaction, model, arguments[0]);
|
||||
} else {
|
||||
return yield* this.Struct.Map.set.call(transaction, model, arguments[0], arguments[1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Y.Map = function* YMap(){
|
||||
var model = yield* this.Struct.map.create.call(this);
|
||||
return new Map(model);
|
||||
};
|
||||
Y.Map.Create = Map;
|
||||
})();
|
16
src/y.js
16
src/y.js
@ -1,11 +1,25 @@
|
||||
/* @flow */
|
||||
|
||||
const GeneratorFunction = (function*(){}).constructor;
|
||||
|
||||
class Y { //eslint-disable-line no-unused-vars
|
||||
constructor (opts) {
|
||||
this.connector = new Y[opts.connector.name](opts.connector);
|
||||
this.db = new Y[opts.db.name](this, opts.db);
|
||||
this.connector = new Y[opts.connector.name](this, opts.connector);
|
||||
var y = this;
|
||||
this.db.requestTransaction(function*(){
|
||||
yield* this.addOperation({
|
||||
id: ["_", 0],
|
||||
struct: "Map",
|
||||
map: {}
|
||||
});
|
||||
y.root = new Y.Map.Create(["_", 0]);
|
||||
});
|
||||
}
|
||||
transact (generator) {
|
||||
if (generator.constructor !== GeneratorFunction) {
|
||||
throw new Error("y.transact requires a Generator function! E.g. function*(){/*..*/}");
|
||||
}
|
||||
this.db.requestTransaction(generator);
|
||||
}
|
||||
destroy () {
|
||||
|
@ -2,6 +2,7 @@
|
||||
/*eslint-env browser,jasmine */
|
||||
|
||||
describe("Yjs (basic)", function(){
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 500;
|
||||
beforeEach(function(){
|
||||
this.users = [];
|
||||
for (var i = 0; i < 5; i++) {
|
||||
@ -21,9 +22,18 @@ describe("Yjs (basic)", function(){
|
||||
}
|
||||
this.users = [];
|
||||
});
|
||||
it("can List.insert and get value from the other user", function(done){
|
||||
this.users[0].val("name", 1);
|
||||
this.users[0].connector.whenSynced(function(){
|
||||
it("There is an initial Map type", function(done){
|
||||
var y = this.users[0];
|
||||
y.transact(function*(){
|
||||
expect(y.root).not.toBeUndefined();
|
||||
done();
|
||||
});
|
||||
});
|
||||
it("Basic get&set of Map property", function(done){
|
||||
var y = this.users[0];
|
||||
y.transact(function*(){
|
||||
yield* y.root.val("stuff", "stuffy");
|
||||
expect(yield* y.root.val("stuff")).toEqual("stuffy");
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
Loading…
x
Reference in New Issue
Block a user