pub enum PaginationOrder {
JsonIdentity,
Column(String),
}Expand description
The total order a LIMIT/OFFSET page falls back to when the client asked
for none (#1303).
A page is a slice of a sequence, and a read with no ORDER BY is not a
sequence: PostgreSQL may return the same relation in a different physical
order for each page, so a client walking ?offset= sees some rows twice and
never sees others — under 200, with no error anywhere. #1287 closed the
half of that where the client did order and the ordering was not total;
this closes the half where it ordered by nothing at all.
§Why the compiler decides and not the SQL layer
A tie-breaker and a default ordering are different things. A tie-breaker has
no semantic content — any total order disambiguates ties inside an ordering
the client chose — so the SQL layer may pick one unaided. A default ordering
decides what “page 2” means when nobody said, which is the schema
author’s call, and choosing well needs the schema: measured against
PostgreSQL 16 over 200 000 rows at a deep offset, data->>'id' costs 7.7×
the unordered plan, a native id column 4.2×, and pk_<type> 1.7×. The
only one of the three a request-time rule can reach without help is the
worst.
This is why the field is derived at compile time and sits beside
relay_cursor_column: the other
pagination family already declares its ordering key in the compiled schema,
for the same reason.
§Deliberately not #[non_exhaustive]
A downstream match over this enum must be exhaustive, so a third way to
reach an identity is a compile error at every site that lowers one rather
than a wildcard arm that silently renders nothing.
Variants§
JsonIdentity
ORDER BY data->>'id' ASC — the entity identity extracted from the JSONB
document as text.
Correct for every type under ADR-0017, which is why it is the answer a
compile with no --database can always give: id is an enforced
invariant, and comparing it as text serves uuid, integer and text keys
alike without knowing which one a type declares. It is also the most
expensive of the three — no index applies — so a compile that can
introspect the relation replaces it with Column.
Column(String)
ORDER BY <column> ASC — a native column on the relation.
Either declared by the author or discovered by introspection
(pk_<type>, then id). The column must be unique over the
relation: a non-unique one leaves the order partial, which is the defect
this field exists to remove rather than a cheaper way to fix it. Nothing
in the catalog reports uniqueness for a view, so a declared column is
checked for existence and taken on trust.
Trait Implementations§
Source§impl Clone for PaginationOrder
impl Clone for PaginationOrder
Source§impl Debug for PaginationOrder
impl Debug for PaginationOrder
Source§impl<'de> Deserialize<'de> for PaginationOrder
impl<'de> Deserialize<'de> for PaginationOrder
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl Eq for PaginationOrder
Source§impl PartialEq for PaginationOrder
impl PartialEq for PaginationOrder
Source§impl Serialize for PaginationOrder
impl Serialize for PaginationOrder
impl StructuralPartialEq for PaginationOrder
Auto Trait Implementations§
impl Freeze for PaginationOrder
impl RefUnwindSafe for PaginationOrder
impl Send for PaginationOrder
impl Sync for PaginationOrder
impl Unpin for PaginationOrder
impl UnsafeUnpin for PaginationOrder
impl UnwindSafe for PaginationOrder
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
Source§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.