supastash
Version:
Offline-first sync engine for Supabase in React Native using SQLite
72 lines (71 loc) • 2.88 kB
JavaScript
import { useEffect } from "react";
import { tableFilters, tableFiltersUsed } from "../../store/tableFilters";
import { logWarn } from "../../utils/logs";
import isValidFilter, { warnOnMisMatch, } from "../../utils/sync/pullFromRemote/validateFilters";
import { checkIfTableExist } from "../../utils/tableValidator";
function warnInvalidFilter(filter, table) {
logWarn(`[Supastash] Invalid filter: ${JSON.stringify(filter)} for table ${table}`);
}
/**
* useSupastashFilters
*
* @description
* Registers filters used for Supastash pull sync logic.
*
* This hook should be called at app startup or anywhere your filter configuration might change.
* You should provide filters for **all tables** unless your Supabase project uses strict SELECT RLS (Row Level Security) policies.
*
* The hook validates filter structure, warns about invalid filters, and detects any mismatch in column/operator structure
* to prevent sync inconsistencies.
*
* 🚨 Incorrect or mismatched filters can lead to unreliable syncing behavior.
*
* @example
* ```ts
* useSupastashFilters({
* orders: [
* { column: "shop_id", operator: "eq", value: currentShopId },
* { column: "status", operator: "in", value: ["pending", "completed"] },
* ],
* inventory: [
* { column: "location_id", operator: "eq", value: activeLocationId },
* ],
* });
* ```
*
* @param {SupastashFilter} filters - An object where each key is a table name, and its value is
* an array of `RealtimeFilter` objects that define the filter criteria for that table's pull sync.
*
* @note This hook does not re-run unless the `filters` object reference changes.
* To force re-evaluation, pass a fresh object (not just mutated data).
*/
export default function useSupastashFilters(filters) {
useEffect(() => {
const addFilters = async () => {
for (const table in filters) {
const tableInDb = await checkIfTableExist(table);
if (!tableInDb) {
logWarn(`Table ${table} does not exist`);
continue;
}
const filtersForTable = filters[table];
if (!filtersForTable) {
logWarn(`No filters for table ${table}`);
continue;
}
const validFilters = filtersForTable.filter((f) => {
const isValid = isValidFilter([f]);
if (!isValid)
warnInvalidFilter(f, table);
return isValid;
});
if (validFilters.length > 0) {
warnOnMisMatch(table, validFilters);
tableFilters.set(table, validFilters);
tableFiltersUsed.add(table);
}
}
};
void addFilters();
}, [filters]);
}