Skip to content

Instantly share code, notes, and snippets.

@rossnelson
Created June 12, 2018 12:54
Show Gist options
  • Save rossnelson/bed0d137f99cb9c063a4bce837bf14f7 to your computer and use it in GitHub Desktop.
Save rossnelson/bed0d137f99cb9c063a4bce837bf14f7 to your computer and use it in GitHub Desktop.
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;
}
})
});
}
};
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',
},
};
}
}
};
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'
}
}
}
}
}
module.exports = App => {
return class MixinBase {
constructor(resource) {
this.resource = resource;
}
}
};
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);
};
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