* feat: add changelog feature and update site navigation - Introduced a new Changelog page with pagination and detailed entry views. - Added components for displaying changelog entries, pagination, and entry details. - Updated site navigation to include a link to the new Changelog page. - Enhanced localization for changelog-related texts in marketing.json. * refactor: enhance Changelog page layout and entry display - Increased the number of changelog entries displayed per page from 2 to 20 for better visibility. - Improved the layout of the Changelog page by adjusting the container styles and removing unnecessary divs. - Updated the ChangelogEntry component to enhance the visual presentation of entries, including a new date badge with an icon. - Refined the CSS styles for Markdoc headings to improve typography and spacing. * refactor: enhance Changelog page functionality and layout - Increased the number of changelog entries displayed per page from 20 to 50 for improved user experience. - Updated ChangelogEntry component to make the highlight prop optional and refined the layout for better visual clarity. - Adjusted styles in ChangelogHeader and ChangelogPagination components for a more cohesive design. - Removed unnecessary order fields from changelog markdown files to streamline content management. * feat: enhance Changelog entry navigation and data loading - Refactored ChangelogEntry page to load previous and next entries for improved navigation. - Introduced ChangelogNavigation component to facilitate navigation between changelog entries. - Updated ChangelogDetail component to display navigation links and entry details. - Enhanced data fetching logic to retrieve all changelog entries alongside the current entry. - Added localization keys for navigation text in marketing.json. * Update package dependencies and enhance documentation layout - Upgraded various packages including @turbo/gen and turbo to version 2.6.0, and react-hook-form to version 7.66.0. - Updated lucide-react to version 0.552.0 across multiple packages. - Refactored documentation layout components for improved styling and structure. - Removed deprecated loading components and adjusted navigation elements for better user experience. - Added placeholder notes in changelog entries for clarity.
431 lines
7.4 KiB
Plaintext
431 lines
7.4 KiB
Plaintext
---
|
|
title: "Querying Data"
|
|
description: "Learn how to query and filter data from your database."
|
|
publishedAt: 2024-04-11
|
|
order: 3
|
|
status: "published"
|
|
---
|
|
|
|
> **Note:** This is mock/placeholder content for demonstration purposes.
|
|
|
|
Efficiently query and filter data using Supabase's query builder.
|
|
|
|
## Basic Queries
|
|
|
|
### Select All
|
|
|
|
```typescript
|
|
const { data, error } = await client
|
|
.from('projects')
|
|
.select('*');
|
|
```
|
|
|
|
### Select Specific Columns
|
|
|
|
```typescript
|
|
const { data, error } = await client
|
|
.from('projects')
|
|
.select('id, name, created_at');
|
|
```
|
|
|
|
### Select with Related Data
|
|
|
|
```typescript
|
|
const { data, error } = await client
|
|
.from('projects')
|
|
.select(`
|
|
id,
|
|
name,
|
|
account:accounts(id, name),
|
|
tasks(id, title, completed)
|
|
`);
|
|
```
|
|
|
|
## Filtering
|
|
|
|
### Equal
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select('*')
|
|
.eq('status', 'active');
|
|
```
|
|
|
|
### Not Equal
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select('*')
|
|
.neq('status', 'deleted');
|
|
```
|
|
|
|
### Greater Than / Less Than
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select('*')
|
|
.gt('created_at', '2024-01-01')
|
|
.lt('budget', 10000);
|
|
```
|
|
|
|
### In Array
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select('*')
|
|
.in('status', ['active', 'pending']);
|
|
```
|
|
|
|
### Like (Pattern Matching)
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select('*')
|
|
.like('name', '%website%');
|
|
```
|
|
|
|
### Full-Text Search
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select('*')
|
|
.textSearch('description', 'design & development');
|
|
```
|
|
|
|
## Ordering
|
|
|
|
### Order By
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select('*')
|
|
.order('created_at', { ascending: false });
|
|
```
|
|
|
|
### Multiple Order By
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select('*')
|
|
.order('status')
|
|
.order('created_at', { ascending: false });
|
|
```
|
|
|
|
## Pagination
|
|
|
|
### Limit
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select('*')
|
|
.limit(10);
|
|
```
|
|
|
|
### Range (Offset)
|
|
|
|
```typescript
|
|
const page = 2;
|
|
const pageSize = 10;
|
|
const from = (page - 1) * pageSize;
|
|
const to = from + pageSize - 1;
|
|
|
|
const { data, count } = await client
|
|
.from('projects')
|
|
.select('*', { count: 'exact' })
|
|
.range(from, to);
|
|
```
|
|
|
|
## Aggregations
|
|
|
|
### Count
|
|
|
|
```typescript
|
|
const { count } = await client
|
|
.from('projects')
|
|
.select('*', { count: 'exact', head: true });
|
|
```
|
|
|
|
### Count with Filters
|
|
|
|
```typescript
|
|
const { count } = await client
|
|
.from('projects')
|
|
.select('*', { count: 'exact', head: true })
|
|
.eq('status', 'active');
|
|
```
|
|
|
|
## Advanced Queries
|
|
|
|
### Multiple Filters
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select('*')
|
|
.eq('account_id', accountId)
|
|
.eq('status', 'active')
|
|
.gte('created_at', startDate)
|
|
.lte('created_at', endDate)
|
|
.order('created_at', { ascending: false })
|
|
.limit(20);
|
|
```
|
|
|
|
### OR Conditions
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select('*')
|
|
.or('status.eq.active,status.eq.pending');
|
|
```
|
|
|
|
### Nested OR
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select('*')
|
|
.or('and(status.eq.active,priority.eq.high),status.eq.urgent');
|
|
```
|
|
|
|
## Joins
|
|
|
|
### Inner Join
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select(`
|
|
*,
|
|
account:accounts!inner(
|
|
id,
|
|
name
|
|
)
|
|
`)
|
|
.eq('account.name', 'Acme Corp');
|
|
```
|
|
|
|
### Left Join
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select(`
|
|
*,
|
|
tasks(*)
|
|
`);
|
|
```
|
|
|
|
## Null Handling
|
|
|
|
### Is Null
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select('*')
|
|
.is('completed_at', null);
|
|
```
|
|
|
|
### Not Null
|
|
|
|
```typescript
|
|
const { data} = await client
|
|
.from('projects')
|
|
.select('*')
|
|
.not('completed_at', 'is', null);
|
|
```
|
|
|
|
## Insert Data
|
|
|
|
### Single Insert
|
|
|
|
```typescript
|
|
const { data, error } = await client
|
|
.from('projects')
|
|
.insert({
|
|
name: 'New Project',
|
|
account_id: accountId,
|
|
status: 'active',
|
|
})
|
|
.select()
|
|
.single();
|
|
```
|
|
|
|
### Multiple Insert
|
|
|
|
```typescript
|
|
const { data, error } = await client
|
|
.from('projects')
|
|
.insert([
|
|
{ name: 'Project 1', account_id: accountId },
|
|
{ name: 'Project 2', account_id: accountId },
|
|
])
|
|
.select();
|
|
```
|
|
|
|
## Update Data
|
|
|
|
### Update with Filter
|
|
|
|
```typescript
|
|
const { data, error } = await client
|
|
.from('projects')
|
|
.update({ status: 'completed' })
|
|
.eq('id', projectId)
|
|
.select()
|
|
.single();
|
|
```
|
|
|
|
### Update Multiple Rows
|
|
|
|
```typescript
|
|
const { data, error } = await client
|
|
.from('projects')
|
|
.update({ status: 'archived' })
|
|
.eq('account_id', accountId)
|
|
.lt('updated_at', oldDate);
|
|
```
|
|
|
|
## Delete Data
|
|
|
|
### Delete with Filter
|
|
|
|
```typescript
|
|
const { error } = await client
|
|
.from('projects')
|
|
.delete()
|
|
.eq('id', projectId);
|
|
```
|
|
|
|
### Delete Multiple
|
|
|
|
```typescript
|
|
const { error } = await client
|
|
.from('projects')
|
|
.delete()
|
|
.in('id', projectIds);
|
|
```
|
|
|
|
## Upsert
|
|
|
|
### Insert or Update
|
|
|
|
```typescript
|
|
const { data, error } = await client
|
|
.from('projects')
|
|
.upsert({
|
|
id: projectId,
|
|
name: 'Updated Name',
|
|
status: 'active',
|
|
})
|
|
.select()
|
|
.single();
|
|
```
|
|
|
|
## RPC (Stored Procedures)
|
|
|
|
### Call Database Function
|
|
|
|
```typescript
|
|
const { data, error } = await client
|
|
.rpc('get_user_projects', {
|
|
user_id: userId,
|
|
});
|
|
```
|
|
|
|
### With Complex Parameters
|
|
|
|
```typescript
|
|
const { data, error } = await client
|
|
.rpc('search_projects', {
|
|
search_term: 'design',
|
|
account_ids: [1, 2, 3],
|
|
min_budget: 5000,
|
|
});
|
|
```
|
|
|
|
## Error Handling
|
|
|
|
### Basic Error Handling
|
|
|
|
```typescript
|
|
const { data, error } = await client
|
|
.from('projects')
|
|
.select('*');
|
|
|
|
if (error) {
|
|
console.error('Error fetching projects:', error.message);
|
|
throw error;
|
|
}
|
|
|
|
return data;
|
|
```
|
|
|
|
### Typed Error Handling
|
|
|
|
```typescript
|
|
import { PostgrestError } from '@supabase/supabase-js';
|
|
|
|
function handleDatabaseError(error: PostgrestError) {
|
|
switch (error.code) {
|
|
case '23505': // unique_violation
|
|
throw new Error('A project with this name already exists');
|
|
case '23503': // foreign_key_violation
|
|
throw new Error('Invalid account reference');
|
|
default:
|
|
throw new Error('Database error: ' + error.message);
|
|
}
|
|
}
|
|
```
|
|
|
|
## TypeScript Types
|
|
|
|
### Generated Types
|
|
|
|
```typescript
|
|
import { Database } from '~/types/database.types';
|
|
|
|
type Project = Database['public']['Tables']['projects']['Row'];
|
|
type ProjectInsert = Database['public']['Tables']['projects']['Insert'];
|
|
type ProjectUpdate = Database['public']['Tables']['projects']['Update'];
|
|
```
|
|
|
|
### Typed Queries
|
|
|
|
```typescript
|
|
const { data } = await client
|
|
.from('projects')
|
|
.select('*')
|
|
.returns<Project[]>();
|
|
```
|
|
|
|
## Performance Tips
|
|
|
|
1. **Select only needed columns** - Don't use `select('*')` unnecessarily
|
|
2. **Use indexes** - Create indexes on frequently filtered columns
|
|
3. **Limit results** - Always paginate large datasets
|
|
4. **Avoid N+1 queries** - Use joins instead of multiple queries
|
|
5. **Use RPC for complex queries** - Move logic to database
|
|
6. **Cache when possible** - Use React Query or similar
|
|
7. **Profile queries** - Use `EXPLAIN ANALYZE` in SQL
|
|
|
|
## Best Practices
|
|
|
|
1. **Always handle errors** - Check error responses
|
|
2. **Validate input** - Use Zod or similar
|
|
3. **Use TypeScript** - Generate and use types
|
|
4. **Consistent naming** - Follow database naming conventions
|
|
5. **Document complex queries** - Add comments
|
|
6. **Test queries** - Unit test database operations
|
|
7. **Monitor performance** - Track slow queries
|