// Package cursor implements Relay-style cursor pagination for go-jet MySQL queries. // // It encodes opaque cursor strings from column values, generates matching WHERE and // ORDER BY clauses, and builds GraphQL Relay–compatible Connection results with // PageInfo and total counts. // // # Requirements // // - [github.com/go-jet/jet/v2/mysql] generated table and column types // - [gitea.auvem.com/go-toolkit/dbx.Queryable] for running queries (optional when // building SQL manually) // // # Setup // // Call [RegisterColumn] (or [RegisterColumnList]) at application startup for every // column referenced by a cursor—index column, order column, and any column held in // OrderValue. The registry resolves columns when encoding, decoding, and building SQL. // [Cursor.OrderCol], value Col methods, and [GetColumnByKey] panic when a column is // not registered. // // # Pagination modes // // Simple pagination sorts and filters on a single column (typically the primary key). // When the order column differs from the index column, tuple ordering applies: // results sort by (order_col, index_col). See [Cursor.UsesTupleOrdering]. // // Composite cursors extend tuple ordering with an encoded OrderValue on each edge. // Required for correct after pagination when sort values can repeat (for example, // many rows sharing the same timestamp). See [Cursor.IsComposite] and [CopyWithVals]. // // # API overview // // Setup — [RegisterColumn], [RegisterColumnList], [GetColumn], [GetColumnByKey] // // Cursor construction — [NewCursor], [NewInt64Value], [NewUint64Value], // [NewStringValue], [NewTimestampValue], [CopyWithVal], [CopyWithVals] // // Serialization — [Cursor.Encode], [Cursor.Decode], [Cursor.DecodeAndOrder], // [NewCursorFromAfterPtr], [NewCursorFromJSON] // // Query integration — [PaginateConds], [OrderByClauses], [QueryCount], [BuildQueryCountFn] // // Relay layer — [PageQuery], [BuildEdges], [ConnectionFromRelayArgs], [Connection], // [PageInfo], [Edge] // // Utilities — [ExtractNodes], [DereferenceSlice] // // # Extension points // // Consumers may define custom cursor value types by implementing the interfaces below. // Built-in types ([Int64Value], [StringValue], and others) demonstrate the pattern. // // [GenericExpr] is the untyped value contract shared by index and order columns. // Implement ColumnKey, IsEmpty, and driver.Valuer. Use JSON struct tags matching // the built-in value types when values are encoded inside a cursor. // // [ExprMarshaler] extends GenericExpr for index columns. Implement Expr and Col to // produce type-safe go-jet expressions. Col requires the column to be registered. // Custom index types that are not handled by the built-in type switch in pagination // fall back to raw SQL comparisons; registering the column is still required. // // [GenericCursor] is implemented by [Cursor] and is the interface used when building // edges, counting pages, and applying pagination conditions without concrete type // parameters. // // OrderValue decoding selects a built-in wrapper type from the registered go-jet // column type (string, integer, timestamp). Custom order values should use one of // the built-in value types or match their JSON shape for the corresponding column // kind. package cursor