Parent
Part of #372 (ADR-0018).
What to build
after() understands nullable order keys and empty position slots. Crossing from a non-NULL leading key into the NULL bucket (the pinned-first conversation list) is one query. None is legal in every non-PK slot; the PK slot still cannot be empty. Column nullability is not consulted — a left_join'd NOT NULL related column may still be NULL when the relation is missing.
Lifts the nullable-order-key refusal from #393.
Acceptance criteria
Blocked by
Parent
Part of #372 (ADR-0018).
What to build
after()understands nullable order keys and empty position slots. Crossing from a non-NULL leading key into the NULL bucket (the pinned-first conversation list) is one query.Noneis legal in every non-PK slot; the PK slot still cannot be empty. Column nullability is not consulted — aleft_join'd NOT NULL related column may still be NULL when the relation is missing.Lifts the nullable-order-key refusal from #393.
Acceptance criteria
after((None, id))continues through the NULL bucket of a leading nullable key (nulls="last"DESC — the Pinch shape).afteron a non-NULL position includes the later NULL-bucket rows when null placement puts NULLs after the cursor.Nonein a non-PK slot is legal;Nonein the PK slot is a build-time error.left_join+Nonefor a NOT NULL related column is a legal position (when traversal is in scope this is tested there; the expansion must already allow it).IS NULLtree from each order key's direction and null placement. Both dialects consume it.nativeresolves at render, not in Python.Blocked by