設計 SQL Connect 結構定義

使用 Firebase SQL Connect 時,您需要設計 GraphQL 結構定義,代表應用程式所需的資料模型。SQL Connect 會將這個結構定義轉換為支援應用程式的 Cloud SQL for PostgreSQL 執行個體。接著,您會編寫查詢和變異,與後端互動,並將這些作業彙整至連接器,以便從用戶端程式碼使用資料。

SQL Connect 提供 AI 工具,協助您設計及實作結構定義。本指南介紹結構定義設計的重要概念,在您開始開發應用程式和後續階段,支援並輔助標準和 AI 輔助工作流程。

入門指南介紹了 PostgreSQL 的電影評論應用程式結構定義。

本指南會進一步開發該結構定義,並提供與最終電影評論應用程式結構定義等效的 SQL 清單。

電影評論應用程式的結構定義

假設您想建構一項服務,讓使用者提交及查看電影評論。

這類應用程式需要初始結構定義,才能支援基本查詢。稍後您將擴充這個結構定義,建立複雜的關聯式查詢。

在 SQL Connect 中,您將定義 GraphQL 類型,定義用戶端可查詢及操控的資料形狀。編寫結構定義時,類型會轉譯為 PostgreSQL 適用的 Cloud SQL 資料表,通常是 GraphQL 類型與資料庫資料表之間的直接關係,但也可能有其他對應關係。本指南提供一些範例,從基本到進階都有。

定義基本 Movie 類型

您可以從 Movie 類型開始。

Movie 的結構定義包含核心指令,例如:

  • @table(name) 和 @col(name):自訂 SQL 資料表和資料欄名稱。如未指定,SQL Connect 會產生蛇形命名法名稱。
  • @col(dataType):自訂 SQL 資料欄類型。
  • @default:在插入期間設定 SQL 資料欄預設值。

詳情請參閱 @table、@col、@default 的參考文件。

# Movies
type Movie @table(name: "movie", key: "id") {
  id: UUID! @col(name: "movie_id") @default(expr: "uuidV4()")
  title: String!
  releaseYear: Int
  genre: String @col(dataType: "varchar(20)")
  rating: Int
  description: String
}

自動將重要的使用者資料儲存為 User 類型

應用程式會追蹤使用者,因此您需要 User 類型。

在這種情況下,@default 指令特別實用。這裡的 id 欄位可以自動從驗證中擷取使用者 ID:請注意下列範例中 @default(expr: "auth.uid") 的使用方式。

# Users
# Suppose a user can leave reviews for movies
type User @table {
  id: String! @default(expr: "auth.uid")
  username: String! @col(dataType: "varchar(50)")
}

重要純量和伺服器值

在進一步瞭解電影評論應用程式之前,請務必先介紹 SQL Connect 鍵純量和伺服器值。

鍵純量是簡潔的物件 ID,SQL Connect 會自動從結構定義中的鍵欄位組合而成。主要純量與效率有關,可讓您透過單一呼叫,找出資料的身分和結構資訊。如果您想對新記錄執行依序動作,且需要專屬 ID 傳遞至後續作業,或想存取關聯索引鍵來執行其他更複雜的作業,這項功能就特別實用。

使用伺服器值,您可以讓伺服器根據 expr 引數中的特定伺服器端 CEL 運算式,使用儲存或可輕鬆計算的值,動態填入資料表中的欄位。舉例來說,您可以定義一個欄位,並使用作業要求 updatedAt: Timestamp! @default(expr: "request.time") 中儲存的時間,在存取該欄位時套用時間戳記。

處理 Actor 和 MovieActor 類型的多對多關係

處理完使用者後,您可以回到電影資料建模。

接下來,你需要演員來主演電影。

Actor 資料表相當簡單。

# Actors
# Suppose an actor can participate in multiple movies and movies can have multiple actors
# Movie - Actors (or vice versa) is a many to many relationship
type Actor @table {
  id: UUID! @default(expr: "uuidV4()")
  name: String! @col(dataType: "varchar(30)")
}

如果您希望演員能參與多部電影,且電影能有多位演員,則需要「join table」。

MovieActor 資料表會處理多對多關係,其主鍵是 [movie, actor] (movie 和 actor 的外鍵欄位) 的組合。

# Join table for many-to-many relationship for movies and actors
# The 'key' param signifies the primary keys of this table
# In this case, the keys are [movieId, actorId], the foreign key fields of the reference fields [movie, actor]
type MovieActor @table(key: ["movie", "actor"]) {
  movie: Movie!
  # movieId: UUID! <- implicitly added foreign key field
  actor: Actor!
  # actorId: UUID! <- implicitly added foreign key field
  role: String! # "main" or "supporting"
  # optional other fields
}

當您使用外鍵限制在資料表上定義 SQL 關係時,SQL Connect 會自動在另一端產生對應的欄位。您不需要定義反向對應欄位 (例如從 Actor 回到 MovieActor)。

處理 MovieMetadata 類型的一對一關係

現在,請追蹤電影導演,並設定與 Movie 的一對一關係。

您可以使用 @ref 指令自訂外鍵限制:

  • @ref(fields) 指定要使用的外鍵欄位。
  • @ref(references) 指定目標資料表中參照的欄位 (預設為主鍵,但 @unique 欄位也適用)。這是較進階的選項,SQL Connect 通常可以為您推論。

詳情請參閱 @ref 的參考文件。

# Movie Metadata
# Movie - MovieMetadata is a one-to-one relationship
type MovieMetadata @table {
  # @unique ensures that each Movie only has one MovieMetadata.
  movie: Movie! @unique
  # Since it references to another table type, it adds a foreign key constraint.
  #  movie: Movie! @unique @ref(fields: "movieId", references: "id")
  #  movieId: UUID! <- implicitly added foreign key field
  director: String
}

使用依據結構定義產生的欄位來建立作業

SQL Connect 作業會根據結構定義中的類型和類型關係,擴充 SQL Connect 自動產生的一組欄位。每當您編輯結構定義時,本機工具就會產生這些欄位。

假設結構定義包含 Movie 類型和相關聯的 Actor 類型。SQL Connect 會產生 movie、movies、actors_on_movies 欄位等。

使用
movie 欄位查詢

movie 欄位代表 Movie 資料表中的單一記錄。

使用這個欄位,依鍵值查詢單一電影。

query GetMovie($myKey: Movie_Key!) {
  movie(key: $myKey) { title }
}

使用
movies 欄位查詢

movies 欄位代表 Movie 資料表中的記錄清單。

使用這個欄位查詢多部電影,例如特定年份的所有電影。

query GetMovies($myYear: Int!) {
  movies(where: { year: { eq: $myYear } }) { title }
}

使用
actors_on_movies 欄位查詢

actors_on_movies 欄位代表連結 Actor 和 Movie 資料表的記錄清單。使用這個欄位查詢與特定電影相關聯的所有演員。

使用這個欄位查詢與特定電影相關聯的所有演員。

  query GetActorsOnMovie($myKey: Movie_Key!) {
    actors_on_movies(where: { movie: { key: { eq: $myKey } } }) {
      actor { name }
    }
  }

瞭解這點後,您可以參閱查詢實作指南和異動實作指南,瞭解如何使用這些欄位實作作業。

更多進階結構定義概念

列舉欄位

SQL Connect 支援對應至 PostgreSQL 列舉類型的列舉欄位。列舉可讓您快速定義靜態、預先定義值的清單,並指定特定順序。

如要在結構定義中新增列舉,請宣告列舉及其預先定義的值,然後在類型中參照該列舉。

enum AspectRatio {
   ACADEMY
   WIDESCREEN
   ANAMORPHIC
   IMAX
   "No information available on aspect ratio"
   UNAVAILABLE
}

type Movie
  @table {
  title: String! 
  genre: String
  description: String
  originalAspectRatio: AspectRatio! @default(value: WIDESCREEN)
  otherAspectRatios: [AspectRatio!]
  tags: [String]
  rating: Float
  imageUrl: String!
  releaseYear: Int
}

在 Movie 類型中,我們新增了列舉欄位 originalAspectRatio,用於表示電影拍攝時的顯示比例,以及另一個欄位 otherAspectRatios,用於列出其他可用的顯示比例。

管理列舉欄位的變更

您可以將新值新增至列舉,但列舉清單的順序非常重要,因此請謹慎插入新值。對列舉進行完全回溯相容的唯一變更,是在值清單的結尾新增值。值得注意的是,在先前發布的列舉之間插入新值,或重新排序現有值,會在使用「小於」等相對運算子的查詢中,變更相對排序。移除或重新命名值一律是回溯不相容的變更。

請勿重新排序列舉值清單中的值;排序方式會影響篩選條件的套用方式,因此非常重要。

調整列舉值時應謹慎,以免破壞舊版作業或用戶端程式碼。移除或重新命名列舉值時,請確認目前的資料庫中沒有任何剩餘的例項。

在作業和用戶端程式碼中使用列舉欄位

在結構定義中新增列舉欄位後,您可以在查詢和用戶端程式碼中使用這個欄位。

如要進一步瞭解如何使用列舉編寫查詢,以及如何編寫用戶端以允許調整列舉,請參閱查詢指南。

其他進階概念

如要進一步瞭解基本但實用的類型和關係,請參閱參考文件中的範例。

支援的資料類型

SQL Connect 支援下列純量資料類型,並使用 @col(dataType:) 指派給 PostgreSQL 類型。

SQL Connect 類型 GraphQL 內建類型或
SQL Connect 自訂類型
預設 PostgreSQL 類型 支援的 PostgreSQL 類型
(括號內為別名)
字串 GraphQL 文字 text
bit(n), varbit(n)
char(n), varchar(n)
整數值 GraphQL int Int2 (smallint、smallserial)、
int4 (integer、int、serial)
浮點值 GraphQL float8 float4 (real)
float8 (double precision)
numeric (decimal)
布林值 GraphQL 布林值 布林值
UUID 自訂 uuid uuid
Int64 自訂 bigint int8 (bigint、bigserial)
numeric (decimal)
日期 自訂 date 日期
時間戳記 自訂 timestamptz

timestamptz

注意:系統不會儲存當地時區資訊。
PostgreSQL 會將這類時間戳記轉換並儲存為世界標準時間。

列舉 自訂 enum

列舉

向量 自訂 vector

向量

請參閱「使用 Vertex AI 執行向量相似度搜尋」。

  • GraphQL List 會對應至一維陣列。
    • 例如,[Int] 對應至 int5[],[Any] 對應至 jsonb[]。
    • SQL Connect 不支援巢狀陣列。

對等 SQL 結構定義

-- Movies Table
CREATE TABLE Movies (
    movie_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    release_year INT,
    genre VARCHAR(30),
    rating INT,
    description TEXT,
    tags TEXT[]
);
-- Movie Metadata Table
CREATE TABLE MovieMetadata (
    movie_id UUID REFERENCES Movies(movie_id) UNIQUE,
    director VARCHAR(255) NOT NULL,
    PRIMARY KEY (movie_id)
);
-- Actors Table
CREATE TABLE Actors (
    actor_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    name VARCHAR(30) NOT NULL
);
-- MovieActor Join Table for Many-to-Many Relationship
CREATE TABLE MovieActor (
    movie_id UUID REFERENCES Movies(movie_id),
    actor_id UUID REFERENCES Actors(actor_id),
    role VARCHAR(50) NOT NULL, # "main" or "supporting"
    PRIMARY KEY (movie_id, actor_id),
    FOREIGN KEY (movie_id) REFERENCES Movies(movie_id),
    FOREIGN KEY (actor_id) REFERENCES Actors(actor_id)
);
-- Users Table
CREATE TABLE Users (
    user_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    user_auth VARCHAR(255) NOT NULL
    username VARCHAR(30) NOT NULL
);
-- Reviews Table
CREATE TABLE Reviews (
    review_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    user_id UUID REFERENCES Users(user_id),
    movie_id UUID REFERENCES Movies(movie_id),
    rating INT,
    review_text TEXT,
    review_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE (movie_id, user_id)
    FOREIGN KEY (user_id) REFERENCES Users(user_id),
    FOREIGN KEY (movie_id) REFERENCES Movies(movie_id)
);
-- Self Join Example for Movie Sequel Relationship
ALTER TABLE Movies
ADD COLUMN sequel_to UUID REFERENCES Movies(movie_id);

後續步驟

您可能感興趣的內容: