借助 Firebase Data Connect,您可以设计一个表示应用所需数据模型的 GraphQL 架构。Data Connect 将此架构转换为支持应用的 Cloud SQL for PostgreSQL 实例。然后,您编写查询和突变来与后端交互,并将这些操作捆绑到连接器中,以便从客户端代码中使用数据。
Data Connect 提供 AI 工具来帮助您设计和实现架构。本指南介绍了架构设计的重要概念,以便在您开始开发应用时以及之后支持和补充您的标准工作流和 AI 辅助工作流。
使用入门指南介绍了 PostgreSQL 的电影影评应用架构。
本指南进一步开发了该架构,并提供了与最终电影影评应用架构等效的 SQL 清单。
电影影评应用的架构
假设您想构建一项服务,让用户可以提交和查看电影影评。
您需要为这类应用提供初始架构,以支持基本查询。您稍后将扩展此架构,以创建复杂的关系型查询。
在 Data Connect 中,您将定义 GraphQL 类型,以定义客户端可以查询和操纵的数据的形状。编写架构时,您的类型会转换为 Cloud SQL for PostgreSQL 表,通常是 GraphQL 类型与数据库表之间的直接关系,不过也可以使用其他映射。本指南展示了一些示例,从基本示例到更高级的示例都有。
定义基本 Movie 类型
您可以从 Movie 类型开始。
Movie 的架构包含以下核心指令:
- @table(name)和- @col(name)可自定义 SQL 表和列名称。 如果未指定,Data Connect 会生成 snake_case 名称。
- @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)")
}
关键标量和服务器值
在深入了解电影评价应用之前,我们有必要先介绍一下 Data Connect 关键标量和服务器值。
键标量是简洁的对象标识符,Data Connect 会根据架构中的关键字段自动组装这些标识符。关键标量与效率有关,可让您通过一次调用即可找到有关数据身份和结构的信息。当您想对新记录执行一系列操作,并且需要一个唯一标识符来传递给后续操作时,以及当您想访问关系键以执行其他更复杂的操作时,它们尤其有用。
使用服务器值,您可以让服务器根据 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)")
}
如果您希望演员参演多部电影,并且电影有多位演员,则需要一个“联接表”。
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 关系时,Data Connect 会自动在另一侧生成相应的字段。您无需定义反向映射字段(例如,从 Actor 反向映射到 MovieActor)。
处理 MovieMetadata 类型中的一对一关系
现在,您可以跟踪电影导演,并与 Movie 建立一对一关系。
您可以使用 @ref 指令自定义外键限制条件:
- @ref(fields)用于指定要使用的外键字段。
- @ref(references)指定目标表中引用的字段(默认为主键,但- @unique字段也适用)。这是一个更高级的选项;Data 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
}
使用根据架构生成的字段来构建操作
您的 Data Connect 操作将扩展一组根据架构中的类型和类型关系自动生成的 Data Connect 字段。每当您修改架构时,本地工具都会生成这些字段。
假设您的架构包含 Movie 类型和关联的 Actor 类型。Data Connect 会生成 movie、movies、actors_on_movies 字段等。
使用 
movie 字段进行查询
      | 
 | 使用此字段按键查询单部电影。 query GetMovie($myKey: Movie_Key!) { movie(key: $myKey) { title } } | 
使用 
movies 字段进行查询
      | 
 | 使用此字段可查询多部电影,例如指定年份的所有电影。 query GetMovies($myYear: Int!) { movies(where: { year: { eq: $myYear } }) { title } } | 
使用 
actors_on_movies 字段进行查询
    | 
 | 使用此字段可查询与指定电影关联的所有演员。 query GetActorsOnMovie($myKey: Movie_Key!) { actors_on_movies(where: { movie: { key: { eq: $myKey } } }) { actor { name } } } | 
考虑到这一点,您可以参阅查询实现指南和突变实现指南,了解如何使用这些字段来实现操作。
更高级的架构概念
枚举字段
Data 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,用于表示其他可用的宽高比列表。
管理枚举字段的更改
您可以向枚举中添加新值,但枚举列表的顺序非常重要,因此请谨慎插入新值。对枚举进行完全向后兼容的唯一更改是向值列表的末尾添加新值。值得注意的是,在之前发布的枚举之间插入新值或对现有值重新排序会更改在查询中使用“小于”等相对运算符时的相对顺序。移除或重命名值始终是向后不兼容的更改。
您绝不应重新排序枚举值列表中的值;排序非常重要,因为它会改变过滤的执行方式。
对枚举值的调整应谨慎进行,以免破坏旧版操作或客户端代码。移除或重命名枚举值时,请确保当前数据库中没有剩余的实例。
在操作和客户端代码中使用枚举字段
现在,您已向架构添加了枚举字段,接下来可以在查询和客户端代码中使用此字段。
如需详细了解如何使用枚举编写查询,以及如何编写客户端以允许调整枚举,请参阅查询指南。
其他高级概念
如需了解更多实用类型和关系,请参阅参考文档中的示例。
支持的数据类型
Data Connect 支持以下标量数据类型,并使用 @col(dataType:) 将其分配给 PostgreSQL 类型。
| Data Connect type | GraphQL 内置类型或 Data Connect 自定义类型 | 默认 PostgreSQL 类型 | 支持的 PostgreSQL 类型 (括号中为别名) | 
|---|---|---|---|
| 字符串 | GraphQL | text | text bit(n)、varbit(n) char(n)、varchar(n) | 
| 整数 | GraphQL | 整数 | Int2(smallint、smallserial)、 int4(integer、int、serial) | 
| 浮点数 | GraphQL | float8 | float4(实数) float8(双精度) numeric(十进制) | 
| 布尔值 | GraphQL | 布尔值 | 布尔值 | 
| UUID | 自定义 | uuid | uuid | 
| Int64 | 自定义 | bigint | int8(bigint、bigserial) numeric(十进制) | 
| 日期 | 自定义 | date | 日期 | 
| 时间戳 | 自定义 | timestamptz | timestamptz 注意:系统不会存储本地时区信息。 | 
| 枚举 | 自定义 | enum | 枚举 | 
| 向量 | 自定义 | vector | 向量 | 
- GraphQL List映射到一维数组。- 例如,[Int]映射到int5[],[Any]映射到jsonb[]。
- Data 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);
后续步骤
您可能感兴趣的内容: