← 課程地圖

SUPABASE CORE · 116

Data Queries:SDK 語法背後仍是資料操作 Contract

.from().select() 很方便,但 correctness 仍取決於 query filter、RLS、constraints、result cardinality 與 error handling。這一課不背 method 清單,而是追蹤一次 CRUD operation 的完整資料流。

Learning outcomes

1. Select

const {
  data,
  error
} = await supabase
  .from("courses")
  .select("id,title,score")
  .gte("score", 60)
  .order(
    "score",
    { ascending: false }
  );

不要只看 data;error、auth context、RLS、filter 都會影響結果。

2. Insert

const {
  data,
  error
} = await supabase
  .from("courses")
  .insert({
    title: "JavaScript",
    score: 90
  })
  .select();

能送 request 不代表能 insert;policy、NOT NULL、CHECK、FK 都可能拒絕。

3. Update / Delete:filter 是 operation scope

await supabase
  .from("courses")
  .update({ score: 95 })
  .eq("id", 42);

少 filter 可能影響多筆。RLS 是 authorization boundary,不替代 application intent。

4. Result cardinality

你預期一筆還是多筆要明確。若 id 必須唯一,應由 database constraint 表達,而不是只靠 UI 假設。

5. Pagination / ordering

.order(
  "created_at",
  { ascending: false }
)
.range(0, 49)

大量資料不能永遠一次抓完。Pagination 需要穩定 ordering,否則 page boundary 可能隨插入漂移。

Project checkpoint:Course Workspace v4

listMyCourses()
createCourse(input)
updateCourse(id, patch)
deleteCourse(id)

Each:
  check error
  know cardinality
  RLS authorization
  constraints validity

Debug evidence:data=[]

  1. error 是什麼?
  2. filter 是否匹配?
  3. session/user context 是誰?
  4. RLS SELECT policy 是否允許?
  5. 資料是否存在?

6. Data API privilege 與 RLS 是兩道不同 gate

新 table 可能已存在於 public schema,但目前 project configuration 未自動把它暴露給 Data API。此時即使你已經 ENABLE RLS、也寫好了 policy,client 仍可能先遇到 table privilege error。

Table exists
  ↓
GRANT SELECT / INSERT / UPDATE / DELETE
  ↓
RLS policy
  ↓
visible / writable rows

典型 evidence:

42501
permission denied for table notes

這種錯誤優先查 role privilege / Data API exposure,不要把它和 data=[] 混在一起。後者更像 query/filter/RLS visibility 問題。

Knowledge check

  1. RLS 存在後 update 為何仍要 filter?
  2. 0 rows 和 network error 的 evidence 差異?
  3. 大量 courses 為何需 pagination?
  4. 設計 listMyCourses 的 order + range。