supabase-database
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseSupabase Database
Supabase数据库
Quick Start
快速开始
When working with Supabase:
- Always use Supabase client from or
@/lib/supabase/server@/lib/supabase/client - Never make queries without filtering by in multitenant tables
tenant_id - Always enable RLS on tables and include tenant verification in policies
- Use prepared parameters (Supabase client methods, never string concatenation)
- Use migrations in for schema changes
supabase/migrations/
在使用Supabase时:
- 始终使用来自或
@/lib/supabase/server的Supabase客户端@/lib/supabase/client - 在多租户表中,查询时必须通过进行过滤
tenant_id - 始终为表启用RLS,并在策略中包含租户验证
- 使用预准备参数(使用Supabase客户端方法,绝对不要使用字符串拼接)
- 如需修改数据库架构,请使用目录下的迁移文件
supabase/migrations/
Key Files
关键文件
- - Supabase client utilities
src/lib/supabase/ - - Supabase integration
src/lib/integrations/supabase/ - - Database migrations
supabase/migrations/ - - Edge functions
supabase/functions/ - - RLS utilities
src/lib/auth/enterprise-rls-utils.ts
- - Supabase客户端工具
src/lib/supabase/ - - Supabase集成代码
src/lib/integrations/supabase/ - - 数据库迁移文件
supabase/migrations/ - - Edge函数
supabase/functions/ - - RLS工具类
src/lib/auth/enterprise-rls-utils.ts
Common Patterns
常见模式
Basic Query with Tenant
带租户过滤的基础查询
typescript
import { createClient } from '@/lib/supabase/server';
import { getTenantFromRequest } from '@/lib/tenant/tenant-service';
const supabase = createClient();
const tenant = await getTenantFromRequest(request);
const { data, error } = await supabase
.from('products')
.select('id, name, price, category_id')
.eq('tenant_id', tenant.id)
.eq('active', true)
.order('created_at', { ascending: false })
.limit(20);
if (error) {
console.error('Query error:', error);
return NextResponse.json({ error: error.message }, { status: 500 });
}typescript
import { createClient } from '@/lib/supabase/server';
import { getTenantFromRequest } from '@/lib/tenant/tenant-service';
const supabase = createClient();
const tenant = await getTenantFromRequest(request);
const { data, error } = await supabase
.from('products')
.select('id, name, price, category_id')
.eq('tenant_id', tenant.id)
.eq('active', true)
.order('created_at', { ascending: false })
.limit(20);
if (error) {
console.error('Query error:', error);
return NextResponse.json({ error: error.message }, { status: 500 });
}Insert with Tenant
带租户信息的插入操作
typescript
const { data, error } = await supabase
.from('products')
.insert({
name: 'Pintura Blanca',
price: 5000,
tenant_id: tenant.id,
category_id: categoryId,
active: true,
})
.select()
.single();typescript
const { data, error } = await supabase
.from('products')
.insert({
name: 'Pintura Blanca',
price: 5000,
tenant_id: tenant.id,
category_id: categoryId,
active: true,
})
.select()
.single();Update with Tenant
带租户信息的更新操作
typescript
const { data, error } = await supabase
.from('products')
.update({ price: 5500 })
.eq('id', productId)
.eq('tenant_id', tenant.id)
.select()
.single();typescript
const { data, error } = await supabase
.from('products')
.update({ price: 5500 })
.eq('id', productId)
.eq('tenant_id', tenant.id)
.select()
.single();RLS Policy Example
RLS策略示例
sql
-- Enable RLS
ALTER TABLE products ENABLE ROW LEVEL SECURITY;
-- Policy for tenant isolation
CREATE POLICY "tenant_isolation_products" ON products
FOR ALL
USING (
tenant_id = (
SELECT id FROM tenants
WHERE slug = current_setting('app.tenant_slug', true)
)
);
-- Policy for public read (if needed)
CREATE POLICY "public_read_products" ON products
FOR SELECT
USING (active = true);sql
-- 启用RLS
ALTER TABLE products ENABLE ROW LEVEL SECURITY;
-- 租户隔离策略
CREATE POLICY "tenant_isolation_products" ON products
FOR ALL
USING (
tenant_id = (
SELECT id FROM tenants
WHERE slug = current_setting('app.tenant_slug', true)
)
);
-- 公共读取策略(如有需要)
CREATE POLICY "public_read_products" ON products
FOR SELECT
USING (active = true);Using RLS Utils
使用RLS工具类
typescript
import { executeWithRLS } from '@/lib/auth/enterprise-rls-utils';
const result = await executeWithRLS(
enterpriseContext,
async (client, rlsContext) => {
return await client
.from('products')
.select('*')
.eq('tenant_id', rlsContext.tenantId);
}
);typescript
import { executeWithRLS } from '@/lib/auth/enterprise-rls-utils';
const result = await executeWithRLS(
enterpriseContext,
async (client, rlsContext) => {
return await client
.from('products')
.select('*')
.eq('tenant_id', rlsContext.tenantId);
}
);Migration Template
迁移模板
sql
-- Migration: add_new_column_to_products
-- Created: 2026-01-23
BEGIN;
-- Add new column
ALTER TABLE products
ADD COLUMN IF NOT EXISTS new_field VARCHAR(255);
-- Create index if needed
CREATE INDEX IF NOT EXISTS idx_products_new_field
ON products(new_field)
WHERE new_field IS NOT NULL;
-- Update RLS policy if needed
-- (Add to existing policy or create new one)
COMMIT;sql
-- 迁移:为products表添加新列
-- 创建时间:2026-01-23
BEGIN;
-- 添加新列
ALTER TABLE products
ADD COLUMN IF NOT EXISTS new_field VARCHAR(255);
-- 按需创建索引
CREATE INDEX IF NOT EXISTS idx_products_new_field
ON products(new_field)
WHERE new_field IS NOT NULL;
-- 按需更新RLS策略
-- (添加到现有策略或创建新策略)
COMMIT;Best Practices
最佳实践
- Always filter by tenant_id in multitenant tables
- Use with specific fields instead of
.select()* - Enable RLS on all tables
- Use migrations for all schema changes
- Test migrations in development first
- Use transactions for multiple related operations
- Index frequently queried fields (tenant_id, foreign keys)
- 多租户表中必须通过tenant_id过滤
- 使用指定字段,而非
.select()* - 为所有表启用RLS
- 所有架构变更都使用迁移文件
- 先在开发环境测试迁移
- 多关联操作使用事务
- 为频繁查询的字段创建索引(tenant_id、外键)
Commands
命令
bash
undefinedbash
undefinedCreate new migration
创建新迁移
supabase migration new migration_name
supabase migration new migration_name
Apply migrations
应用迁移
supabase db push
supabase db push
Reset database (development)
重置数据库(开发环境)
supabase db reset
supabase db reset
Generate TypeScript types
生成TypeScript类型
supabase gen types typescript --local > src/types/database.ts
undefinedsupabase gen types typescript --local > src/types/database.ts
undefined