@@ -47,10 +47,10 @@ module.exports =
4747
4848 'use strict' ;
4949
50- var _slicedToArray = ( function ( ) { function sliceIterator ( arr , i ) { var _arr = [ ] ; var _n = true ; var _d = false ; var _e = undefined ; try { for ( var _i = arr [ Symbol . iterator ] ( ) , _s ; ! ( _n = ( _s = _i . next ( ) ) . done ) ; _n = true ) { _arr . push ( _s . value ) ; if ( i && _arr . length === i ) break ; } } catch ( err ) { _d = true ; _e = err ; } finally { try { if ( ! _n && _i [ "return" ] ) _i [ "return" ] ( ) ; } finally { if ( _d ) throw _e ; } } return _arr ; } return function ( arr , i ) { if ( Array . isArray ( arr ) ) { return arr ; } else if ( Symbol . iterator in Object ( arr ) ) { return sliceIterator ( arr , i ) ; } else { throw new TypeError ( "Invalid attempt to destructure non-iterable instance" ) ; } } ; } ) ( ) ;
51-
5250 var _createClass = ( function ( ) { function defineProperties ( target , props ) { for ( var i = 0 ; i < props . length ; i ++ ) { var descriptor = props [ i ] ; descriptor . enumerable = descriptor . enumerable || false ; descriptor . configurable = true ; if ( "value" in descriptor ) descriptor . writable = true ; Object . defineProperty ( target , descriptor . key , descriptor ) ; } } return function ( Constructor , protoProps , staticProps ) { if ( protoProps ) defineProperties ( Constructor . prototype , protoProps ) ; if ( staticProps ) defineProperties ( Constructor , staticProps ) ; return Constructor ; } ; } ) ( ) ;
5351
52+ var _slicedToArray = ( function ( ) { function sliceIterator ( arr , i ) { var _arr = [ ] ; var _n = true ; var _d = false ; var _e = undefined ; try { for ( var _i = arr [ Symbol . iterator ] ( ) , _s ; ! ( _n = ( _s = _i . next ( ) ) . done ) ; _n = true ) { _arr . push ( _s . value ) ; if ( i && _arr . length === i ) break ; } } catch ( err ) { _d = true ; _e = err ; } finally { try { if ( ! _n && _i [ "return" ] ) _i [ "return" ] ( ) ; } finally { if ( _d ) throw _e ; } } return _arr ; } return function ( arr , i ) { if ( Array . isArray ( arr ) ) { return arr ; } else if ( Symbol . iterator in Object ( arr ) ) { return sliceIterator ( arr , i ) ; } else { throw new TypeError ( "Invalid attempt to destructure non-iterable instance" ) ; } } ; } ) ( ) ;
53+
5454 function _classCallCheck ( instance , Constructor ) { if ( ! ( instance instanceof Constructor ) ) { throw new TypeError ( "Cannot call a class as a function" ) ; } }
5555
5656 function _defineProperty ( obj , key , value ) { if ( key in obj ) { Object . defineProperty ( obj , key , { value : value , enumerable : true , configurable : true , writable : true } ) ; } else { obj [ key ] = value ; } return obj ; }
@@ -68,6 +68,66 @@ module.exports =
6868 return resourceConfig . table || underscore ( resourceConfig . name ) ;
6969 }
7070
71+ /**
72+ * Lookup and apply table joins to query if field contains a `.`
73+ * @param {string } field - Field defined in where filter
74+ * @param {object } query - knex query to modify
75+ * @param {object } resourceConfig - Resource of primary query/table
76+ * @param {string[] } existingJoins - Array of fully qualitifed field names for
77+ * any existing table joins for query
78+ * @returns {string } - field updated to perspective of applied joins
79+ */
80+ function applyTableJoins ( field , query , resourceConfig , existingJoins ) {
81+ if ( DSUtils . contains ( field , '.' ) ) {
82+ ( function ( ) {
83+ var parts = field . split ( '.' ) ;
84+ var localResourceConfig = resourceConfig ;
85+
86+ var relationPath = [ ] ;
87+
88+ var _loop = function _loop ( ) {
89+ var relationName = parts . shift ( ) ;
90+ var relationResourceConfig = resourceConfig . getResource ( relationName ) ;
91+ relationPath . push ( relationName ) ;
92+
93+ if ( ! existingJoins . some ( function ( t ) {
94+ return t === relationPath . join ( '.' ) ;
95+ } ) ) {
96+ var _localResourceConfig$ = localResourceConfig . relationList . filter ( function ( r ) {
97+ return r . relation === relationName ;
98+ } ) ;
99+
100+ var _localResourceConfig$2 = _slicedToArray ( _localResourceConfig$ , 1 ) ;
101+
102+ var relation = _localResourceConfig$2 [ 0 ] ;
103+
104+ if ( relation ) {
105+ var table = getTable ( localResourceConfig ) ;
106+ var localId = table + '.' + relation . localKey ;
107+
108+ var relationTable = getTable ( relationResourceConfig ) ;
109+ var foreignId = relationTable + '.' + relationResourceConfig . idAttribute ;
110+
111+ query . join ( relationTable , localId , foreignId ) ;
112+ existingJoins . push ( relationPath . join ( '.' ) ) ;
113+ } else {
114+ // hopefully a qualified local column
115+ }
116+ }
117+ localResourceConfig = relationResourceConfig ;
118+ } ;
119+
120+ while ( parts . length >= 2 ) {
121+ _loop ( ) ;
122+ }
123+
124+ field = getTable ( localResourceConfig ) + '.' + parts [ 0 ] ;
125+ } ) ( ) ;
126+ }
127+
128+ return field ;
129+ }
130+
71131 function loadWithRelations ( items , resourceConfig , options ) {
72132 var _this = this ;
73133
@@ -363,57 +423,30 @@ module.exports =
363423 }
364424
365425 DSUtils . forOwn ( criteria , function ( v , op ) {
366- if ( DSUtils . contains ( field , '.' ) ) {
367- ( function ( ) {
368- var parts = field . split ( '.' ) ;
369- var localResourceConfig = resourceConfig ;
370-
371- var relationPath = [ ] ;
372-
373- var _loop = function _loop ( ) {
374- var relationName = parts . shift ( ) ;
375- var relationResourceConfig = resourceConfig . getResource ( relationName ) ;
376- relationPath . push ( relationName ) ;
377-
378- if ( ! joinedTables . some ( function ( t ) {
379- return t === relationPath . join ( '.' ) ;
380- } ) ) {
381- var _localResourceConfig$ = localResourceConfig . relationList . filter ( function ( r ) {
382- return r . relation === relationName ;
383- } ) ;
384-
385- var _localResourceConfig$2 = _slicedToArray ( _localResourceConfig$ , 1 ) ;
386-
387- var relation = _localResourceConfig$2 [ 0 ] ;
388-
389- if ( relation ) {
390- var _table = getTable ( localResourceConfig ) ;
391- var localId = _table + '.' + relation . localKey ;
392-
393- var relationTable = getTable ( relationResourceConfig ) ;
394- var foreignId = relationTable + '.' + relationResourceConfig . idAttribute ;
395-
396- query = query . join ( relationTable , localId , foreignId ) ;
397- joinedTables . push ( relationPath . join ( '.' ) ) ;
398- } else {
399- // local column
400- }
401- }
402- localResourceConfig = relationResourceConfig ;
403- } ;
404-
405- while ( parts . length >= 2 ) {
406- _loop ( ) ;
407- }
408-
409- field = getTable ( localResourceConfig ) + '.' + parts [ 0 ] ;
410- } ) ( ) ;
426+ // Apply table joins (if needed)
427+ if ( DSUtils . contains ( field , ',' ) ) {
428+ var splitFields = field . split ( ',' ) . map ( function ( c ) {
429+ return c . trim ( ) ;
430+ } ) ;
431+ field = splitFields . map ( function ( splitField ) {
432+ return applyTableJoins ( splitField , query , resourceConfig , joinedTables ) ;
433+ } ) . join ( ',' ) ;
434+ } else {
435+ field = applyTableJoins ( field , query , resourceConfig , joinedTables ) ;
411436 }
412437
413438 if ( op === '==' || op === '===' ) {
414- query = query . where ( field , v ) ;
439+ if ( v === null ) {
440+ query = query . whereNull ( field ) ;
441+ } else {
442+ query = query . where ( field , v ) ;
443+ }
415444 } else if ( op === '!=' || op === '!==' ) {
416- query = query . where ( field , '!=' , v ) ;
445+ if ( v === null ) {
446+ query = query . whereNotNull ( field ) ;
447+ } else {
448+ query = query . where ( field , '!=' , v ) ;
449+ }
417450 } else if ( op === '>' ) {
418451 query = query . where ( field , '>' , v ) ;
419452 } else if ( op === '>=' ) {
@@ -430,12 +463,58 @@ module.exports =
430463 query = query . where ( field , 'in' , v ) ;
431464 } else if ( op === 'notIn' ) {
432465 query = query . whereNotIn ( field , v ) ;
466+ } else if ( op === 'near' ) {
467+ var milesRegex = / ( \d + ( \. \d + ) ? ) \s * ( m | M ) i l e s $ / ;
468+ var kilometersRegex = / ( \d + ( \. \d + ) ? ) \s * ( k | K ) $ / ;
469+
470+ var radius = undefined ;
471+ var unitsPerDegree = undefined ;
472+ if ( typeof v . radius === 'number' || milesRegex . test ( v . radius ) ) {
473+ radius = typeof v . radius === 'number' ? v . radius : v . radius . match ( milesRegex ) [ 1 ] ;
474+ unitsPerDegree = 69.0 ; // miles per degree
475+ } else if ( kilometersRegex . test ( v . radius ) ) {
476+ radius = v . radius . match ( kilometersRegex ) [ 1 ] ;
477+ unitsPerDegree = 111.045 ; // kilometers per degree;
478+ } else {
479+ throw new Error ( 'Unknown radius distance units' ) ;
480+ }
481+
482+ var _field$split$map = field . split ( ',' ) . map ( function ( c ) {
483+ return c . trim ( ) ;
484+ } ) ;
485+
486+ var _field$split$map2 = _slicedToArray ( _field$split$map , 2 ) ;
487+
488+ var latitudeColumn = _field$split$map2 [ 0 ] ;
489+ var longitudeColumn = _field$split$map2 [ 1 ] ;
490+
491+ var _v$center = _slicedToArray ( v . center , 2 ) ;
492+
493+ var latitude = _v$center [ 0 ] ;
494+ var longitude = _v$center [ 1 ] ;
495+
496+ // Uses indexes on `latitudeColumn` / `longitudeColumn` if available
497+
498+ query = query . whereBetween ( latitudeColumn , [ latitude - radius / unitsPerDegree , latitude + radius / unitsPerDegree ] ) . whereBetween ( longitudeColumn , [ longitude - radius / ( unitsPerDegree * Math . cos ( latitude * ( Math . PI / 180 ) ) ) , longitude + radius / ( unitsPerDegree * Math . cos ( latitude * ( Math . PI / 180 ) ) ) ] ) ;
499+
500+ if ( v . calculateDistance ) {
501+ var distanceColumn = typeof v . calculateDistance === 'string' ? v . calculateDistance : 'distance' ;
502+ query = query . select ( knex . raw ( '\n ' + unitsPerDegree + ' * DEGREES(ACOS(\n COS(RADIANS(?)) * COS(RADIANS(' + latitudeColumn + ')) *\n COS(RADIANS(' + longitudeColumn + ') - RADIANS(?)) +\n SIN(RADIANS(?)) * SIN(RADIANS(' + latitudeColumn + '))\n )) AS ' + distanceColumn , [ latitude , longitude , latitude ] ) ) ;
503+ }
433504 } else if ( op === 'like' ) {
434505 query = query . where ( field , 'like' , v ) ;
435506 } else if ( op === '|==' || op === '|===' ) {
436- query = query . orWhere ( field , v ) ;
507+ if ( v === null ) {
508+ query = query . orWhereNull ( field ) ;
509+ } else {
510+ query = query . orWhere ( field , v ) ;
511+ }
437512 } else if ( op === '|!=' || op === '|!==' ) {
438- query = query . orWhere ( field , '!=' , v ) ;
513+ if ( v === null ) {
514+ query = query . orWhereNotNull ( field ) ;
515+ } else {
516+ query = query . orWhere ( field , '!=' , v ) ;
517+ }
439518 } else if ( op === '|>' ) {
440519 query = query . orWhere ( field , '>' , v ) ;
441520 } else if ( op === '|>=' ) {
0 commit comments