RippleDB
RippleDB
InternalArchitecture

Query Model & Invalidation

Why row queries can be precise, list queries must be rerun, and sorting is the same class as filtering.

10. Query model (critical section)

This is where most systems fall apart. This is also where we made very explicit choices.

10.1 Two classes of queries

We distinguish two fundamentally different kinds of queries:

A) Row queries

  • Fetch a single entity by ID
  • Example:
SELECT * FROM inquiries WHERE id = ?

B) List queries

  • Any query with:
    • WHERE
    • ORDER BY
    • JOIN
    • aggregates
    • pagination

Examples:

SELECT id FROM inquiries WHERE status = 'open'
SELECT i.*, c.name FROM inquiries i JOIN customers c ...

10.2 Why this distinction matters

Row queries:

  • membership is fixed
  • can be invalidated precisely

List queries:

  • membership & ordering are dynamic
  • cannot be safely incrementally updated without understanding SQL
  • must be rerun

This is not a limitation of our system — it’s a property of SQL.

11. Broad invalidation is intentional

11.1 The core insight

Without parsing SQL or re-implementing it in JS:

You cannot know whether a list query’s result changed.

This applies to:

  • filtering
  • sorting
  • joins
  • pagination

Therefore:

All list queries must be invalidated broadly.

11.2 Example (why precision is impossible)

SELECT id FROM inquiries WHERE date > '2002-01-11'

If a row changes date, you cannot know in JS whether it:

  • entered the list
  • left the list
  • moved pages

Unless you run the query again. So we do.

11.3 Policy summary

Query TypeInvalidation Strategy
Row queryPrecise (by ID)
List queryBroad (rerun whole query)

This is a design choice, not a shortcut.

12. Sorting & filtering

Sorting is the same problem class as filtering.

If a field used in ORDER BY changes:

  • row position may change
  • page boundaries may change

Therefore:

  • sorting also requires broad invalidation
  • there is no special case

On this page