@@ -5,11 +5,12 @@ import { trans } from "i18n";
5
5
import { includes } from "lodash" ;
6
6
import { CompAction , MultiBaseComp } from "lowcoder-core" ;
7
7
import { keyValueListControl } from "../../controls/keyValueListControl" ;
8
- import { ParamsJsonControl , ParamsStringControl } from "../../controls/paramsControl" ;
8
+ import { ParamsJsonControl , ParamsStringControl , ParamsControlType } from "../../controls/paramsControl" ;
9
9
import { withTypeAndChildrenAbstract } from "../../generators/withType" ;
10
10
import { QueryResult } from "../queryComp" ;
11
11
import { QUERY_EXECUTION_ERROR , QUERY_EXECUTION_OK } from "constants/queryConstants" ;
12
12
import { JSONValue } from "util/jsonTypes" ;
13
+ import { FunctionProperty } from "../queryCompUtils" ;
13
14
import {
14
15
HttpHeaderPropertyView ,
15
16
HttpParametersPropertyView ,
@@ -81,26 +82,43 @@ export class SseHttpQuery extends SseHttpTmpQuery {
81
82
}
82
83
83
84
override getView ( ) {
85
+ const children = this . children ;
86
+ const params = [
87
+ ...children . headers . getQueryParams ( ) ,
88
+ ...children . params . getQueryParams ( ) ,
89
+ ...children . bodyFormData . getQueryParams ( ) ,
90
+ ...children . path . getQueryParams ( ) ,
91
+ ...children . body . getQueryParams ( ) ,
92
+ ] ;
93
+
94
+ return this . createStreamingQueryView ( params ) ;
95
+ }
96
+
97
+ private createStreamingQueryView ( params : FunctionProperty [ ] ) {
84
98
return async ( props : {
99
+ queryId : string ;
100
+ applicationId : string ;
101
+ applicationPath : string [ ] ;
85
102
args ?: Record < string , unknown > ;
103
+ variables ?: any ;
104
+ timeout : InstanceType < ParamsControlType > ;
86
105
callback ?: ( result : QueryResult ) => void ;
87
106
} ) : Promise < QueryResult > => {
88
- const children = this . children ;
89
107
90
108
try {
91
109
const timer = performance . now ( ) ;
92
110
93
- // Build the complete URL with parameters
94
- const baseUrl = this . buildUrl ( props . args ) ;
95
- const headers = this . buildHeaders ( props . args ) ;
96
- const method = children . httpMethod . getView ( ) ;
111
+ // Process parameters like toQueryView does
112
+ const processedParams = this . processParameters ( params , props ) ;
113
+
114
+ // Build request from processed parameters
115
+ const { url, headers, method, body } = this . buildRequestFromParams ( processedParams ) ;
97
116
98
- // For GET requests, use EventSource API (standard SSE)
117
+ // Execute streaming logic
99
118
if ( method === "GET" ) {
100
- return this . handleEventSource ( baseUrl , headers , props , timer ) ;
119
+ return this . handleEventSource ( url , headers , props , timer ) ;
101
120
} else {
102
- // For POST/PUT/etc, use fetch with streaming response
103
- return this . handleStreamingFetch ( baseUrl , headers , method , props , timer ) ;
121
+ return this . handleStreamingFetch ( url , headers , method , body , props , timer ) ;
104
122
}
105
123
106
124
} catch ( error ) {
@@ -109,6 +127,67 @@ export class SseHttpQuery extends SseHttpTmpQuery {
109
127
} ;
110
128
}
111
129
130
+ private processParameters ( params : FunctionProperty [ ] , props : any ) {
131
+ let mappedVariables : Array < { key : string , value : string } > = [ ] ;
132
+ Object . keys ( props . variables || { } )
133
+ . filter ( k => k !== "$queryName" )
134
+ . forEach ( key => {
135
+ const value = Object . hasOwn ( props . variables [ key ] , 'value' ) ? props . variables [ key ] . value : props . variables [ key ] ;
136
+ mappedVariables . push ( {
137
+ key : `${ key } .value` ,
138
+ value : value || ""
139
+ } ) ;
140
+ } ) ;
141
+
142
+ return [
143
+ ...params . filter ( param => {
144
+ return ! mappedVariables . map ( v => v . key ) . includes ( param . key ) ;
145
+ } ) . map ( ( { key, value } ) => ( { key, value : value ( props . args ) } ) ) ,
146
+ ...Object . entries ( props . timeout . getView ( ) ) . map ( ( [ key , value ] ) => ( {
147
+ key,
148
+ value : ( value as any ) ( props . args ) ,
149
+ } ) ) ,
150
+ ...mappedVariables ,
151
+ ] ;
152
+ }
153
+
154
+ private buildRequestFromParams ( processedParams : Array < { key : string , value : any } > ) {
155
+ debugger ;
156
+ const paramMap = new Map ( processedParams . map ( p => [ p . key , p . value ] ) ) ;
157
+
158
+ // Extract URL
159
+ const baseUrl = paramMap . get ( 'path' ) || '' ;
160
+ const url = new URL ( baseUrl ) ;
161
+
162
+ // Add query parameters
163
+ Object . entries ( paramMap ) . forEach ( ( [ key , value ] ) => {
164
+ if ( key . startsWith ( 'params.' ) && key . endsWith ( '.value' ) ) {
165
+ const paramName = key . replace ( 'params.' , '' ) . replace ( '.value' , '' ) ;
166
+ if ( value ) url . searchParams . append ( paramName , String ( value ) ) ;
167
+ }
168
+ } ) ;
169
+
170
+ // Build headers
171
+ const headers : Record < string , string > = { } ;
172
+ Object . entries ( paramMap ) . forEach ( ( [ key , value ] ) => {
173
+ if ( key . startsWith ( 'headers.' ) && key . endsWith ( '.value' ) ) {
174
+ const headerName = key . replace ( 'headers.' , '' ) . replace ( '.value' , '' ) ;
175
+ if ( value ) headers [ headerName ] = String ( value ) ;
176
+ }
177
+ } ) ;
178
+
179
+ // Get method and body
180
+ const method = paramMap . get ( 'httpMethod' ) || 'GET' ;
181
+ const bodyType = paramMap . get ( 'bodyType' ) ;
182
+ let body : string | FormData | undefined ;
183
+
184
+ if ( bodyType === 'application/json' || bodyType === 'text/plain' ) {
185
+ body = paramMap . get ( 'body' ) as string ;
186
+ }
187
+
188
+ return { url : url . toString ( ) , headers, method, body } ;
189
+ }
190
+
112
191
private async handleEventSource (
113
192
url : string ,
114
193
headers : Record < string , string > ,
@@ -146,6 +225,7 @@ export class SseHttpQuery extends SseHttpTmpQuery {
146
225
url : string ,
147
226
headers : Record < string , string > ,
148
227
method : string ,
228
+ body : string | FormData | undefined ,
149
229
props : any ,
150
230
timer : number
151
231
) : Promise < QueryResult > {
@@ -161,7 +241,7 @@ export class SseHttpQuery extends SseHttpTmpQuery {
161
241
'Accept' : 'text/event-stream' ,
162
242
'Cache-Control' : 'no-cache' ,
163
243
} ,
164
- body : this . buildRequestBody ( props . args ) ,
244
+ body,
165
245
signal : this . controller . signal ,
166
246
} ) ;
167
247
@@ -236,67 +316,6 @@ export class SseHttpQuery extends SseHttpTmpQuery {
236
316
}
237
317
}
238
318
239
- private buildUrl ( args ?: Record < string , unknown > ) : string {
240
- const children = this . children ;
241
- const basePath = children . path . children . text . getView ( ) ;
242
- const params = children . params . getView ( ) ;
243
-
244
- // Build URL with parameters
245
- const url = new URL ( basePath ) ;
246
- params . forEach ( ( param : any ) => {
247
- if ( param . key && param . value ) {
248
- const value = typeof param . value === 'function' ? param . value ( args ) : param . value ;
249
- url . searchParams . append ( param . key , String ( value ) ) ;
250
- }
251
- } ) ;
252
-
253
- return url . toString ( ) ;
254
- }
255
-
256
- private buildHeaders ( args ?: Record < string , unknown > ) : Record < string , string > {
257
- const headers : Record < string , string > = { } ;
258
-
259
- this . children . headers . getView ( ) . forEach ( ( header : any ) => {
260
- if ( header . key && header . value ) {
261
- const value = typeof header . value === 'function' ? header . value ( args ) : header . value ;
262
- headers [ header . key ] = String ( value ) ;
263
- }
264
- } ) ;
265
-
266
- return headers ;
267
- }
268
-
269
- private buildRequestBody ( args ?: Record < string , unknown > ) : string | FormData | undefined {
270
- const bodyType = this . children . bodyType . getView ( ) ;
271
-
272
- switch ( bodyType ) {
273
- case "application/json" :
274
- return this . children . body . children . text . getView ( ) as string ;
275
- case "text/plain" :
276
- return this . children . body . children . text . getView ( ) as string ;
277
- case "application/x-www-form-urlencoded" :
278
- const formData = new URLSearchParams ( ) ;
279
- this . children . bodyFormData . getView ( ) . forEach ( ( item : any ) => {
280
- if ( item . key && item . value ) {
281
- const value = typeof item . value === 'function' ? item . value ( args ) : item . value ;
282
- formData . append ( item . key , String ( value ) ) ;
283
- }
284
- } ) ;
285
- return formData . toString ( ) ;
286
- case "multipart/form-data" :
287
- const multipartData = new FormData ( ) ;
288
- this . children . bodyFormData . getView ( ) . forEach ( ( item : any ) => {
289
- if ( item . key && item . value ) {
290
- const value = typeof item . value === 'function' ? item . value ( args ) : item . value ;
291
- multipartData . append ( item . key , String ( value ) ) ;
292
- }
293
- } ) ;
294
- return multipartData ;
295
- default :
296
- return undefined ;
297
- }
298
- }
299
-
300
319
private createSuccessResponse ( data : JSONValue , runTime ?: number ) : QueryResult {
301
320
return {
302
321
data,
0 commit comments