Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
fdc4c4e
fix lint errors
morganchen12 Nov 11, 2025
0b3d4d1
fix missing header
morganchen12 Nov 11, 2025
55524cb
remove file that caused build breakages
morganchen12 Nov 11, 2025
a077cba
fix c++ format error
cherylEnkidu Nov 11, 2025
8e23996
remove duplicate vector
cherylEnkidu Nov 12, 2025
c10da97
fix c++ type error
cherylEnkidu Nov 12, 2025
c2572eb
fix type error 2
cherylEnkidu Nov 12, 2025
770a728
fix more type error
cherylEnkidu Nov 12, 2025
559a355
try solving assertion failure
cherylEnkidu Nov 12, 2025
9035aad
try another flag
cherylEnkidu Nov 13, 2025
e0fe92d
test ASSERT_DEATH on github ci
cherylEnkidu Nov 13, 2025
8b7df8c
test new flag: ABSL_HAVE_EXCEPTIONS
cherylEnkidu Nov 13, 2025
8cce4af
verify behaviour
cherylEnkidu Nov 14, 2025
f83e670
test reverted re2 version
cherylEnkidu Nov 14, 2025
e2e053d
add cmake settings
cherylEnkidu Nov 14, 2025
d462e20
add absl cmake settings
cherylEnkidu Nov 14, 2025
d1f9c98
Merge branch 'feat/pipeline/private-preview' into mc/format
cherylEnkidu Nov 17, 2025
f90bdfe
revert changes
cherylEnkidu Nov 17, 2025
44195b8
fix stack-use-after-scope
cherylEnkidu Nov 17, 2025
0a30c20
remove unnessary changes
cherylEnkidu Nov 17, 2025
af72cd8
enable emulator EXPERIMENTAL_MODE
cherylEnkidu Nov 17, 2025
5721bf9
update emulator version
cherylEnkidu Nov 18, 2025
ac6286e
remove echo
cherylEnkidu Nov 19, 2025
454c75e
rename some expressions
cherylEnkidu Nov 21, 2025
f9c2439
fix broken tests
cherylEnkidu Nov 21, 2025
d63d845
merge in private preview feature branch
cherylEnkidu Nov 24, 2025
31b3944
solve merge error
cherylEnkidu Nov 24, 2025
4d348f7
expose public API of realtime Pipeline
cherylEnkidu Nov 24, 2025
0dae5a9
Merge branch 'cheryl/AddExprAsBool' into cheryl/realppl1
cherylEnkidu Nov 26, 2025
1a267b1
fix hanging test
cherylEnkidu Nov 28, 2025
cf2c715
separate expression file
cherylEnkidu Dec 1, 2025
78bb8a6
fix format
cherylEnkidu Dec 1, 2025
28ed0d3
optimize the file dependency
cherylEnkidu Dec 1, 2025
59df4b5
rename expression file
cherylEnkidu Dec 1, 2025
036960e
fix cocoapods build
cherylEnkidu Dec 2, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
440 changes: 225 additions & 215 deletions Firestore/Example/Firestore.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion Firestore/Swift/Source/PipelineResultChange.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
import Foundation

@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
struct PipelineResultChange: Sendable {
public struct PipelineResultChange: Sendable {
public enum ChangeType {
case added, modified, removed
}
Expand Down
2 changes: 1 addition & 1 deletion Firestore/Swift/Source/SwiftAPI/Firestore+Pipeline.swift
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ import Foundation
///
/// - Returns: A `RealtimePipelineSource` for building a realtime pipeline.
@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
@nonobjc internal func realtimePipeline() -> RealtimePipelineSource {
@nonobjc func realtimePipeline() -> RealtimePipelineSource {
return RealtimePipelineSource(db: self) { stages, db in
RealtimePipeline(stages: stages, db: db)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@
import Foundation

@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
struct PipelineListenOptions: Sendable, Equatable, Hashable {
public struct PipelineListenOptions: Sendable, Equatable, Hashable {
/// Defines how to handle server-generated timestamps that are not yet known locally
/// during latency compensation.
struct ServerTimestampBehavior: Sendable, Equatable, Hashable {
public struct ServerTimestampBehavior: Sendable, Equatable, Hashable {
/// The raw string value for the behavior, used for implementation and hashability.
let rawValue: String
/// Creates a new behavior with a private raw value.
Expand Down Expand Up @@ -91,7 +91,7 @@ struct PipelineListenOptions: Sendable, Equatable, Hashable {
}

@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
struct RealtimePipeline: @unchecked Sendable {
public struct RealtimePipeline: @unchecked Sendable {
private var stages: [Stage]

let bridge: RealtimePipelineBridge
Expand All @@ -103,7 +103,7 @@ struct RealtimePipeline: @unchecked Sendable {
bridge = RealtimePipelineBridge(stages: stages.map { $0.bridge }, db: db)
}

struct Snapshot: Sendable {
public struct Snapshot: Sendable {
/// An array of all the results in the `PipelineSnapshot`.
let results_cache: [PipelineResult]

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.

@available(iOS 13, tvOS 13, macOS 10.15, macCatalyst 13, watchOS 7, *)
struct RealtimePipelineSource: @unchecked Sendable {
public struct RealtimePipelineSource: @unchecked Sendable {
let db: Firestore
let factory: ([Stage], Firestore) -> RealtimePipeline

Expand All @@ -22,27 +22,62 @@ struct RealtimePipelineSource: @unchecked Sendable {
self.factory = factory
}

func collection(_ path: String) -> RealtimePipeline {
public func collection(_ path: String) -> RealtimePipeline {
return factory([CollectionSource(collection: db.collection(path), db: db)], db)
}

func collection(_ coll: CollectionReference) -> RealtimePipeline {
public func collection(_ coll: CollectionReference) -> RealtimePipeline {
return factory([CollectionSource(collection: coll, db: db)], db)
}

func collectionGroup(_ collectionId: String) -> RealtimePipeline {
public func collectionGroup(_ collectionId: String) -> RealtimePipeline {
return factory(
[CollectionGroupSource(collectionId: collectionId)],
db
)
}

func documents(_ docs: [DocumentReference]) -> RealtimePipeline {
public func documents(_ docs: [DocumentReference]) -> RealtimePipeline {
return factory([DocumentsSource(docs: docs, db: db)], db)
}

func documents(_ paths: [String]) -> RealtimePipeline {
public func documents(_ paths: [String]) -> RealtimePipeline {
let docs = paths.map { db.document($0) }
return factory([DocumentsSource(docs: docs, db: db)], db)
}

/// Creates a `RealtimePipeline` from an existing `Query`.
///
/// This allows you to convert a standard Firestore query into a pipeline, which can then be
/// further modified with additional pipeline stages.
///
/// - Parameter query: The `Query` to convert into a pipeline.
/// - Returns: A `RealtimePipeline` that is equivalent to the given query.
public func create(from query: Query) -> RealtimePipeline {
let stageBridges = PipelineBridge.createStageBridges(from: query)
let stages: [Stage] = stageBridges.map { bridge in
switch bridge.name {
case "collection":
return CollectionSource(
bridge: bridge as! CollectionSourceStageBridge,
db: query.firestore
)
case "collection_group":
return CollectionGroupSource(bridge: bridge as! CollectionGroupSourceStageBridge)
case "documents":
return DocumentsSource(bridge: bridge as! DocumentsSourceStageBridge, db: query.firestore)
case "where":
return Where(bridge: bridge as! WhereStageBridge)
case "limit":
return Limit(bridge: bridge as! LimitStageBridge)
case "sort":
return Sort(bridge: bridge as! SortStageBridge)
case "offset":
return Offset(bridge: bridge as! OffsetStageBridge)
default:
fatalError("Unknown stage type \(bridge.name)")
}
}
return factory(stages, db)
}
}
38 changes: 38 additions & 0 deletions Firestore/Swift/Tests/Integration/QueryIntegrationTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -332,3 +332,41 @@ class QueryIntegrationTests: FSTIntegrationTestCase {
)
}
}

class QueryAsPipelineIntegrationTests: QueryIntegrationTests {
override class var isRunningPipeline: Bool {
return true
}

override func check(_ coll: CollectionReference, query: Query,
matchesResult expectedKeys: [String]) async throws {
let collPipeline = coll.firestore.realtimePipeline().create(from: coll)
var collIterator = collPipeline.snapshotStream().makeAsyncIterator()
var _ = try await collIterator.next()

let pipeline = query.firestore.realtimePipeline().create(from: query)

var cacheIterator = pipeline.snapshotStream(options: .init(source: .cache)).makeAsyncIterator()
let cacheSnapshot = try await cacheIterator.next()
let cacheResultIds = cacheSnapshot?.results().map { $0.id }

var serverIterator = pipeline.snapshotStream(options: .init(
includeMetadataChanges: true,
source: .default
)).makeAsyncIterator()
var serverSnapshot = try await serverIterator.next()
if serverSnapshot?.metadata.isFromCache == true {
serverSnapshot = try await serverIterator.next()
}
let serverResultIds = serverSnapshot?.results().map { $0.id }

var remoteKeysIterator = pipeline.snapshotStream(options: .init(source: .cache))
.makeAsyncIterator()
let remoteKeysSnapshot = try await remoteKeysIterator.next()
let remoteKeysResultIds = remoteKeysSnapshot?.results().map { $0.id }

XCTAssertEqual(cacheResultIds, serverResultIds)
XCTAssertEqual(serverResultIds, remoteKeysResultIds)
XCTAssertEqual(remoteKeysResultIds, expectedKeys)
}
}
Loading
Loading