@@ -132,21 +132,100 @@ export async function runFirebasePlugin(
132
132
133
133
if ( actionName === "FS.QueryFireStore" ) {
134
134
const data = await withFirestoreCollection ( async ( ref ) => {
135
+ const structuredQuery = actionData . query ;
136
+ if ( ! structuredQuery ) {
137
+ throw badRequest ( "Missing structuredQuery in action data" ) ;
138
+ }
139
+
135
140
let query : FirebaseFirestore . Query < FirebaseFirestore . DocumentData > = ref ;
141
+
142
+ // Apply `where` filters
143
+ if ( structuredQuery . where && structuredQuery . where . fieldFilter ) {
144
+ const fieldFilter = structuredQuery . where . fieldFilter ;
145
+ const fieldPath = fieldFilter . field ?. fieldPath ;
146
+ const operator = fieldFilter . op ;
147
+ const value = fieldFilter . value ;
148
+
149
+ if ( ! fieldPath || ! operator || value === undefined ) {
150
+ throw badRequest ( "Invalid fieldFilter in where clause" ) ;
151
+ }
152
+
153
+ let firestoreOp : FirebaseFirestore . WhereFilterOp ;
154
+ switch ( operator ) {
155
+ case "EQUAL" :
156
+ firestoreOp = "==" ;
157
+ break ;
158
+ case "GREATER_THAN" :
159
+ firestoreOp = ">" ;
160
+ break ;
161
+ case "LESS_THAN" :
162
+ firestoreOp = "<" ;
163
+ break ;
164
+ case "GREATER_THAN_OR_EQUAL" :
165
+ firestoreOp = ">=" ;
166
+ break ;
167
+ case "LESS_THAN_OR_EQUAL" :
168
+ firestoreOp = "<=" ;
169
+ break ;
170
+ case "ARRAY_CONTAINS" :
171
+ firestoreOp = "array-contains" ;
172
+ break ;
173
+ default :
174
+ throw badRequest ( `Unsupported operator: ${ operator } ` ) ;
175
+ }
176
+
177
+ const actualValue = value . integerValue ?? value . stringValue ?? value . booleanValue ?? value . doubleValue ;
178
+ if ( actualValue === undefined ) {
179
+ throw badRequest ( "Unsupported value type in structuredQuery" ) ;
180
+ }
136
181
137
- // Parse Query JSON from actionData.query
138
- if ( actionData . query ) {
139
- for ( const condition of actionData . query ) {
140
- const { field, op, value } = condition ;
141
- if ( ! field || ! op || value === undefined ) {
142
- throw badRequest ( "Invalid query condition: " + JSON . stringify ( condition ) ) ;
182
+ query = query . where ( fieldPath , firestoreOp , actualValue ) ;
183
+ }
184
+
185
+ // Apply `orderBy`
186
+ if ( structuredQuery . orderBy && Array . isArray ( structuredQuery . orderBy ) ) {
187
+ for ( const order of structuredQuery . orderBy ) {
188
+ if ( order . field && order . field . fieldPath ) {
189
+ query = query . orderBy (
190
+ order . field . fieldPath ,
191
+ ( order . direction || "asc" ) as FirebaseFirestore . OrderByDirection
192
+ ) ;
143
193
}
144
- query = query . where ( field , op as WhereFilterOp , value ) ;
145
194
}
146
195
}
147
-
148
- // Execute the query and retrieve results
196
+
197
+ // Apply `limit`
198
+ if ( structuredQuery . limit ) {
199
+ query = query . limit ( structuredQuery . limit ) ;
200
+ }
201
+
202
+ // Apply `offset` (Firestore SDK doesn't support offset directly; simulate it with startAfter)
203
+ if ( structuredQuery . offset ) {
204
+ const offsetSnapshot = await query . limit ( structuredQuery . offset ) . get ( ) ;
205
+ const lastVisible = offsetSnapshot . docs [ offsetSnapshot . docs . length - 1 ] ;
206
+ if ( lastVisible ) {
207
+ query = query . startAfter ( lastVisible ) ;
208
+ }
209
+ }
210
+
211
+ // Apply `startAt` and `endAt` cursors, checking for undefined values
212
+ if ( structuredQuery . startAt && structuredQuery . startAt . values ) {
213
+ const startAtValues = structuredQuery . startAt . values . map ( ( v : { integerValue : any ; stringValue : any ; booleanValue : any ; doubleValue : any ; } ) => v . integerValue ?? v . stringValue ?? v . booleanValue ?? v . doubleValue ) . filter ( ( value : any ) => value !== undefined ) ;
214
+ if ( startAtValues . length > 0 ) {
215
+ query = query . startAt ( ...startAtValues ) ;
216
+ }
217
+ }
218
+
219
+ if ( structuredQuery . endAt && structuredQuery . endAt . values ) {
220
+ const endAtValues = structuredQuery . endAt . values . map ( ( v : { integerValue : any ; stringValue : any ; booleanValue : any ; doubleValue : any ; } ) => v . integerValue ?? v . stringValue ?? v . booleanValue ?? v . doubleValue ) . filter ( ( value : any ) => value !== undefined ) ;
221
+ if ( endAtValues . length > 0 ) {
222
+ query = query . endAt ( ...endAtValues ) ;
223
+ }
224
+ }
225
+
226
+ // Execute the query
149
227
const snapshot = await query . get ( ) ;
228
+
150
229
if ( snapshot . empty ) {
151
230
return [ ] ;
152
231
}
0 commit comments