knex/test/unit/builder.js

321 lines
9.4 KiB
JavaScript

var _ = require('underscore');
var when = require('when');
var Builder = require('../../lib/builder').Builder;
var Common = require('../../lib/common').Common;
var Raw = require('../../lib/raw').Raw;
describe('Builder', function () {
var builder;
beforeEach(function() {
builder = new Builder({
query: function(obj) {
return when.resolve(obj);
},
grammar: require('../../clients/server/mysql/grammar').grammar
});
});
describe('constructor', function () {
it('accepts the current Knex instance, attaching the client, and grammar', function() {
var grammar = {some: 'grammar'};
var client = {some: 'db'};
var knex = {client: client, grammar: grammar};
var reset = sinon.stub(Builder.prototype, 'reset');
var builder = new Builder(knex);
expect(builder.knex).to.eql(knex);
expect(builder.client).to.eql(client);
expect(builder.grammar).to.eql(grammar);
reset.should.have.been.calledOnce;
reset.restore();
});
});
describe('from', function() {
it('sets the tableName', function() {
expect(builder.table).to.be.empty;
var result = builder.from('myTable');
expect(builder.table).to.equal('myTable');
expect(result).to.equal(builder);
});
it('returns the tableName when no arguments are passed', function() {
expect(builder.table).to.be.empty;
var result = builder.from('myTable');
expect(builder.from()).to.equal('myTable');
});
});
describe('column', function() {
it('adds a value to the columns array', function() {
expect(builder.columns).to.have.length(0);
builder.column('myColumn');
expect(builder.columns).to.have.length(1);
});
});
describe('distinct', function() {
it('sets the isDistinct flag to true', function() {
builder.distinct('distinctCol');
expect(builder.columns[0]).to.equal('distinctCol');
});
it('adds the column to the columns array', function() {
builder.distinct('distinctCol');
expect(builder.flags.distinct).to.be.true;
});
});
describe('toSql', function() {
it('sets the type to "select" if not otherwise set', function() {
expect(builder.type).not.to.exist;
builder.toSql();
expect(builder.type).to.equal('select');
});
it('compiles based on the type, passing the current context', function(done) {
var compileSelect = builder.grammar.compileSelect;
builder.grammar.compileSelect = function(ctx) {
expect(ctx).to.eql(builder);
builder.grammar.compileSelect = compileSelect;
done();
};
builder.toSql();
});
});
describe('toString', function() {
it('should properly escape the query string', function() {
var output = "select * from `items` outer join `users` on `items`.`id` = `users`.`id` where `id` = 'User' or `id` = (SELECT id from otheritems)";
expect(builder
.from('items')
.join('users', function() {
this.on('items.id', '=', 'users.id');
this.type('outer');
})
.where('id', '=', 'User')
.orWhere('id', '=', new Raw({}).query('(SELECT id from otheritems)')).toString()).to.equal(output);
});
});
describe('clone', function() {
it('should keep the correct type when cloning the instance', function() {
var cloned = builder.insert({a: 'value'}).into('tableName').clone();
expect(cloned.type).to.equal('insert');
});
});
describe('reset', function() {
});
describe('join', function() {
var JoinClause = require('../../lib/builder/joinclause').JoinClause;
it('accepts the joining table, the first column, operator, second column, and (optional) type', function() {
expect(builder.joins).to.have.length(0);
builder.from('users');
builder.join('accounts', 'users.id', '=', 'accounts.id');
expect(builder.joins).to.have.length(1);
expect(builder.joins[0]).to.be.an.instanceOf(JoinClause);
expect(builder.toString()).to.equal("select * from `users` inner join `accounts` on `users`.`id` = `accounts`.`id`");
});
it('accepts a different join type as the fifth parameter', function() {
builder.from('users');
builder.join('accounts', 'users.id', '=', 'accounts.id', 'left outer');
expect(builder.toString()).to.equal("select * from `users` left outer join `accounts` on `users`.`id` = `accounts`.`id`");
});
it('may take a function as the second argument, for a grouped join', function() {
builder.join('accounts', function(join) {
expect(builder.joins).to.have.length(0);
expect(this).to.be.an.instanceOf(JoinClause);
expect(join).to.be.an.instanceOf(JoinClause);
});
});
});
describe('where', function() {
describe('where', function() {
it('should allow a function as the first argument, for a grouped where clause', function() {
builder.where('id', '=', 1);
expect(builder.wheres).to.have.length(1);
expect(builder.bindings).to.have.length(1);
var subWhere = function(qb) {
expect(this).to.equal(qb);
expect(this).to.be.an.instanceOf(Builder);
this.where({id: 3}).orWhere('id', 4);
};
builder.where(subWhere);
expect(builder.bindings).to.have.length(3);
expect(builder.wheres).to.have.length(2);
expect(builder.from('test').toString()).to.equal("select * from `test` where `id` = 1 and (`id` = 3 or `id` = 4)");
});
it('should allow a raw instance as the first argument, which will add a whereRaw clause', function() {
builder.where(new Raw({}).query('id > ?', 2));
expect(builder.wheres).to.have.length(1);
expect(builder.bindings).to.have.length(1);
expect(builder.bindings[0]).to.equal(2);
});
it('should allow an object as the first argument, which will assume to be a k/v pair of where "="', function() {
builder.where({id: 2, name: 'Test'});
expect(builder.wheres).to.have.length(2);
expect(builder.bindings).to.have.length(2);
});
it('should assume that if the second argument is not an operator, it should be an "="', function() {
builder.where('id', 2);
expect(builder.wheres).to.have.length(1);
expect(builder.bindings[0]).to.equal(2);
});
it('should accept a function as the "value", for a sub select', function() {
builder.where('id', '=', function(qb) {
expect(this).to.equal(qb);
expect(this).to.be.an.instanceOf(Builder);
this.select('account_id').from('names').where('names.id', '>', 1).orWhere(function() {
this.where('names.first_name', 'like', 'Tim%').andWhere('names.id', '>', 10);
});
});
expect(builder.bindings).to.have.length(3);
expect(builder.toString()).to.equal("select * where `id` = (select `account_id` from `names` where `names`.`id` > 1 or (`names`.`first_name` like 'Tim%' and `names`.`id` > 10))");
});
it('should not do whereNull on where("foo", "<>", null) #76', function() {
var query = builder.where('foo', '<>', null);
expect(query.toString()).to.equal('select * where `foo` <> NULL');
});
it('should expand where("foo", "!=") to - where id = "!="', function() {
var query = builder.where('foo', '!=');
expect(query.toString()).to.equal("select * where `foo` = '!='");
});
});
describe('whereRaw', function() {
it('is called by orWhereRaw, passing the sql, bindings, and "or"', function() {
});
});
describe('whereExists', function() {
});
});
describe('groupBy', function() {
});
describe('orderBy', function() {
});
describe('union', function() {
});
describe('having', function() {
});
describe('offset / limit', function() {
});
describe('aggregate', function() {
});
describe('select', function() {
it('should throw if a table has not been specified when compiling');
});
describe('insert', function() {
it('sets the type to insert', function() {
builder.insert();
expect(builder.type).to.equal('insert');
});
it('sets the values to be insert', function() {
var spy = sinon.spy(builder, 'prepValues');
builder.insert({key: 1, key2: 2});
spy.should.have.been.calledOnce;
});
it('sorts the values in arrays', function() {
builder.insert([{key1: 'tim', key2: 'test'}, {key2: 'test2', key1: null}]);
expect(_.map(builder.values, function(val) {
return _.pluck(val, '0');
})).to.eql([['key1', 'key2'], ['key1', 'key2']]);
});
it('does not mutate the values being inserted', function() {
var x = [{a: 1}, {b: 2}];
var y = [{a: 1}, {b: 2}];
builder.insert(x);
expect(x).to.eql(y);
});
it('takes a second argument to set the isReturning, using the returning method', function() {
expect(builder.flags.returning).to.be.empty;
builder.insert({'insert': 'val'}, 'user_id');
expect(builder.flags.returning).to.equal('user_id');
});
});
describe('update', function() {
it('sorts the values in arrays', function() {
builder.update({key1: 'tim', key2: 'test'});
expect(_.pluck(builder.values, '0')).to.eql(['key1', 'key2']);
expect(builder.bindings).to.have.length(2);
});
});
describe('delete', function() {
});
describe('truncate', function() {
});
});