new approach for type definitions

This commit is contained in:
Kevin Jahns 2016-03-10 17:49:36 +01:00
parent ba4f444f32
commit d79e3102fc
7 changed files with 121 additions and 64 deletions

View File

@ -91,7 +91,6 @@ module.exports = function (gulp, helperOptions) {
var browserify = require('browserify') var browserify = require('browserify')
var source = require('vinyl-source-stream') var source = require('vinyl-source-stream')
var buffer = require('vinyl-buffer') var buffer = require('vinyl-buffer')
return browserify({ return browserify({
entries: files.specs, entries: files.specs,
debug: true debug: true

View File

@ -224,6 +224,9 @@ module.exports = function (Y /* :any */) {
var o = ops[i] var o = ops[i]
if (o.id == null || o.id[0] !== this.y.connector.userId) { if (o.id == null || o.id[0] !== this.y.connector.userId) {
var required = Y.Struct[o.struct].requiredOps(o) var required = Y.Struct[o.struct].requiredOps(o)
if (o.requires != null) {
required = required.concat(o.requires)
}
this.whenOperationsExist(required, o) this.whenOperationsExist(required, o)
} }
} }
@ -372,7 +375,7 @@ module.exports = function (Y /* :any */) {
} }
// notify parent, if it was instanciated as a custom type // notify parent, if it was instanciated as a custom type
if (t != null) { if (t != null && opIsDeleted) {
yield* t._changed(transaction, Y.utils.copyObject(op)) yield* t._changed(transaction, Y.utils.copyObject(op))
} }
} }

View File

@ -25,7 +25,7 @@ g.g = g
g.YConcurrency_TestingMode = true g.YConcurrency_TestingMode = true
jasmine.DEFAULT_TIMEOUT_INTERVAL = 100000 jasmine.DEFAULT_TIMEOUT_INTERVAL = 5000
g.describeManyTimes = function describeManyTimes (times, name, f) { g.describeManyTimes = function describeManyTimes (times, name, f) {
for (var i = 0; i < times; i++) { for (var i = 0; i < times; i++) {
@ -221,15 +221,18 @@ g.compareAllUsers = async(function * compareAllUsers (users) {
// TODO: make requestTransaction return a promise.. // TODO: make requestTransaction return a promise..
u.db.requestTransaction(function * () { u.db.requestTransaction(function * () {
yield* t2.call(this) yield* t2.call(this)
expect(s1).toEqual(s2) var db2 = []
expect(allDels1).toEqual(allDels2) // inner structure
expect(ds1).toEqual(ds2) // exported structure
var count = 0
yield* this.os.iterate(this, null, null, function * (o) { yield* this.os.iterate(this, null, null, function * (o) {
o = Y.utils.copyObject(o) o = Y.utils.copyObject(o)
delete o.origin delete o.origin
delete o.originOf delete o.originOf
expect(db1[count++]).toEqual(o) db2.push(o)
})
expect(s1).toEqual(s2)
expect(allDels1).toEqual(allDels2) // inner structure
expect(ds1).toEqual(ds2) // exported structure
db2.forEach((o, i) => {
expect(db1[i]).toEqual(o)
}) })
}) })
} }
@ -237,7 +240,7 @@ g.compareAllUsers = async(function * compareAllUsers (users) {
} }
}) })
g.createUsers = async(function * createUsers (self, numberOfUsers, database) { g.createUsers = async(function * createUsers (self, numberOfUsers, database, initType) {
if (Y.utils.globalRoom.users[0] != null) { if (Y.utils.globalRoom.users[0] != null) {
yield Y.utils.globalRoom.flushAll() yield Y.utils.globalRoom.flushAll()
} }
@ -246,6 +249,7 @@ g.createUsers = async(function * createUsers (self, numberOfUsers, database) {
Y.utils.globalRoom.users[u].y.destroy() Y.utils.globalRoom.users[u].y.destroy()
} }
self.users = null self.users = null
yield wait()
var promises = [] var promises = []
for (var i = 0; i < numberOfUsers; i++) { for (var i = 0; i < numberOfUsers; i++) {
@ -261,7 +265,7 @@ g.createUsers = async(function * createUsers (self, numberOfUsers, database) {
debug: false debug: false
}, },
share: { share: {
root: 'Map' root: initType || 'Map'
} }
})) }))
} }

View File

@ -259,11 +259,18 @@ module.exports = function (Y/* :any */) {
} }
}, },
encode: function (op) { encode: function (op) {
return { var e = {
struct: 'List', struct: 'List',
id: op.id, id: op.id,
type: op.type type: op.type
} }
if (op.requires != null) {
e.requires = op.requires
}
if (op.info != null) {
e.info = op.info
}
return e
}, },
requiredOps: function () { requiredOps: function () {
/* /*
@ -332,12 +339,19 @@ module.exports = function (Y/* :any */) {
} }
}, },
encode: function (op) { encode: function (op) {
return { var e = {
struct: 'Map', struct: 'Map',
type: op.type, type: op.type,
id: op.id, id: op.id,
map: {} // overwrite map!! map: {} // overwrite map!!
} }
if (op.requires != null) {
e.requires = op.requires
}
if (op.info != null) {
e.info = op.info
}
return e
}, },
requiredOps: function () { requiredOps: function () {
return [] return []

View File

@ -87,25 +87,28 @@ module.exports = function (Y/* :any */) {
If it does not exist yes, create it. If it does not exist yes, create it.
TODO: delete type from store.initializedTypes[id] when corresponding id was deleted! TODO: delete type from store.initializedTypes[id] when corresponding id was deleted!
*/ */
* getType (id) { * getType (id, args) {
var sid = JSON.stringify(id) var sid = JSON.stringify(id)
var t = this.store.initializedTypes[sid] var t = this.store.initializedTypes[sid]
if (t == null) { if (t == null) {
var op/* :MapStruct | ListStruct */ = yield* this.getOperation(id) var op/* :MapStruct | ListStruct */ = yield* this.getOperation(id)
if (op != null) { if (op != null) {
t = yield* Y[op.type].initType.call(this, this.store, op) t = yield* Y[op.type].typeDefinition.initType.call(this, this.store, op, args)
this.store.initializedTypes[sid] = t this.store.initializedTypes[sid] = t
} }
} }
return t return t
} }
* createType (typedefinition, id) { * createType (typedefinition, id) {
var structname = typedefinition.struct var structname = typedefinition[0].struct
id = id || this.store.getNextOpId() id = id || this.store.getNextOpId()
var op = Y.Struct[structname].create(id) var op = Y.Struct[structname].create(id)
op.type = typedefinition.name op.type = typedefinition[0].name
if (typedefinition[0].appendAdditionalInfo != null) {
yield* typedefinition[0].appendAdditionalInfo.call(this, op, typedefinition[1])
}
yield* this.applyCreatedOperations([op]) yield* this.applyCreatedOperations([op])
return yield* this.getType(id) return yield* this.getType(id, typedefinition[1])
} }
/* /*
Apply operations that this user created (no remote ones!) Apply operations that this user created (no remote ones!)
@ -117,7 +120,7 @@ module.exports = function (Y/* :any */) {
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* this.store.tryExecute.call(this, op) yield* this.store.tryExecute.call(this, op)
if (op.id == null || op.id[0] !== '_') { if (op.id == null || typeof op.id[1] !== 'string') {
send.push(Y.Struct[op.struct].encode(op)) send.push(Y.Struct[op.struct].encode(op))
} }
} }
@ -643,7 +646,7 @@ module.exports = function (Y/* :any */) {
} }
* addOperation (op) { * addOperation (op) {
yield* this.os.put(op) yield* this.os.put(op)
if (!this.store.y.connector.isDisconnected() && this.store.forwardAppliedOperations && op.id[0] !== '_') { if (!this.store.y.connector.isDisconnected() && this.store.forwardAppliedOperations && typeof op.id[1] !== 'string') {
// is connected, and this is not going to be send in addOperation // is connected, and this is not going to be send in addOperation
this.store.y.connector.broadcastOps([op]) this.store.y.connector.broadcastOps([op])
} }
@ -653,12 +656,13 @@ module.exports = function (Y/* :any */) {
if (o != null || id[0] !== '_') { if (o != null || id[0] !== '_') {
return o return o
} else { } else {
// generate this operation? /* // generate this operation?
if (typeof id[1] === 'string') { if (typeof id[1] === 'string') {
var comp = id[1].split('_') var comp = id[1].split('_')
if (comp.length > 1) { if (comp.length > 2 || id[0] === '_') {
var struct = comp[0] var struct = comp[0]
var op = Y.Struct[struct].create(id) var op = Y.Struct[struct].create(id)
op.type = comp[1]
yield* this.setOperation(op) yield* this.setOperation(op)
return op return op
} else { } else {
@ -668,9 +672,8 @@ module.exports = function (Y/* :any */) {
return null return null
} }
} else { } else {
// Can only generate one operation at a time */
return null return null
}
} }
} }
* removeOperation (id) { * removeOperation (id) {

View File

@ -26,7 +26,40 @@
module.exports = function (Y /* : any*/) { module.exports = function (Y /* : any*/) {
Y.utils = {} Y.utils = {}
class EventHandler { class EventListenerHandler {
constructor () {
this.eventListeners = []
}
destroy () {
this.eventListeners = null
}
/*
Basic event listener boilerplate...
*/
addEventListener (f) {
this.eventListeners.push(f)
}
removeEventListener (f) {
this.eventListeners = this.eventListeners.filter(function (g) {
return f !== g
})
}
removeAllEventListeners () {
this.eventListeners = []
}
callEventListeners (event) {
for (var i = 0; i < this.eventListeners.length; i++) {
try {
this.eventListeners[i](event)
} catch (e) {
console.error('User events must not throw Errors!')
}
}
}
}
Y.utils.EventListenerHandler = EventListenerHandler
class EventHandler extends EventListenerHandler {
/* :: /* ::
waiting: Array<Insertion | Deletion>; waiting: Array<Insertion | Deletion>;
awaiting: number; awaiting: number;
@ -41,16 +74,16 @@ module.exports = function (Y /* : any*/) {
all prematurely called operations were executed ("waiting operations") all prematurely called operations were executed ("waiting operations")
*/ */
constructor (onevent /* : Function */) { constructor (onevent /* : Function */) {
super()
this.waiting = [] this.waiting = []
this.awaiting = 0 this.awaiting = 0
this.onevent = onevent this.onevent = onevent
this.eventListeners = []
} }
destroy () { destroy () {
super.destroy()
this.waiting = null this.waiting = null
this.awaiting = null this.awaiting = null
this.onevent = null this.onevent = null
this.eventListeners = null
} }
/* /*
Call this when a new operation arrives. It will be executed right away if Call this when a new operation arrives. It will be executed right away if
@ -72,30 +105,6 @@ module.exports = function (Y /* : any*/) {
this.awaiting++ this.awaiting++
this.onevent(ops) this.onevent(ops)
} }
/*
Basic event listener boilerplate...
TODO: maybe put this in a different type..
*/
addEventListener (f) {
this.eventListeners.push(f)
}
removeEventListener (f) {
this.eventListeners = this.eventListeners.filter(function (g) {
return f !== g
})
}
removeAllEventListeners () {
this.eventListeners = []
}
callEventListeners (event) {
for (var i = 0; i < this.eventListeners.length; i++) {
try {
this.eventListeners[i](event)
} catch (e) {
console.log('User events must not throw Errors!') // eslint-disable-line
}
}
}
/* /*
Call this when you successfully awaited the execution of n Insert operations Call this when you successfully awaited the execution of n Insert operations
*/ */
@ -192,10 +201,26 @@ module.exports = function (Y /* : any*/) {
this.initType = def.initType this.initType = def.initType
this.class = def.class this.class = def.class
this.name = def.name this.name = def.name
if (def.appendAdditionalInfo != null) {
this.appendAdditionalInfo = def.appendAdditionalInfo
}
this.parseArguments = (def.parseArguments || function () {
return [this]
}).bind(this)
this.parseArguments.typeDefinition = this
} }
} }
Y.utils.CustomType = CustomType Y.utils.CustomType = CustomType
Y.utils.isTypeDefinition = function isTypeDefinition (v) {
if (v != null) {
if (v instanceof Y.utils.CustomType) return [v]
else if (v.constructor === Array && v[0] instanceof Y.utils.CustomType) return v
else if (v instanceof Function && v.typeDefinition instanceof Y.utils.CustomType) return [v.typeDefinition]
}
return false
}
/* /*
Make a flat copy of an object Make a flat copy of an object
(just copy properties) (just copy properties)

View File

@ -14,7 +14,11 @@ module.exports = Y
Y.requiringModules = requiringModules Y.requiringModules = requiringModules
Y.extend = function (name, value) { Y.extend = function (name, value) {
Y[name] = value if (value instanceof Y.utils.CustomType) {
Y[name] = value.parseArguments
} else {
Y[name] = value
}
if (requiringModules[name] != null) { if (requiringModules[name] != null) {
requiringModules[name].resolve() requiringModules[name].resolve()
delete requiringModules[name] delete requiringModules[name]
@ -29,9 +33,10 @@ function requestModules (modules) {
var extention = typeof regeneratorRuntime !== 'undefined' ? '.js' : '.es6' var extention = typeof regeneratorRuntime !== 'undefined' ? '.js' : '.es6'
var promises = [] var promises = []
for (var i = 0; i < modules.length; i++) { for (var i = 0; i < modules.length; i++) {
var modulename = 'y-' + modules[i].toLowerCase() var module = modules[i].split('(')[0]
if (Y[modules[i]] == null) { var modulename = 'y-' + module.toLowerCase()
if (requiringModules[modules[i]] == null) { if (Y[module] == null) {
if (requiringModules[module] == null) {
// module does not exist // module does not exist
if (typeof window !== 'undefined' && window.Y !== 'undefined') { if (typeof window !== 'undefined' && window.Y !== 'undefined') {
var imported = document.createElement('script') var imported = document.createElement('script')
@ -39,7 +44,7 @@ function requestModules (modules) {
document.head.appendChild(imported) document.head.appendChild(imported)
let requireModule = {} let requireModule = {}
requiringModules[modules[i]] = requireModule requiringModules[module] = requireModule
requireModule.promise = new Promise(function (resolve) { requireModule.promise = new Promise(function (resolve) {
requireModule.resolve = resolve requireModule.resolve = resolve
}) })
@ -130,15 +135,19 @@ class YConfig {
this.db.requestTransaction(function * requestTransaction () { this.db.requestTransaction(function * requestTransaction () {
// create shared object // create shared object
for (var propertyname in opts.share) { for (var propertyname in opts.share) {
var typename = opts.share[propertyname] var typeConstructor = opts.share[propertyname].split('(')
var id = ['_', Y[typename].struct + '_' + propertyname] var typeName = typeConstructor.splice(0, 1)
var op = yield* this.getOperation(id) var args = []
if (op.type !== typename) { if (typeConstructor.length === 1) {
// not already in the db try {
op.type = typename args = JSON.parse('[' + typeConstructor[0].split(')')[0] + ']')
yield* this.setOperation(op) } catch (e) {
throw new Error('Was not able to parse type definition! (share.' + propertyname + ')')
}
} }
share[propertyname] = yield* this.getType(id) var id = ['_', propertyname + '_' + typeConstructor]
var type = Y[typeName]
share[propertyname] = yield* this.createType(type.apply(type.typeDefinition, args), id)
} }
this.store.whenTransactionsFinished() this.store.whenTransactionsFinished()
.then(callback) .then(callback)