Skip to content

Commit

Permalink
Merge pull request #47 from seegno/feature/mysql-support
Browse files Browse the repository at this point in the history
Add support for MySQL
  • Loading branch information
abelsoares committed Mar 1, 2017
2 parents fda3690 + 95777de commit fd4c1a5
Show file tree
Hide file tree
Showing 8 changed files with 212 additions and 3 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
/node_modules
/test.sqlite3
/test/coverage
/test/mysql/knexfile.js
/test/postgres/knexfile.js
/test/sqlite/knexfile.js
5 changes: 5 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,11 +1,16 @@
language: node_js

services:
- mysql

addons:
postgresql: "9.2"

before_script:
- cp test/mysql/knexfile.js.dist test/mysql/knexfile.js
- cp test/postgres/knexfile.js.dist test/postgres/knexfile.js
- cp test/sqlite/knexfile.js.dist test/sqlite/knexfile.js
- mysql -e "create database \`bookshelf-json-columns\`;" -uroot
- psql -U postgres -c 'create database "bookshelf-json-columns";'

node_js:
Expand Down
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -75,12 +75,12 @@ bookshelf.Model.extend({

Contributions are welcome and greatly appreciated, so feel free to fork this repository and submit pull requests.

**bookshelf-json-columns** supports PostgreSQL and SQLite3. You can find test suites for each of these database engines in the *test/postgres* and *test/sqlite* folders.
**bookshelf-json-columns** supports PostgreSQL, SQLite3 and MySQL. You can find test suites for all these database engines in the *test* folder.

### Setting up

- Fork and clone the **bookshelf-json-columns** repository.
- Duplicate *test/postgres/knexfile.js.dist* and *test/sqlite/knexfile.js.dist* files and update them to your needs.
- Duplicate all *.dist* knexfiles and update them to your needs.
- Make sure all the tests pass:

```sh
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
"eslint-config-seegno": "8.0.0",
"knex": "0.12.6",
"mocha": "3.1.2",
"mysql": "2.12.0",
"nyc": "8.3.2",
"pg": "6.1.0",
"pre-commit": "1.1.3",
Expand Down
2 changes: 1 addition & 1 deletion src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ function parse(model, response, options = {}) {
export default Bookshelf => {
const Model = Bookshelf.Model.prototype;
const client = Bookshelf.knex.client.config.client;
const parseOnFetch = client === 'sqlite' || client === 'sqlite3';
const parseOnFetch = client === 'sqlite' || client === 'sqlite3' || client === 'mysql';

Bookshelf.Model = Bookshelf.Model.extend({
initialize() {
Expand Down
1 change: 1 addition & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,6 @@
* Test suite.
*/

import './mysql';
import './postgres';
import './sqlite';
187 changes: 187 additions & 0 deletions test/mysql/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@

/**
* Module dependencies.
*/

import { dropTable, recreateTable } from '../utils';
import bookshelf from 'bookshelf';
import jsonColumns from '../../src';
import knex from 'knex';
import knexfile from './knexfile';
import should from 'should';
import sinon from 'sinon';

/**
* Test `bookshelf-json-columns` plugin with MySQL client.
*/

describe('with MySQL client', () => {
const repository = bookshelf(knex(knexfile));
const ModelPrototype = repository.Model.prototype;

repository.plugin(jsonColumns);

before(async () => {
await recreateTable(repository);
});

after(async () => {
await dropTable(repository);
});

describe('when a JSON column is not registered', () => {
const Model = repository.Model.extend({ tableName: 'test' });

it('should throw an error on create', async () => {
try {
await Model.forge().save({ foo: { bar: 'baz' } });

should.fail();
} catch (e) {
e.should.be.instanceOf(Error);
e.code.should.equal('ER_BAD_FIELD_ERROR');
}
});

it('should throw an error creating through a collection', async () => {
const Collection = repository.Collection.extend({ model: Model });
const collection = Collection.forge();

try {
await collection.create(Model.forge({ foo: { bar: 'baz' } }));

should.fail();
} catch (e) {
e.should.be.instanceOf(Error);
e.code.should.equal('ER_BAD_FIELD_ERROR');
}
});

it('should throw an error on update', async () => {
const model = await Model.forge().save();

try {
await model.save({ foo: { bar: 'baz' } });

should.fail();
} catch (e) {
e.should.be.instanceOf(Error);
e.code.should.equal('ER_BAD_FIELD_ERROR');
}
});

it('should not override model prototype initialize method', async () => {
sinon.spy(ModelPrototype, 'initialize');

Model.forge();

ModelPrototype.initialize.callCount.should.equal(1);

sinon.restore(ModelPrototype);
});
});

describe('when a JSON column is registered', () => {
const Model = repository.Model.extend({ tableName: 'test' }, { jsonColumns: ['foo'] });

it('should keep a JSON value on create', async () => {
const model = await Model.forge().save({ foo: { bar: 'baz' } });

model.get('foo').should.eql({ bar: 'baz' });
});

it('should keep a JSON value using save with a key and value', async () => {
const model = await Model.forge().save('foo', { bar: 'baz' }, { method: 'insert' });

model.get('foo').should.eql({ bar: 'baz' });
});

it('should keep a JSON value when creating through a collection', async () => {
const Collection = repository.Collection.extend({ model: Model });
const collection = Collection.forge();

await collection.create(Model.forge({ foo: { bar: 'baz' } }));

collection.at(0).get('foo').should.eql({ bar: 'baz' });
});

it('should keep a null value on create', async () => {
const model = await Model.forge().save();

should(model.get('foo')).be.undefined();
});

it('should keep a JSON value on update', async () => {
const model = await Model.forge().save();

await model.save({ foo: { bar: 'baz' } });

model.get('foo').should.eql({ bar: 'baz' });
});

it('should keep a null value on update', async () => {
const model = await Model.forge().save();

await model.save();

should(model.get('foo')).be.undefined();
});

it('should not stringify null values on update with `patch` option', async () => {
sinon.spy(ModelPrototype, 'save');

const model = await Model.forge().save();

await model.save({ foo: null }, { patch: true });

ModelPrototype.save.callCount.should.equal(2);
ModelPrototype.save.secondCall.args[0].should.eql({ foo: null });

sinon.restore(ModelPrototype);
});

it('should keep a JSON value when updating with `patch` option', async () => {
const model = await Model.forge().save();

await model.save({ foo: { bar: 'baz' } }, { patch: true });

model.get('foo').should.eql({ bar: 'baz' });
});

it('should keep a JSON value when updating other columns', async () => {
const model = await Model.forge().save({ foo: { bar: 'baz' } });

await model.save({ qux: 'qix' }, { patch: true });

model.get('foo').should.eql({ bar: 'baz' });
});

it('should keep a JSON value on fetch', async () => {
await Model.forge().save({ foo: { bar: 'baz' }, qux: 'qix' });

const model = await Model.forge({ qux: 'qix' }).fetch();

model.get('foo').should.eql({ bar: 'baz' });
});

it('should keep a JSON value when updating through query', async () => {
const model = await Model.forge().save({ foo: { bar: 'baz' } });

model.query().update({ qux: 'qix' });

await model.refresh();

model.get('foo').should.eql({ bar: 'baz' });
});

it('should not override model initialize method', async () => {
sinon.spy(ModelPrototype, 'initialize');

Model.forge();

ModelPrototype.initialize.callCount.should.equal(1);

sinon.restore(ModelPrototype);
});
});
});
14 changes: 14 additions & 0 deletions test/mysql/knexfile.js.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@

/**
* Export MySQL knexfile.
*/

export default {
client: 'mysql',
connection: {
charset: 'utf8',
database: 'bookshelf-json-columns',
host: 'localhost',
user: 'root'
}
};

0 comments on commit fd4c1a5

Please sign in to comment.