@@ -142,7 +142,6 @@ proto.insert = function* (table, rows, options) {
142142} ;
143143
144144proto . update = function * ( table , row , options ) {
145- // TODO: support multi rows
146145 options = options || { } ;
147146 if ( ! options . columns ) {
148147 options . columns = Object . keys ( row ) ;
@@ -174,6 +173,134 @@ proto.update = function* (table, row, options) {
174173 return yield this . query ( sql ) ;
175174} ;
176175
176+ /**
177+ *
178+ * Update multiple rows from a table
179+ *
180+ * UPDATE `table_name` SET
181+ * `column1` CASE
182+ * WHEN condition1 THEN 'value11'
183+ * WHEN condition2 THEN 'value12'
184+ * WHEN condition3 THEN 'value13'
185+ * ELSE `column1` END,
186+ * `column2` CASE
187+ * WHEN condition1 THEN 'value21'
188+ * WHEN condition2 THEN 'value22'
189+ * WHEN condition3 THEN 'value23'
190+ * ELSE `column2` END
191+ * WHERE condition
192+ *
193+ * See MySQL Case Syntax: https://dev.mysql.com/doc/refman/5.7/en/case.html
194+ *
195+ * @param {String } table table name
196+ * @param {Array<Object> } options Object Arrays
197+ * each Object needs a primary key `id`, or each Object has `row` and `where` properties
198+ * e.g.
199+ * [{ id: 1, name: 'fengmk21' }]
200+ * or [{ row: { name: 'fengmk21' }, where: { id: 1 } }]
201+ * @return {object } update result
202+ */
203+ proto . updateRows = function * ( table , options ) {
204+ if ( ! Array . isArray ( options ) ) {
205+ throw new Error ( 'Options should be array' ) ;
206+ }
207+
208+ /**
209+ * {
210+ * column: {
211+ * when: [ 'WHEN condition1 THEN ?', 'WHEN condition12 THEN ?' ],
212+ * then: [ value1, value1 ]
213+ * }
214+ * }
215+ */
216+ const SQL_CASE = { } ;
217+ // e.g. { id: [], column: [] }
218+ const WHERE = { } ;
219+
220+ options . forEach ( option => {
221+
222+ if ( ! option . hasOwnProperty ( 'id' ) && ! ( option . row && option . where ) ) {
223+ throw new Error ( 'Can not auto detect updateRows condition, please set option.row and option.where, or make sure option.id exists' ) ;
224+ }
225+
226+ // convert { id, column } to { row: { column }, where: { id } }
227+ if ( option . hasOwnProperty ( 'id' ) ) {
228+ const where = { id : option . id } ;
229+ const row = Object . keys ( option ) . reduce ( ( result , key ) => {
230+ if ( key !== 'id' ) {
231+ result [ key ] = option [ key ] ;
232+ }
233+ return result ;
234+ } , { } ) ;
235+ option = { row, where } ;
236+ }
237+
238+ let where = this . _where ( option . where ) ;
239+ where = where . indexOf ( 'WHERE' ) === - 1 ? where : where . substring ( where . indexOf ( 'WHERE' ) + 5 ) ;
240+ for ( const key in option . row ) {
241+ if ( ! SQL_CASE [ key ] ) {
242+ SQL_CASE [ key ] = { when : [ ] , then : [ ] } ;
243+ }
244+ SQL_CASE [ key ] . when . push ( ' WHEN ' + where + ' THEN ? ' ) ;
245+ SQL_CASE [ key ] . then . push ( option . row [ key ] ) ;
246+ }
247+
248+ for ( const key in option . where ) {
249+ if ( ! WHERE [ key ] ) {
250+ WHERE [ key ] = [ ] ;
251+ }
252+ if ( WHERE [ key ] . indexOf ( option . where [ key ] ) === - 1 ) {
253+ WHERE [ key ] . push ( option . where [ key ] ) ;
254+ }
255+ }
256+ } ) ;
257+
258+ let SQL = [ 'UPDATE ?? SET ' ] ;
259+ let VALUES = [ table ] ;
260+
261+ const TEMPLATE = [ ] ;
262+ for ( const key in SQL_CASE ) {
263+ let templateSql = ' ?? = CASE ' ;
264+ VALUES . push ( key ) ;
265+ templateSql += SQL_CASE [ key ] . when . join ( ' ' ) ;
266+ VALUES = VALUES . concat ( SQL_CASE [ key ] . then ) ;
267+ templateSql += ' ELSE ?? END ' ;
268+ TEMPLATE . push ( templateSql ) ;
269+ VALUES . push ( key ) ;
270+ }
271+
272+ SQL += TEMPLATE . join ( ' , ' ) ;
273+ SQL += this . _where ( WHERE ) ;
274+
275+ /**
276+ * e.g.
277+ *
278+ * updateRows(table, [
279+ * {id: 1, name: 'fengmk21', email: 'm@fengmk 21.com'},
280+ * {id: 2, name: 'fengmk22', email: 'm@fengmk 22.com'},
281+ * {id: 3, name: 'fengmk23', email: 'm@fengmk 23.com'},
282+ * ])
283+ *
284+ * UPDATE `ali-sdk-test-user` SET
285+ * `name` =
286+ * CASE
287+ * WHEN `id` = 1 THEN 'fengmk21'
288+ * WHEN `id` = 2 THEN 'fengmk22'
289+ * WHEN `id` = 3 THEN 'fengmk23'
290+ * ELSE `name` END,
291+ * `email` =
292+ * CASE
293+ * WHEN `id` = 1 THEN 'm@fengmk21.com'
294+ * WHEN `id` = 2 THEN 'm@fengmk22.com'
295+ * WHEN `id` = 3 THEN 'm@fengmk23.com'
296+ * ELSE `email` END
297+ * WHERE `id` IN (1, 2, 3)
298+ */
299+ const sql = this . format ( SQL , VALUES ) ;
300+ debug ( 'updateRows(%j, %j) \n=> %j' , table , options , sql ) ;
301+ return yield this . query ( sql ) ;
302+ } ;
303+
177304proto . delete = function * ( table , where ) {
178305 const sql = this . format ( 'DELETE FROM ??' , [ table ] ) +
179306 this . _where ( where ) ;
0 commit comments