@@ -714,6 +714,182 @@ describe('POST /get_resource_data', () => {
714714 } ) ;
715715 } ) ;
716716
717+ it ( 'keeps computed helper fields when columns are not requested' , async ( ) => {
718+ const res = await agent
719+ . set ( 'Cookie' , authCookie )
720+ . post ( '/adminapi/v1/get_resource_data' )
721+ . send ( {
722+ resourceId : 'cars_sl' ,
723+ source : 'list' ,
724+ limit : 1 ,
725+ offset : 0 ,
726+ sort : [ ] ,
727+ filters : [ { field : 'id' , operator : 'eq' , value : createdRecordId } ] ,
728+ } ) ;
729+
730+ expect ( res . status ) . toEqual ( 200 ) ;
731+ expect ( res . body . error ) . toBeUndefined ( ) ;
732+ expect ( res . body . data [ 0 ] . _label ) . toBe ( '🚘 Abobus amogus 🚗' ) ;
733+ } ) ;
734+
735+ it ( 'returns exactly requested columns and omits computed helper fields' , async ( ) => {
736+ const res = await agent
737+ . set ( 'Cookie' , authCookie )
738+ . post ( '/adminapi/v1/get_resource_data' )
739+ . send ( {
740+ resourceId : 'cars_sl' ,
741+ source : 'list' ,
742+ limit : 1 ,
743+ offset : 0 ,
744+ sort : [ ] ,
745+ filters : [ { field : 'id' , operator : 'eq' , value : createdRecordId } ] ,
746+ columns : [ 'model' , 'price' ] ,
747+ } ) ;
748+
749+ expect ( res . status ) . toEqual ( 200 ) ;
750+ expect ( res . body . error ) . toBeUndefined ( ) ;
751+ expect ( res . body . data [ 0 ] ) . toEqual ( {
752+ model : 'Abobus amogus' ,
753+ price : 1234 ,
754+ } ) ;
755+ expect ( res . body . data [ 0 ] . _label ) . toBeUndefined ( ) ;
756+ expect ( res . body . data [ 0 ] . _clickUrl ) . toBeUndefined ( ) ;
757+ } ) ;
758+
759+ it ( 'returns an error for unknown requested columns' , async ( ) => {
760+ const res = await agent
761+ . set ( 'Cookie' , authCookie )
762+ . post ( '/adminapi/v1/get_resource_data' )
763+ . send ( {
764+ resourceId : 'cars_sl' ,
765+ source : 'list' ,
766+ limit : 1 ,
767+ offset : 0 ,
768+ sort : [ ] ,
769+ filters : [ ] ,
770+ columns : [ 'missing_column' ] ,
771+ } ) ;
772+
773+ expect ( res . status ) . toEqual ( 200 ) ;
774+ expect ( res . body . error ) . toBe ( 'Column missing_column not found in resource cars_sl' ) ;
775+ } ) ;
776+
777+ it ( 'supports selecting only a virtual column without leaking internal fallback columns' , async ( ) => {
778+ const res = await agent
779+ . set ( 'Cookie' , authCookie )
780+ . post ( '/adminapi/v1/get_resource_data' )
781+ . send ( {
782+ resourceId : 'adminuser' ,
783+ source : 'list' ,
784+ limit : 1 ,
785+ offset : 0 ,
786+ sort : [ ] ,
787+ filters : [ { field : 'email' , operator : 'eq' , value : 'adminforth' } ] ,
788+ columns : [ 'password' ] ,
789+ } ) ;
790+
791+ expect ( res . status ) . toEqual ( 200 ) ;
792+ expect ( res . body . error ) . toBeUndefined ( ) ;
793+ expect ( res . body . data [ 0 ] ) . toEqual ( { } ) ;
794+ } ) ;
795+
796+ it ( 'projects requested foreign columns after reference post-processing' , async ( ) => {
797+ const adminUserRes = await agent
798+ . set ( 'Cookie' , authCookie )
799+ . post ( '/adminapi/v1/get_resource_data' )
800+ . send ( {
801+ resourceId : 'adminuser' ,
802+ source : 'list' ,
803+ limit : 1 ,
804+ offset : 0 ,
805+ sort : [ ] ,
806+ filters : [ { field : 'email' , operator : 'eq' , value : 'adminforth' } ] ,
807+ columns : [ 'id' ] ,
808+ } ) ;
809+
810+ expect ( adminUserRes . status ) . toEqual ( 200 ) ;
811+ expect ( adminUserRes . body . error ) . toBeUndefined ( ) ;
812+ const adminUserId = adminUserRes . body . data [ 0 ] . id ;
813+
814+ const updateRes = await agent
815+ . set ( 'Cookie' , authCookie )
816+ . post ( '/adminapi/v1/update_record' )
817+ . send ( {
818+ resourceId : 'cars_sl' ,
819+ recordId : createdRecordId ,
820+ meta : { } ,
821+ record : {
822+ seller_id : adminUserId ,
823+ } ,
824+ } ) ;
825+
826+ expect ( updateRes . status ) . toEqual ( 200 ) ;
827+ expect ( updateRes . body . error ) . toBeUndefined ( ) ;
828+
829+ const res = await agent
830+ . set ( 'Cookie' , authCookie )
831+ . post ( '/adminapi/v1/get_resource_data' )
832+ . send ( {
833+ resourceId : 'cars_sl' ,
834+ source : 'list' ,
835+ limit : 1 ,
836+ offset : 0 ,
837+ sort : [ ] ,
838+ filters : [ { field : 'id' , operator : 'eq' , value : createdRecordId } ] ,
839+ columns : [ 'seller_id' ] ,
840+ } ) ;
841+
842+ expect ( res . status ) . toEqual ( 200 ) ;
843+ expect ( res . body . error ) . toBeUndefined ( ) ;
844+ expect ( res . body . data [ 0 ] ) . toEqual ( {
845+ seller_id : {
846+ label : '👤 adminforth' ,
847+ pk : adminUserId ,
848+ } ,
849+ } ) ;
850+ } ) ;
851+
852+ it ( 'projects polymorphic foreign columns without leaking polymorphic discriminator columns' , async ( ) => {
853+ const createRes = await agent
854+ . set ( 'Cookie' , authCookie )
855+ . post ( '/adminapi/v1/create_record' )
856+ . send ( {
857+ resourceId : 'polymorphic_car_refs' ,
858+ record : {
859+ record_id : createdRecordId ,
860+ image_path : 'test-image.png' ,
861+ } ,
862+ requiredColumnsToSkip : [ ] ,
863+ meta : { } ,
864+ } ) ;
865+
866+ expect ( createRes . status ) . toEqual ( 200 ) ;
867+ expect ( createRes . body . error ) . toBeUndefined ( ) ;
868+
869+ const res = await agent
870+ . set ( 'Cookie' , authCookie )
871+ . post ( '/adminapi/v1/get_resource_data' )
872+ . send ( {
873+ resourceId : 'polymorphic_car_refs' ,
874+ source : 'list' ,
875+ limit : 1 ,
876+ offset : 0 ,
877+ sort : [ ] ,
878+ filters : [ { field : 'id' , operator : 'eq' , value : createRes . body . newRecordId } ] ,
879+ columns : [ 'record_id' ] ,
880+ } ) ;
881+
882+ expect ( res . status ) . toEqual ( 200 ) ;
883+ expect ( res . body . error ) . toBeUndefined ( ) ;
884+ expect ( res . body . data [ 0 ] ) . toEqual ( {
885+ record_id : {
886+ label : '🚘 Abobus amogus 🚗' ,
887+ pk : createdRecordId ,
888+ } ,
889+ } ) ;
890+ expect ( res . body . data [ 0 ] . resource_id ) . toBeUndefined ( ) ;
891+ } ) ;
892+
717893 describe ( 'POST /get_resource' , ( ) => {
718894 beforeAll ( async ( ) => {
719895 const res = await agent
0 commit comments