@@ -46,6 +46,14 @@ SQLConnector.Transaction = Transaction;
4646 */
4747SQLConnector . prototype . relational = true ;
4848
49+ /**
50+ * Set the multiInsertSupported property to indicate if multiple value insert SQL dialect is supported or not
51+ * This can be overridden by derived connectors to allow `insert multiple values` dialect for createAll
52+ * By default, it is set to false for backward compatibility
53+ * @type {boolean }
54+ */
55+ SQLConnector . prototype . multiInsertSupported = false ;
56+
4957/**
5058 * Invoke a prototype method on the super class
5159 * @param {String } methodName Method name
@@ -540,6 +548,53 @@ SQLConnector.prototype.buildInsert = function(model, data, options) {
540548 return this . parameterize ( insertStmt ) ;
541549} ;
542550
551+ /**
552+ * Build INSERT SQL statement for multiple values
553+ * @param {String } model The model name
554+ * @param {Object } data The array of model data object
555+ * @param {Object } options The options object
556+ * @returns {Object } The ParameterizedSQL Object with INSERT SQL statement
557+ */
558+ SQLConnector . prototype . buildInsertAll = function ( model , data , options ) {
559+ if ( ! this . multiInsertSupported ) {
560+ debug ( 'multiple value insert SQL dialect is not supported by this connector' ) ;
561+ // return immediately if multiInsertSupported=false in connector
562+ return null ;
563+ }
564+ const fieldsArray = this . buildFieldsFromArray ( model , data ) ;
565+ if ( fieldsArray . length === 0 ) {
566+ debug ( 'no fields found for insert query' ) ;
567+ // return immediately if no fields found
568+ return null ;
569+ }
570+ const insertStmt = this . buildInsertInto ( model , fieldsArray [ 0 ] , options ) ;
571+
572+ for ( let i = 0 ; i < fieldsArray . length ; i ++ ) {
573+ const columnValues = fieldsArray [ i ] . columnValues ;
574+ const isLast = ( i === ( fieldsArray . length - 1 ) ) ;
575+ const isFirst = ( i === 0 ) ;
576+
577+ if ( columnValues . length ) {
578+ const values = ParameterizedSQL . join ( columnValues , ',' ) ;
579+ // Multi value query.
580+ // This lets multiple row insertion in single query
581+ values . sql = ( isFirst ? 'VALUES ' : '' ) +
582+ '(' + values . sql + ')' +
583+ ( isLast ? '' : ',' ) ;
584+ insertStmt . merge ( values ) ;
585+ } else {
586+ // Insert default values if no values provided
587+ insertStmt . merge ( this . buildInsertDefaultValues ( model , data , options ) ) ;
588+ }
589+ }
590+
591+ const returning = this . buildInsertReturning ( model , data , options ) ;
592+ if ( returning ) {
593+ insertStmt . merge ( returning ) ;
594+ }
595+ return this . parameterize ( insertStmt ) ;
596+ } ;
597+
543598/**
544599 * Execute a SQL statement with given parameters.
545600 *
@@ -630,6 +685,34 @@ SQLConnector.prototype.create = function(model, data, options, callback) {
630685 } ) ;
631686} ;
632687
688+ /**
689+ * Create multiple data models in a single insert query
690+ * Works only if `multiInsertSupported` is set to true for the connector
691+ *
692+ * @param {String } model The model name
693+ * @param {Object } data The model instances data
694+ * @param {Object } options Options object
695+ * @param {Function } [callback] The callback function
696+ */
697+ SQLConnector . prototype . createAll = function ( model , data , options , callback ) {
698+ const self = this ;
699+ const stmt = this . buildInsertAll ( model , data , options ) ;
700+ if ( ! stmt ) {
701+ debug ( 'empty SQL statement returned for insert into multiple values' ) ;
702+ callback ( new Error (
703+ g . f ( 'empty SQL statement returned for insert into multiple values' ) ,
704+ ) ) ;
705+ }
706+ this . execute ( stmt . sql , stmt . params , options , function ( err , info ) {
707+ if ( err ) {
708+ callback ( err ) ;
709+ } else {
710+ const insertedId = self . getInsertedId ( model , info ) ;
711+ callback ( err , insertedId ) ;
712+ }
713+ } ) ;
714+ } ;
715+
633716/**
634717 * Save the model instance into the database
635718 * @param {String } model The model name
@@ -1177,6 +1260,24 @@ SQLConnector.prototype.buildFields = function(model, data, excludeIds) {
11771260 return this . _buildFieldsForKeys ( model , data , keys , excludeIds ) ;
11781261} ;
11791262
1263+ /**
1264+ * Build an array of fields for the database operation from data array
1265+ * @param {String } model Model name
1266+ * @param {Object } data Array of Model data object
1267+ * @param {Boolean } excludeIds Exclude id properties or not, default to false
1268+ * @returns {[{names: Array, values: Array, properties: Array}] }
1269+ */
1270+ SQLConnector . prototype . buildFieldsFromArray = function ( model , data , excludeIds ) {
1271+ const fields = [ ] ;
1272+ if ( data . length > 0 ) {
1273+ const keys = Object . keys ( data [ 0 ] ) ;
1274+ for ( let i = 0 ; i < data . length ; i ++ ) {
1275+ fields . push ( this . _buildFieldsForKeys ( model , data [ i ] , keys , excludeIds ) ) ;
1276+ }
1277+ }
1278+ return fields ;
1279+ } ;
1280+
11801281/**
11811282 * Build an array of fields for the replace database operation
11821283 * @param {String } model Model name
0 commit comments