Skip to content

Commit

Permalink
Merge pull request #2 from fabrix-app/v1
Browse files Browse the repository at this point in the history
[feat] Fabrix Resolvers
  • Loading branch information
scott-wyatt authored Jul 11, 2018
2 parents f9ec48f + 33883bb commit ce6b181
Show file tree
Hide file tree
Showing 11 changed files with 563 additions and 78 deletions.
30 changes: 19 additions & 11 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,11 @@ A basic `config/store.js` can be found here : https://github.com/fabrix-app/spoo
### Models

```js
module.exports = class User extends Model {
//More about supported schema here : http://docs.sequelizejs.com/en/latest/docs/models-definition/
import { FabrixModel as Model } from '@fabrix/fabrix/dist/common'
import { SequelizeResolver } from '@fabrix/spool-sequelize'

export class User extends Model {
// More about supported schema here : http://docs.sequelizejs.com/en/latest/docs/models-definition/
static schema (app, Sequelize) {
return {
name: { type: Sequelize.STRING, allowNull: false },
Expand All @@ -51,21 +54,26 @@ module.exports = class User extends Model {
return {
migrate: 'drop', //override default models configurations if needed
store: 'sqlite', //override default models configurations if needed
//More informations about supported models options here : http://docs.sequelizejs.com/en/latest/docs/models-definition/#configuration
// More informations about supported models options here : http://docs.sequelizejs.com/en/latest/docs/models-definition/#configuration
options: {}
}
}

// The Way this model interacts with Sequelize
static get resolver () {
return SequelizeResolver
}

// If you need associations, put them here
associate(models) {
//More information about associations here : http://docs.sequelizejs.com/en/latest/docs/associations/
models.User.hasMany(models.Role, {
as: 'roles',
onDelete: 'CASCADE',
foreignKey: {
allowNull: true
}
})
// More information about associations here : http://docs.sequelizejs.com/en/latest/docs/associations/
models.User.hasMany(models.Role, {
as: 'roles',
onDelete: 'CASCADE',
foreignKey: {
allowNull: true
}
})
}
}
```
Expand Down
288 changes: 288 additions & 0 deletions lib/SequelizeResolver.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,288 @@
import { FabrixModel, FabrixResolver } from '@fabrix/fabrix/dist/common'
import { Sequelize, Model, DataTypes } from 'sequelize'
import { Transformer } from './transformer'

export class SequelizeResolver extends FabrixResolver {
private _connection
private _sequelizeModel

constructor (model: FabrixModel, datastore?: Sequelize) {
super(model)
if (!model) {
throw new RangeError('Resolver must be given a Model to bind to')
}
}

get connection() {
return this._connection
}

set connection(connection) {
this._connection = connection
}

get sequelizeModel() {
return this._sequelizeModel
}

public connect(modelName, schema, options) {
this._sequelizeModel = this._connection.define(modelName, schema, options)

const instanceMethods = Transformer.getModelPrototypes(this.model)
const classMethods = Transformer.getModelMethods(this.model, instanceMethods)

// Assign Class Methods from the Model
Object.keys(classMethods).forEach(c => {
this._sequelizeModel[c] = classMethods[c]
})

// Assign Instance Methods from the Model
Object.keys(instanceMethods).forEach(i => {
this._sequelizeModel.prototype[i] = instanceMethods[i]
})

// Add this model to the connection.models for use later
this._connection.models[modelName] = this._sequelizeModel

// Bind the new methods to the models
const resolverMethods = Transformer.getClassMethods(this)
Object.entries(resolverMethods).forEach(([ _, method]: [any, string]) => {
this.model[method] = this[method].bind(this)
})
}

/**
* Getters
*/
get associations() {
if (this._sequelizeModel) {
return this._sequelizeModel.associations
}
}

/**
* Class Methods
*/

addScope(name, scope, options = {}) {
if (this._sequelizeModel) {
return this._sequelizeModel.addScope(name, scope, options)
}
}

aggregate(filed, aggregateFunction, options = {}) {
if (this._sequelizeModel) {
return this._sequelizeModel.aggregate(filed, aggregateFunction, options)
}
}

belongsTo(target, options = {}) {
if (this._sequelizeModel) {
return this._sequelizeModel.belongsTo(target, options)
}
}

belongsToMany(target, options = {}) {
if (this._sequelizeModel) {
return this._sequelizeModel.belongsToMany(target, options)
}
}

build(options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.build(options)
}
}

bulkCreate(records: any[], options = {}) {
if (this._sequelizeModel) {
return this._sequelizeModel.bulkCreate(records, options)
}
}

count(criteria, options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.count(criteria, options)
}
}

create (values, options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.create(values, options)
}
}

decrement(fields, options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.decrement(fields, options)
}
}
describe(schema, options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.describe(schema, options)
}
}

// Delete is a Fabrix Alias of Sequelize.destroy
delete(options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.destroy(options)
}
}

destroy(options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.destroy(options)
}
}

drop(options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.drop(options)
}
}

findAll(options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.findAll(options)
}
}

findAndCountAll(options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.findAndCountAll(options)
}
}

findById(id, options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.findById(id, options)
}
}

findOne(criteria, options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.findOne(criteria, options)
}
}

findOrBuild(criteria, defaults, options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.findOrBuild(criteria, defaults, options)
}
}

findOrCreate(criteria, defaults, options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.findOrCreate(criteria, defaults, options)
}
}

getTableName() {
if (this._sequelizeModel) {
return this._sequelizeModel.getTableName()
}
}

hasMany(arget, options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.hasMany(arget, options)
}
}

hasOne(target, options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.hasOne(target, options)
}
}

increment(fields, options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.increment(fields, options)
}
}

init(attributes, options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.init(attributes, options)
}
}

max(criteria, options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.max(criteria, options)
}
}

min(criteria, options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.min(criteria, options)
}
}

removeAttribute(attribute) {
if (this._sequelizeModel) {
return this._sequelizeModel.removeAttribute(attribute)
}
}

restore(options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.restore(options)
}
}

// Conflicts with Fabrix Resolver?
// schema(schema, options = { }) {
//
// }

scope(options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.scope(options)
}
}

sum(riteria, options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.sum(riteria, options)
}
}

sync(options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.sync(options)
}
}

truncate(options = { }) {
if (this._sequelizeModel) {
return this._sequelizeModel.truncate(options)
}
}

unscoped() {
if (this._sequelizeModel) {
return this._sequelizeModel.unscoped()
}
}

// Save is a Fabrix Alias of Sequelize.update
save(values, options = {}) {
if (this._sequelizeModel) {
return this._sequelizeModel.update(values, options)
}
}

update(values, options = {}) {
if (this._sequelizeModel) {
return this._sequelizeModel.update(values, options)
}
}

upsert(values, options = {}) {
if (this._sequelizeModel) {
return this._sequelizeModel.upsert(values, options)
}
}
}
19 changes: 7 additions & 12 deletions lib/SequelizeSpool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import * as api from './api/index'

export class SequelizeSpool extends DatastoreSpool {
_datastore = Sequelize

private _connections: {[key: string]: any} = { }
private _models: {[key: string]: any} = { }

Expand Down Expand Up @@ -56,24 +57,18 @@ export class SequelizeSpool extends DatastoreSpool {
/**
* Merge configuration into models, load Sequelize collections.
*/
// configure() {
//
// }
configure() {
// Holds a collection of the connections made through Sequelize
this._connections = Transformer.getConnections(this.app)
// Holds a collection of the Sequelize models
this._models = Transformer.getModels(this.app, this.connections)
}

/**
* Initialize Sequelize. This will compile the schema and connect to the
* database.
*/
async initialize() {
this._connections = Transformer.getConnections(this.app)
this._models = Transformer.getModels(this.app, this.connections)

// Replaces the app sequelize models with their sequelize versions
// The originals are still in app.api.models
Object.keys(this.models).forEach( m => {
this.app.models[m] = this.models[m]
})

// Migrate the connections and/or models by their migration strategy
return this.migrate()
}
Expand Down
12 changes: 11 additions & 1 deletion lib/api/services/TapestryService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,20 @@ export class TapestryService extends Service {
* @private
*/
_getModel(modelName) {
return this.app.models[modelName]
const model = this.app.models[modelName]
|| this.app.spools['sequelize'].models[modelName]
|| _.find(this.app.models, {tableName: modelName})
|| _.find(this.app.spools['sequelize'].models, {tableName: modelName})

if (model && model.resolver && model.resolver.sequelizeModel) {
return model.resolver.sequelizeModel
}
else if (model && model.sequelizeModel) {
return model.sequelizeModel
}
else {
return model
}
}

/**
Expand Down
Loading

0 comments on commit ce6b181

Please sign in to comment.