updated OperationBuffer
This commit is contained in:
parent
4b08cbe875
commit
ae790b6947
@ -1,3 +1,9 @@
|
|||||||
|
[ignore]
|
||||||
|
.*/node_modules/.*
|
||||||
|
.*/build/.*
|
||||||
|
./y.js
|
||||||
|
./y.js.map
|
||||||
|
|
||||||
[include]
|
[include]
|
||||||
|
|
||||||
[libs]
|
[libs]
|
||||||
|
174
src/IndexedDB.js
174
src/IndexedDB.js
@ -6,17 +6,54 @@ type State = {
|
|||||||
|
|
||||||
type StateVector = Array<State>;
|
type StateVector = Array<State>;
|
||||||
|
|
||||||
type StateSet = Object<number>;
|
type StateSet = Object;
|
||||||
|
|
||||||
|
type IDBTransaction = Function;
|
||||||
|
type IDBObjectStore = Function;
|
||||||
|
type IDBRequest = Function;
|
||||||
|
type IDBCursor = Function;
|
||||||
|
type IDBKeyRange = Function;
|
||||||
|
|
||||||
|
type IDBOpenDBRequest = Function;
|
||||||
|
|
||||||
|
declare var indexedDB : Object;
|
||||||
|
|
||||||
|
declare var setTimeout : Function;
|
||||||
|
|
||||||
|
class AbstractTransaction { //eslint-disable-line no-unused-vars
|
||||||
|
constructor () {
|
||||||
|
}
|
||||||
|
*addOperation (op) {
|
||||||
|
var state = yield* this.getState(op.uid[0]);
|
||||||
|
if (state == null){
|
||||||
|
state = {
|
||||||
|
user: op.uid[0],
|
||||||
|
clock: 0
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (op.uid[1] === state.clock){
|
||||||
|
state.clock++;
|
||||||
|
yield* this.setState(state);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var IndexedDB = (function(){ //eslint-disable-line no-unused-vars
|
var IndexedDB = (function(){ //eslint-disable-line no-unused-vars
|
||||||
class Transaction {
|
class Transaction extends AbstractTransaction{
|
||||||
|
transaction: IDBTransaction;
|
||||||
|
sv: IDBObjectStore;
|
||||||
|
ob: IDBObjectStore;
|
||||||
constructor (transaction) {
|
constructor (transaction) {
|
||||||
|
super();
|
||||||
this.transaction = transaction;
|
this.transaction = transaction;
|
||||||
this.sv = transaction.objectStore("StateVector");
|
this.sv = transaction.objectStore("StateVector");
|
||||||
this.ob = transaction.objectStore("OperationBuffer");
|
this.ob = transaction.objectStore("OperationBuffer");
|
||||||
}
|
}
|
||||||
*setOperation (op) {
|
*setOperation (op) {
|
||||||
|
yield* (function*(){})();
|
||||||
yield this.ob.put(op);
|
yield this.ob.put(op);
|
||||||
return op;
|
return op;
|
||||||
}
|
}
|
||||||
@ -34,78 +71,91 @@ var IndexedDB = (function(){ //eslint-disable-line no-unused-vars
|
|||||||
}
|
}
|
||||||
*getStateVector () : StateVector {
|
*getStateVector () : StateVector {
|
||||||
var stateVector = [];
|
var stateVector = [];
|
||||||
var cursor = yield this.sv.openCursor();
|
var cursorResult = this.sv.openCursor();
|
||||||
while ((cursor = yield cursor.continue) != null) {
|
var cursor;
|
||||||
|
while ((cursor = yield cursorResult) != null) {
|
||||||
stateVector.push(cursor.value);
|
stateVector.push(cursor.value);
|
||||||
|
cursor.continue();
|
||||||
}
|
}
|
||||||
return stateVector;
|
return stateVector;
|
||||||
}
|
}
|
||||||
*getStateSet () : StateSet {
|
*getStateSet () : StateSet {
|
||||||
|
var sv : StateVector = yield* this.getStateVector();
|
||||||
|
var ss : StateSet = {};
|
||||||
|
for (var state of sv){
|
||||||
|
ss[state.user] = state.clock;
|
||||||
|
}
|
||||||
|
return ss;
|
||||||
}
|
}
|
||||||
getOperations () {
|
|
||||||
return function* () {
|
*getOperations (startSS : StateSet) {
|
||||||
var op = yield this.getOperation(["u1", 0]);
|
if (startSS == null){
|
||||||
return op.uid;
|
startSS = {};
|
||||||
};
|
}
|
||||||
|
var ops = [];
|
||||||
|
|
||||||
|
var endSV : StateVector = yield* this.getStateVector();
|
||||||
|
for (var endState of endSV) {
|
||||||
|
var user = endState.user;
|
||||||
|
var startPos = startSS[user] || 0;
|
||||||
|
var endPos = endState.clock;
|
||||||
|
var range = IDBKeyRange.bound([user, startPos], [user, endPos]);
|
||||||
|
var cursorResult = this.ob.openCursor(range);
|
||||||
|
var cursor;
|
||||||
|
while ((cursor = yield cursorResult) != null) {
|
||||||
|
ops.push(cursor.value);
|
||||||
|
cursor.continue();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ops;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
getOperations: (state_map)->
|
|
||||||
flow = Promise.resolve()
|
|
||||||
ops = []
|
|
||||||
that = this
|
|
||||||
hb = that.t.objectStore("HistoryBuffer")
|
|
||||||
|
|
||||||
that.getStateVector().then (end_state_vector)->
|
|
||||||
for end_state of end_state_vector
|
|
||||||
# convert to the db-structure
|
|
||||||
do (end_state = end_state)->
|
|
||||||
start_state =
|
|
||||||
user: end_state.name
|
|
||||||
state: state_map[end_state] ? 0
|
|
||||||
|
|
||||||
flow = flow.then ()->
|
|
||||||
from = [start_state.user, start_state.number]
|
|
||||||
to = [end_state.user, end_state.number]
|
|
||||||
cursor = event.target.result
|
|
||||||
if cursor?
|
|
||||||
ops.push cursor.value # add Operation
|
|
||||||
cursor.continue()
|
|
||||||
else
|
|
||||||
# got all ops from this user
|
|
||||||
defer.resolve ops
|
|
||||||
defer.promise
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
class DB {
|
class DB {
|
||||||
|
namespace: string;
|
||||||
|
ready: Promise;
|
||||||
|
whenReadyListeners: Array<Function>;
|
||||||
constructor (namespace : string) {
|
constructor (namespace : string) {
|
||||||
|
this.whenReadyListeners = [];
|
||||||
this.namespace = namespace;
|
this.namespace = namespace;
|
||||||
this.ready = new Promise(function(yay, nay){
|
this.ready = false;
|
||||||
var req = indexedDB.open(namespace); //eslint-disable-line no-undef
|
|
||||||
req.onerror = function(){
|
var req = indexedDB.open(namespace); //eslint-disable-line no-undef
|
||||||
nay("Couldn't open the IndexedDB database!");
|
req.onerror = function(){
|
||||||
};
|
throw new Error("Couldn't open the IndexedDB database!");
|
||||||
req.onsuccess = function(event){
|
};
|
||||||
yay(event.target.result);
|
req.onsuccess = (event)=>{
|
||||||
};
|
this.db = event.target.result;
|
||||||
req.onupgradeneeded = function(event){
|
this.whenReadyListeners.forEach(function(f){
|
||||||
var db = event.target.result;
|
setTimeout(f, 0);
|
||||||
db.createObjectStore("OperationBuffer", {keyPath: "uid"});
|
});
|
||||||
db.createObjectStore("StateVector", {keyPath: "user"});
|
this.whenReadyListeners = null;
|
||||||
};
|
this.ready = true;
|
||||||
}).catch(function(message){
|
};
|
||||||
throw new Error(message);
|
req.onupgradeneeded = function(event){
|
||||||
});
|
var db = event.target.result;
|
||||||
|
db.createObjectStore("OperationBuffer", {keyPath: "uid"});
|
||||||
|
db.createObjectStore("StateVector", {keyPath: "user"});
|
||||||
|
};
|
||||||
|
}
|
||||||
|
whenReady (f : Function) {
|
||||||
|
if (this.ready){
|
||||||
|
setTimeout(f, 0);
|
||||||
|
} else {
|
||||||
|
this.whenReadyListeners.push(f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
requestTransaction (makeGen : Function) {
|
requestTransaction (makeGen : Function) {
|
||||||
this.ready.then(function(db){
|
this.whenReady(()=>{
|
||||||
var transaction = new Transaction(db.transaction(["OperationBuffer", "StateVector"], "readwrite"));
|
var transaction = new Transaction(this.db.transaction(["OperationBuffer", "StateVector"], "readwrite"));
|
||||||
var gen = makeGen.apply(transaction);
|
var gen = makeGen.apply(transaction);
|
||||||
|
|
||||||
function handle(res){
|
function handle(res : any){
|
||||||
var request = res.value;
|
var request : any = res.value;
|
||||||
if (res.done){
|
if (res.done){
|
||||||
return;
|
return;
|
||||||
} else if (request.constructor === IDBRequest) {
|
} else if (request.constructor === IDBRequest
|
||||||
|
|| request.constructor === IDBCursor
|
||||||
|
|| request.constructor === IDBOpenDBRequest) {
|
||||||
request.onsuccess = function(){
|
request.onsuccess = function(){
|
||||||
handle(gen.next(request.result));
|
handle(gen.next(request.result));
|
||||||
};
|
};
|
||||||
@ -113,13 +163,15 @@ var IndexedDB = (function(){ //eslint-disable-line no-unused-vars
|
|||||||
gen.throw(err);
|
gen.throw(err);
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
gen.throw("You may not yield this type!");
|
gen.throw("You can not yield this type!");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
handle(gen.next());
|
||||||
return handle(gen.next());
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
*removeDatabase () {
|
||||||
|
return yield indexedDB.deleteDatabase(this.namespace);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return DB;
|
return DB;
|
||||||
})();
|
})();
|
||||||
|
@ -8,10 +8,10 @@ if(typeof window !== "undefined"){
|
|||||||
it("can create transactions", function(done) {
|
it("can create transactions", function(done) {
|
||||||
ob.requestTransaction(function*(){
|
ob.requestTransaction(function*(){
|
||||||
var op = yield* this.setOperation({
|
var op = yield* this.setOperation({
|
||||||
"uid": ["u1", 0],
|
"uid": ["1", 0],
|
||||||
"stuff": true
|
"stuff": true
|
||||||
});
|
});
|
||||||
expect(yield* this.getOperation(["u1", 0]))
|
expect(yield* this.getOperation(["1", 0]))
|
||||||
.toEqual(op);
|
.toEqual(op);
|
||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
@ -26,7 +26,6 @@ if(typeof window !== "undefined"){
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("yield throws if request is unknown", function(done){
|
it("yield throws if request is unknown", function(done){
|
||||||
|
|
||||||
ob.requestTransaction(function*(){
|
ob.requestTransaction(function*(){
|
||||||
try {
|
try {
|
||||||
yield this.getOperations(["u1", 0]);
|
yield this.getOperations(["u1", 0]);
|
||||||
@ -39,5 +38,59 @@ if(typeof window !== "undefined"){
|
|||||||
done();
|
done();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("sets and gets stateVector", function(done){
|
||||||
|
ob.requestTransaction(function*(){
|
||||||
|
var s1 = {user: "1", clock: 1};
|
||||||
|
var s2 = {user: "2", clock: 3};
|
||||||
|
yield* this.setState(s1);
|
||||||
|
yield* this.setState(s2);
|
||||||
|
var sv = yield* this.getStateVector();
|
||||||
|
expect(sv).not.toBeUndefined();
|
||||||
|
expect(sv).toEqual([s1, s2]);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("gets stateSet", function(done){
|
||||||
|
ob.requestTransaction(function*(){
|
||||||
|
var s1 = {user: "1", clock: 1};
|
||||||
|
var s2 = {user: "2", clock: 3};
|
||||||
|
yield* this.setState(s1);
|
||||||
|
yield* this.setState(s2);
|
||||||
|
var sv = yield* this.getStateSet();
|
||||||
|
expect(sv).not.toBeUndefined();
|
||||||
|
expect(sv).toEqual({
|
||||||
|
"1": 1,
|
||||||
|
"2": 3
|
||||||
|
});
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it("getOperations returns operations (no parameters)", function(done){
|
||||||
|
ob.requestTransaction(function*(){
|
||||||
|
var s1 = {user: "1", clock: 55};
|
||||||
|
yield* this.setState(s1);
|
||||||
|
var op1 = yield* this.setOperation({
|
||||||
|
"uid": ["1", 0],
|
||||||
|
"stuff": true
|
||||||
|
});
|
||||||
|
var op2 = yield* this.setOperation({
|
||||||
|
"uid": ["1", 3],
|
||||||
|
"stuff": true
|
||||||
|
});
|
||||||
|
var ops = yield* this.getOperations();
|
||||||
|
expect(ops.length).toBeGreaterThan(1);
|
||||||
|
expect(ops[0]).toEqual(op1);
|
||||||
|
expect(ops[1]).toEqual(op2);
|
||||||
|
done();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
afterAll(function(){
|
||||||
|
ob.requestTransaction(function*(){
|
||||||
|
yield* ob.removeDatabase();
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
|
|
||||||
class OperationBuffer { //eslint-disable-line no-unused-vars
|
class OperationBuffer { //eslint-disable-line no-unused-vars
|
||||||
i : number;
|
|
||||||
constructor () {
|
constructor () {
|
||||||
this.i = 4;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,13 +1,2 @@
|
|||||||
/* @flow */
|
/* @flow */
|
||||||
/*eslint-env browser,jasmine,console */
|
/*eslint-env browser,jasmine,console */
|
||||||
|
|
||||||
describe("Operation Buffer", function() {
|
|
||||||
var OB = new OperationBuffer();
|
|
||||||
|
|
||||||
it("contains spec with an expectation", function(done) {
|
|
||||||
setTimeout(function(){
|
|
||||||
done();
|
|
||||||
}, 1000);
|
|
||||||
expect(OB.i).toBe(4);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user