Created
June 12, 2018 12:54
-
-
Save rossnelson/bed0d137f99cb9c063a4bce837bf14f7 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const _ = require('lodash'); | |
module.exports = App => { | |
return function composer(superclass) { | |
const mixins = superclass.mixins(); | |
mixins.forEach(mixin => { | |
mixin = App.get(`Resources.Mixins.${mixin}`); | |
defineInstanceFunctions(superclass, mixin); | |
defineStaticFunctions(superclass, mixin); | |
}); | |
mergeMapping(superclass); | |
return superclass; | |
}; | |
function defineInstanceFunctions(mixed, mixin) { | |
Object.getOwnPropertyNames(mixin.prototype).forEach(value => { | |
if (_.includes(['constructor', ''], value)) { | |
return; | |
} | |
if (mixed.prototype.hasOwnProperty(value)) { | |
App.Logger.info( | |
'Composer mixin instance method already defined on resource', | |
mixed.name, | |
mixin.name, | |
value, | |
); | |
return Object.defineProperty(mixed.prototype, value, { | |
get() { | |
return this[value](); | |
} | |
}); | |
} | |
Reflect.deleteProperty(mixed.prototype, value); | |
Object.defineProperty(mixed.prototype, value, { | |
get() { | |
const inst = new mixin(this); | |
return inst[value](); | |
} | |
}); | |
}); | |
} | |
function defineStaticFunctions(mixed, mixin) { | |
Object.getOwnPropertyNames(mixin).forEach(value => { | |
if (_.includes(['prototype', 'name', 'length', '_mapping'], value)) { | |
return; | |
} | |
console.log(value); | |
if (mixed.hasOwnProperty(value)) { | |
App.Logger.info( | |
'Composer mixin static method already defined on resource', | |
mixed.name, | |
mixin.name, | |
value, | |
); | |
return Object.defineProperty(mixed, value, { | |
get() { | |
return this[value](); | |
} | |
}); | |
} | |
Reflect.deleteProperty(mixed, value); | |
Object.defineProperty(mixed, value, { | |
get: () => { | |
return mixin[value](); | |
} | |
}); | |
}); | |
} | |
function mergeMapping(superclass) { | |
if (superclass.hasOwnProperty('mapping')) { | |
throw new Error( | |
'Superclass cannot define mapping. Create a mixin to define mapped fields', | |
); | |
} | |
let mapping = superclass.mixins().reduce((result, name) => { | |
const mixin = App.get(`Resources.Mixins.${name}`); | |
if (!mixin._mapping) { return result; } | |
return _.merge(result, mixin._mapping()); | |
}, {}); | |
const sortedKeys = _.sortBy(Object.keys(mapping), prop => mapping[prop].weight) | |
const sorted = {} | |
sortedKeys.forEach(key => sorted[key] = mapping[key]) | |
mapping = sorted; | |
Object.defineProperty(superclass.prototype, 'mapping', { | |
value: mapping, | |
}); | |
Object.defineProperty(superclass, 'mapping', { | |
value: mapping, | |
}); | |
Object.defineProperty(superclass.prototype, '_delegate', { | |
value: {}, | |
writable: true | |
}) | |
Object.defineProperty(superclass.prototype, '_changes', { | |
value: {}, | |
writable: true | |
}) | |
Object.keys(mapping).forEach(prop => { | |
Object.defineProperty(superclass.prototype, prop, { | |
get() { | |
return this._delegate[prop]; | |
}, | |
set(new_value) { | |
if (this[prop] !== new_value) { | |
this._changes[prop] = { old_value: this[prop], new_value }; | |
} | |
this._delegate[prop] = new_value; | |
} | |
}) | |
}); | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = App => { | |
const Base = App.get('Resources.Mixins.Base'); | |
return class Device extends Base { | |
static _mapping() { | |
return { | |
humidity: { | |
weight: 50, | |
type: 'text', | |
path: 'name', | |
}, | |
}; | |
} | |
} | |
}; | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = App => { | |
const Base = App.get('Resources.Mixins.Base'); | |
return class Common extends Base { | |
static _mapping() { | |
return { | |
name: { | |
weight: -100, | |
type: 'text', | |
path: 'name' | |
}, | |
created_at: { | |
weight: 100, | |
type: 'text', | |
path: 'created_at' | |
}, | |
updated_at: { | |
weight: 101, | |
type: 'text', | |
path: 'updated_at' | |
} | |
} | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = App => { | |
return class MixinBase { | |
constructor(resource) { | |
this.resource = resource; | |
} | |
} | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
module.exports = App => { | |
const Base = App.get('Resources.BaseResource'); | |
class DeviceResource extends Base { | |
// static sqlModel() { | |
// return App.Postgres.get('Device'); | |
// } | |
// static sqlModelType() { | |
// return 'Device'; | |
// } | |
static mixins() { | |
return [ | |
// Features | |
// 'Persisted', | |
// 'Sql', | |
// Data Model | |
'Common', | |
'Device' | |
]; | |
} | |
} | |
const composer = App.get('Resources.Composer'); | |
return composer(DeviceResource); | |
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const _ = require('lodash'); | |
module.exports = App => { | |
return class BaseResource { | |
constructor(fields = {}) { | |
fields = !!fields ? fields : {}; | |
Object.keys(this.mapping).forEach(key => { | |
this[key] = fields[key]; | |
}) | |
} | |
static setAll(collection) { | |
return collection.map(item => new this(item)); | |
} | |
hasChanges() { | |
return !!Object.keys(this._changes).length; | |
} | |
getChanges() { | |
return this._changes; | |
} | |
toJSON() { | |
const data = {}; | |
const keys = Object.keys(this.mapping); | |
keys.forEach((key) => { | |
const config = this.mapping[key]; | |
if (config.schema_ignore) { return; } | |
let val = _.get(this, key); | |
console.log(config.path, this[config.path], val); | |
if (!val && !!config.path && !!this[config.path]) { | |
val = this[config.path](); | |
} | |
val = !_.isUndefined(val) ? val : null; | |
data[key] = val; | |
}); | |
return data; | |
} | |
} | |
}; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment