1
+ import { DomainError } from "tstl/exception/DomainError" ;
1
2
import * as orm from "typeorm" ;
2
3
3
4
import { Belongs } from "../decorators/Belongs" ;
@@ -50,6 +51,14 @@ export class JoinQueryBuilder<Mine extends object> {
50
51
private readonly mine_ : Creator < Mine > ;
51
52
private readonly alias_ : string ;
52
53
54
+ private readonly joined_ : Map <
55
+ SpecialFields < Mine , Relationship . Joinable < any > > ,
56
+ IJoined
57
+ > ;
58
+
59
+ /* -----------------------------------------------------------
60
+ CONNSTRUCTOR
61
+ ----------------------------------------------------------- */
53
62
/**
54
63
* Default Constructor.
55
64
*
@@ -65,6 +74,58 @@ export class JoinQueryBuilder<Mine extends object> {
65
74
this . stmt_ = stmt ;
66
75
this . mine_ = mine ;
67
76
this . alias_ = alias === undefined ? mine . name : alias ;
77
+ this . joined_ = new Map ( ) ;
78
+ }
79
+
80
+ private _Take_join <
81
+ Field extends SpecialFields < Mine , Relationship . Joinable < any > > ,
82
+ > (
83
+ method : IJoined . Method ,
84
+ field : SpecialFields < Mine , Relationship . Joinable < any > > ,
85
+ alias : string | undefined ,
86
+ closure :
87
+ | ( (
88
+ builder : JoinQueryBuilder <
89
+ Relationship . Joinable . TargetType < Mine , Field >
90
+ > ,
91
+ ) => void )
92
+ | undefined ,
93
+ joiner : ( asset : IAsset < Mine , Field > ) => void ,
94
+ ) : JoinQueryBuilder < Relationship . Joinable . TargetType < Mine , Field > > {
95
+ // PREPARE ASSET
96
+ const asset : IAsset < Mine , Field > = prepare_asset (
97
+ this . mine_ ,
98
+ field ,
99
+ alias ,
100
+ ) ;
101
+
102
+ // CHECK OLDBIE
103
+ const oldbie : IJoined | undefined = this . joined_ . get ( field ) ;
104
+ if ( oldbie !== undefined ) {
105
+ if ( method !== oldbie . method )
106
+ throw new DomainError (
107
+ `Error on safe.JoinQueryBuilder.${ method } (): ${ this . mine_ . name } .${ field } already has been joined by ${ oldbie . method } ().` ,
108
+ ) ;
109
+ else if ( asset . alias !== oldbie . alias )
110
+ throw new DomainError (
111
+ `Error on safe.JoinQueryBuilder.${ method } (): ${ this . mine_ . name } .${ field } already has been joined with another alias "${ oldbie . alias } ".` ,
112
+ ) ;
113
+ return oldbie . builder ;
114
+ }
115
+
116
+ // DO JOIN
117
+ joiner ( asset ) ;
118
+
119
+ // BUILDER
120
+ const builder = new JoinQueryBuilder (
121
+ this . stmt_ ,
122
+ asset . metadata . target ( ) ,
123
+ asset . alias ,
124
+ ) ;
125
+ this . joined_ . set ( field , { method, alias : asset . alias , builder } ) ;
126
+
127
+ if ( closure ) closure ( builder ) ;
128
+ return builder ;
68
129
}
69
130
70
131
/* -----------------------------------------------------------
@@ -146,8 +207,7 @@ export class JoinQueryBuilder<Mine extends object> {
146
207
) => void ,
147
208
) : JoinQueryBuilder < Relationship . Joinable . TargetType < Mine , Field > > {
148
209
return this . _Join_atomic (
149
- ( target , alias , condition ) =>
150
- this . stmt_ . innerJoin ( target , alias , condition ) ,
210
+ "innerJoin" ,
151
211
field ,
152
212
...get_parametric_tuple ( alias , closure ) ,
153
213
) ;
@@ -229,8 +289,7 @@ export class JoinQueryBuilder<Mine extends object> {
229
289
) => void ,
230
290
) : JoinQueryBuilder < Relationship . Joinable . TargetType < Mine , Field > > {
231
291
return this . _Join_atomic (
232
- ( target , alias , condition ) =>
233
- this . stmt_ . leftJoin ( target , alias , condition ) ,
292
+ "leftJoin" ,
234
293
field ,
235
294
...get_parametric_tuple ( alias , closure ) ,
236
295
) ;
@@ -239,11 +298,7 @@ export class JoinQueryBuilder<Mine extends object> {
239
298
private _Join_atomic <
240
299
Field extends SpecialFields < Mine , Relationship . Joinable < any > > ,
241
300
> (
242
- joiner : (
243
- target : Creator < Relationship . Joinable . TargetType < Mine , Field > > ,
244
- alias : string ,
245
- condition : string ,
246
- ) => orm . SelectQueryBuilder < any > ,
301
+ method : "innerJoin" | "leftJoin" ,
247
302
field : Field ,
248
303
alias : string | undefined ,
249
304
closure :
@@ -254,44 +309,31 @@ export class JoinQueryBuilder<Mine extends object> {
254
309
) => void )
255
310
| undefined ,
256
311
) : JoinQueryBuilder < Relationship . Joinable . TargetType < Mine , Field > > {
257
- // PREPRAE ASSET
258
- const asset : IAsset < Mine , Field > = prepare_asset (
259
- this . mine_ ,
260
- field ,
261
- alias ,
262
- ) ;
312
+ return this . _Take_join ( method , field , alias , closure , ( asset ) => {
313
+ // LIST UP EACH FIELDS
314
+ const [ myField , targetField ] = ( ( ) => {
315
+ if ( asset . belongs === true )
316
+ return [
317
+ asset . metadata . foreign_key_field ,
318
+ get_primary_column ( asset . metadata . target ( ) ) ,
319
+ ] ;
320
+
321
+ const inverseMetadata : Belongs . ManyToOne . IMetadata < Mine > =
322
+ ReflectAdaptor . get (
323
+ asset . metadata . target ( ) . prototype ,
324
+ asset . metadata . inverse ,
325
+ ) as Belongs . ManyToOne . IMetadata < Mine > ;
263
326
264
- // LIST UP EACH FIELDS
265
- const [ myField , targetField ] = ( ( ) => {
266
- if ( asset . belongs === true )
267
327
return [
268
- asset . metadata . foreign_key_field ,
269
- get_primary_column ( asset . metadata . target ( ) ) ,
328
+ get_primary_column ( this . mine_ ) ,
329
+ inverseMetadata . foreign_key_field ,
270
330
] ;
331
+ } ) ( ) ;
271
332
272
- const inverseMetadata : Belongs . ManyToOne . IMetadata < Mine > =
273
- ReflectAdaptor . get (
274
- asset . metadata . target ( ) . prototype ,
275
- asset . metadata . inverse ,
276
- ) as Belongs . ManyToOne . IMetadata < Mine > ;
277
-
278
- return [
279
- inverseMetadata . foreign_key_field ,
280
- get_primary_column ( this . mine_ ) ,
281
- ] ;
282
- } ) ( ) ;
283
-
284
- // DO JOIN
285
- const condition : string = `${ this . alias_ } .${ myField } = ${ asset . alias } .${ targetField } ` ;
286
- joiner ( asset . metadata . target ( ) , asset . alias , condition ) ;
287
-
288
- // CALL-BACK
289
- return call_back (
290
- this . stmt_ ,
291
- asset . metadata . target ( ) ,
292
- asset . alias ,
293
- closure ,
294
- ) ;
333
+ // DO JOIN
334
+ const condition : string = `${ this . alias_ } .${ myField } = ${ asset . alias } .${ targetField } ` ;
335
+ this . stmt_ [ method ] ( asset . metadata . target ( ) , asset . alias , condition ) ;
336
+ } ) ;
295
337
}
296
338
297
339
/* -----------------------------------------------------------
@@ -383,7 +425,7 @@ export class JoinQueryBuilder<Mine extends object> {
383
425
) => void ,
384
426
) : JoinQueryBuilder < Relationship . Joinable . TargetType < Mine , Field > > {
385
427
return this . _Join_and_select (
386
- ( field , alias ) => this . stmt_ . innerJoinAndSelect ( field , alias ) ,
428
+ " innerJoinAndSelect" ,
387
429
field ,
388
430
...get_parametric_tuple ( alias , closure ) ,
389
431
) ;
@@ -475,7 +517,7 @@ export class JoinQueryBuilder<Mine extends object> {
475
517
) => void ,
476
518
) : JoinQueryBuilder < Relationship . Joinable . TargetType < Mine , Field > > {
477
519
return this . _Join_and_select (
478
- ( field , alias ) => this . stmt_ . leftJoinAndSelect ( field , alias ) ,
520
+ " leftJoinAndSelect" ,
479
521
field ,
480
522
...get_parametric_tuple ( alias , closure ) ,
481
523
) ;
@@ -484,7 +526,7 @@ export class JoinQueryBuilder<Mine extends object> {
484
526
private _Join_and_select <
485
527
Field extends SpecialFields < Mine , Relationship . Joinable < any > > ,
486
528
> (
487
- joiner : ( field : string , alias : string ) => orm . SelectQueryBuilder < any > ,
529
+ method : "innerJoinAndSelect" | "leftJoinAndSelect" ,
488
530
field : Field ,
489
531
alias : string | undefined ,
490
532
closure :
@@ -495,33 +537,16 @@ export class JoinQueryBuilder<Mine extends object> {
495
537
) => void )
496
538
| undefined ,
497
539
) {
498
- // PREPARE ASSET
499
- const asset : IAsset < Mine , Field > = prepare_asset (
500
- this . mine_ ,
501
- field ,
502
- alias ,
503
- ) ;
504
- const index : string = RelationshipVariable . getter (
505
- asset . belongs ? "belongs" : "has" ,
506
- field ,
507
- ) ;
508
-
509
- // DO JOIN
510
- joiner ( `${ this . alias_ } .${ index } ` , asset . alias ) ;
511
-
512
- // CALL-BACK
513
- return call_back (
514
- this . stmt_ ,
515
- asset . metadata . target ( ) ,
516
- asset . alias ,
517
- closure ,
518
- ) ;
540
+ return this . _Take_join ( method , field , alias , closure , ( asset ) => {
541
+ const index : string = RelationshipVariable . getter (
542
+ asset . belongs ? "belongs" : "has" ,
543
+ field ,
544
+ ) ;
545
+ this . stmt_ [ method ] ( `${ this . alias_ } .${ index } ` , asset . alias ) ;
546
+ } ) ;
519
547
}
520
548
}
521
549
522
- /* -----------------------------------------------------------
523
- BACKGROUND
524
- ----------------------------------------------------------- */
525
550
type IAsset <
526
551
Mine extends object ,
527
552
Field extends SpecialFields < Mine , Relationship . Joinable < any > > ,
@@ -567,21 +592,6 @@ function prepare_asset<
567
592
} ;
568
593
}
569
594
570
- function call_back < Target extends object > (
571
- stmt : orm . SelectQueryBuilder < any > ,
572
- target : Creator < Target > ,
573
- alias : string ,
574
- closure : ( ( builder : JoinQueryBuilder < Target > ) => void ) | undefined ,
575
- ) : JoinQueryBuilder < Target > {
576
- const ret : JoinQueryBuilder < Target > = new JoinQueryBuilder (
577
- stmt ,
578
- target ,
579
- alias ,
580
- ) ;
581
- if ( closure !== undefined ) closure ( ret ) ;
582
- return ret ;
583
- }
584
-
585
595
function get_parametric_tuple < Func extends Function > (
586
596
x ?: string | Func ,
587
597
y ?: Func ,
@@ -592,3 +602,16 @@ function get_parametric_tuple<Func extends Function>(
592
602
function get_primary_column ( creator : Creator < object > ) : string {
593
603
return ITableInfo . get ( creator ) . primaryColumn ;
594
604
}
605
+
606
+ interface IJoined {
607
+ method : IJoined . Method ;
608
+ alias : string ;
609
+ builder : JoinQueryBuilder < any > ;
610
+ }
611
+ namespace IJoined {
612
+ export type Method =
613
+ | "innerJoin"
614
+ | "leftJoin"
615
+ | "innerJoinAndSelect"
616
+ | "leftJoinAndSelect" ;
617
+ }
0 commit comments