2015-12-08 11:37:31 -06:00
// MSSQL Query Compiler
// ------
'use strict' ;
2015-12-09 17:53:53 -06:00
var _ = require ( 'lodash' ) ;
2015-12-08 11:37:31 -06:00
var inherits = require ( 'inherits' ) ;
var QueryCompiler = require ( '../../../query/compiler' ) ;
var assign = require ( 'lodash/object/assign' ) ;
function QueryCompiler _MSSQL ( client , builder ) {
QueryCompiler . call ( this , client , builder ) ;
}
inherits ( QueryCompiler _MSSQL , QueryCompiler ) ;
assign ( QueryCompiler _MSSQL . prototype , {
2015-12-09 17:53:53 -06:00
_emptyInsertValue : 'default values' ,
2015-12-08 11:37:31 -06:00
2015-12-09 17:53:53 -06:00
// Compiles an "insert" query, allowing for multiple
// inserts using a single query statement.
insert : function insert ( ) {
var insertValues = this . single . insert || [ ] ;
var sql = 'insert into ' + this . tableName + ' ' ;
var returning = this . single . returning ;
var returningSql = returning ? this . _returning ( 'insert' , returning ) + ' ' : '' ;
if ( Array . isArray ( insertValues ) ) {
if ( insertValues . length === 0 ) {
return '' ;
}
} else if ( typeof insertValues === 'object' && _ . isEmpty ( insertValues ) ) {
return {
sql : sql + returningSql + this . _emptyInsertValue ,
returning : returning
} ;
}
var insertData = this . _prepInsert ( insertValues ) ;
if ( typeof insertData === 'string' ) {
sql += insertData ;
} else {
if ( insertData . columns . length ) {
sql += '(' + this . formatter . columnize ( insertData . columns ) ;
sql += ') ' + returningSql + 'values (' ;
var i = - 1 ;
while ( ++ i < insertData . values . length ) {
if ( i !== 0 ) sql += '), (' ;
sql += this . formatter . parameterize ( insertData . values [ i ] ) ;
}
sql += ')' ;
} else if ( insertValues . length === 1 && insertValues [ 0 ] ) {
sql += returningSql + this . _emptyInsertValue ;
} else {
sql = '' ;
}
}
return {
sql : sql ,
returning : returning
} ;
} ,
// Compiles an `update` query, allowing for a return value.
2015-12-08 11:37:31 -06:00
update : function update ( ) {
var updates = this . _prepUpdate ( this . single . update ) ;
2015-12-09 17:53:53 -06:00
var join = this . join ( ) ;
2015-12-08 11:37:31 -06:00
var where = this . where ( ) ;
var order = this . order ( ) ;
var limit = this . limit _ ( ) ;
2015-12-09 17:53:53 -06:00
var returning = this . single . returning ;
return {
sql : 'update ' + ( limit ? limit + ' ' : '' ) + this . tableName + ( join ? ' ' + join : '' ) + ' set ' + updates . join ( ', ' ) + ( returning ? ' ' + this . _returning ( 'update' , returning ) : '' ) + ( where ? ' ' + where : '' ) + ( order ? ' ' + order : '' ) + ( ! returning ? this . _returning ( 'rowcount' , '@@rowcount' ) : '' ) ,
returning : returning || '@@rowcount'
} ;
} ,
// Compiles a `delete` query.
del : function del ( ) {
// Make sure tableName is processed by the formatter first.
var tableName = this . tableName ;
var wheres = this . where ( ) ;
var returning = this . single . returning ;
return {
sql : 'delete from ' + tableName + ( returning ? ' ' + this . _returning ( 'del' , returning ) : '' ) + ( wheres ? ' ' + wheres : '' ) + ( ! returning ? this . _returning ( 'rowcount' , '@@rowcount' ) : '' ) ,
returning : returning || '@@rowcount'
} ;
2015-12-08 11:37:31 -06:00
} ,
// Compiles the columns in the query, specifying if an item was distinct.
columns : function columns ( ) {
var distinct = false ;
if ( this . onlyUnions ( ) ) return '' ;
var columns = this . grouped . columns || [ ] ;
var i = - 1 ,
sql = [ ] ;
if ( columns ) {
while ( ++ i < columns . length ) {
var stmt = columns [ i ] ;
if ( stmt . distinct ) distinct = true ;
if ( stmt . type === 'aggregate' ) {
sql . push ( this . aggregate ( stmt ) ) ;
} else if ( stmt . value && stmt . value . length > 0 ) {
sql . push ( this . formatter . columnize ( stmt . value ) ) ;
}
}
}
if ( sql . length === 0 ) sql = [ '*' ] ;
var limit = this . limit _ ( ) ;
return 'select ' + ( distinct ? 'distinct ' : '' ) + ( limit ? limit + ' ' : '' ) + sql . join ( ', ' ) + ( this . tableName ? ' from ' + this . tableName : '' ) ;
} ,
2015-12-09 17:53:53 -06:00
_returning : function _returning ( method , value ) {
switch ( method ) {
case 'update' :
case 'insert' :
return value ? 'output ' + this . formatter . columnizeWithPrefix ( 'inserted.' , value ) : '' ;
case 'del' :
return value ? 'output ' + this . formatter . columnizeWithPrefix ( 'deleted.' , value ) : '' ;
case 'rowcount' :
return value ? ';select @@rowcount' : '' ;
}
} ,
2015-12-08 11:37:31 -06:00
// Compiles a `truncate` query.
truncate : function truncate ( ) {
return 'truncate table ' + this . tableName ;
} ,
forUpdate : function forUpdate ( ) {
return 'with (READCOMMITTEDLOCK)' ;
} ,
forShare : function forShare ( ) {
return 'with (NOLOCK)' ;
} ,
// Compiles a `columnInfo` query.
columnInfo : function columnInfo ( ) {
var column = this . single . columnInfo ;
return {
2015-12-09 17:53:53 -06:00
sql : 'select * from information_schema.columns where table_name = ? and table_schema = \'dbo\'' ,
bindings : [ this . single . table ] ,
2015-12-08 11:37:31 -06:00
output : function output ( resp ) {
var out = resp . reduce ( function ( columns , val ) {
columns [ val . COLUMN _NAME ] = {
defaultValue : val . COLUMN _DEFAULT ,
type : val . DATA _TYPE ,
maxLength : val . CHARACTER _MAXIMUM _LENGTH ,
nullable : val . IS _NULLABLE === 'YES'
} ;
return columns ;
} , { } ) ;
return column && out [ column ] || out ;
}
} ;
} ,
limit _ : function limit _ ( ) {
var noLimit = ! this . single . limit && this . single . limit !== 0 ;
if ( noLimit ) return '' ;
return 'top (' + this . formatter . parameter ( this . single . limit ) + ')' ;
} ,
limit : function limit ( ) {
return '' ;
2015-12-09 17:53:53 -06:00
} ,
offset : function offset ( ) {
if ( ! this . single . offset ) return '' ;
return 'offset ' + this . formatter . parameter ( this . single . offset ) + ' rows' ;
2015-12-08 11:37:31 -06:00
}
} ) ;
// Set the QueryBuilder & QueryCompiler on the client object,
// incase anyone wants to modify things to suit their own purposes.
module . exports = QueryCompiler _MSSQL ;