From b10a69904db888e27ba7d3152e99c0fb57288983 Mon Sep 17 00:00:00 2001 From: Ivan Vasilov Date: Sat, 26 Sep 2026 21:55:41 +0200 Subject: [PATCH] feat: add defaultStringCollation option to supabaseCollectionOptions Exposes @tanstack/db's defaultStringCollation on SupabaseCollectionOptions and forwards it to queryCollectionOptions, defaulting to { stringSort: 'lexical' } so string ordering is predictable when a query's orderBy clause doesn't specify its own compareOptions. Co-Authored-By: Claude Sonnet 5 --- README.md | 1 + src/db.ts | 14 +++++++++++++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 0392ee3..4734c88 100644 --- a/README.md +++ b/README.md @@ -134,6 +134,7 @@ const todos = createCollection( | `realtime` | `boolean` | No | When `true`, subscribes to Postgres changes and reconciles inserts, updates, and deletes into the collection. Defaults to `false`. | | `realtimeUseFilter` | `boolean` | No | **Experimental.** Only applies when `realtime` is `true`. When `true`, each active query's `WHERE` clause is pushed to the Realtime subscription as a `postgres_changes` filter, so the channel only receives changes those queries care about. Defaults to `false`, which subscribes to every change on the table and filters client-side — simpler, at the cost of more Realtime traffic. Queries whose `WHERE` cannot be expressed as a Realtime filter (e.g. `or(...)`) transparently fall back to the unfiltered subscription. | | `queryClient` | `QueryClient` | No | TanStack Query client. If omitted, a shared global client is used. | +| `defaultStringCollation` | `StringCollationConfig` | No | Controls how string columns are compared when ordering, matching the database's collation settings. Defaults to `{ stringSort: 'lexical' }` (byte-order comparison). Pass `{ stringSort: 'locale', locale, localeOptions }` for locale-aware sorting. | **Returns** a collection options object to pass to `createCollection`. diff --git a/src/db.ts b/src/db.ts index ae2ec69..1ba8439 100644 --- a/src/db.ts +++ b/src/db.ts @@ -1,7 +1,11 @@ /* biome-ignore-all lint/suspicious/noExplicitAny: collection items are typed by the caller's schema, not statically known here */ import type { StandardSchemaV1 } from "@standard-schema/spec" import type { SupabaseClient } from "@supabase/supabase-js" -import { BasicIndex, type Collection } from "@tanstack/db" +import { + BasicIndex, + type Collection, + type StringCollationConfig, +} from "@tanstack/db" import type { QueryClient } from "@tanstack/query-core" import { queryCollectionOptions } from "@tanstack/query-db-collection" import { @@ -15,6 +19,12 @@ import { getQueryClient } from "./query-client" import { syncTableSubscription, type TableEntry } from "./realtime" interface SupabaseCollectionOptions { + /** + * Controls how string columns are compared when ordering, matching the + * database's collation settings. Defaults to `{ stringSort: 'lexical' }` + * (byte-order comparison). + */ + defaultStringCollation?: StringCollationConfig /** * The columns that uniquely identify a row. Used to extract the key for * storing the item in the collection and to build the where clause for @@ -97,6 +107,7 @@ export const supabaseCollectionOptions = ({ supabase, realtime, realtimeUseFilter = false, + defaultStringCollation = { stringSort: `lexical` }, }: SupabaseCollectionOptions) => { // if the query client is not provided, use the global query client queryClient = queryClient ?? getQueryClient() @@ -139,6 +150,7 @@ export const supabaseCollectionOptions = ({ onDelete: (ctx) => supabaseOnDelete(supabase, tableName, keyColumns, ctx), autoIndex: "eager", defaultIndexType: BasicIndex, + defaultStringCollation, }) const originalSync = config.sync.sync