从 Supabase 迁移
CloudBase PG 的设计在很多关键点上有意对齐 Supabase:相同的 auth / storage schema 划分、对齐的 JWT claims(sub / role / aud)、相同的 anon / authenticated / service_role 三角色模型、相同的「GRANT + RLS」双层权限范式。绝大多数 Supabase 项目可以以最小改动迁移过来。
本文聚焦"代码与 SQL 层面"的对齐与差异,不涉及云资源迁移工具与 计费层面的内容。
心智模型对照
| 概念 | Supabase | CloudBase PG | 说明 |
|---|---|---|---|
| 数据库角色 | anon / authenticated / service_role | anon / authenticated / service_role | ✅ 名称语义一致 |
| 账号 schema | auth | auth | ✅ 名称一致 |
| 云存储 schema | storage | storage | ✅ 名称一致 |
JWT sub | uuid 字符串 | varchar(64) 字符串 | ✅ 直接兼容 |
JWT role | anon / authenticated / service_role | anon / authenticated / service_role | ✅ 直接兼容 |
| 客户端 SDK | @supabase/supabase-js | @cloudbase/js-sdk | API 风格相近,主要方法名对齐 |
| 行级权限 | RLS Policy | RLS Policy | ✅ 标准 PostgreSQL 特性,写法完全一致 |
| 自动 REST API | PostgREST | PostgREST | ✅ 同一开源项目,查询语法基本一致 |
| RPC 调用 | .rpc() | .rpc() | ✅ 直接兼容 |
| 文件存储权限 | RLS over storage.objects | RLS over storage.objects | ✅ 同一思路 |
| anon Token | anon API key | anon Publishable Key | ✅ 同一概念 |
| service Token | service_role API key | service_role API Key | ✅ 同一概念 |
关键差异
| 差异点 | Supabase | CloudBase PG | 迁移动作 |
|---|---|---|---|
| REST 端点路径 | /rest/v1/<table> | /v1/rdb/rest/<table> | 修改 base URL |
| 认证端点路径 | /auth/v1/... | /auth/v1/... | ✅ 一致 |
| 域名 | <project>.supabase.co | <envId>.api.tcloudbasegateway.com | 替换域名 |
| Realtime(实时订阅) | ✅ 内置 | ❌ 不支持 | 改为轮询 / WebSocket 自建 |
| GraphQL API | ✅ pg_graphql | ❌ 不支持 | 仅使用 RESTful |
| 数据库 branching | ✅ | ❌ 不支持 | 用环境隔离(dev / staging / prod) |
| DDL 通道 | 直连数据库 / Studio | 控制台 SQL 编辑器 / 云 API ExecutePGSql | 用 ExecutePGSql 替换直连 SQL 客户端的部分流程 |
三步迁移流程
第一步:了解预置辅助函数(无需操作)
CloudBase PG 环境已预置 auth.uid()、auth.jwt()、auth.role()、auth.email() 等辅助函数,与 Supabase 内置函数语义一致,原有 RLS Policy SQL 无需修改即可复用。
以下是这些预置函数的定义(仅供参考,环境已内置,无需手动执行):
-- 当前用户 ID(对应 JWT 的 sub)
CREATE OR REPLACE FUNCTION auth.uid() RETURNS text
LANGUAGE sql STABLE AS $$
SELECT current_setting('request.jwt.claims', true)::json->>'sub'
$$;
-- 当前角色
CREATE OR REPLACE FUNCTION auth.role() RETURNS text
LANGUAGE sql STABLE AS $$
SELECT current_setting('request.jwt.claims', true)::json->>'role'
$$;
-- 完整 JWT claims
CREATE OR REPLACE FUNCTION auth.jwt() RETURNS jsonb
LANGUAGE sql STABLE AS $$
SELECT current_setting('request.jwt.claims', true)::jsonb
$$;
-- 当前邮箱(如有)
CREATE OR REPLACE FUNCTION auth.email() RETURNS text
LANGUAGE sql STABLE AS $$
SELECT current_setting('request.jwt.claims', true)::json->>'email'
$$;
第二步:迁移表结构与 RLS Policy
几乎可以直接套用:
CREATE TABLE/ALTER TABLE:完全兼容CREATE POLICY含auth.uid()/auth.role()等:环境已预置这些函数,无需修改- 外键
REFERENCES auth.users(id):CloudBase 中auth.users.id类型为varchar(64)(与 Supabase 的 uuid 字符串兼容),可直接引用;也可去掉外键以保持解耦
注意点:
-- Supabase 中的常见写法(直接套用即可)
CREATE TABLE public.todos (
id bigserial PRIMARY KEY,
title text NOT NULL,
owner_id varchar(64) NOT NULL DEFAULT auth.uid(),
created_at timestamptz DEFAULT now()
);
ALTER TABLE public.todos ENABLE ROW LEVEL SECURITY;
GRANT SELECT, INSERT, UPDATE, DELETE ON public.todos TO authenticated;
GRANT USAGE, SELECT ON SEQUENCE public.todos_id_seq TO authenticated;
CREATE POLICY todos_owner_all ON public.todos
FOR ALL TO authenticated
USING (owner_id = auth.uid())
WITH CHECK (owner_id = auth.uid());
上面这段 SQL 同时适用于 Supabase 和 CloudBase PG,零改动。
第三步:替换客户端代码
初始化
- import { createClient } from '@supabase/supabase-js';
- const supabase = createClient(
- 'https://<project>.supabase.co',
- '<anon-key>'
- );
+ import cloudbase from '@cloudbase/js-sdk';
+ const app = cloudbase.init({
+ env: '<envId>',
+ accessKey: '<Publishable Key>', // 等价于 supabase 的 anon key
+ });
+ const auth = app.auth;
+ const db = app.rdb();
查询
绝大部分链式 API 完全一致:
// 共用:Supabase 与 CloudBase 完全相同的写法
const { data, error } = await db
.from('todos')
.select('id, title, is_completed')
.eq('is_completed', false)
.order('created_at', { ascending: false })
.limit(20);
写入 / 更新 / 删除
// INSERT
await db.from('todos').insert({ title: '...' });
// UPDATE
await db.from('todos').update({ is_completed: true }).eq('id', 1);
// DELETE
await db.from('todos').delete().eq('id', 1);
// UPSERT
await db.from('todos').upsert({ id: 1, title: '...' });
API 与 Supabase 一致。