@@ -177,6 +177,10 @@ class RequestHandler extends APIHandlerBase {
177177 status : 400 ,
178178 title : 'Invalid value for type' ,
179179 } ,
180+ duplicatedFieldsParameter : {
181+ status : 400 ,
182+ title : 'Fields Parameter Duplicated' ,
183+ } ,
180184 forbidden : {
181185 status : 403 ,
182186 title : 'Operation is forbidden' ,
@@ -185,6 +189,7 @@ class RequestHandler extends APIHandlerBase {
185189 status : 422 ,
186190 title : 'Operation is unprocessable due to validation errors' ,
187191 } ,
192+
188193 unknownError : {
189194 status : 400 ,
190195 title : 'Unknown error' ,
@@ -511,7 +516,7 @@ class RequestHandler extends APIHandlerBase {
511516 // handle "include" query parameter
512517 let include : string [ ] | undefined ;
513518 if ( query ?. include ) {
514- const { select, error, allIncludes } = this . buildRelationSelect ( type , query . include ) ;
519+ const { select, error, allIncludes } = this . buildRelationSelect ( type , query . include , query ) ;
515520 if ( error ) {
516521 return error ;
517522 }
@@ -521,6 +526,20 @@ class RequestHandler extends APIHandlerBase {
521526 include = allIncludes ;
522527 }
523528
529+ // handle partial results for requested type
530+ const { select, error } = this . buildPartialSelect ( type , query ) ;
531+ if ( error ) return error ;
532+ if ( select ) {
533+ args . select = { ...select , ...args . select } ;
534+ if ( args . include ) {
535+ args . select = {
536+ ...args . select ,
537+ ...args . include ,
538+ } ;
539+ args . include = undefined ;
540+ }
541+ }
542+
524543 const entity = await prisma [ type ] . findUnique ( args ) ;
525544
526545 if ( entity ) {
@@ -555,7 +574,7 @@ class RequestHandler extends APIHandlerBase {
555574 // handle "include" query parameter
556575 let include : string [ ] | undefined ;
557576 if ( query ?. include ) {
558- const { select : relationSelect , error, allIncludes } = this . buildRelationSelect ( type , query . include ) ;
577+ const { select : relationSelect , error, allIncludes } = this . buildRelationSelect ( type , query . include , query ) ;
559578 if ( error ) {
560579 return error ;
561580 }
@@ -566,7 +585,14 @@ class RequestHandler extends APIHandlerBase {
566585 select = relationSelect ;
567586 }
568587
569- select = select ?? { [ relationship ] : true } ;
588+ // handle partial results for requested type
589+ if ( ! select ) {
590+ const { select : partialFields , error } = this . buildPartialSelect ( lowerCaseFirst ( relationInfo . type ) , query ) ;
591+ if ( error ) return error ;
592+
593+ select = partialFields ? { [ relationship ] : { select : { ...partialFields } } } : { [ relationship ] : true } ;
594+ }
595+
570596 const args : any = {
571597 where : this . makePrismaIdFilter ( typeInfo . idFields , resourceId ) ,
572598 select,
@@ -710,7 +736,7 @@ class RequestHandler extends APIHandlerBase {
710736 // handle "include" query parameter
711737 let include : string [ ] | undefined ;
712738 if ( query ?. include ) {
713- const { select, error, allIncludes } = this . buildRelationSelect ( type , query . include ) ;
739+ const { select, error, allIncludes } = this . buildRelationSelect ( type , query . include , query ) ;
714740 if ( error ) {
715741 return error ;
716742 }
@@ -720,6 +746,20 @@ class RequestHandler extends APIHandlerBase {
720746 include = allIncludes ;
721747 }
722748
749+ // handle partial results for requested type
750+ const { select, error } = this . buildPartialSelect ( type , query ) ;
751+ if ( error ) return error ;
752+ if ( select ) {
753+ args . select = { ...select , ...args . select } ;
754+ if ( args . include ) {
755+ args . select = {
756+ ...args . select ,
757+ ...args . include ,
758+ } ;
759+ args . include = undefined ;
760+ }
761+ }
762+
723763 const { offset, limit } = this . getPagination ( query ) ;
724764 if ( offset > 0 ) {
725765 args . skip = offset ;
@@ -738,6 +778,7 @@ class RequestHandler extends APIHandlerBase {
738778 } ;
739779 } else {
740780 args . take = limit ;
781+
741782 const [ entities , count ] = await Promise . all ( [
742783 prisma [ type ] . findMany ( args ) ,
743784 prisma [ type ] . count ( { where : args . where ?? { } } ) ,
@@ -762,6 +803,33 @@ class RequestHandler extends APIHandlerBase {
762803 }
763804 }
764805
806+ private buildPartialSelect ( type : string , query : Record < string , string | string [ ] > | undefined ) {
807+ const selectFieldsQuery = query ?. [ `fields[${ type } ]` ] ;
808+ if ( ! selectFieldsQuery ) {
809+ return { select : undefined , error : undefined } ;
810+ }
811+
812+ if ( Array . isArray ( selectFieldsQuery ) ) {
813+ return {
814+ select : undefined ,
815+ error : this . makeError ( 'duplicatedFieldsParameter' , `duplicated fields query for type ${ type } ` ) ,
816+ } ;
817+ }
818+
819+ const typeInfo = this . typeMap [ lowerCaseFirst ( type ) ] ;
820+ if ( ! typeInfo ) {
821+ return { select : undefined , error : this . makeUnsupportedModelError ( type ) } ;
822+ }
823+
824+ const selectFieldNames = selectFieldsQuery . split ( ',' ) . filter ( ( i ) => i ) ;
825+
826+ const fields = selectFieldNames . reduce ( ( acc , curr ) => ( { ...acc , [ curr ] : true } ) , { } ) ;
827+
828+ return {
829+ select : { ...this . makeIdSelect ( typeInfo . idFields ) , ...fields } ,
830+ } ;
831+ }
832+
765833 private addTotalCountToMeta ( meta : any , total : any ) {
766834 return meta ? Object . assign ( meta , { total } ) : Object . assign ( { } , { total } ) ;
767835 }
@@ -1790,7 +1858,11 @@ class RequestHandler extends APIHandlerBase {
17901858 return { sort : result , error : undefined } ;
17911859 }
17921860
1793- private buildRelationSelect ( type : string , include : string | string [ ] ) {
1861+ private buildRelationSelect (
1862+ type : string ,
1863+ include : string | string [ ] ,
1864+ query : Record < string , string | string [ ] > | undefined
1865+ ) {
17941866 const typeInfo = this . typeMap [ lowerCaseFirst ( type ) ] ;
17951867 if ( ! typeInfo ) {
17961868 return { select : undefined , error : this . makeUnsupportedModelError ( type ) } ;
@@ -1820,11 +1892,24 @@ class RequestHandler extends APIHandlerBase {
18201892 return { select : undefined , error : this . makeUnsupportedModelError ( relationInfo . type ) } ;
18211893 }
18221894
1895+ // handle partial results for requested type
1896+ const { select, error } = this . buildPartialSelect ( lowerCaseFirst ( relationInfo . type ) , query ) ;
1897+ if ( error ) return { select : undefined , error } ;
1898+
18231899 if ( i !== parts . length - 1 ) {
1824- currPayload [ relation ] = { include : { ...currPayload [ relation ] ?. include } } ;
1825- currPayload = currPayload [ relation ] . include ;
1900+ if ( select ) {
1901+ currPayload [ relation ] = { select : { ...select } } ;
1902+ currPayload = currPayload [ relation ] . select ;
1903+ } else {
1904+ currPayload [ relation ] = { include : { ...currPayload [ relation ] ?. include } } ;
1905+ currPayload = currPayload [ relation ] . include ;
1906+ }
18261907 } else {
1827- currPayload [ relation ] = true ;
1908+ currPayload [ relation ] = select
1909+ ? {
1910+ select : { ...select } ,
1911+ }
1912+ : true ;
18281913 }
18291914 }
18301915 }
0 commit comments