@@ -1537,6 +1537,27 @@ function NumberType(val) {
15371537 return ! isNaN ( num ) ? num : val ;
15381538}
15391539
1540+ function coerceArray ( val ) {
1541+ if ( Array . isArray ( val ) ) {
1542+ return val ;
1543+ }
1544+
1545+ if ( ! utils . isPlainObject ( val ) ) {
1546+ throw new Error ( g . f ( 'Value is not an {{array}} or {{object}} with sequential numeric indices' ) ) ;
1547+ }
1548+
1549+ var arrayVal = new Array ( Object . keys ( val ) . length ) ;
1550+ for ( var i = 0 ; i < arrayVal . length ; ++ i ) {
1551+ if ( ! val . hasOwnProperty ( i ) ) {
1552+ throw new Error ( g . f ( 'Value is not an {{array}} or {{object}} with sequential numeric indices' ) ) ;
1553+ }
1554+
1555+ arrayVal [ i ] = val [ i ] ;
1556+ }
1557+
1558+ return arrayVal ;
1559+ }
1560+
15401561/*
15411562 * Coerce values based the property types
15421563 * @param {Object } where The where clause
@@ -1561,16 +1582,18 @@ DataAccessObject._coerce = function(where) {
15611582 // Handle logical operators
15621583 if ( p === 'and' || p === 'or' || p === 'nor' ) {
15631584 var clauses = where [ p ] ;
1564- if ( Array . isArray ( clauses ) ) {
1565- for ( var k = 0 ; k < clauses . length ; k ++ ) {
1566- self . _coerce ( clauses [ k ] ) ;
1567- }
1568- } else {
1569- err = new Error ( g . f ( 'The %s operator has invalid clauses %j' , p , clauses ) ) ;
1585+ try {
1586+ clauses = coerceArray ( clauses ) ;
1587+ } catch ( e ) {
1588+ err = new Error ( g . f ( 'The %s operator has invalid clauses %j: %s' , p , clauses , e . message ) ) ;
15701589 err . statusCode = 400 ;
15711590 throw err ;
15721591 }
15731592
1593+ for ( var k = 0 ; k < clauses . length ; k ++ ) {
1594+ self . _coerce ( clauses [ k ] ) ;
1595+ }
1596+
15741597 continue ;
15751598 }
15761599 var DataType = props [ p ] && props [ p ] . type ;
@@ -1625,15 +1648,21 @@ DataAccessObject._coerce = function(where) {
16251648 switch ( operator ) {
16261649 case 'inq' :
16271650 case 'nin' :
1628- if ( ! Array . isArray ( val ) ) {
1629- err = new Error ( g . f ( 'The %s property has invalid clause %j' , p , where [ p ] ) ) ;
1651+ case 'between' :
1652+ try {
1653+ val = coerceArray ( val ) ;
1654+ } catch ( e ) {
1655+ err = new Error ( g . f ( 'The %s property has invalid clause %j: %s' , p , where [ p ] , e ) ) ;
16301656 err . statusCode = 400 ;
16311657 throw err ;
16321658 }
1633- break ;
1634- case 'between' :
1635- if ( ! Array . isArray ( val ) || val . length !== 2 ) {
1636- err = new Error ( g . f ( 'The %s property has invalid clause %j' , p , where [ p ] ) ) ;
1659+
1660+ if ( operator === 'between' && val . length !== 2 ) {
1661+ err = new Error ( g . f (
1662+ 'The %s property has invalid clause %j: Expected precisely 2 values, received %d' ,
1663+ p ,
1664+ where [ p ] ,
1665+ val . length ) ) ;
16371666 err . statusCode = 400 ;
16381667 throw err ;
16391668 }
@@ -1643,7 +1672,10 @@ DataAccessObject._coerce = function(where) {
16431672 case 'ilike' :
16441673 case 'nilike' :
16451674 if ( ! ( typeof val === 'string' || val instanceof RegExp ) ) {
1646- err = new Error ( g . f ( 'The %s property has invalid clause %j' , p , where [ p ] ) ) ;
1675+ err = new Error ( g . f (
1676+ 'The %s property has invalid clause %j: Expected a string or RegExp' ,
1677+ p ,
1678+ where [ p ] ) ) ;
16471679 err . statusCode = 400 ;
16481680 throw err ;
16491681 }
@@ -1660,6 +1692,14 @@ DataAccessObject._coerce = function(where) {
16601692 }
16611693 }
16621694 }
1695+
1696+ try {
1697+ // Coerce val into an array if it resembles an array-like object
1698+ val = coerceArray ( val ) ;
1699+ } catch ( e ) {
1700+ // NOOP when not coercable into an array.
1701+ }
1702+
16631703 // Coerce the array items
16641704 if ( Array . isArray ( val ) ) {
16651705 for ( var i = 0 ; i < val . length ; i ++ ) {
0 commit comments