@@ -2347,4 +2347,207 @@ class PipelineIntegrationTests: FSTIntegrationTestCase {
2347
2347
2348
2348
TestHelper . compare ( pipelineSnapshot: snapshot, expected: expectedResults, enforceOrder: true )
2349
2349
}
2350
+
2351
+ func testSupportsRand( ) async throws {
2352
+ let collRef = collectionRef ( withDocuments: bookDocs)
2353
+ let db = collRef. firestore
2354
+
2355
+ let pipeline = db. pipeline ( )
2356
+ . collection ( collRef. path)
2357
+ . limit ( 10 )
2358
+ . select ( RandomExpr ( ) . as ( " result " ) )
2359
+
2360
+ let snapshot = try await pipeline. execute ( )
2361
+
2362
+ XCTAssertEqual ( snapshot. results. count, 10 , " Should fetch 10 documents " )
2363
+
2364
+ for doc in snapshot. results {
2365
+ guard let resultValue = doc. get ( " result " ) else {
2366
+ XCTFail ( " Document \( doc. id ?? " unknown " ) should have a 'result' field " )
2367
+ continue
2368
+ }
2369
+ guard let doubleValue = resultValue as? Double else {
2370
+ XCTFail ( " Result value for document \( doc. id ?? " unknown " ) is not a Double: \( resultValue) " )
2371
+ continue
2372
+ }
2373
+ XCTAssertGreaterThanOrEqual (
2374
+ doubleValue,
2375
+ 0.0 ,
2376
+ " Result for \( doc. id ?? " unknown " ) should be >= 0.0 "
2377
+ )
2378
+ XCTAssertLessThan ( doubleValue, 1.0 , " Result for \( doc. id ?? " unknown " ) should be < 1.0 " )
2379
+ }
2380
+ }
2381
+
2382
+ func testSupportsArray( ) async throws {
2383
+ let db = firestore ( )
2384
+ let collRef = collectionRef ( withDocuments: bookDocs)
2385
+
2386
+ let pipeline = db. pipeline ( )
2387
+ . collection ( collRef. path)
2388
+ . sort ( Field ( " rating " ) . descending ( ) )
2389
+ . limit ( 1 )
2390
+ . select ( ArrayExpression ( [ 1 , 2 , 3 , 4 ] ) . as ( " metadata " ) )
2391
+
2392
+ let snapshot = try await pipeline. execute ( )
2393
+
2394
+ XCTAssertEqual ( snapshot. results. count, 1 , " Should retrieve one document " )
2395
+
2396
+ let expectedResults : [ String : Sendable ? ] = [ " metadata " : [ 1 , 2 , 3 , 4 ] ]
2397
+
2398
+ if let resultDoc = snapshot. results. first {
2399
+ TestHelper . compare ( pipelineResult: resultDoc, expected: expectedResults)
2400
+ } else {
2401
+ XCTFail ( " No document retrieved for testSupportsArray " )
2402
+ }
2403
+ }
2404
+
2405
+ func testEvaluatesExpressionInArray( ) async throws {
2406
+ let db = firestore ( )
2407
+ let collRef = collectionRef ( withDocuments: bookDocs)
2408
+
2409
+ let pipeline = db. pipeline ( )
2410
+ . collection ( collRef. path)
2411
+ . sort ( Field ( " rating " ) . descending ( ) )
2412
+ . limit ( 1 )
2413
+ . select ( ArrayExpression ( [
2414
+ 1 ,
2415
+ 2 ,
2416
+ Field ( " genre " ) ,
2417
+ Field ( " rating " ) . multiply ( 10 ) ,
2418
+ ] ) . as ( " metadata " ) )
2419
+
2420
+ let snapshot = try await pipeline. execute ( )
2421
+
2422
+ XCTAssertEqual ( snapshot. results. count, 1 , " Should retrieve one document " )
2423
+
2424
+ let expectedResults : [ String : Sendable ? ] = [ " metadata " : [ 1 , 2 , " Fantasy " , 47.0 ] ]
2425
+
2426
+ if let resultDoc = snapshot. results. first {
2427
+ TestHelper . compare ( pipelineResult: resultDoc, expected: expectedResults)
2428
+ } else {
2429
+ XCTFail ( " No document retrieved for testEvaluatesExpressionInArray " )
2430
+ }
2431
+ }
2432
+
2433
+ func testSupportsArrayOffset( ) async throws {
2434
+ let db = firestore ( )
2435
+ let collRef = collectionRef ( withDocuments: bookDocs)
2436
+
2437
+ let expectedResultsPart1 : [ [ String : Sendable ? ] ] = [
2438
+ [ " firstTag " : " adventure " ] , // book4 (rating 4.7)
2439
+ [ " firstTag " : " politics " ] , // book10 (rating 4.6)
2440
+ [ " firstTag " : " classic " ] , // book2 (rating 4.5)
2441
+ ]
2442
+
2443
+ // Part 1: Using arrayOffset as FunctionExpr("array_offset", ...)
2444
+ // (Assuming direct top-level ArrayOffset() isn't available, as per Expr.swift structure)
2445
+ let pipeline1 = db. pipeline ( )
2446
+ . collection ( collRef. path)
2447
+ . sort ( Field ( " rating " ) . descending ( ) )
2448
+ . limit ( 3 )
2449
+ . select ( Field ( " tags " ) . arrayOffset ( 0 ) . as ( " firstTag " ) )
2450
+
2451
+ let snapshot1 = try await pipeline1. execute ( )
2452
+ XCTAssertEqual ( snapshot1. results. count, 3 , " Part 1: Should retrieve three documents " )
2453
+ TestHelper . compare (
2454
+ pipelineSnapshot: snapshot1,
2455
+ expected: expectedResultsPart1,
2456
+ enforceOrder: true
2457
+ )
2458
+ }
2459
+
2460
+ func testSupportsMap( ) async throws {
2461
+ let db = firestore ( )
2462
+ let collRef = collectionRef ( withDocuments: bookDocs)
2463
+
2464
+ let pipeline = db. pipeline ( )
2465
+ . collection ( collRef. path)
2466
+ . sort ( Field ( " rating " ) . descending ( ) )
2467
+ . limit ( 1 )
2468
+ . select ( MapExpression ( [ " foo " : " bar " ] ) . as ( " metadata " ) )
2469
+
2470
+ let snapshot = try await pipeline. execute ( )
2471
+
2472
+ XCTAssertEqual ( snapshot. results. count, 1 , " Should retrieve one document " )
2473
+
2474
+ let expectedResult : [ String : Sendable ? ] = [ " metadata " : [ " foo " : " bar " ] ]
2475
+
2476
+ if let resultDoc = snapshot. results. first {
2477
+ TestHelper . compare ( pipelineResult: resultDoc, expected: expectedResult)
2478
+ } else {
2479
+ XCTFail ( " No document retrieved for testSupportsMap " )
2480
+ }
2481
+ }
2482
+
2483
+ func testEvaluatesExpressionInMap( ) async throws {
2484
+ let db = firestore ( )
2485
+ let collRef = collectionRef ( withDocuments: bookDocs)
2486
+
2487
+ let pipeline = db. pipeline ( )
2488
+ . collection ( collRef. path)
2489
+ . sort ( Field ( " rating " ) . descending ( ) )
2490
+ . limit ( 1 )
2491
+ . select ( MapExpression ( [
2492
+ " genre " : Field ( " genre " ) , // "Fantasy"
2493
+ " rating " : Field ( " rating " ) . multiply ( 10 ) , // 4.7 * 10 = 47.0
2494
+ ] ) . as ( " metadata " ) )
2495
+
2496
+ let snapshot = try await pipeline. execute ( )
2497
+
2498
+ XCTAssertEqual ( snapshot. results. count, 1 , " Should retrieve one document " )
2499
+
2500
+ // Expected: genre is "Fantasy", rating is 4.7 for book4
2501
+ let expectedResult : [ String : Sendable ? ] = [ " metadata " : [ " genre " : " Fantasy " , " rating " : 47.0 ] ]
2502
+
2503
+ if let resultDoc = snapshot. results. first {
2504
+ TestHelper . compare ( pipelineResult: resultDoc, expected: expectedResult)
2505
+ } else {
2506
+ XCTFail ( " No document retrieved for testEvaluatesExpressionInMap " )
2507
+ }
2508
+ }
2509
+
2510
+ func testSupportsMapRemove( ) async throws {
2511
+ let db = firestore ( )
2512
+ let collRef = collectionRef ( withDocuments: bookDocs)
2513
+
2514
+ let expectedResult : [ String : Sendable ? ] = [ " awards " : [ " nebula " : false ] ]
2515
+
2516
+ let pipeline2 = db. pipeline ( )
2517
+ . collection ( collRef. path)
2518
+ . sort ( Field ( " rating " ) . descending ( ) )
2519
+ . limit ( 1 )
2520
+ . select ( Field ( " awards " ) . mapRemove ( " hugo " ) . as ( " awards " ) )
2521
+
2522
+ let snapshot2 = try await pipeline2. execute ( )
2523
+ XCTAssertEqual ( snapshot2. results. count, 1 , " Should retrieve one document " )
2524
+ if let resultDoc2 = snapshot2. results. first {
2525
+ TestHelper . compare ( pipelineResult: resultDoc2, expected: expectedResult)
2526
+ } else {
2527
+ XCTFail ( " No document retrieved for testSupportsMapRemove " )
2528
+ }
2529
+ }
2530
+
2531
+ func testSupportsMapMerge( ) async throws {
2532
+ let db = firestore ( )
2533
+ let collRef = collectionRef ( withDocuments: bookDocs)
2534
+
2535
+ let expectedResult : [ String : Sendable ? ] =
2536
+ [ " awards " : [ " hugo " : false , " nebula " : false , " fakeAward " : true ] ]
2537
+ let mergeMap : [ String : Sendable ] = [ " fakeAward " : true ]
2538
+
2539
+ let pipeline = db. pipeline ( )
2540
+ . collection ( collRef. path)
2541
+ . sort ( Field ( " rating " ) . descending ( ) )
2542
+ . limit ( 1 )
2543
+ . select ( Field ( " awards " ) . mapMerge ( mergeMap) . as ( " awards " ) )
2544
+
2545
+ let snapshot = try await pipeline. execute ( )
2546
+ XCTAssertEqual ( snapshot. results. count, 1 , " Should retrieve one document " )
2547
+ if let resultDoc = snapshot. results. first {
2548
+ TestHelper . compare ( pipelineResult: resultDoc, expected: expectedResult)
2549
+ } else {
2550
+ XCTFail ( " No document retrieved for testSupportsMapMerge " )
2551
+ }
2552
+ }
2350
2553
}
0 commit comments