Skip to content

Commit

Permalink
feat: multi datasource support load same models (#63)
Browse files Browse the repository at this point in the history
  • Loading branch information
dead-horse committed Nov 12, 2018
1 parent b41598e commit c4998e1
Show file tree
Hide file tree
Showing 10 changed files with 265 additions and 1 deletion.
63 changes: 62 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ Please put models under `app/model` dir by default.

Define a model first.

> NOTE: `app.model` is an [Instance of Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor), so you can use methods like: `app.model.sync, app.model.query ...`
> NOTE: `options.delegate` default to `model`, so `app.model` is an [Instance of Sequelize](http://docs.sequelizejs.com/class/lib/sequelize.js~Sequelize.html#instance-constructor-constructor), so you can use methods like: `app.model.sync, app.model.query ...`
```js
// app/model/user.js
Expand Down Expand Up @@ -194,6 +194,67 @@ exports.sequelize = {
};
```

Then we can define model like this:

```js
// app/model/user.js
module.exports = app => {
const { STRING, INTEGER, DATE } = app.Sequelize;

const User = app.model.define('user', {
login: STRING,
name: STRING(30),
password: STRING(32),
age: INTEGER,
last_sign_in_at: DATE,
created_at: DATE,
updated_at: DATE,
});

return User;
};

// app/admin_model/user.js
module.exports = app => {
const { STRING, INTEGER, DATE } = app.Sequelize;

const User = app.adminModel.define('user', {
login: STRING,
name: STRING(30),
password: STRING(32),
age: INTEGER,
last_sign_in_at: DATE,
created_at: DATE,
updated_at: DATE,
});

return User;
};
```

If you define the same model for different datasource, the same model file will be excute twice for different database, so we can use the secound argument to get the sequelize instance:

```js
// app/model/user.js
// if this file will load multiple times for different datasource
// we can use the secound argument to get the sequelize instance
module.exports = (app, model) => {
const { STRING, INTEGER, DATE } = app.Sequelize;

const User = model.define('user', {
login: STRING,
name: STRING(30),
password: STRING(32),
age: INTEGER,
last_sign_in_at: DATE,
created_at: DATE,
updated_at: DATE,
});

return User;
};
```

### Customize Sequelize

By default, egg-sequelize will use sequelize@4, you can cusomize sequelize version by pass sequelize instance with `config.sequelize.Sequelize` like this:
Expand Down
5 changes: 5 additions & 0 deletions lib/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,11 @@ module.exports = app => {
models.push(model);
return true;
},
initializer(factory) {
if (typeof factory === 'function') {
return factory(app, sequelize);
}
},
});
Object.assign(model[delegate[len - 1]], app[target]);

Expand Down
85 changes: 85 additions & 0 deletions test/datasources_same_dir.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
'use strict';

const assert = require('assert');
const mm = require('egg-mock');

describe('test/datasources_same_dir.test.js', () => {
let app;

before(() => {
app = mm.app({
baseDir: 'apps/datasources-same-dir',
});
return app.ready();
});
before(async () => {
await app.model.sync({ force: true });
await app.sequelize.sync({ force: true });
});

after(mm.restore);

describe('Base', () => {
it('sequelize init success', () => {
assert(app.model);
assert(app.sequelize);
assert(app.Sequelize);
});

it('ctx model property getter', () => {
const ctx = app.mockContext();
assert(ctx.model);
assert(ctx.model.User);
assert(ctx.model.Monkey);
assert(ctx.model.Person);
assert(ctx.sequelize);
assert(ctx.sequelize.User);
assert(ctx.sequelize.Monkey);
assert(!ctx.sequelize.Person); // ignored
assert(ctx.model.User !== ctx.sequelize.User);
});

it('has right tableName', () => {
assert(app.model.Person.tableName === 'people');
assert(app.model.User.tableName === 'users');
assert(app.model.Monkey.tableName === 'the_monkeys');
assert(app.sequelize.User.tableName === 'users');
assert(app.sequelize.Monkey.tableName === 'the_monkeys');
});
});

describe('Test model', () => {
it('User.test method work', async function() {
await app.model.User.test();
});

it('should work timestramp', async function() {
let user = await app.model.User.create({ name: 'huacnlee' });
assert(user.isNewRecord === false);
assert(user.name === 'huacnlee');
assert(user.created_at !== null);
assert(user.updated_at !== null);

user = await app.sequelize.User.create({ name: 'huacnlee' });
assert(user.isNewRecord === false);
assert(user.name === 'huacnlee');
assert(user.created_at !== null);
assert(user.updated_at !== null);
});
});

describe('Associate', () => {
it('ctx model associate init success', () => {
const ctx = app.mockContext();
assert.ok(ctx.model);
assert.ok(ctx.model.User);
assert.ok(ctx.model.User.prototype.hasPosts);
assert.ok(ctx.model.Post);

assert.ok(ctx.sequelize);
assert.ok(ctx.sequelize.User);
assert.ok(ctx.sequelize.User.prototype.hasPosts);
assert.ok(ctx.sequelize.Post);
});
});
});
10 changes: 10 additions & 0 deletions test/fixtures/apps/datasources-same-dir/app/model/Person.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
'use strict';

module.exports = (app, model) => {
const { STRING } = app.Sequelize;
const Person = model.define('person', {
name: STRING(30),
});

return Person;
};
28 changes: 28 additions & 0 deletions test/fixtures/apps/datasources-same-dir/app/model/monkey.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use strict';

module.exports = (app, model) => {
const { STRING, INTEGER, DATE } = app.Sequelize;
const Monkey = model.define('monkey', {
name: {
type: STRING,
allowNull: false,
},
user_id: INTEGER,
created_at: DATE,
updated_at: DATE,
}, {
tableName: 'the_monkeys',

classMethods: {
},

instanceMethods: {
},
});

Monkey.findUser = async function() {
return model.User.find({ id: 1 });
};

return Monkey;
};
4 changes: 4 additions & 0 deletions test/fixtures/apps/datasources-same-dir/app/model/other.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
'use strict';

module.exports = {
};
19 changes: 19 additions & 0 deletions test/fixtures/apps/datasources-same-dir/app/model/post.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
'use strict';

const assert = require('assert');

module.exports = (app, model) => {
const { INTEGER, STRING } = app.Sequelize;
const Post = model.define('post', {
user_id: INTEGER,
name: STRING(30),
});

Post.associate = function() {
assert.ok(model.User);
assert.ok(model.Post);
model.Post.belongsTo(model.User, { as: 'user', foreignKey: 'user_id' });
};

return Post;
};
28 changes: 28 additions & 0 deletions test/fixtures/apps/datasources-same-dir/app/model/user.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
'use strict';

const assert = require('assert');

module.exports = (app, model) => {
const { STRING, INTEGER } = app.Sequelize;
const User = model.define('user', {
name: STRING(30),
age: INTEGER,
});

User.associate = function() {
assert.ok(model.User);
assert.ok(model.Post);
model.User.hasMany(model.Post, { as: 'posts', foreignKey: 'user_id' });
};

User.test = async function() {
assert(app.config);
assert(model.User === this);
const monkey = await model.Monkey.create({ name: 'The Monkey' });
assert(monkey.id);
assert(monkey.isNewRecord === false);
assert(monkey.name === 'The Monkey');
};

return User;
};
21 changes: 21 additions & 0 deletions test/fixtures/apps/datasources-same-dir/config/config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
'use strict';

exports.sequelize = {
datasources: [
{
delegate: 'model',
baseDir: 'model',
database: 'test',
dialect: 'mysql',
},
{
delegate: 'sequelize',
baseDir: 'model',
database: 'test1',
dialect: 'mysql',
exclude: 'Person.js',
},
],
};

exports.keys = '0jN4Fw7ZBjo4xtrLklDg4g==';
3 changes: 3 additions & 0 deletions test/fixtures/apps/datasources-same-dir/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"name": "datasources-same-dir"
}

0 comments on commit c4998e1

Please sign in to comment.