Determines subquery index effects for dependency move events.
The subquery index tracks which values are present in the dependency view. When a move event occurs, the index must be updated — but the timing of that update depends on whether the move triggers buffering.
Broadening and narrowing
While a move-in is being buffered, transactions continue to arrive and must be filtered. To avoid missing relevant rows, the index is broadened (made more permissive) as soon as buffering starts. Once the move-in query completes and the splice is done, the index is narrowed back to its final state.
For a positive (IN) subquery:
- Adding values to the index broadens the filter (more rows match).
- So a move-in adds to the index when buffering starts.
For a negated (NOT IN) subquery:
- Adding values to the index narrows the filter (fewer rows match).
- So a dependency move-in does not update the index when buffering starts (keeping the filter broad); the add is deferred until complete.
- A dependency move-out broadens the filter by removing the value from the index immediately, and that removal remains correct after the splice.
Effect tables
When buffering starts
| Dep move | Polarity | Index effect |
|---|---|---|
| move_in | positive | AddToSubqueryIndex |
| move_in | negated | (none) |
| move_out | positive | (none) |
| move_out | negated | RemoveFromSubqueryIndex |
When complete (splice finished, or immediate for non-buffering cases)
| Dep move | Polarity | Index effect |
|---|---|---|
| move_in | positive | (none) |
| move_in | negated | AddToSubqueryIndex |
| move_out | positive | RemoveFromSubqueryIndex |
| move_out | negated | (none) |
Caller conventions
- Non-buffering cases (positive move-out, negated move-in): the move
completes atomically, so callers use
effects_for_complete/3. - Buffering cases (positive move-in, negated move-out): callers use
effects_for_buffering/3when entering buffering andeffects_for_complete/3at splice time.
Summary
Functions
Returns index effects to apply when a dependency move event starts buffering.
Returns index effects to apply when a move event completes.
Types
@type move() :: {:move_in | :move_out, non_neg_integer(), list()}
Functions
@spec effects_for_buffering(Electric.Shapes.DnfPlan.t(), move(), [String.t()]) :: [ Electric.Shapes.Consumer.Effects.AddToSubqueryIndex.t() | Electric.Shapes.Consumer.Effects.RemoveFromSubqueryIndex.t() ]
Returns index effects to apply when a dependency move event starts buffering.
Used only by buffering cases to broaden the filter before the move-in query runs. Calling this for an immediate (non-buffering) move is a bug in the caller.
@spec effects_for_complete(Electric.Shapes.DnfPlan.t(), move(), [String.t()]) :: [ Electric.Shapes.Consumer.Effects.AddToSubqueryIndex.t() | Electric.Shapes.Consumer.Effects.RemoveFromSubqueryIndex.t() ]
Returns index effects to apply when a move event completes.
For buffering cases this is called at splice time. For non-buffering cases (where the move completes atomically) this is the only function called.