Connect a Refine application
@taruvi/refine-providers connects Refine data hooks to app-scoped TaruviBase
tables. The provider maps Refine resources, filters, sorters, pagination, and
query metadata to the same Database API the JavaScript SDK uses.
Use the provider for Refine list, detail, and form views:
- list, read-one, and read-many hooks;
- create, update, and delete hooks, including upserts and filtered deletes
through
meta; - aggregates through
meta.aggregate,meta.groupBy, andmeta.having; - vector and hybrid queries through explicit flat query parameters;
- flat and nested
AND/ORfilters; - sorting and server pagination;
- field projection; and
- per-record action hints.
Install the packages#
npm install \
@refinedev/core \
@taruvi/refine-providers \
@taruvi/sdk
Register the provider#
Create one browser client and pass it to dataProvider. The resource name
maps to the table name unless a hook supplies meta.tableName.
import {Refine} from '@refinedev/core';
import {dataProvider} from '@taruvi/refine-providers';
import {Auth, Client} from '@taruvi/sdk';
const client = new Client({
apiUrl: import.meta.env.VITE_TARUVI_SITE_URL,
appSlug: import.meta.env.VITE_TARUVI_APP_SLUG,
});
const auth = new Auth(client);
export function App() {
if (!auth.hasToken()) {
return <button onClick={() => auth.login()}>Sign in to TaruviBase</button>;
}
return (
<Refine
dataProvider={dataProvider(client)}
resources={[{name: 'tasks'}]}
/>
);
}
The JavaScript SDK captures the hosted-login callback's session_token in
the browser, stores it locally, and sends it through X-Session-Token. Do not
pass the token constructor option in browser code; that option is read only
by non-browser runtimes. Never put an API key in browser code.
Define the record type#
Refine records need an id. Match the remaining fields to the TaruviBase table
schema:
type Task = {
id: string;
title: string;
done: boolean;
};
Import the hooks and filter helper once, then keep each task example focused on the operation:
import {useList, useMany, useOne} from '@refinedev/core';
import {toRefineFilters} from '@taruvi/refine-providers';
List records#
Place data hooks inside a component rendered beneath <Refine>.
useList<Task>({
resource: 'tasks',
filters: [{field: 'done', operator: 'eq', value: false}],
sorters: [
{field: 'title', order: 'asc'},
{field: 'id', order: 'asc'},
],
pagination: {
currentPage: 1,
pageSize: 20,
mode: 'server',
},
});
Refine 5 exposes the records and matching count through result.data and
result.total. Request state is available through query.
Read one record#
useOne<Task>({
resource: 'tasks',
id: 'TASK_UUID',
});
The provider calls the single-record Database route and maps its data object
to the hook result.
Read several records by ID#
Use useMany when a view already has a bounded set of primary keys. In this
example, taskIds is an array of task UUIDs.
useMany<Task>({
resource: 'tasks',
ids: taskIds,
});
Refine 5 exposes the returned records through result.data. TaruviBase's provider
maps useMany to one Database list query with an in filter on id; set
meta.idColumnName only when the table's primary key isn't id.
Select fields#
Use TaruviBase metadata when a query needs only part of each record:
useList<Pick<Task, 'id' | 'title' | 'done'>>({
resource: 'tasks',
pagination: {currentPage: 1, pageSize: 20, mode: 'server'},
meta: {
select: ['id', 'title', 'done'],
},
});
Compose nested filters#
Use toRefineFilters when a query includes TaruviBase-specific operators or a
nested logical group. The provider converts the logical object to the
Database JSON filter tree.
useList<Task>({
resource: 'tasks',
filters: toRefineFilters({
operator: 'and',
value: [
{field: 'done', operator: 'eq', value: false},
{
operator: 'or',
value: [
{field: 'title', operator: 'contains', value: 'release'},
{field: 'title', operator: 'contains', value: 'docs'},
],
},
],
}),
pagination: {currentPage: 1, pageSize: 20, mode: 'server'},
});
Import toRefineFilters from @taruvi/refine-providers to compose nested
and and or groups. For negation, use inverse operators such as ne, nin,
ncontains, or nnull, or send the serialized tree shown in
Negate a condition.
Read related records#
Read the root rows first, collect their foreign-key values, and issue a
second bounded useList query for the related table, so each table gets its
own access check. Join the results by their foreign-key values in the component
or data layer. See the complete
related-record workflow.
Request allowed actions#
The provider maps meta.allowedActions to the Database
allowed_actions query parameter:
useList<Task>({
resource: 'tasks',
meta: {allowedActions: ['update', 'delete']},
pagination: {currentPage: 1, pageSize: 20, mode: 'server'},
});
When enabled by the service, each row can include an _allowed_actions array
for UI affordances. Treat it as a hint for the current response; every
mutation is still authorized by the server when it is submitted.
Provider mapping#
| Refine input | TaruviBase request |
|---|---|
resource | Table name |
useMany.ids | in filter on id, or meta.idColumnName |
pagination.currentPage | page |
pagination.pageSize | page_size |
sorters | ordering |
| Field filters | field or field__operator |
meta.select | fields |
meta.tableName | Table-name override |
meta.search | search |
meta.allowedActions | allowed_actions |
Keep pagination in server mode for paged TaruviBase collections. Use
pagination: {mode: 'off'} only when the request should omit pagination
parameters.
Search and aggregate#
Use full-text, vector, and hybrid queries
for ranked or keyword retrieval. Full-text search uses meta.search; vector
and hybrid controls use flat eq filters with the API's exact query parameter
names. Keep those controls outside nested logical groups.
Use aggregation metadata to
count, group, calculate summaries, and filter groups. Summary rows are in
result.data; for an ungrouped count, read result.data[0].count after success.
Write records#
useCreate, useUpdate, and useDelete create, update, and delete records;
useCreateMany, useUpdateMany, and useDeleteMany work on several at once.
meta.upsert inserts or updates on the primary key, and
meta.deleteByFilter deletes every record that matches meta.filters. See the
Refine data provider reference. Use
TaruviBase Console for one-off changes.
Follow the record examples for hook
bindings and event handlers. For batches, see the
bulk-operation examples:
useCreateMany sends separate requests, useUpdateMany applies one shared
values object, and useDeleteMany returns the submitted IDs. Read those IDs
again to confirm deletion.