Data Connect 的通用表达式语言语法参考文档

本参考指南介绍了与为 @auth(expr:)@check(expr:) 指令创建表达式相关的通用表达式语言 (CEL) 语法。

如需查看有关 CEL 的完整参考信息,请参阅 CEL 规范

在查询和更改中传入的测试变量

借助 @auth(expr) 语法,您可以访问和测试查询和更改中的变量。

例如,您可以使用 vars.status 添加操作变量(例如 $status)。

mutation Update($id: UUID!, $status: Any) @auth(expr: "has(vars.status)")

表达式可用的数据

@auth(expr:)@check(expr:) CEL 表达式都可以对以下内容进行求值:

  • request.operationName
  • varsrequest.variables 的别名)
  • authrequest.auth 的别名)

此外,@check(expr:) 表达式还可以评估:

  • this(当前字段的值)

request.operationName 对象

request.operarationName 对象存储操作类型(查询或更改)。

vars 对象

借助 vars 对象,表达式可以访问在查询或更改中传递的所有变量。

您可以在表达式中使用 vars.<variablename> 作为完全限定的 request.variables.<variablename> 的别名:

# The following are equivalent
mutation StringType($v: String!) @auth(expr: "vars.v == 'hello'")
mutation StringType($v: String!) @auth(expr: "request.variables.v == 'hello'")

auth 对象

Authentication 可识别请求访问您数据的用户,并以对象的形式(您可在表达式中构建)提供信息。

在过滤条件和表达式中,您可以将 auth 用作 request.auth 的别名。

auth 对象包含以下信息:

  • uid:分配给请求用户的唯一身份用户 ID。
  • tokenAuthentication 收集的值映射。

如需详细了解 auth.token 的内容,请参阅身份验证令牌中的数据

this 绑定

绑定 this 的计算结果为 @check 指令附加到的字段。在基本情况下,您可以评估单值查询结果。

mutation UpdateMovieTitle($movieId: UUID!, $newTitle: String!) @auth(level: USER) @transaction {
  # Step 1: Query and check
  query @redact {
    moviePermission( # Look up a join table called MoviePermission with a compound key.
      key: {movieId: $movieId, userId_expr: "auth.uid"}
    ) {
      # Check if the user has the editor role for the movie. `this` is the string value of `role`.
      # If the parent moviePermission is null, the @check will also fail automatically.
      role @check(expr: "this == 'editor'", message: "You must be an editor of this movie to update title")
    }
  }
  # Step 2: Act
  movie_update(id: $movieId, data: {
    title: $newTitle
  })
}

如果返回的字段因任何祖先都是列表而出现多次,则系统会使用绑定到每个值的 this 对每个出现情况进行测试。

对于任何给定路径,如果祖先为 null[],则不会到达该字段,并且系统会跳过对该路径的 CEL 评估。换句话说,只有当 thisnull 或非 null 时才会进行评估,而不会是 undefined

如果字段本身是列表或对象,this 会遵循相同的结构(包括在对象的情况下选择的所有后代),如以下示例所示。

mutation UpdateMovieTitle2($movieId: UUID!, $newTitle: String!) @auth(level: USER) @transaction {
  # Step 1: Query and check
  query {
    moviePermissions( # Now we query for a list of all matching MoviePermissions.
      where: {movieId: {eq: $movieId}, userId: {eq_expr: "auth.uid"}}
    # This time we execute the @check on the list, so `this` is the list of objects.
    # We can use the `.exists` macro to check if there is at least one matching entry.
    ) @check(expr: "this.exists(p, p.role == 'editor')", message: "You must be an editor of this movie to update title") {
      role
    }
  }
  # Step 2: Act
  movie_update(id: $movieId, data: {
    title: $newTitle
  })
}

复杂表达式语法

您可以通过与 &&|| 运算符组合来编写更复杂的表达式。

mutation UpsertUser($username: String!) @auth(expr: "(auth != null) && (vars.username == 'joe')")

以下部分介绍了所有可用的运算符。

运算符和运算符优先级

请参考下表,了解运算符及其相应优先级。

给定任意表达式 ab、字段 f 和索引 i

运算符 说明 关联度
a[i] a() a.f 索引、调用、字段访问 从左到右
!a -a 一元否定 从右到左
a/b a%b a*b 乘法运算符 从左到右
a+b a-b 加法运算符 从左到右
a>b a>=b a<b a<=b 关系运算符 从左到右
a in b 存在于列表或映射中 从左到右
type(a) == t 类型比较,其中 t 可以是 bool、int、float、number、string、list、map、timestamp 或 duration 从左到右
a==b a!=b 比较运算符 从左到右
a && b 条件“与” 从左到右
a || b 条件“或” 从左到右
a ? true_value : false_value 三元表达式 从左到右

身份验证令牌中的数据

auth.token 对象可能包含以下值:

字段 说明
email 与账号关联的电子邮件地址(如果存在)。
email_verified 如果用户已验证他们可以访问 email 地址,则为 true。某些提供方会自动验证他们拥有的电子邮件地址。
phone_number 与账号关联的电话号码(如果有)。
name 用户的显示名(如果已设置)。
sub 用户的 Firebase UID。此 UID 在项目中是唯一的。
firebase.identities 与此用户账号关联的所有身份的字典。字典的键可以是以下任一值:emailphonegoogle.comfacebook.comgithub.comtwitter.com。字典的值是与账号关联的每个身份提供方的唯一标识符的数组。例如,auth.token.firebase.identities["google.com"][0] 包含与该账号关联的第一个 Google 用户 ID。
firebase.sign_in_provider 用于获取此令牌的登录服务提供方。可以是以下任一字符串:custompasswordphoneanonymousgoogle.comfacebook.comgithub.comtwitter.com
firebase.tenant 与账号关联的租户 ID(如果有)。例如 tenant2-m6tyz

JWT ID 令牌中的其他字段

您还可以访问以下 auth.token 字段:

自定义令牌声明
alg 算法 "RS256"
iss 颁发者 您项目的服务账号电子邮件地址
sub 主题 您项目的服务账号电子邮件地址
aud 受众 "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat 颁发时间 当前时间(与 UNIX 计时原点之间相隔的秒数)
exp 到期时间 令牌到期的时间(与 UNIX 计时原点之间相隔的秒数),该时间可能比 iat 晚最多 3600 秒
注意:这仅会控制自定义令牌本身的过期时间。但是,一旦您使用 signInWithCustomToken() 让用户登录,他们将一直在设备上保持登录状态,直到其会话失效或用户退出账号为止。
<claims>(可选) 要包含在令牌中的可选自定义声明,可通过表达式中的 auth.token(或 request.auth.token)访问。例如,如果您创建自定义声明 adminClaim,则可以使用 auth.token.adminClaim 访问它。