@@ -18,50 +18,6 @@ function getTable (resourceConfig) {
18
18
return resourceConfig . table || underscore ( resourceConfig . name )
19
19
}
20
20
21
- /**
22
- * Lookup and apply table joins to query if field contains a `.`
23
- * @param {string } field - Field defined in where filter
24
- * @param {object } query - knex query to modify
25
- * @param {object } resourceConfig - Resource of primary query/table
26
- * @param {string[] } existingJoins - Array of fully qualitifed field names for
27
- * any existing table joins for query
28
- * @returns {string } - field updated to perspective of applied joins
29
- */
30
- function applyTableJoins ( field , query , resourceConfig , existingJoins ) {
31
- if ( DSUtils . contains ( field , '.' ) ) {
32
- let parts = field . split ( '.' )
33
- let localResourceConfig = resourceConfig
34
-
35
- let relationPath = [ ]
36
- while ( parts . length >= 2 ) {
37
- let relationName = parts . shift ( )
38
- let relationResourceConfig = resourceConfig . getResource ( relationName )
39
- relationPath . push ( relationName )
40
-
41
- if ( ! existingJoins . some ( t => t === relationPath . join ( '.' ) ) ) {
42
- let [ relation ] = localResourceConfig . relationList . filter ( r => r . relation === relationName )
43
- if ( relation ) {
44
- let table = getTable ( localResourceConfig )
45
- let localId = `${ table } .${ relation . localKey } `
46
-
47
- let relationTable = getTable ( relationResourceConfig )
48
- let foreignId = `${ relationTable } .${ relationResourceConfig . idAttribute } `
49
-
50
- query . join ( relationTable , localId , foreignId )
51
- existingJoins . push ( relationPath . join ( '.' ) )
52
- } else {
53
- // hopefully a qualified local column
54
- }
55
- }
56
- localResourceConfig = relationResourceConfig
57
- }
58
-
59
- field = `${ getTable ( localResourceConfig ) } .${ parts [ 0 ] } `
60
- }
61
-
62
- return field
63
- }
64
-
65
21
function loadWithRelations ( items , resourceConfig , options ) {
66
22
let tasks = [ ]
67
23
let instance = Array . isArray ( items ) ? null : items
@@ -291,6 +247,7 @@ class DSSqlAdapter {
291
247
292
248
filterQuery ( resourceConfig , params , options ) {
293
249
let table = getTable ( resourceConfig )
250
+ let joinedTables = [ ]
294
251
let query
295
252
296
253
if ( params instanceof Object . getPrototypeOf ( this . query . client ) . QueryBuilder ) {
@@ -308,8 +265,6 @@ class DSSqlAdapter {
308
265
params . orderBy = params . orderBy || params . sort
309
266
params . skip = params . skip || params . offset
310
267
311
- let joinedTables = [ ]
312
-
313
268
DSUtils . forEach ( DSUtils . keys ( params ) , k => {
314
269
let v = params [ k ]
315
270
if ( ! DSUtils . contains ( reserved , k ) ) {
@@ -331,16 +286,68 @@ class DSSqlAdapter {
331
286
'==' : criteria
332
287
}
333
288
}
334
-
335
- DSUtils . forOwn ( criteria , ( v , op ) => {
336
- // Apply table joins (if needed)
289
+
290
+ let processRelationField = ( field ) => {
291
+ let parts = field . split ( '.' )
292
+ let localResourceConfig = resourceConfig
293
+ let relationPath = [ ]
294
+
295
+ while ( parts . length >= 2 ) {
296
+ let relationName = parts . shift ( )
297
+ let relationResourceConfig = resourceConfig . getResource ( relationName )
298
+ relationPath . push ( relationName )
299
+
300
+ if ( localResourceConfig . relationList ) {
301
+ let [ relation ] = localResourceConfig . relationList . filter ( r => r . relation === relationName )
302
+ if ( relation ) {
303
+ if ( relation . type === 'belongsTo' || relation . type === 'hasOne' ) {
304
+ // Apply table join for belongsTo/hasOne property (if not done already)
305
+ if ( ! joinedTables . some ( t => t === relationPath . join ( '.' ) ) ) {
306
+ let table = getTable ( localResourceConfig )
307
+ let localId = `${ table } .${ relation . localKey } `
308
+
309
+ let relationTable = getTable ( relationResourceConfig )
310
+ let foreignId = `${ relationTable } .${ relationResourceConfig . idAttribute } `
311
+
312
+ query . join ( relationTable , localId , foreignId )
313
+ joinedTables . push ( relationPath . join ( '.' ) )
314
+ }
315
+ } else if ( relation . type === 'hasMany' ) {
316
+ // Perform `WHERE EXISTS` subquery for hasMany property
317
+ let table = getTable ( localResourceConfig )
318
+ let localId = `${ table } .${ localResourceConfig . idAttribute } `
319
+
320
+ let relationTable = getTable ( relationResourceConfig )
321
+ let foreignId = `${ relationTable } .${ relation . foreignKey } `
322
+
323
+ let existsParams = {
324
+ [ foreignId ] : { '===' : knex . raw ( localId ) } ,
325
+ [ parts [ 0 ] ] : criteria
326
+ } ;
327
+ query . whereExists ( this . filterQuery ( relationResourceConfig , existsParams , options ) ) ;
328
+ criteria = null ; // criteria handled by EXISTS subquery
329
+ }
330
+ } else {
331
+ // hopefully a qualified local column
332
+ }
333
+
334
+ localResourceConfig = relationResourceConfig
335
+ }
336
+ }
337
+
338
+ return `${ getTable ( localResourceConfig ) } .${ parts [ 0 ] } `
339
+ }
340
+
341
+ if ( DSUtils . contains ( field , '.' ) ) {
337
342
if ( DSUtils . contains ( field , ',' ) ) {
338
343
let splitFields = field . split ( ',' ) . map ( c => c . trim ( ) )
339
- field = splitFields . map ( splitField => applyTableJoins ( splitField , query , resourceConfig , joinedTables ) ) . join ( ',' )
344
+ field = splitFields . map ( splitField => processRelationField ( splitField ) ) . join ( ',' )
340
345
} else {
341
- field = applyTableJoins ( field , query , resourceConfig , joinedTables )
346
+ field = processRelationField ( field , query , resourceConfig , joinedTables )
342
347
}
343
-
348
+ }
349
+
350
+ DSUtils . forOwn ( criteria , ( v , op ) => {
344
351
if ( op === '==' || op === '===' ) {
345
352
if ( v === null ) {
346
353
query = query . whereNull ( field )
0 commit comments