1- let knex = require ( 'knex' )
2- let JSData = require ( 'js-data' )
3- let underscore = require ( 'mout/string/underscore' )
4- let unique = require ( 'mout/array/unique' )
5- let toString = require ( 'mout/lang/toString' )
6- let { DSUtils } = JSData
1+ import knex from 'knex' ;
2+ import Promise from 'bluebird' ;
3+ import { contains , unique } from 'mout/array'
4+ import { isEmpty , isObject , isString , toString } from 'mout/lang' ;
5+ import { deepMixIn , forOwn , get , omit } from 'mout/object'
6+ import { underscore } from 'mout/string' ;
7+ import { DSUtils } from 'js-data' ;
8+ const { removeCircular } = DSUtils ;
79
810let reserved = [
911 'orderBy' ,
@@ -22,134 +24,132 @@ function loadWithRelations (items, resourceConfig, options) {
2224 let tasks = [ ]
2325 let instance = Array . isArray ( items ) ? null : items
2426
25- DSUtils . forEach ( resourceConfig . relationList , def => {
26- let relationName = def . relation
27- let relationDef = resourceConfig . getResource ( relationName )
27+ if ( resourceConfig . relationList ) {
28+ resourceConfig . relationList . forEach ( def => {
29+ let relationName = def . relation
30+ let relationDef = resourceConfig . getResource ( relationName )
2831
29- let containedName = null
30- if ( DSUtils . contains ( options . with , relationName ) ) {
31- containedName = relationName
32- } else if ( DSUtils . contains ( options . with , def . localField ) ) {
33- containedName = def . localField
34- } else {
35- return
36- }
32+ let containedName = null
33+ if ( contains ( options . with , relationName ) ) {
34+ containedName = relationName
35+ } else if ( contains ( options . with , def . localField ) ) {
36+ containedName = def . localField
37+ } else {
38+ return
39+ }
3740
38- let __options = DSUtils . deepMixIn ( { } , options . orig ? options . orig ( ) : options )
41+ let __options = deepMixIn ( { } , options . orig ? options . orig ( ) : options )
3942
40- // Filter to only properties under current relation
41- __options . with = options . with . filter ( relation => {
42- return relation !== containedName &&
43- relation . indexOf ( containedName ) === 0 &&
44- relation . length >= containedName . length &&
45- relation [ containedName . length ] === '.'
46- } ) . map ( relation => relation . substr ( containedName . length + 1 ) )
43+ // Filter to only properties under current relation
44+ __options . with = options . with . filter ( relation => {
45+ return relation !== containedName &&
46+ relation . indexOf ( containedName ) === 0 &&
47+ relation . length >= containedName . length &&
48+ relation [ containedName . length ] === '.'
49+ } ) . map ( relation => relation . substr ( containedName . length + 1 ) )
4750
48- let task
51+ let task
4952
50- if ( ( def . type === 'hasOne' || def . type === 'hasMany' ) && def . foreignKey ) {
51- let foreignKeyFilter
52- if ( instance ) {
53- foreignKeyFilter = { '==' : instance [ resourceConfig . idAttribute ] }
54- } else {
55- foreignKeyFilter = { 'in' : items . map ( item => item [ resourceConfig . idAttribute ] ) }
56- }
57- task = this . findAll ( resourceConfig . getResource ( relationName ) , {
58- where : {
59- [ def . foreignKey ] : foreignKeyFilter
60- }
61- } , __options ) . then ( relatedItems => {
62- if ( instance ) {
63- if ( def . type === 'hasOne' && relatedItems . length ) {
64- instance [ def . localField ] = relatedItems [ 0 ]
65- } else {
66- instance [ def . localField ] = relatedItems
53+ if ( ( def . type === 'hasOne' || def . type === 'hasMany' ) && def . foreignKey ) {
54+ task = this . findAll ( resourceConfig . getResource ( relationName ) , {
55+ where : {
56+ [ def . foreignKey ] : instance ?
57+ { '==' : instance [ resourceConfig . idAttribute ] } :
58+ { 'in' : items . map ( item => item [ resourceConfig . idAttribute ] ) }
6759 }
68- } else {
69- DSUtils . forEach ( items , item => {
70- let attached = relatedItems . filter ( ri => ri [ def . foreignKey ] === item [ resourceConfig . idAttribute ] )
71- if ( def . type === 'hasOne' && attached . length ) {
72- item [ def . localField ] = attached [ 0 ]
60+ } , __options ) . then ( relatedItems => {
61+ if ( instance ) {
62+ if ( def . type === 'hasOne' && relatedItems . length ) {
63+ instance [ def . localField ] = relatedItems [ 0 ]
7364 } else {
74- item [ def . localField ] = attached
65+ instance [ def . localField ] = relatedItems
7566 }
76- } )
77- }
67+ } else {
68+ items . forEach ( item => {
69+ let attached = relatedItems . filter ( ri => ri [ def . foreignKey ] === item [ resourceConfig . idAttribute ] )
70+ if ( def . type === 'hasOne' && attached . length ) {
71+ item [ def . localField ] = attached [ 0 ]
72+ } else {
73+ item [ def . localField ] = attached
74+ }
75+ } )
76+ }
7877
79- return relatedItems
80- } )
81- } else if ( def . type === 'hasMany' && def . localKeys ) {
82- // TODO: Write test for with: hasMany property with localKeys
83- let localKeys = [ ]
84-
85- if ( instance ) {
86- let itemKeys = instance [ def . localKeys ] || [ ]
87- itemKeys = Array . isArray ( itemKeys ) ? itemKeys : Object . keys ( itemKeys )
88- localKeys = localKeys . concat ( itemKeys || [ ] )
89- } else {
90- DSUtils . forEach ( items , item => {
91- let itemKeys = item [ def . localKeys ] || [ ]
92- itemKeys = Array . isArray ( itemKeys ) ? itemKeys : Object . keys ( itemKeys )
93- localKeys = localKeys . concat ( itemKeys || [ ] )
78+ return relatedItems
9479 } )
95- }
80+ } else if ( def . type === 'hasMany' && def . localKeys ) {
81+ // TODO: Write test for with: hasMany property with localKeys
82+ let localKeys = [ ]
9683
97- task = this . findAll ( resourceConfig . getResource ( relationName ) , {
98- where : {
99- [ relationDef . idAttribute ] : {
100- 'in' : DSUtils . filter ( unique ( localKeys ) , x => x )
101- }
102- }
103- } , __options ) . then ( relatedItems => {
10484 if ( instance ) {
105- instance [ def . localField ] = relatedItems
85+ let itemKeys = instance [ def . localKeys ] || [ ]
86+ itemKeys = Array . isArray ( itemKeys ) ? itemKeys : Object . keys ( itemKeys )
87+ localKeys = localKeys . concat ( itemKeys || [ ] )
10688 } else {
107- DSUtils . forEach ( items , item => {
89+ items . forEach ( item => {
10890 let itemKeys = item [ def . localKeys ] || [ ]
109- let attached = relatedItems . filter ( ri => itemKeys && DSUtils . contains ( itemKeys , ri [ relationDef . idAttribute ] ) )
110- item [ def . localField ] = attached
91+ itemKeys = Array . isArray ( itemKeys ) ? itemKeys : Object . keys ( itemKeys )
92+ localKeys = localKeys . concat ( itemKeys || [ ] )
11193 } )
11294 }
11395
114- return relatedItems
115- } )
116- } else if ( def . type === 'belongsTo' || ( def . type === 'hasOne' && def . localKey ) ) {
117- if ( instance ) {
118- let id = DSUtils . get ( instance , def . localKey )
119- if ( id ) {
120- task = this . find ( resourceConfig . getResource ( relationName ) , DSUtils . get ( instance , def . localKey ) , __options ) . then ( relatedItem => {
121- instance [ def . localField ] = relatedItem
122- return relatedItem
123- } )
124- }
125- } else {
126- let ids = DSUtils . filter ( items . map ( item => DSUtils . get ( item , def . localKey ) ) , x => x )
127- if ( ids . length ) {
128- task = this . findAll ( resourceConfig . getResource ( relationName ) , {
129- where : {
130- [ relationDef . idAttribute ] : {
131- 'in' : ids
132- }
96+ task = this . findAll ( resourceConfig . getResource ( relationName ) , {
97+ where : {
98+ [ relationDef . idAttribute ] : {
99+ 'in' : filter ( unique ( localKeys ) , x => x )
133100 }
134- } , __options ) . then ( relatedItems => {
135- DSUtils . forEach ( items , item => {
136- DSUtils . forEach ( relatedItems , relatedItem => {
137- if ( relatedItem [ relationDef . idAttribute ] === item [ def . localKey ] ) {
138- item [ def . localField ] = relatedItem
101+ }
102+ } , __options ) . then ( relatedItems => {
103+ if ( instance ) {
104+ instance [ def . localField ] = relatedItems
105+ } else {
106+ items . forEach ( item => {
107+ let itemKeys = item [ def . localKeys ] || [ ]
108+ let attached = relatedItems . filter ( ri => itemKeys && contains ( itemKeys , ri [ relationDef . idAttribute ] ) )
109+ item [ def . localField ] = attached
110+ } )
111+ }
112+
113+ return relatedItems
114+ } )
115+ } else if ( def . type === 'belongsTo' || ( def . type === 'hasOne' && def . localKey ) ) {
116+ if ( instance ) {
117+ let id = get ( instance , def . localKey )
118+ if ( id ) {
119+ task = this . find ( resourceConfig . getResource ( relationName ) , get ( instance , def . localKey ) , __options ) . then ( relatedItem => {
120+ instance [ def . localField ] = relatedItem
121+ return relatedItem
122+ } )
123+ }
124+ } else {
125+ let ids = items . map ( item => get ( item , def . localKey ) ) . filter ( x => x )
126+ if ( ids . length ) {
127+ task = this . findAll ( resourceConfig . getResource ( relationName ) , {
128+ where : {
129+ [ relationDef . idAttribute ] : {
130+ 'in' : ids
139131 }
132+ }
133+ } , __options ) . then ( relatedItems => {
134+ items . forEach ( item => {
135+ relatedItems . forEach ( relatedItem => {
136+ if ( relatedItem [ relationDef . idAttribute ] === item [ def . localKey ] ) {
137+ item [ def . localField ] = relatedItem
138+ }
139+ } )
140140 } )
141+ return relatedItems
141142 } )
142- return relatedItems
143- } )
143+ }
144144 }
145145 }
146- }
147146
148- if ( task ) {
149- tasks . push ( task )
150- }
151- } )
152- return DSUtils . Promise . all ( tasks )
147+ if ( task ) {
148+ tasks . push ( task )
149+ }
150+ } )
151+ }
152+ return Promise . all ( tasks )
153153}
154154
155155class DSSqlAdapter {
@@ -161,7 +161,7 @@ class DSSqlAdapter {
161161 } else {
162162 this . query = knex ( options )
163163 }
164- DSUtils . deepMixIn ( this . defaults , options )
164+ deepMixIn ( this . defaults , options )
165165 }
166166
167167 find ( resourceConfig , id , options ) {
@@ -195,7 +195,7 @@ class DSSqlAdapter {
195195 }
196196
197197 create ( resourceConfig , attrs , options ) {
198- attrs = DSUtils . removeCircular ( DSUtils . omit ( attrs , resourceConfig . relationFields || [ ] ) )
198+ attrs = removeCircular ( omit ( attrs , resourceConfig . relationFields || [ ] ) )
199199 let query = options && options . transaction || this . query
200200 return query ( getTable ( resourceConfig ) )
201201 . insert ( attrs , resourceConfig . idAttribute )
@@ -211,7 +211,7 @@ class DSSqlAdapter {
211211 }
212212
213213 update ( resourceConfig , id , attrs , options ) {
214- attrs = DSUtils . removeCircular ( DSUtils . omit ( attrs , resourceConfig . relationFields || [ ] ) )
214+ attrs = removeCircular ( omit ( attrs , resourceConfig . relationFields || [ ] ) )
215215 let query = options && options . transaction || this . query
216216 return query ( getTable ( resourceConfig ) )
217217 . where ( resourceConfig . idAttribute , toString ( id ) )
@@ -220,7 +220,7 @@ class DSSqlAdapter {
220220 }
221221
222222 updateAll ( resourceConfig , attrs , params , options ) {
223- attrs = DSUtils . removeCircular ( DSUtils . omit ( attrs , resourceConfig . relationFields || [ ] ) )
223+ attrs = removeCircular ( omit ( attrs , resourceConfig . relationFields || [ ] ) )
224224 return this . filterQuery ( resourceConfig , params , options ) . then ( items => {
225225 return items . map ( item => item [ resourceConfig . idAttribute ] )
226226 } ) . then ( ids => {
@@ -265,10 +265,10 @@ class DSSqlAdapter {
265265 params . orderBy = params . orderBy || params . sort
266266 params . skip = params . skip || params . offset
267267
268- DSUtils . forEach ( Object . keys ( params ) , k => {
268+ Object . keys ( params ) . forEach ( k => {
269269 let v = params [ k ]
270- if ( ! DSUtils . contains ( reserved , k ) ) {
271- if ( DSUtils . isObject ( v ) ) {
270+ if ( ! contains ( reserved , k ) ) {
271+ if ( isObject ( v ) ) {
272272 params . where [ k ] = v
273273 } else {
274274 params . where [ k ] = {
@@ -279,9 +279,9 @@ class DSSqlAdapter {
279279 }
280280 } )
281281
282- if ( ! DSUtils . isEmpty ( params . where ) ) {
283- DSUtils . forOwn ( params . where , ( criteria , field ) => {
284- if ( ! DSUtils . isObject ( criteria ) ) {
282+ if ( ! isEmpty ( params . where ) ) {
283+ forOwn ( params . where , ( criteria , field ) => {
284+ if ( ! isObject ( criteria ) ) {
285285 params . where [ field ] = {
286286 '==' : criteria
287287 }
@@ -337,16 +337,16 @@ class DSSqlAdapter {
337337 return `${ getTable ( localResourceConfig ) } .${ parts [ 0 ] } `
338338 }
339339
340- if ( DSUtils . contains ( field , '.' ) ) {
341- if ( DSUtils . contains ( field , ',' ) ) {
340+ if ( contains ( field , '.' ) ) {
341+ if ( contains ( field , ',' ) ) {
342342 let splitFields = field . split ( ',' ) . map ( c => c . trim ( ) )
343343 field = splitFields . map ( splitField => processRelationField ( splitField ) ) . join ( ',' )
344344 } else {
345345 field = processRelationField ( field , query , resourceConfig , joinedTables )
346346 }
347347 }
348348
349- DSUtils . forOwn ( criteria , ( v , op ) => {
349+ forOwn ( criteria , ( v , op ) => {
350350 if ( op === '==' || op === '===' ) {
351351 if ( v === null ) {
352352 query = query . whereNull ( field )
@@ -454,16 +454,16 @@ class DSSqlAdapter {
454454 }
455455
456456 if ( params . orderBy ) {
457- if ( DSUtils . isString ( params . orderBy ) ) {
457+ if ( isString ( params . orderBy ) ) {
458458 params . orderBy = [
459459 [ params . orderBy , 'asc' ]
460460 ]
461461 }
462462 for ( var i = 0 ; i < params . orderBy . length ; i ++ ) {
463- if ( DSUtils . isString ( params . orderBy [ i ] ) ) {
463+ if ( isString ( params . orderBy [ i ] ) ) {
464464 params . orderBy [ i ] = [ params . orderBy [ i ] , 'asc' ]
465465 }
466- query = DSUtils . upperCase ( params . orderBy [ i ] [ 1 ] ) === 'DESC' ? query . orderBy ( params . orderBy [ i ] [ 0 ] , 'desc' ) : query . orderBy ( params . orderBy [ i ] [ 0 ] , 'asc' )
466+ query = params . orderBy [ i ] [ 1 ] . toUpperCase ( ) === 'DESC' ? query . orderBy ( params . orderBy [ i ] [ 0 ] , 'desc' ) : query . orderBy ( params . orderBy [ i ] [ 0 ] , 'asc' )
467467 }
468468 }
469469
0 commit comments