@@ -500,32 +500,22 @@ export class BaseOrm<T, C, J> {
500
500
return this . applyHaving < V > ( column , operator , value )
501
501
}
502
502
503
- applyInRandomOrder ( ) : this {
504
- this . selectFromQuery = this . selectFromQuery . orderBy ( sql ` ${ sql . raw ( 'RANDOM()' ) } ` )
505
-
506
- return this
507
- }
508
-
509
- inRandomOrder ( ) : this {
510
- return this . applyInRandomOrder ( )
511
- }
512
-
513
503
applyOrderByDesc ( column : keyof C ) : this {
514
504
this . selectFromQuery = this . selectFromQuery . orderBy ( column , 'desc' )
515
505
516
506
return this
517
507
}
518
508
509
+ orderByDesc ( column : keyof C ) : this {
510
+ return this . applyOrderByDesc ( column )
511
+ }
512
+
519
513
applyOrderByAsc ( column : keyof C ) : this {
520
514
this . selectFromQuery = this . selectFromQuery . orderBy ( column , 'asc' )
521
515
522
516
return this
523
517
}
524
518
525
- orderByDesc ( column : keyof C ) : this {
526
- return this . applyOrderByDesc ( column )
527
- }
528
-
529
519
orderByAsc ( column : keyof C ) : this {
530
520
return this . applyOrderByAsc ( column )
531
521
}
@@ -552,20 +542,220 @@ export class BaseOrm<T, C, J> {
552
542
return this . applyJoin ( table , firstCol , secondCol )
553
543
}
554
544
555
- async applyUpdate < U > ( values : U ) : Promise < T | undefined > {
556
- if ( ! values || Object . keys ( values ) . length === 0 )
557
- return undefined
545
+ async applyPluck < K extends keyof T > ( field : K ) : Promise < T [ K ] [ ] > {
546
+ let models
547
+
548
+ if ( this . hasSelect ) {
549
+ models = await this . selectFromQuery . execute ( )
550
+ }
551
+ else {
552
+ models = await this . selectFromQuery . selectAll ( ) . execute ( )
553
+ }
554
+
555
+ return models . map ( ( model : T ) => model [ field ] )
556
+ }
557
+
558
+ async pluck < K extends keyof T > ( field : K ) : Promise < T [ K ] [ ] > {
559
+ return await this . applyPluck ( field )
560
+ }
561
+
562
+ applyInRandomOrder ( ) : this {
563
+ this . selectFromQuery = this . selectFromQuery . orderBy ( sql ` ${ sql . raw ( 'RANDOM()' ) } ` )
564
+
565
+ return this
566
+ }
567
+
568
+ inRandomOrder ( ) : this {
569
+ return this . applyInRandomOrder ( )
570
+ }
571
+
572
+ applyWhereExists ( callback : ( qb : any ) => any ) : this {
573
+ this . selectFromQuery = this . selectFromQuery . where ( ( { exists, selectFrom } : any ) =>
574
+ exists ( callback ( { exists, selectFrom } ) ) ,
575
+ )
576
+
577
+ return this
578
+ }
579
+
580
+ whereExists ( callback : ( qb : any ) => any ) : this {
581
+ return this . applyWhereExists ( callback )
582
+ }
583
+
584
+ applyHas ( relation : string ) : this {
585
+ this . selectFromQuery = this . selectFromQuery . where ( ( { exists, selectFrom } : any ) =>
586
+ exists (
587
+ selectFrom ( relation )
588
+ . select ( '1' )
589
+ . whereRef ( `${ relation } .${ this . tableName . slice ( 0 , - 1 ) } _id` , '=' , `${ this . tableName } .id` ) ,
590
+ ) ,
591
+ )
592
+
593
+ return this
594
+ }
595
+
596
+ has ( relation : string ) : this {
597
+ return this . applyHas ( relation )
598
+ }
599
+
600
+ applyDoesntHave ( relation : string ) : this {
601
+ this . selectFromQuery = this . selectFromQuery . where ( ( { not, exists, selectFrom } : any ) =>
602
+ not (
603
+ exists (
604
+ selectFrom ( relation )
605
+ . select ( '1' )
606
+ . whereRef ( `${ relation } .${ this . tableName . slice ( 0 , - 1 ) } _id` , '=' , `${ this . tableName } .id` ) ,
607
+ ) ,
608
+ ) ,
609
+ )
558
610
559
- await this . updateFromQuery
560
- . set ( values as any )
611
+ return this
612
+ }
613
+
614
+ doesntHave ( relation : string ) : this {
615
+ return this . applyDoesntHave ( relation )
616
+ }
617
+
618
+ applyWhereHas ( relation : string , callback : ( query : any ) => void ) : this {
619
+ this . selectFromQuery = this . selectFromQuery
620
+ . where ( ( { exists, selectFrom } : any ) => {
621
+ const subquery = selectFrom ( relation )
622
+ . select ( '1' )
623
+ . whereRef ( `${ relation } .${ this . tableName . slice ( 0 , - 1 ) } _id` , '=' , `${ this . tableName } .id` )
624
+
625
+ // Apply the callback to the subquery
626
+ callback ( subquery )
627
+
628
+ return exists ( subquery )
629
+ } )
630
+
631
+ return this
632
+ }
633
+
634
+ whereHas ( relation : string , callback : ( query : any ) => void ) : this {
635
+ return this . applyWhereHas ( relation , callback )
636
+ }
637
+
638
+ applyWhereDoesntHave ( relation : string , callback : ( query : any ) => void ) : this {
639
+ this . selectFromQuery = this . selectFromQuery
640
+ . where ( ( { exists, selectFrom, not } : any ) => {
641
+ const subquery = selectFrom ( relation )
642
+ . select ( '1' )
643
+ . whereRef ( `${ relation } .${ this . tableName . slice ( 0 , - 1 ) } _id` , '=' , `${ this . tableName } .id` )
644
+
645
+ // Apply the callback to the subquery
646
+ callback ( subquery )
647
+
648
+ return not ( exists ( subquery ) )
649
+ } )
650
+
651
+ return this
652
+ }
653
+
654
+ whereDoesntHave ( relation : string , callback : ( query : any ) => void ) : this {
655
+ return this . applyWhereDoesntHave ( relation , callback )
656
+ }
657
+
658
+ async applyPaginate ( options : { limit ?: number , offset ?: number , page ?: number } = { limit : 10 , offset : 0 , page : 1 } ) : Promise < { data : T [ ] , paging : { total_records : number , page : number , total_pages : number } , next_cursor : number | null } > {
659
+ const totalRecordsResult = await DB . instance . selectFrom ( this . tableName )
660
+ . select ( DB . instance . fn . count ( 'id' ) . as ( 'total' ) )
661
+ . executeTakeFirst ( )
662
+
663
+ const totalRecords = Number ( totalRecordsResult ?. total ) || 0
664
+ const totalPages = Math . ceil ( totalRecords / ( options . limit ?? 10 ) )
665
+
666
+ const modelsWithExtra = await DB . instance . selectFrom ( this . tableName )
667
+ . selectAll ( )
668
+ . orderBy ( 'id' , 'asc' )
669
+ . limit ( ( options . limit ?? 10 ) + 1 )
670
+ . offset ( ( ( options . page ?? 1 ) - 1 ) * ( options . limit ?? 10 ) )
671
+ . execute ( )
672
+
673
+ let nextCursor = null
674
+ if ( modelsWithExtra . length > ( options . limit ?? 10 ) )
675
+ nextCursor = modelsWithExtra . pop ( ) ?. id ?? null
676
+
677
+ this . mapCustomGetters ( modelsWithExtra )
678
+ await this . loadRelations ( modelsWithExtra )
679
+
680
+ return {
681
+ data : modelsWithExtra as T [ ] ,
682
+ paging : {
683
+ total_records : totalRecords ,
684
+ page : options . page || 1 ,
685
+ total_pages : totalPages ,
686
+ } ,
687
+ next_cursor : nextCursor ,
688
+ }
689
+ }
690
+
691
+ async paginate ( options : { limit ?: number , offset ?: number , page ?: number } = { limit : 10 , offset : 0 , page : 1 } ) : Promise < { data : T [ ] , paging : { total_records : number , page : number , total_pages : number } , next_cursor : number | null } > {
692
+ return await this . applyPaginate ( options )
693
+ }
694
+
695
+ async applyMax ( field : keyof C ) : Promise < number > {
696
+ const result = await this . selectFromQuery
697
+ . select ( sql `MAX(${ sql . raw ( field as string ) } ) as max` )
698
+ . executeTakeFirst ( )
699
+
700
+ return result . max || 0
701
+ }
702
+
703
+ async max ( field : keyof C ) : Promise < number > {
704
+ return await this . applyMax ( field )
705
+ }
706
+
707
+ async applyMin ( field : keyof C ) : Promise < number > {
708
+ const result = await this . selectFromQuery
709
+ . select ( sql `MIN(${ sql . raw ( field as string ) } ) as min` )
710
+ . executeTakeFirst ( )
711
+
712
+ return result . min || 0
713
+ }
714
+
715
+ async min ( field : keyof C ) : Promise < number > {
716
+ return await this . applyMin ( field )
717
+ }
718
+
719
+ async applyAvg ( field : keyof C ) : Promise < number > {
720
+ const result = await this . selectFromQuery
721
+ . select ( sql `AVG(${ sql . raw ( field as string ) } ) as avg` )
561
722
. executeTakeFirst ( )
562
723
563
- // If we have an ID in the current instance, try to find the updated model
564
- if ( ( this as any ) . id ) {
565
- return await this . applyFind ( ( this as any ) . id )
724
+ return result . avg || 0
725
+ }
726
+
727
+ async avg ( field : keyof C ) : Promise < number > {
728
+ return await this . applyAvg ( field )
729
+ }
730
+
731
+ async applyChunk ( size : number , callback : ( models : T [ ] ) => Promise < void > ) : Promise < void > {
732
+ let page = 1
733
+ let hasMore = true
734
+
735
+ while ( hasMore ) {
736
+ // Get one batch
737
+ const models = await this . selectFromQuery
738
+ . selectAll ( )
739
+ . limit ( size )
740
+ . offset ( ( page - 1 ) * size )
741
+ . execute ( )
742
+
743
+ // If we got fewer results than chunk size, this is the last batch
744
+ if ( models . length < size ) {
745
+ hasMore = false
746
+ }
747
+
748
+ // Process this batch
749
+ if ( models . length > 0 ) {
750
+ await callback ( models )
751
+ }
752
+
753
+ page ++
566
754
}
755
+ }
567
756
568
- return undefined
757
+ async chunk ( size : number , callback : ( models : T [ ] ) => Promise < void > ) : Promise < void > {
758
+ await this . applyChunk ( size , callback )
569
759
}
570
760
571
761
// Methods to be implemented by child classes
0 commit comments