(
deltaA: Index<K, V1>,
deltaB: Index<K, V2>,
results: MultiSet<any>,
)
| 193 | } |
| 194 | |
| 195 | private emitRightOuterResults( |
| 196 | deltaA: Index<K, V1>, |
| 197 | deltaB: Index<K, V2>, |
| 198 | results: MultiSet<any>, |
| 199 | ): void { |
| 200 | // Emit unmatched right rows from deltaB |
| 201 | if (deltaB.size > 0) { |
| 202 | for (const [key, valueIterator] of deltaB.entriesIterators()) { |
| 203 | const currentMultiplicityA = |
| 204 | this.#indexA.getConsolidatedMultiplicity(key) |
| 205 | const deltaMultiplicityA = deltaA.getConsolidatedMultiplicity(key) |
| 206 | const finalMultiplicityA = currentMultiplicityA + deltaMultiplicityA |
| 207 | |
| 208 | if (finalMultiplicityA === 0) { |
| 209 | for (const [value, multiplicity] of valueIterator) { |
| 210 | if (multiplicity !== 0) { |
| 211 | results.add([key, [null, value]], multiplicity) |
| 212 | } |
| 213 | } |
| 214 | } |
| 215 | } |
| 216 | } |
| 217 | |
| 218 | // Handle presence transitions from left side changes |
| 219 | if (deltaA.size > 0) { |
| 220 | for (const key of deltaA.getPresenceKeys()) { |
| 221 | const before = this.#indexA.getConsolidatedMultiplicity(key) |
| 222 | const deltaMult = deltaA.getConsolidatedMultiplicity(key) |
| 223 | if (deltaMult === 0) continue |
| 224 | const after = before + deltaMult |
| 225 | |
| 226 | // Skip transition handling if presence doesn't flip (both zero or both non-zero) |
| 227 | // Note: Index updates happen later regardless - we're only skipping null-extension emissions here |
| 228 | if ((before === 0) === (after === 0)) continue |
| 229 | |
| 230 | // Determine the type of transition: |
| 231 | // - 0 → non-zero: Left becomes non-empty, right rows transition from unmatched to matched |
| 232 | // → RETRACT previously emitted null-extended rows (emit with negative multiplicity) |
| 233 | // - non-zero → 0: Left becomes empty, right rows transition from matched to unmatched |
| 234 | // → EMIT new null-extended rows (emit with positive multiplicity) |
| 235 | const transitioningToMatched = before === 0 |
| 236 | |
| 237 | for (const [value, multiplicity] of this.#indexB.getIterator(key)) { |
| 238 | if (multiplicity !== 0) { |
| 239 | results.add( |
| 240 | [key, [null, value]], |
| 241 | transitioningToMatched ? -multiplicity : +multiplicity, |
| 242 | ) |
| 243 | } |
| 244 | } |
| 245 | } |
| 246 | } |
| 247 | } |
| 248 | } |
| 249 | |
| 250 | /** |
no test coverage detected