@@ -18,6 +18,7 @@ import getInverseReferenceFields from "../../../model/getInverseReferenceFields"
18
18
import log from "../../../log" ;
19
19
import visitModel from "../../../model/visitModel" ;
20
20
import { Migration } from "../../ContentPersistence" ;
21
+ import { Model } from "../../../../typings" ;
21
22
22
23
const ops : any = {
23
24
eq : "=" ,
@@ -111,6 +112,9 @@ const getRecursiveOrderField = (
111
112
return false ;
112
113
} ;
113
114
115
+ const getModel = ( name : string , models : Model [ ] ) =>
116
+ models . find ( m => m . name . toLowerCase ( ) === name . toLowerCase ( ) ) ;
117
+
114
118
export default class KnexContent implements ContentAdapter {
115
119
knex : knex ;
116
120
@@ -436,47 +440,67 @@ export default class KnexContent implements ContentAdapter {
436
440
) {
437
441
let fullData : Cotype . Data [ ] = [ ] ;
438
442
443
+ const getLinkableModelNames = ( checkModels : string [ ] ) => {
444
+ const foundModels : string [ ] = [ ] ;
445
+ checkModels . forEach ( name => {
446
+ const foundModel = getModel ( name , models ) ;
447
+ if ( foundModel ) foundModels . push ( foundModel . name ) ;
448
+ } ) ;
449
+
450
+ return foundModels ;
451
+ } ;
452
+
439
453
const fetch = async (
440
454
ids : string [ ] ,
441
455
types : string [ ] ,
442
456
prevTypes : string [ ] ,
443
457
first : boolean
444
458
) => {
445
- // TODO Factor out function (model, types): {hasRefs, hasInverseRefs}
446
-
447
459
// Only get references when needed
448
460
// since this can be a expensive db operation
449
- let modelHasReverseReferences = false ;
450
- let modelHasReferences = false ;
451
-
461
+ let hasRefs = false ;
462
+ let hasInverseRefs = false ;
463
+ let implicitTypes : string [ ] = [ ] ;
452
464
( first ? [ model . name ] : prevTypes ) . forEach ( typeName => {
453
- const typeModel = first
454
- ? model
455
- : models . find ( m => m . name . toLowerCase ( ) === typeName . toLowerCase ( ) ) ;
456
-
465
+ const typeModel = first ? model : getModel ( typeName , models ) ;
457
466
if ( ! typeModel ) return ;
458
467
459
- visitModel ( typeModel , ( key , value ) => {
468
+ visitModel ( typeModel , ( _ , value ) => {
460
469
if ( ! ( "type" in value ) ) return ;
461
470
462
471
if ( value . type === "references" ) {
463
- modelHasReverseReferences = true ;
472
+ hasRefs = true ;
473
+
474
+ // No types means this data is only needed to populate _urls in refs
475
+ if ( types . length === 0 ) {
476
+ implicitTypes = implicitTypes . concat (
477
+ getLinkableModelNames ( [ value . model ! ] )
478
+ ) ;
479
+ }
464
480
}
465
481
if ( value . type === "content" ) {
466
- modelHasReferences = true ;
482
+ hasInverseRefs = true ;
483
+ // No types means this data is only needed to populate _urls in refs
484
+ if ( types . length === 0 ) {
485
+ implicitTypes = implicitTypes . concat (
486
+ getLinkableModelNames ( value . models || [ value . model ! ] )
487
+ ) ;
488
+ }
467
489
}
468
490
} ) ;
469
491
} ) ;
470
492
471
493
// we don't need to load anything if a model has no refs and it is a first level fetch
472
494
// otherwise we still need to load the main data of that join
473
- if ( first && ! modelHasReverseReferences && ! modelHasReferences ) return [ ] ;
495
+ if ( first && ! hasRefs && ! hasInverseRefs ) return [ ] ;
496
+
497
+ const refTypes = ! ! types . length ? types : implicitTypes ;
474
498
475
- const refs = modelHasReferences
476
- ? this . loadRefs ( ids , ! first && types , published )
499
+ const refs = hasInverseRefs
500
+ ? this . loadRefs ( ids , ! first && refTypes , published )
477
501
: [ ] ;
478
- const inverseRefs = modelHasReverseReferences
479
- ? this . loadInverseRefs ( ids , ! first && types , published )
502
+ const inverseRefs = hasRefs
503
+ ? this . loadInverseRefs ( ids , ! first && refTypes , published )
480
504
: [ ] ;
481
505
482
506
const [ data , inverseData ] = await Promise . all ( [ refs , inverseRefs ] ) ;
@@ -486,12 +510,17 @@ export default class KnexContent implements ContentAdapter {
486
510
} ;
487
511
488
512
let checkIds = id ;
489
- for ( let i = 0 ; i < joins . length ; i ++ ) {
513
+
514
+ /**
515
+ * Go one level deeper than joins suggest in order to provide
516
+ * enough data to populate all _url fields later on
517
+ */
518
+ for ( let i = 0 ; i < joins . length + 1 ; i ++ ) {
490
519
const join = joins [ i ] ;
491
520
492
521
const data = await fetch (
493
522
checkIds ,
494
- Object . keys ( join ) ,
523
+ Object . keys ( join || { } ) ,
495
524
Object . keys ( joins [ i - 1 ] || { } ) ,
496
525
i === 0
497
526
) ;
@@ -745,7 +774,7 @@ export default class KnexContent implements ContentAdapter {
745
774
if ( contents . length > 0 ) {
746
775
// TODO action delete/unpublish/schedule
747
776
const err = new ReferenceConflictError ( { type : "content" } ) ;
748
- err . refs = contents . map ( ( c :any ) => this . parseData ( c ) ) ;
777
+ err . refs = contents . map ( ( c : any ) => this . parseData ( c ) ) ;
749
778
throw err ;
750
779
}
751
780
}
@@ -888,7 +917,7 @@ export default class KnexContent implements ContentAdapter {
888
917
889
918
return {
890
919
total,
891
- items : items . map ( ( i :any ) => this . parseData ( i ) )
920
+ items : items . map ( ( i : any ) => this . parseData ( i ) )
892
921
} ;
893
922
}
894
923
@@ -910,7 +939,7 @@ export default class KnexContent implements ContentAdapter {
910
939
. where ( "content_references.media" , "=" , media )
911
940
. andWhere ( "contents.deleted" , false ) ;
912
941
913
- return contents . map ( ( c :any ) => this . parseData ( c ) ) ;
942
+ return contents . map ( ( c : any ) => this . parseData ( c ) ) ;
914
943
}
915
944
916
945
async list (
@@ -1297,7 +1326,7 @@ export default class KnexContent implements ContentAdapter {
1297
1326
state : "applied"
1298
1327
} ) ;
1299
1328
const outstanding = migrations . filter (
1300
- m => ! applied . some ( ( a :any ) => a . name === m . name )
1329
+ m => ! applied . some ( ( a : any ) => a . name === m . name )
1301
1330
) ;
1302
1331
1303
1332
if ( ! outstanding . length ) {
0 commit comments