taruvi-database
Overview
Reference module for all Taruvi datatable and database query work — covering Refine hooks, query operators, aggregation patterns, and performance rules for summary views.
Compliance rule: This skill's prescribed query strategies (server-side search/filter/sort for lists, debounced Autocomplete for dropdowns) are mandatory, not suggestions. Do not fall back to simpler patterns. If a requirement cannot be met, stop and ask the user.
When to Use This Skill
- Building a list, table, or detail screen backed by a Taruvi datatable
- Writing or optimizing filtered/sorted/paginated queries
- Building dashboard KPI cards or summary charts
- Using
useList,useOne,useMany,useCreate,useUpdate,useDelete, oruseDeleteMany - Implementing
groupBy,aggregate, orhavingfor grouped metrics - Modeling graph relationships between datatables
Do not use this skill for: raw storage file queries (use taruvi-storage skill), user management CRUD (use taruvi-refine-providers skill with userDataProvider), or multi-resource operations (use taruvi-functions skill).
Step-by-Step Instructions
- Open and read
../taruvi-refine-providers/references/database-provider.mdfor the full query API (CRUD, filters, sorting, pagination, aggregation, graph). - Confirm the current non-deprecated package path for the data operation you are about to use.
- Do not introduce new code on deprecated providers, hooks, or compatibility helpers.
- Identify the query shape needed:
- List/table UI → plain filtered row query with pagination
- Dashboard card / KPI (single table) → datatable
groupBy+aggregate - Dashboard element needing data from 2+ tables → saved analytics query via
appDataProvider+useCustom - Related data → graph options with
include/depthmeta keys
- Apply the preference order:
- single-table aggregates via datatable provider for most dashboard metrics
- saved analytics queries when a dashboard element needs data from 2+ tables
- raw row queries only when the page actually needs rows
- never fetch full row sets into React to derive summary metrics
- For every backend-backed list UI:
- backend pagination is required by default
- default list
pageSizeis10; recommend supporting10,20,50, and100as selectable sizes - search, filters, and sort order must be pushed into the backend query by default
- list pages should expose visible search input and relevant filter controls by default
- when the list uses MUI
DataGrid, default to RefineuseDataGridso pagination/filter/sort state stays server-driven - do not fetch rows and apply the primary list filtering/search logic in React unless the user explicitly asks for client-side behavior
- For every network-backed dropdown/typeahead:
- query options from the backend with pagination (default option
pageSize10) - debounce search input
- push the search term into backend filters
- avoid preloading large option sets and filtering them client-side
- query options from the backend with pagination (default option
- Validate the query shape scales — avoid N+1 patterns.
Verification checklist
After writing queries, verify:
- Single-table dashboard metrics use datatable
aggregate+groupBy; dashboard elements needing data from 2+ tables use saved analytics queries - Dashboard/summary views use one
aggregate + groupByquery, not N separate filtered queries - All list UIs include
paginationwith a reasonablepageSize - List views default to
pageSize10and support10/20/50/100options unless explicitly scoped otherwise - All backend-backed list filtering, search, and sorting are server-side by default
- Backend-backed list pages include visible search and relevant filter controls by default (or explicit user-requested omission)
- Backend-backed MUI
DataGridlists useuseDataGridby default (or include an explicit reason they cannot) - Network-backed dropdown/typeahead options are loaded with debounced server-side search and pagination
- Graph queries have an explicit
depthlimit -
havingis only used after agroupBy, never as a substitute forfilters - No N+1 patterns (e.g., looping
useOnecalls inside a list render) - No page fetches full row sets into React just to derive cards, pies, or trend charts
- No backend-backed list page applies its primary search/filter logic in React unless the user explicitly requested client-side behavior
Examples
Filtered list with pagination:
const { data } = useList({
resource: "orders",
filters: [{ field: "status", operator: "eq", value: "pending" }],
sorters: [{ field: "created_at", order: "desc" }],
pagination: { pageSize: 10 },
});
Recommended page-size options for list UIs: 10, 20, 50, 100 (default 10).
List UX baseline (production-ready):
- Include a visible search input and common filters (for example status/department/date).
- Bind search/filter state to backend query params.
- Keep list state URL-syncable when possible.
Single-table dashboard (datatable aggregate):
const { data } = useList({
resource: "orders",
meta: {
aggregate: ["count"],
groupBy: ["status"],
},
});
// Returns: [{ status: "pending", count: 14 }, { status: "completed", count: 82 }]
Post-aggregation filter with having:
meta: {
aggregate: ["count"],
groupBy: ["team"],
having: { count__gte: 5 },
}
Multi-table dashboard element — saved analytics query (required when element needs data from 2+ tables):
const { result } = useCustom({
url: "hrms-dashboard-summary",
method: "post",
dataProviderName: "app",
payload: {},
meta: { kind: "analytics" },
});
Gotchas
- N separate queries for a dashboard — if you see separate
useListcalls per status/category to build a summary, that is a performance bug. Replace with onegroupByquery for single-table data, or a saved analytics query if the element needs data from 2+ tables. - Full row fetch for KPI pages — if a dashboard pulls complete table rows into React and then computes totals/charts client-side, that is a bug. Always push aggregation to the server.
- Deprecated query path — if a dashboard only works through a deprecated package path, do not ship that as the final implementation. Resolve the canonical package API first.
- Graph data without depth limit — always set
depthwhen using graph/edge queries. Without it, the query traverses unbounded relationships and will time out on any non-trivial dataset. havingwithoutgroupBy—havingonly works after agroupBy. It is not a substitute for afiltersclause. Usinghavingalone silently returns no results.- Large datasets without pagination — always add
paginationfor list UIs. Unbounded queries will time out on tables with >1000 rows. - Client-side list filtering on backend data — if a list fetches backend rows and then applies its main search or filter logic in React, that is a correctness and scalability smell. Move that logic into backend filters/sorters unless the user explicitly asked for local filtering.
- No list controls — backend-backed lists without visible search/filter controls are usually not production-ready unless the user explicitly requested a minimal table.
- Manual MUI grid state wiring — if a backend-backed MUI
DataGridlist hand-wires pagination/filter/sort state withuseList, preferuseDataGridunless there is a concrete limitation that requires manual wiring. - Client-filtered remote dropdown options — if a dropdown fetches remote options once and filters locally, it will miss matches and fail to scale. Use debounced server-side search with paginated option loading.
aggregateexpects an array —aggregate: "count"will fail silently. Useaggregate: ["count"].- Filter operator typos — the operator is
"eq", not"equals"or"=". Common operators:eq,ne,lt,gt,lte,gte,contains,in.
References
../taruvi-refine-providers/references/database-provider.md— core operations, query features, aggregation patterns, graph
More from taruvi-ai/taruvi-skills
taruvi-app-developer
>
19taruvi-functions
>
18taruvi-storage
>
18taruvi-refine-providers
>
18taruvi-backend-provisioning
Provision Taruvi backend resources via the Taruvi MCP server — datatables with Frictionless schemas, storage buckets, users, roles, Cerbos policies, serverless functions, analytics queries, secrets, tags, and audited raw SQL. Use when the user wants to create a datatable, add a role, write a Cerbos policy, provision a bucket, upsert schema, assign a role, register a function, run an analytics query, or otherwise change Taruvi's backend state. TRIGGERS include "Taruvi datatable", "Frictionless schema", "Cerbos policy", "manage_policies", "provision Taruvi", "upsert rows", "multi-tenant table", "Taruvi MCP tools", "create_update_schema", "delete_datatable", "execute_raw_sql". SKIP when writing Python code that runs inside a Taruvi function (use taruvi-functions) or building Refine UI (use taruvi-refine-frontend). Knows all 24 MCP tool contracts, correct invocation order, destructive-op protocol, and the Frictionless/Cerbos essentials the tools expect.
8