@@ -98,6 +98,107 @@ it.effect("serializes form-exploded query arrays as repeated parameters", () =>
9898 ) ,
9999) ;
100100
101+ it . effect ( "serializes default form query objects using their fields" , ( ) =>
102+ Effect . promise ( ( ) =>
103+ withServer ( async ( { baseUrl, requests } ) => {
104+ const operation = OperationBinding . make ( {
105+ method : "get" ,
106+ servers : [ ] ,
107+ pathTemplate : "/domains" ,
108+ requestBody : Option . none ( ) ,
109+ responseBody : Option . none ( ) ,
110+ parameters : [
111+ OperationParameter . make ( {
112+ name : "params" ,
113+ location : "query" ,
114+ required : false ,
115+ schema : Option . some ( {
116+ type : "object" ,
117+ additionalProperties : { type : "string" } ,
118+ } ) ,
119+ // Query parameters default to form + explode=true in OAS.
120+ style : Option . none ( ) ,
121+ explode : Option . none ( ) ,
122+ allowReserved : Option . none ( ) ,
123+ description : Option . none ( ) ,
124+ } ) ,
125+ ] ,
126+ } ) ;
127+
128+ await Effect . runPromise (
129+ invokeWithLayer (
130+ operation ,
131+ { params : { region : "west" , tier : "standard" } } ,
132+ baseUrl ,
133+ { } ,
134+ { } ,
135+ FetchHttpClient . layer ,
136+ ) ,
137+ ) ;
138+
139+ const url = new URL ( requests [ 0 ] ! , "http://executor.test" ) ;
140+ expect ( url . searchParams . get ( "region" ) ) . toBe ( "west" ) ;
141+ expect ( url . searchParams . get ( "tier" ) ) . toBe ( "standard" ) ;
142+ expect ( url . searchParams . has ( "params" ) ) . toBe ( false ) ;
143+ } ) ,
144+ ) ,
145+ ) ;
146+
147+ it . effect ( "serializes non-exploded and deep-object query objects" , ( ) =>
148+ Effect . promise ( ( ) =>
149+ withServer ( async ( { baseUrl, requests } ) => {
150+ const operation = OperationBinding . make ( {
151+ method : "get" ,
152+ servers : [ ] ,
153+ pathTemplate : "/filters" ,
154+ requestBody : Option . none ( ) ,
155+ responseBody : Option . none ( ) ,
156+ parameters : [
157+ OperationParameter . make ( {
158+ name : "color" ,
159+ location : "query" ,
160+ required : false ,
161+ schema : Option . some ( { type : "object" } ) ,
162+ style : Option . some ( "form" ) ,
163+ explode : Option . some ( false ) ,
164+ allowReserved : Option . none ( ) ,
165+ description : Option . none ( ) ,
166+ } ) ,
167+ OperationParameter . make ( {
168+ name : "filter" ,
169+ location : "query" ,
170+ required : false ,
171+ schema : Option . some ( { type : "object" } ) ,
172+ style : Option . some ( "deepObject" ) ,
173+ explode : Option . some ( true ) ,
174+ allowReserved : Option . none ( ) ,
175+ description : Option . none ( ) ,
176+ } ) ,
177+ ] ,
178+ } ) ;
179+
180+ await Effect . runPromise (
181+ invokeWithLayer (
182+ operation ,
183+ {
184+ color : { R : 100 , G : 200 , B : 150 } ,
185+ filter : { status : "active" , owner : "alice" } ,
186+ } ,
187+ baseUrl ,
188+ { } ,
189+ { } ,
190+ FetchHttpClient . layer ,
191+ ) ,
192+ ) ;
193+
194+ const url = new URL ( requests [ 0 ] ! , "http://executor.test" ) ;
195+ expect ( url . searchParams . get ( "color" ) ) . toBe ( "R,100,G,200,B,150" ) ;
196+ expect ( url . searchParams . get ( "filter[status]" ) ) . toBe ( "active" ) ;
197+ expect ( url . searchParams . get ( "filter[owner]" ) ) . toBe ( "alice" ) ;
198+ } ) ,
199+ ) ,
200+ ) ;
201+
101202it . effect ( "uses operation base URL and preserves reserved path expansion when allowed" , ( ) =>
102203 Effect . promise ( ( ) =>
103204 withServer ( async ( { baseUrl, requests } ) => {
0 commit comments