supabase-database

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Supabase Database

Supabase数据库

Quick Start

快速开始

When working with Supabase:
  1. Always use Supabase client from
    @/lib/supabase/server
    or
    @/lib/supabase/client
  2. Never make queries without filtering by
    tenant_id
    in multitenant tables
  3. Always enable RLS on tables and include tenant verification in policies
  4. Use prepared parameters (Supabase client methods, never string concatenation)
  5. Use migrations in
    supabase/migrations/
    for schema changes
在使用Supabase时:
  1. 始终使用来自
    @/lib/supabase/server
    @/lib/supabase/client
    的Supabase客户端
  2. 在多租户表中,查询时必须通过
    tenant_id
    进行过滤
  3. 始终为表启用RLS,并在策略中包含租户验证
  4. 使用预准备参数(使用Supabase客户端方法,绝对不要使用字符串拼接)
  5. 如需修改数据库架构,请使用
    supabase/migrations/
    目录下的迁移文件

Key Files

关键文件

  • src/lib/supabase/
    - Supabase client utilities
  • src/lib/integrations/supabase/
    - Supabase integration
  • supabase/migrations/
    - Database migrations
  • supabase/functions/
    - Edge functions
  • src/lib/auth/enterprise-rls-utils.ts
    - RLS utilities
  • src/lib/supabase/
    - Supabase客户端工具
  • src/lib/integrations/supabase/
    - Supabase集成代码
  • supabase/migrations/
    - 数据库迁移文件
  • supabase/functions/
    - Edge函数
  • src/lib/auth/enterprise-rls-utils.ts
    - RLS工具类

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
    .select()
    with specific fields
    instead of
    *
  • 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
undefined
bash
undefined

Create 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
undefined
supabase gen types typescript --local > src/types/database.ts
undefined