數據連線的一般運算語言語法參考資料

本參考指南涵蓋與為 @auth(expr:)@check(expr:) 指令建立運算式相關的一般運算語言 (CEL) 語法。

如需完整的 CEL 參考資訊,請參閱 CEL 規格

在查詢和突變中傳遞的測試變數

@auth(expr) 語法可讓您存取及測試查詢和變動中的變數。

舉例來說,您可以使用 vars.status 納入作業變數,例如 $status

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

運算式可用的資料:要求、回應、this

資料的用途包括:

  • @auth(expr:)@check(expr:) 指令中,使用 CEL 運算式進行評估
  • 使用伺服器運算式指派,<field>_expr

@auth(expr:)@check(expr:) CEL 運算式都可以評估下列項目:

  • request.operationName
  • vars (request.variables 的別名)
  • auth (request.auth 的別名)

在突變中,您可以存取及指派下列內容:

  • response (檢查多步驟邏輯中的部分結果)

此外,@check(expr:) 運算式可以評估:

  • this (目前欄位的值)
  • response (檢查多步驟邏輯中的部分結果)

request.operationName 繫結

request.operarationName 繫結會儲存作業類型,可以是查詢或變異。

vars繫結 (request.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 繫結 (request.auth)

Authentication 會識別要求存取您資料的使用者,並提供該資訊做為繫結,您可以在運算式中建構該繫結。

在篩選器和運算式中,您可以使用 auth 做為 request.auth 的別名。

授權繫結包含下列資訊:

  • uid:指派給要求使用者的專屬使用者 ID。
  • token:由 Authentication 收集的值對應表。

如要進一步瞭解 auth.token 的內容,請參閱「授權權杖中的資料」。

response 繫結

response 繫結包含伺服器在回應查詢或變動時組裝的資料,因為該資料正在組裝中

隨著作業進行,每完成一個步驟,response 就會包含成功完成步驟的回應資料。

response 繫結的結構會根據相關聯作業的形狀而定,包括 (多個) 巢狀欄位和 (如適用) 內嵌查詢。

請注意,存取嵌入式查詢回應資料時,欄位可能包含任何資料類型,具體取決於嵌入式查詢中要求的資料;存取突變欄位 (例如 _insert_delete) 傳回的資料時,這些資料可能包含 UUID 金鑰、刪除次數和空值 (請參閱突變參考資料)。

例如:

  • 在含有內嵌查詢的突變中,繫結會在 response.query.<fieldName>.<fieldName>.... 包含查詢資料,在本例中為 response.query.todoListresponse.query.todoList.priorityresponse
mutation CheckTodoPriority(
  $uniqueListName: String!
) {
  # This query is identified as `response.query`
  query @check(expr: "response.query.todoList.priority == 'high'", message: "This list is not for high priority items!") {
    # This field is identified as `response.query.todoList`
    todoList(where: { name: $uniqueListName }) {
      # This field is identified as `response.query.todoList.priority`
      priority
    }
  }
}
  • 舉例來說,在多步驟變動中 (例如有多個 _insert 欄位),response 繫結會在 response.<fieldName>.<fieldName>.... 包含部分資料,在本例中為 response.todoList_insert.id
mutation CreateTodoListWithFirstItem(
  $listName: String!,
  $itemContent: String!
) @transaction {
  # Step 1
  todoList_insert(data: {
    id_expr: "uuidV4()",
    name: $listName,
  })
  # Step 2:
  todo_insert(data: {
    listId_expr: "response.todoList_insert.id" # <-- Grab the newly generated ID from the partial response so far.
    content: $itemContent,
  })
}

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、數字、字串、清單、對應、時間戳記或時間長度 從左到右
a==b a!=b 比較運算子 從左到右
a && b 條件式 AND 從左到右
a || b 條件式 OR 從左到右
a ? true_value : false_value 三元運算式 從左到右

驗證權杖中的資料

auth.token 物件可能包含下列值:

欄位 說明
email 與帳戶相關聯的電子郵件地址 (如有)。
email_verified true,前提是使用者已驗證自己有權存取 email 地址。部分供應商會自動驗證他們擁有的電子郵件地址。
phone_number 與帳戶相關聯的電話號碼 (如有)。
name 使用者的顯示名稱 (如有設定)。
sub 使用者的 Firebase UID。這項 ID 在專案中不得重複。
firebase.identities 與這個使用者帳戶相關聯的所有身分識別字典。字典的鍵可以是下列任一項:emailphonegoogle.comfacebook.comgithub.comtwitter.com。字典的值是與帳戶相關聯的每個身分識別提供者的專屬 ID 陣列。舉例來說,auth.token.firebase.identities["google.com"][0] 包含與帳戶相關聯的第一個 Google 使用者 ID。
firebase.sign_in_provider 用來取得這個權杖的登入資訊提供者。可以是下列任一字串:custompasswordphoneanonymousgoogle.comfacebook.comgithub.comtwitter.com
firebase.tenant 與帳戶相關聯的 tenantId (如有)。例如 tenant2-m6tyz

JWT ID 權杖中的其他欄位

您也可以存取下列 auth.token 欄位:

自訂權杖聲明
alg 演算法 "RS256"
iss 核發單位 專案的服務帳戶電子郵件地址
sub 主旨 專案的服務帳戶電子郵件地址
aud 目標對象 "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat 核發時間 目前時間,以 UNIX Epoch 紀元時間為始 (單位為秒)
exp 到期時間 權杖到期時間,以秒為單位,自 UNIX Epoch 紀元時間開始算起。iat 最多可延後 3600 秒
注意:這項設定只會控管自訂權杖本身的到期時間,不過,一旦使用 signInWithCustomToken() 登入使用者,他們就會保持登入裝置的狀態,直到工作階段失效或使用者登出為止。
<claims> (選填) 要在權杖中加入的選用自訂聲明,可透過運算式中的 auth.token (或 request.auth.token) 存取。舉例來說,如果您建立自訂聲明 adminClaim,可以使用 auth.token.adminClaim 存取該聲明。