var should = require('./init.js'); var Post, PostWithStringId, PostWithUniqueTitle, db; describe('mysql', function () { before(function (done) { db = getDataSource(); Post = db.define('PostWithDefaultId', { title: { type: String, length: 255, index: true }, content: { type: String }, comments: [String], history: Object, stars: Number }); PostWithStringId = db.define('PostWithStringId', { id: {type: String, id: true}, title: { type: String, length: 255, index: true }, content: { type: String } }); PostWithUniqueTitle = db.define('PostWithUniqueTitle', { title: { type: String, length: 255, index: {unique: true} }, content: { type: String } }); db.automigrate(['PostWithDefaultId', 'PostWithStringId', 'PostWithUniqueTitle'], function (err) { should.not.exist(err); done(err); }); }); beforeEach(function (done) { Post.destroyAll(function () { PostWithStringId.destroyAll(function () { PostWithUniqueTitle.destroyAll(function () { done(); }); }); }); }); it('should allow array or object', function (done) { Post.create({title: 'a', content: 'AAA', comments: ['1', '2'], history: {a: 1, b: 'b'}}, function (err, post) { should.not.exist(err); Post.findById(post.id, function (err, p) { p.id.should.be.equal(post.id); p.content.should.be.equal(post.content); p.title.should.be.equal('a'); p.comments.should.eql(['1', '2']); p.history.should.eql({a: 1, b: 'b'}); done(); }); }); }); it('updateOrCreate should update the instance', function (done) { Post.create({title: 'a', content: 'AAA'}, function (err, post) { post.title = 'b'; Post.updateOrCreate(post, function (err, p) { should.not.exist(err); p.id.should.be.equal(post.id); p.content.should.be.equal(post.content); Post.findById(post.id, function (err, p) { p.id.should.be.equal(post.id); p.content.should.be.equal(post.content); p.title.should.be.equal('b'); done(); }); }); }); }); it('updateOrCreate should update the instance without removing existing properties', function (done) { Post.create({title: 'a', content: 'AAA'}, function (err, post) { post = post.toObject(); delete post.title; Post.updateOrCreate(post, function (err, p) { should.not.exist(err); p.id.should.be.equal(post.id); p.content.should.be.equal(post.content); Post.findById(post.id, function (err, p) { p.id.should.be.equal(post.id); p.content.should.be.equal(post.content); p.title.should.be.equal('a'); done(); }); }); }); }); it('updateOrCreate should create a new instance if it does not exist', function (done) { var post = {id: 123, title: 'a', content: 'AAA'}; Post.updateOrCreate(post, function (err, p) { should.not.exist(err); p.title.should.be.equal(post.title); p.content.should.be.equal(post.content); p.id.should.be.equal(post.id); Post.findById(p.id, function (err, p) { p.id.should.be.equal(post.id); p.content.should.be.equal(post.content); p.title.should.be.equal(post.title); p.id.should.be.equal(post.id); done(); }); }); }); it('save should update the instance with the same id', function (done) { Post.create({title: 'a', content: 'AAA'}, function (err, post) { post.title = 'b'; post.save(function (err, p) { should.not.exist(err); p.id.should.be.equal(post.id); p.content.should.be.equal(post.content); Post.findById(post.id, function (err, p) { p.id.should.be.equal(post.id); p.content.should.be.equal(post.content); p.title.should.be.equal('b'); done(); }); }); }); }); it('save should update the instance without removing existing properties', function (done) { Post.create({title: 'a', content: 'AAA'}, function (err, post) { delete post.title; post.save(function (err, p) { should.not.exist(err); p.id.should.be.equal(post.id); p.content.should.be.equal(post.content); Post.findById(post.id, function (err, p) { p.id.should.be.equal(post.id); p.content.should.be.equal(post.content); p.title.should.be.equal('a'); done(); }); }); }); }); it('save should create a new instance if it does not exist', function (done) { var post = new Post({id: 123, title: 'a', content: 'AAA'}); post.save(post, function (err, p) { should.not.exist(err); p.title.should.be.equal(post.title); p.content.should.be.equal(post.content); p.id.should.be.equal(post.id); Post.findById(p.id, function (err, p) { should.not.exist(err); p.id.should.be.equal(post.id); p.content.should.be.equal(post.content); p.title.should.be.equal(post.title); p.id.should.be.equal(post.id); done(); }); }); }); it('all return should honor filter.fields', function (done) { var post = new Post({title: 'b', content: 'BBB'}) post.save(function (err, post) { Post.all({fields: ['title'], where: {title: 'b'}}, function (err, posts) { should.not.exist(err); posts.should.have.lengthOf(1); post = posts[0]; post.should.have.property('title', 'b'); post.should.not.have.property('content'); should.not.exist(post.id); done(); }); }); }); it('find should order by id if the order is not set for the query filter', function (done) { PostWithStringId.create({id: '2', title: 'c', content: 'CCC'}, function (err, post) { PostWithStringId.create({id: '1', title: 'd', content: 'DDD'}, function (err, post) { PostWithStringId.find(function (err, posts) { should.not.exist(err); posts.length.should.be.equal(2); posts[0].id.should.be.equal('1'); PostWithStringId.find({limit: 1, offset: 0}, function (err, posts) { should.not.exist(err); posts.length.should.be.equal(1); posts[0].id.should.be.equal('1'); PostWithStringId.find({limit: 1, offset: 1}, function (err, posts) { should.not.exist(err); posts.length.should.be.equal(1); posts[0].id.should.be.equal('2'); done(); }); }); }); }); }); }); it('should allow to find using like', function (done) { Post.create({title: 'My Post', content: 'Hello'}, function (err, post) { Post.find({where: {title: {like: 'M%st'}}}, function (err, posts) { should.not.exist(err); posts.should.have.property('length', 1); done(); }); }); }); it('should support like for no match', function (done) { Post.create({title: 'My Post', content: 'Hello'}, function (err, post) { Post.find({where: {title: {like: 'M%XY'}}}, function (err, posts) { should.not.exist(err); posts.should.have.property('length', 0); done(); }); }); }); it('should allow to find using nlike', function (done) { Post.create({title: 'My Post', content: 'Hello'}, function (err, post) { Post.find({where: {title: {nlike: 'M%st'}}}, function (err, posts) { should.not.exist(err); posts.should.have.property('length', 0); done(); }); }); }); it('should support nlike for no match', function (done) { Post.create({title: 'My Post', content: 'Hello'}, function (err, post) { Post.find({where: {title: {nlike: 'M%XY'}}}, function (err, posts) { should.not.exist(err); posts.should.have.property('length', 1); done(); }); }); }); it('should support "and" operator that is satisfied', function (done) { Post.create({title: 'My Post', content: 'Hello'}, function (err, post) { Post.find({where: {and: [ {title: 'My Post'}, {content: 'Hello'} ]}}, function (err, posts) { should.not.exist(err); posts.should.have.property('length', 1); done(); }); }); }); it('should support "and" operator that is not satisfied', function (done) { Post.create({title: 'My Post', content: 'Hello'}, function (err, post) { Post.find({where: {and: [ {title: 'My Post'}, {content: 'Hello1'} ]}}, function (err, posts) { should.not.exist(err); posts.should.have.property('length', 0); done(); }); }); }); it('should support "or" that is satisfied', function (done) { Post.create({title: 'My Post', content: 'Hello'}, function (err, post) { Post.find({where: {or: [ {title: 'My Post'}, {content: 'Hello1'} ]}}, function (err, posts) { should.not.exist(err); posts.should.have.property('length', 1); done(); }); }); }); it('should support "or" operator that is not satisfied', function (done) { Post.create({title: 'My Post', content: 'Hello'}, function (err, post) { Post.find({where: {or: [ {title: 'My Post1'}, {content: 'Hello1'} ]}}, function (err, posts) { should.not.exist(err); posts.should.have.property('length', 0); done(); }); }); }); // The where object should be parsed by the connector it('should support where for count', function (done) { Post.create({title: 'My Post', content: 'Hello'}, function (err, post) { Post.count({and: [ {title: 'My Post'}, {content: 'Hello'} ]}, function (err, count) { should.not.exist(err); count.should.be.equal(1); Post.count({and: [ {title: 'My Post1'}, {content: 'Hello'} ]}, function (err, count) { should.not.exist(err); count.should.be.equal(0); done(); }); }); }); }); // The where object should be parsed by the connector it('should support where for destroyAll', function (done) { Post.create({title: 'My Post1', content: 'Hello'}, function (err, post) { Post.create({title: 'My Post2', content: 'Hello'}, function (err, post) { Post.destroyAll({and: [ {title: 'My Post1'}, {content: 'Hello'} ]}, function (err) { should.not.exist(err); Post.count(function (err, count) { should.not.exist(err); count.should.be.equal(1); done(); }); }); }); }); }); it('should not allow SQL injection for inq operator', function (done) { Post.create({title: 'My Post1', content: 'Hello', stars: 5}, function (err, post) { Post.create({title: 'My Post2', content: 'Hello', stars: 20}, function (err, post) { Post.find({where: {title: {inq: ['SELECT title from PostWithDefaultId']}}}, function (err, posts) { should.not.exist(err); posts.should.have.property('length', 0); done(); }); }); }); }); it('should not allow SQL injection for lt operator', function (done) { Post.create({title: 'My Post1', content: 'Hello', stars: 5}, function (err, post) { Post.create({title: 'My Post2', content: 'Hello', stars: 20}, function (err, post) { Post.find({where: {stars: {lt: 'SELECT title from PostWithDefaultId'}}}, function (err, posts) { should.not.exist(err); posts.should.have.property('length', 0); done(); }); }); }); }); it('should not allow SQL injection for nin operator', function (done) { Post.create({title: 'My Post1', content: 'Hello', stars: 5}, function (err, post) { Post.create({title: 'My Post2', content: 'Hello', stars: 20}, function (err, post) { Post.find({where: {title: {nin: ['SELECT title from PostWithDefaultId']}}}, function (err, posts) { should.not.exist(err); posts.should.have.property('length', 2); done(); }); }); }); }); it('should not allow SQL injection for inq operator with number column', function (done) { Post.create({title: 'My Post1', content: 'Hello', stars: 5}, function (err, post) { Post.create({title: 'My Post2', content: 'Hello', stars: 20}, function (err, post) { Post.find({where: {stars: {inq: ['SELECT title from PostWithDefaultId']}}}, function (err, posts) { should.not.exist(err); posts.should.have.property('length', 0); done(); }); }); }); }); it('should not allow SQL injection for inq operator with array value', function (done) { Post.create({title: 'My Post1', content: 'Hello', stars: 5}, function (err, post) { Post.create({title: 'My Post2', content: 'Hello', stars: 20}, function (err, post) { Post.find({where: {stars: {inq: [5, 'SELECT title from PostWithDefaultId']}}}, function (err, posts) { should.not.exist(err); posts.should.have.property('length', 1); done(); }); }); }); }); it('should not allow SQL injection for between operator', function (done) { Post.create({title: 'My Post1', content: 'Hello', stars: 5}, function (err, post) { Post.create({title: 'My Post2', content: 'Hello', stars: 20}, function (err, post) { Post.find({where: {stars: {between: [5, 'SELECT title from PostWithDefaultId']}}}, function (err, posts) { should.not.exist(err); posts.should.have.property('length', 0); done(); }); }); }); }); it('should convert NaN to NULL for query', function(done) { Post.create({title: 'My Post1', content: 'Hello', stars: 5}, function(err, post) { Post.findById('x', function(err, post) { should.not.exist(err); should.not.exist(post); done(); }); }); }); it('should not allow duplicate titles', function (done) { var data = {title: 'a', content: 'AAA'}; PostWithUniqueTitle.create(data, function (err, post) { should.not.exist(err); PostWithUniqueTitle.create(data, function (err, post) { should.exist(err); done(); }); }); }); after(function (done) { Post.destroyAll(function () { PostWithStringId.destroyAll(function () { PostWithUniqueTitle.destroyAll(done); }); }); }); });