Skip to content

Commit 4e0b2ee

Browse files
committed
feat(firestore, ios): enable substring, timestampAdd, timestampSubtract, arrayGet pipeline support
1 parent e8111d8 commit 4e0b2ee

12 files changed

Lines changed: 411 additions & 586 deletions

File tree

docs/firestore/pipelines/sdk-compatibility.mdx

Lines changed: 0 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -51,21 +51,6 @@ These exports exist in both SDKs but differ in typing or optional parameters:
5151
| ------ | ----------------------------------------------------------------------- |
5252
| `Type` | Local type discriminator union used with `isType()` and related helpers |
5353

54-
# iOS expression limitations
55-
56-
Even when an expression helper is exported from `@react-native-firebase/firestore/pipelines`, the **iOS native runtime** may not implement it yet. Using these functions in a pipeline on iOS throws before `execute()` completes:
57-
58-
| Function | Status on iOS |
59-
| ------------------- | ------------- |
60-
| `arrayGet` | Not supported |
61-
| `substring` | Not supported |
62-
| `timestampAdd` | Not supported |
63-
| `timestampSubtract` | Not supported |
64-
65-
**Android** and **macOS** do not apply this check; macOS uses the web SDK path. Prefer testing pipeline samples on Android or macOS when they use the functions above until iOS parity lands.
66-
67-
The list is defined in `packages/firestore/lib/pipelines/pipeline_support.ts` and kept in sync with `RNFBFirestorePipelineNodeBuilder.swift`.
68-
6954
# Platform execution matrix
7055

7156
| Platform | Execution backend | Pipeline database |

eslint.config.mjs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import * as eslintPluginMdx from 'eslint-plugin-mdx';
1313
export default defineConfig([
1414
globalIgnores([
1515
'packages/**/dist/',
16+
'packages/**/android/build/',
1617
'**/type-test.ts',
1718
'packages/ai/__tests__/test-utils'
1819
]),

okf-bundle/packages/firestore/pipeline-coverage-work-queue.md

Lines changed: 97 additions & 83 deletions
Large diffs are not rendered by default.

okf-bundle/packages/firestore/pipeline-platform-parity.md

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,6 @@ No permanent `Platform.android` / `Platform.ios` e2e workaround without registry
5050

5151
| ID | Area | Symptom | Justification | E2e |
5252
|----|------|---------|---------------|-----|
53-
| **P-003** | iOS unsupported functions | JS pre-execute throw via `IOS_UNSUPPORTED_FUNCTION_NAMES` (**4 names**; was 9) | List likely **partially stale** vs iOS **12.15** CHANGELOG — see [sdk-support-audit](pipeline-sdk-support-audit.md). `stringRepeat`, `switchOn`, `trunc`, `conditional`, and `round` **confirmed supported** — guards removed; unified cross-platform e2e. | Reduced iOS pipelines until runtime verification completes — [work queue](pipeline-coverage-work-queue.md) |
54-
| **P-003a** | *(per-function hooks)* | `substring`, `arrayGet`, `timestampAdd`, `timestampSubtract` | Subset of P-003 — see [§ iOS unsupported function e2e map](#ios-unsupported-function-e2e-map) | One or more tests each |
5553
| **P-013** | iOS extended aggregate accumulators | `first`/`last`/`minimum`/`maximum` with expression args skipped on iOS only (L3740) | **Likely iOS SDK** — functions not in unsupported list; needs SDK repro; document until confirmed | L3740–3790 |
5654
| **P-014** | Execute `indexMode` / `rawOptions` on iOS | iOS parser rejects at native boundary | iOS SDK gap | L3796–3798 skip (iOS + macOS) |
5755
| **P-015** | Source `rawOptions` on iOS | iOS parser rejects `pipeline.source.rawOptions` | iOS SDK gap; Android applies `CollectionHints` | L3795–3845 (Android-only execute) |
@@ -88,23 +86,6 @@ No permanent `Platform.android` / `Platform.ios` e2e workaround without registry
8886

8987
---
9088

91-
## iOS unsupported function e2e map
92-
93-
Durable per-function status. **Live probes:** [work queue](pipeline-coverage-work-queue.md#j0--ios-runtime-guard-probes-do-first).
94-
95-
| Function | Throw asserted | Reduced iOS pipeline | Approx line | SDK / verification status |
96-
|----------|----------------|----------------------|-------------|---------------------------|
97-
| `round` ||| L1654 | No CHANGELOG entry — **sdk-supported-bridge-ok**; guard removed; unified e2e |
98-
| `conditional` ||| L1344 | **Added 12.11****sdk-supported-bridge-ok**; guard removed; wire name `conditional`; unified e2e |
99-
| `switchOn` ||| L1471 | **Added 12.12****sdk-supported-bridge-ok**; guard removed; unified e2e |
100-
| `trunc` ||| L1758 | **Added 12.11****sdk-supported-bridge-ok**; guard removed; unified e2e |
101-
| `substring` | Yes | Yes | L1770 | No CHANGELOG entry — **sdk-unsupported-confirmed**; guard + reduced e2e retained |
102-
| `stringRepeat` ||| L1985 | **Added 12.12****sdk-supported-bridge-ok**; guard removed; unified e2e |
103-
| `arrayGet` | Yes | Yes | L2265, L2648 | No CHANGELOG entry — **pending-probe** (+ possible RNFB receiver gap) |
104-
| `timestampAdd` / `timestampSubtract` | Yes | Yes | L2903 | No CHANGELOG entry — **pending-probe** |
105-
106-
---
107-
10889
## Architecture drift (document-only)
10990

11091
| ID | Note |
@@ -121,8 +102,8 @@ Durable per-function status. **Live probes:** [work queue](pipeline-coverage-wor
121102
|--------|---------|
122103
| E2e inventory (`Pipeline.e2e.js`) | 31 `Platform.*` branch sites; macOS vs iOS/Android total count delta is app harness only (see P-006) |
123104
| Native bridge diff (Swift vs Java NodeBuilder/Parser) | Primary drift in NodeBuilder coercion; secondary in Parser + stage fields |
124-
| JS guards audit (`pipeline_support.ts`) | Single runtime `isIOS` branch; execute-options JS gate on all platforms |
125-
| [SDK support audit](pipeline-sdk-support-audit.md) | Pins iOS 12.15 / Android 34.15; guard list likely partially stale — runtime verification required |
105+
| JS guards audit (`pipeline_validate.ts` / `pipeline_runtime.ts`) | Execute-options JS gate on all platforms; no iOS function-name pre-execute block |
106+
| [SDK support audit](pipeline-sdk-support-audit.md) | Pins iOS 12.15 / Android 34.15; bridge + runtime e2e verification |
126107

127108
# Parity remediation workflow
128109

okf-bundle/packages/firestore/pipeline-sdk-support-audit.md

Lines changed: 38 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,14 @@
11
---
22
type: Reference
33
title: Firestore Pipeline SDK support audit
4-
description: Repeatable method to determine which pipeline functions are unsupported on each platform, and reconciliation of the iOS JS guard list against upstream SDK releases.
4+
description: Repeatable method to determine which pipeline functions are supported on each platform, and reconciliation of RNFB bridge lowering against upstream SDK releases.
55
tags: [firestore, pipelines, ios, android, sdk, parity, audit]
66
timestamp: 2026-06-25T00:00:00Z
77
---
88

99
# Purpose
1010

11-
RNFB maintains `IOS_UNSUPPORTED_FUNCTION_NAMES` and reduced iOS e2e. The list dates from SDK runtime `invalid-argument` failures even when RNFB lowering existed.
12-
13-
Upstream SDKs shipped expression additions since; stale guards falsely classify P-003 as SDK-unsupported.
14-
15-
This method compares guards to primary sources and requires runtime verification before guard/e2e changes.
11+
RNFB pipeline parity depends on native bridge lowering matching pinned Firebase SDKs. This method compares RNFB exports, CHANGELOG evidence, bridge code, and runtime e2e execute probes.
1612

1713
Related: [Platform parity](pipeline-platform-parity.md), [work queue](pipeline-coverage-work-queue.md) (live status).
1814

@@ -43,8 +39,8 @@ Use the right source per platform/question:
4339

4440
| Layer | Tool / source | Proves | Does **not** prove |
4541
|-------|----------------|--------|-------------------|
46-
| **A — Public API surface** | `yarn compare:types``firestore-pipelines` ([config](../../../.github/scripts/compare-types/configs/firestore-pipelines.ts)) | firebase-js-sdk **exports** missing from RNFB types, extra RN exports, signature drift | Native iOS/Android **runtime** execute; stale `IOS_UNSUPPORTED_*` guards; macOS runtime for new JS-only backend features |
47-
| **B — JS / macOS runtime** | firebase-js-sdk CHANGELOG + macOS e2e (`Platform.other` path uses web SDK) | What the **pinned npm `firebase`** package can execute on macOS | Native bridge behaviour; iOS guard list |
42+
| **A — Public API surface** | `yarn compare:types``firestore-pipelines` ([config](../../../.github/scripts/compare-types/configs/firestore-pipelines.ts)) | firebase-js-sdk **exports** missing from RNFB types, extra RN exports, signature drift | Native iOS/Android **runtime** execute; macOS runtime for new JS-only backend features |
43+
| **B — JS / macOS runtime** | firebase-js-sdk CHANGELOG + macOS e2e (`Platform.other` path uses web SDK) | What the **pinned npm `firebase`** package can execute on macOS | Native bridge behaviour |
4844
| **C — Native runtime** | Native Firestore CHANGELOGs + iOS/Android e2e execute probes | What **linked iOS/Android SDKs** accept through RNFB native bridges | RNFB type exports; JS SDK additions RN has not typed yet |
4945

5046
`compare:types` is necessary, not sufficient:
@@ -57,7 +53,7 @@ Use firebase-js-sdk CHANGELOG for verification/macOS context, not instead of nat
5753

5854
- `missingInRN`: read [@firebase/firestore CHANGELOG](https://github.com/firebase/firebase-js-sdk/blob/main/packages/firestore/CHANGELOG.md) to date/export context and native lag.
5955
- macOS parity: macOS uses `executeWebSdkPipeline`; run macOS e2e if RN exports name and JS SDK added behavior.
60-
- iOS guard reconciliation: JS CHANGELOG is weak alone; native CHANGELOG + runtime probe matter more.
56+
- iOS bridge reconciliation: native CHANGELOG + runtime e2e probe matter most.
6157

6258
Rule: every firebase pin bump → `yarn compare:types`; every native pin bump → native CHANGELOG + runtime probes; consult JS CHANGELOG for API/macOS questions.
6359

@@ -81,10 +77,10 @@ RNFB serializes helper `name`; native builders normalize:
8177

8278
| JS / serialized `name` | iOS wire (typical) | Android wire (typical) |
8379
|------------------------|--------------------|-------------------------|
84-
| `conditional` | `cond` | `conditional()` API |
85-
| `timestampSubtract` | `timestamp_sub` | receiver `.timestampSubtract()` |
86-
| `timestampAdd` | `timestamp_add` | receiver `.timestampAdd()` |
87-
| `arrayGet` | `array_get` (raw) | receiver `.arrayGet()` |
80+
| `conditional` | `conditional` | `conditional()` API |
81+
| `timestampSubtract` | `timestamp_subtract` (RNFB currently emits `timestamp_sub`**wrong**) | receiver `.timestampSubtract()` |
82+
| `timestampAdd` | `timestamp_add` (generic wire; **needs receiver chain** on iOS) | receiver `.timestampAdd()` |
83+
| `arrayGet` | `array_get` (generic wire; **needs receiver chain** on iOS) | receiver `.arrayGet()` |
8884
| `stringRepeat` | `string_repeat` | raw `string_repeat` |
8985
| `switchOn` | `switch_on` | raw `switch_on` |
9086

@@ -106,24 +102,22 @@ Per function:
106102

107103
| Column | Source |
108104
|--------|--------|
109-
| In JS guard? | `pipeline_support.ts` |
110105
| iOS CHANGELOG ≤ pin | Yes / No / N/A |
111106
| Android CHANGELOG ≤ pin | Yes / No / N/A |
112107
| iOS bridge lowers? | Swift builder |
113108
| Android bridge lowers? | Java builder |
114-
| iOS e2e today | Full / reduced / throw-only |
109+
| iOS e2e today | Full / reduced / skip |
115110
| **Classification** | See below |
116-
| **Next action** | Runtime guard probe / bridge remediation / document only |
111+
| **Next action** | Bridge remediation / runtime e2e probe / document only |
117112

118113
**Classification values:**
119114

120115
| Value | Meaning |
121116
|-------|---------|
122-
| `sdk-supported-stale-guard` | CHANGELOG + bridge lowering; guard likely obsolete — **runtime probe required** |
123117
| `sdk-unsupported-confirmed` | No CHANGELOG entry + runtime probe fails on pinned SDK |
124118
| `rnfb-bridge-gap` | SDK may support; RNFB lowering missing or wrong shape on one platform |
125-
| `sdk-supported-bridge-ok` | Probe passed; remove guard + restore full e2e |
126-
| `pending-probe` | Insufficient evidence — **do not** change guard until step 6 |
119+
| `sdk-supported-bridge-ok` | Bridge lowering + unified cross-platform e2e pass |
120+
| `pending-probe` | Insufficient evidence — do not change e2e until probed |
127121

128122
## 6. Runtime verification (authoritative)
129123

@@ -133,29 +127,24 @@ Probe order/gates/live status: [work queue](pipeline-coverage-work-queue.md#j0--
133127

134128
**Per-function probe (iOS):**
135129

136-
1. Branch from current main; **one function at a time**.
137-
2. Remove that name from `IOS_UNSUPPORTED_FUNCTION_NAMES` only.
138-
3. Restore full assertion block in matching `Pipeline.e2e.js` test (remove `expectIOSUnsupportedFunctions` + reduced iOS pipeline).
139-
4. Run the implement/review gate defined in the [work queue runtime guard protocol](pipeline-coverage-work-queue.md#phase-j-iteration-protocol-strict).
140-
5. Record outcome:
141-
- **`independent-review` pass**`sdk-supported-bridge-ok`; remove guard permanently; close P-003 sub-row; `commit` work type after `review_gate` closed.
130+
1. Branch from current main; **one function or batch at a time** when bridge work is scoped.
131+
2. Implement or fix native lowering; unify matching `Pipeline.e2e.js` assertions cross-platform.
132+
3. Run the implement/review gate defined in the [work queue runtime protocol](pipeline-coverage-work-queue.md#phase-j-iteration-protocol-strict).
133+
4. Record outcome:
134+
- **`independent-review` pass**`sdk-supported-bridge-ok`; close parity row; `commit` after `review_gate` closed.
142135
- **`invalid-argument` / pipeline execute error** → capture exact message; classify `sdk-unsupported-confirmed` or `rnfb-bridge-gap` (compare native request in debug logs).
143-
6. Revert before next function unless committing a confirmed removal.
144-
145-
**Optional batch probe:** temporary e2e `describe` loops minimal pipeline per function; still one guard change per commit.
146136

147-
Android already runs full pipelines; macOS uses JS SDK. Probes are **iOS-only**.
137+
Android already runs full pipelines; macOS uses JS SDK. Probes focus on **native iOS/Android** execute paths.
148138

149139
## 7. Update artifacts
150140

151141
After probes update:
152142

153143
| Artifact | Update |
154144
|----------|--------|
155-
| `pipeline_support.ts` | `IOS_UNSUPPORTED_FUNCTION_NAMES` |
156-
| `RNFBFirestorePipelineNodeBuilder.swift` | Comment block ~L883–893 + any new lowering |
157-
| `Pipeline.e2e.js` | Remove reduced iOS pipelines for confirmed functions |
158-
| [pipeline-platform-parity.md](pipeline-platform-parity.md) | P-003 / iOS unsupported map |
145+
| `RNFBFirestorePipelineNodeBuilder.swift` / Android NodeBuilder | New or fixed lowering |
146+
| `Pipeline.e2e.js` | Unified cross-platform assertions |
147+
| [pipeline-platform-parity.md](pipeline-platform-parity.md) | Bridge / SDK gap rows |
159148
| [pipeline-coverage-work-queue.md](pipeline-coverage-work-queue.md) | Live remediation tracker |
160149

161150
Re-run on `@react-native-firebase/app` `sdkVersions` bump.
@@ -186,38 +175,36 @@ Re-run on `@react-native-firebase/app` `sdkVersions` bump.
186175

187176
Live probes/gates: [work queue](pipeline-coverage-work-queue.md#j0--ios-runtime-guard-probes-do-first).
188177

189-
| Function | JS guard | iOS bridge | Android bridge | CHANGELOG @ 12.15 | Classification | Verification status |
190-
|----------|----------|------------|----------------|-------------------|----------------|---------------------|
191-
| `stringRepeat` | No | Generic `string_repeat` | raw | **Added 12.12** | **sdk-supported-bridge-ok** | Guard removed; unified cross-platform e2e |
192-
| `switchOn` | No | Generic `switch_on` | raw | **Added 12.12** | **sdk-supported-bridge-ok** | Guard removed; unified cross-platform e2e |
193-
| `trunc` | No | Generic `trunc` | raw | **Added 12.11** | **sdk-supported-bridge-ok** | Guard removed; unified cross-platform e2e |
194-
| `conditional` | No | `conditional` wire | `Expression.conditional()` | **ConditionalExpression 12.11** | **sdk-supported-bridge-ok** | Guard removed; iOS wire `cond``conditional`; unified e2e |
195-
| `round` | No | Generic `round` | raw | Not listed | **sdk-supported-bridge-ok** | Guard removed; unified cross-platform e2e |
196-
| `substring` | Yes | Generic `substring` | raw | Not listed | **sdk-unsupported-confirmed** | Runtime verification failed on pinned iOS SDK; guard retained |
197-
| `timestampAdd` | Yes | Generic `timestamp_add` only | receiver chain | Not listed | **pending-probe**; suspect real SDK gap | Runtime probe pending; if fail → document SDK gap |
198-
| `timestampSubtract` | Yes | Generic `timestamp_sub` | receiver chain | Not listed | Same as timestampAdd | Runtime probe pending |
199-
| `arrayGet` | Yes | Generic `array_get` only | receiver chain | Not listed | **rnfb-bridge-gap** + **pending-probe** | Runtime probe pending; if SDK ok → iOS receiver parity |
178+
| Function | iOS bridge | Android bridge | CHANGELOG @ 12.15 | Classification | Verification status |
179+
|----------|------------|----------------|-------------------|----------------|---------------------|
180+
| `stringRepeat` | Generic `string_repeat` | raw | **Added 12.12** | **sdk-supported-bridge-ok** | Unified cross-platform e2e |
181+
| `switchOn` | Generic `switch_on` | raw | **Added 12.12** | **sdk-supported-bridge-ok** | Unified cross-platform e2e |
182+
| `trunc` | Generic `trunc` | raw | **Added 12.11** | **sdk-supported-bridge-ok** | Unified cross-platform e2e |
183+
| `conditional` | `conditional` wire | `Expression.conditional()` | **ConditionalExpression 12.11** | **sdk-supported-bridge-ok** | iOS wire `cond``conditional`; unified e2e |
184+
| `round` | Generic `round` | raw | Not listed | **sdk-supported-bridge-ok** | Unified cross-platform e2e |
185+
| `substring` | Receiver chain (`.substring()`) | raw | Not listed (SDK API present) | **sdk-supported-bridge-ok** | iOS receiver lowering; unified cross-platform e2e |
186+
| `timestampAdd` | Receiver chain (`.timestampAdd()`) | receiver chain | Not listed (SDK API present) | **sdk-supported-bridge-ok** | iOS receiver lowering; unified cross-platform e2e |
187+
| `timestampSubtract` | Receiver chain (`.timestampSubtract()`); wire `timestamp_subtract` | receiver chain | Not listed (SDK API present) | **sdk-supported-bridge-ok** | Fixed wire name + iOS receiver lowering; unified e2e |
188+
| `arrayGet` | Receiver chain (`.arrayGet()`) | receiver chain | Not listed (SDK API present) | **sdk-supported-bridge-ok** | iOS receiver lowering; unified cross-platform e2e |
200189

201190
## Impact on parity registry
202191

203192
| Registry row | Reconciliation finding |
204193
|--------------|------------------------|
205-
| **P-003** (umbrella iOS unsupported) | **Partially stale**`stringRepeat`, `switchOn`, `trunc`, `conditional`, and `round` confirmed supported (guards removed); `substring` **sdk-unsupported-confirmed** (guard correct); remaining guarded names need runtime verification |
206-
| **P-003a** (per-function e2e) | Ten iOS reduced/throw tests may shrink after runtime guard probes |
207-
| **P-013** (iOS aggregate skip L3740) | Unrelated to guard list — separate SDK/bridge investigation |
208-
| **P-001, P-005, P-010–P-012** (bridge gaps) | Unchanged — operand coercion is independent of function guard list |
194+
| **P-013** (iOS aggregate skip L3740) | Unrelated — separate SDK/bridge investigation |
195+
| **P-001, P-005, P-010–P-012** (bridge gaps) | Unchanged — operand coercion is independent of function support matrix |
209196

210197
## Recommended remediation order
211198

212199
Live order/gates: [work queue](pipeline-coverage-work-queue.md).
213200

214201
| Step | Work |
215202
|------|------|
216-
| **1** | iOS runtime guard probes — one commit per confirmed guard removal ([§6](#6-runtime-verification-authoritative)) |
203+
| **1** | iOS runtime bridge probes + unified e2e ([§6](#6-runtime-verification-authoritative)) |
217204
| **2** | P-001 Android operand coercion |
218205
| **3–7** | Remaining bridge items from [parity registry](pipeline-platform-parity.md) |
219206

220-
**Do not** treat P-003 e2e reduced pipelines as permanent SDK limitations until runtime verification completes.
207+
Treat reduced iOS e2e branches as bridge/SDK gaps until native lowering or SDK support is confirmed.
221208

222209
---
223210

@@ -229,4 +216,4 @@ Live order/gates: [work queue](pipeline-coverage-work-queue.md).
229216
- [ ] Diff **native** Firestore CHANGELOGs since last audit (layer C)
230217
- [ ] Re-run bridge lowering grep for new/changed function names
231218
- [ ] Update matrix; run **runtime guard probes** for any function moving from “unsupported” to “CHANGELOG added” on **native**
232-
- [ ] Sync `pipeline_support.ts` ↔ Swift comment ↔ parity doc
219+
- [ ] Sync parity doc ↔ native lowering comments

0 commit comments

Comments
 (0)