@@ -5,6 +5,7 @@ import { match, P } from 'ts-pattern';
55import type { BuiltinType , DataSourceProviderType , FieldDef , GetModels , SchemaDef } from '../../../schema' ;
66import { enumerate } from '../../../utils/enumerate' ;
77import type { OrArray } from '../../../utils/type-utils' ;
8+ import { DELEGATE_JOINED_FIELD_PREFIX } from '../../constants' ;
89import type {
910 BooleanFilter ,
1011 BytesFilter ,
@@ -20,13 +21,17 @@ import {
2021 buildFieldRef ,
2122 buildJoinPairs ,
2223 flattenCompoundUniqueFilters ,
24+ getDelegateDescendantModels ,
2325 getField ,
2426 getIdFields ,
2527 getManyToManyRelation ,
2628 getRelationForeignKeyFieldPairs ,
2729 isEnum ,
30+ isInheritedField ,
31+ isRelationField ,
2832 makeDefaultOrderBy ,
2933 requireField ,
34+ requireModel ,
3035} from '../../query-utils' ;
3136
3237export abstract class BaseCrudDialect < Schema extends SchemaDef > {
@@ -35,25 +40,11 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
3540 protected readonly options : ClientOptions < Schema > ,
3641 ) { }
3742
38- abstract get provider ( ) : DataSourceProviderType ;
39-
4043 transformPrimitive ( value : unknown , _type : BuiltinType , _forArrayField : boolean ) {
4144 return value ;
4245 }
4346
44- abstract buildRelationSelection (
45- query : SelectQueryBuilder < any , any , any > ,
46- model : string ,
47- relationField : string ,
48- parentAlias : string ,
49- payload : true | FindArgs < Schema , GetModels < Schema > , true > ,
50- ) : SelectQueryBuilder < any , any , any > ;
51-
52- abstract buildSkipTake (
53- query : SelectQueryBuilder < any , any , any > ,
54- skip : number | undefined ,
55- take : number | undefined ,
56- ) : SelectQueryBuilder < any , any , any > ;
47+ // #region common query builders
5748
5849 buildFilter (
5950 eb : ExpressionBuilder < any , any > ,
@@ -788,6 +779,92 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
788779 return result ;
789780 }
790781
782+ buildSelectAllFields (
783+ model : string ,
784+ query : SelectQueryBuilder < any , any , any > ,
785+ omit ?: Record < string , boolean | undefined > ,
786+ joinedBases : string [ ] = [ ] ,
787+ ) {
788+ const modelDef = requireModel ( this . schema , model ) ;
789+ let result = query ;
790+
791+ for ( const field of Object . keys ( modelDef . fields ) ) {
792+ if ( isRelationField ( this . schema , model , field ) ) {
793+ continue ;
794+ }
795+ if ( omit ?. [ field ] === true ) {
796+ continue ;
797+ }
798+ result = this . buildSelectField ( result , model , model , field , joinedBases ) ;
799+ }
800+
801+ // select all fields from delegate descendants and pack into a JSON field `$delegate$Model`
802+ const descendants = getDelegateDescendantModels ( this . schema , model ) ;
803+ for ( const subModel of descendants ) {
804+ if ( ! joinedBases . includes ( subModel . name ) ) {
805+ joinedBases . push ( subModel . name ) ;
806+ result = this . buildDelegateJoin ( model , subModel . name , result ) ;
807+ }
808+ result = result . select ( ( eb ) => {
809+ const jsonObject : Record < string , Expression < any > > = { } ;
810+ for ( const field of Object . keys ( subModel . fields ) ) {
811+ if (
812+ isRelationField ( this . schema , subModel . name , field ) ||
813+ isInheritedField ( this . schema , subModel . name , field )
814+ ) {
815+ continue ;
816+ }
817+ jsonObject [ field ] = eb . ref ( `${ subModel . name } .${ field } ` ) ;
818+ }
819+ return this . buildJsonObject ( eb , jsonObject ) . as ( `${ DELEGATE_JOINED_FIELD_PREFIX } ${ subModel . name } ` ) ;
820+ } ) ;
821+ }
822+
823+ return result ;
824+ }
825+
826+ buildSelectField (
827+ query : SelectQueryBuilder < any , any , any > ,
828+ model : string ,
829+ modelAlias : string ,
830+ field : string ,
831+ joinedBases : string [ ] ,
832+ ) {
833+ const fieldDef = requireField ( this . schema , model , field ) ;
834+
835+ if ( fieldDef . computed ) {
836+ // TODO: computed field from delegate base?
837+ return query . select ( ( eb ) => buildFieldRef ( this . schema , model , field , this . options , eb ) . as ( field ) ) ;
838+ } else if ( ! fieldDef . originModel ) {
839+ // regular field
840+ return query . select ( sql . ref ( `${ modelAlias } .${ field } ` ) . as ( field ) ) ;
841+ } else {
842+ // field from delegate base, build a join
843+ let result = query ;
844+ if ( ! joinedBases . includes ( fieldDef . originModel ) ) {
845+ joinedBases . push ( fieldDef . originModel ) ;
846+ result = this . buildDelegateJoin ( model , fieldDef . originModel , result ) ;
847+ }
848+ result = this . buildSelectField ( result , fieldDef . originModel , fieldDef . originModel , field , joinedBases ) ;
849+ return result ;
850+ }
851+ }
852+
853+ buildDelegateJoin ( thisModel : string , otherModel : string , query : SelectQueryBuilder < any , any , any > ) {
854+ const idFields = getIdFields ( this . schema , thisModel ) ;
855+ query = query . leftJoin ( otherModel , ( qb ) => {
856+ for ( const idField of idFields ) {
857+ qb = qb . onRef ( `${ thisModel } .${ idField } ` , '=' , `${ otherModel } .${ idField } ` ) ;
858+ }
859+ return qb ;
860+ } ) ;
861+ return query ;
862+ }
863+
864+ // #endregion
865+
866+ // #region utils
867+
791868 private negateSort ( sort : SortOrder , negated : boolean ) {
792869 return negated ? ( sort === 'asc' ? 'desc' : 'asc' ) : sort ;
793870 }
@@ -842,6 +919,32 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
842919 return eb . not ( this . and ( eb , ...args ) ) ;
843920 }
844921
922+ // #endregion
923+
924+ // #region abstract methods
925+
926+ abstract get provider ( ) : DataSourceProviderType ;
927+
928+ /**
929+ * Builds selection for a relation field.
930+ */
931+ abstract buildRelationSelection (
932+ query : SelectQueryBuilder < any , any , any > ,
933+ model : string ,
934+ relationField : string ,
935+ parentAlias : string ,
936+ payload : true | FindArgs < Schema , GetModels < Schema > , true > ,
937+ ) : SelectQueryBuilder < any , any , any > ;
938+
939+ /**
940+ * Builds skip and take clauses.
941+ */
942+ abstract buildSkipTake (
943+ query : SelectQueryBuilder < any , any , any > ,
944+ skip : number | undefined ,
945+ take : number | undefined ,
946+ ) : SelectQueryBuilder < any , any , any > ;
947+
845948 /**
846949 * Builds an Kysely expression that returns a JSON object for the given key-value pairs.
847950 */
@@ -877,4 +980,6 @@ export abstract class BaseCrudDialect<Schema extends SchemaDef> {
877980 * Whether the dialect supports DISTINCT ON.
878981 */
879982 abstract get supportsDistinctOn ( ) : boolean ;
983+
984+ // #endregion
880985}
0 commit comments