Referenz zur CEL-Syntax (Common Expression Language) für SQL Connect

In dieser Referenzanleitung wird die Syntax der Common Expression Language (CEL) behandelt, die für das Erstellen von Ausdrücken für die Direktiven @auth(expr:) und @check(expr:) relevant ist.

Vollständige Referenzinformationen zu CEL finden Sie in der CEL-Spezifikation.

Testvariablen, die in Abfragen und Mutationen übergeben werden

Mit der Syntax @auth(expr) können Sie auf Variablen aus Abfragen und Mutationen zugreifen und sie testen.

Sie können beispielsweise eine Vorgangsvariable wie $status mit vars.status einfügen.

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

Für Ausdrücke verfügbare Daten: Anfrage, Antwort, „this“

Sie verwenden Daten für Folgendes:

  • Auswertung mit CEL-Ausdrücken in den Direktiven @auth(expr:) und @check(expr:)
  • Zuweisung mit Serverausdrücken, <field>_expr.

Mit den CEL-Ausdrücken @auth(expr:) und @check(expr:) kann Folgendes ausgewertet werden:

  • request.operationName
  • vars (Alias für request.variables)
  • auth (Alias für request.auth)

In Mutationen können Sie auf die Inhalte von Folgendem zugreifen und sie zuweisen:

  • response (um Teilergebnisse in mehrstufiger Logik zu prüfen)

Außerdem können mit @check(expr:)-Ausdrücken folgende Elemente ausgewertet werden:

  • this (der Wert des aktuellen Felds)
  • response (um Teilergebnisse in mehrstufiger Logik zu prüfen)

Die Bindung „request.operationName“

Die request.operarationName Bindung speichert den Vorgangstyp, entweder „query“ oder „mutation“.

Die Bindung vars (request.vars)

Mit der Bindung vars können Ihre Ausdrücke auf alle Variablen zugreifen, die in Ihrer Abfrage oder Mutation übergeben werden.

Sie können vars.<variablename> in einem Ausdruck als Alias für das vollqualifizierte request.variables.<variablename> verwenden:

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

Die Bindung auth (request.auth)

Authentication identifiziert Nutzer, die Zugriff auf Ihre Daten anfordern. Diese Informationen werden als Bindung bereitgestellt, die Sie in Ihren Ausdrücken verwenden können.

In Ihren Filtern und Ausdrücken können Sie auth als Alias für request.auth verwenden.

Die Bindung „auth“ enthält die folgenden Informationen:

  • uid: Eine eindeutige Nutzer-ID, die dem anfragenden Nutzer zugewiesen wurde.
  • token: Eine Zuordnung von Werten, die von Authentication erfasst wurden.

Weitere Informationen zum Inhalt von auth.token finden Sie unter Daten in Auth-Tokens

Die Bindung response

Die Bindung response enthält die Daten, die vom Server als Antwort auf eine Abfrage oder Mutation zusammengestellt werden, während diese Daten zusammengestellt werden.

Im Laufe des Vorgangs enthält response nach Abschluss jedes Schritts die Antwortdaten aus den erfolgreich abgeschlossenen Schritten.

Die Bindung response ist entsprechend der Form des zugehörigen Vorgangs strukturiert, einschließlich (mehreren) verschachtelten Feldern und (falls zutreffend) eingebetteten Abfragen.

Wenn Sie auf Antwortdaten eingebetteter Abfragen zugreifen, können Felder je nach den in der eingebetteten Abfrage angeforderten Daten einen beliebigen Datentyp enthalten. Wenn Sie auf Daten zugreifen, die von Mutationsfeldern wie _insert und _delete zurückgegeben werden, können diese UUID-Schlüssel, die Anzahl der Löschvorgänge oder Nullwerte enthalten (siehe die Mutationsreferenz).

Beispiel:

  • In einer Mutation, die eine eingebettete Abfrage enthält, enthält die response Bindung Suchdaten unter response.query.<fieldName>.<fieldName>...., in diesem Fall response.query.todoList und response.query.todoList.priority.
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
    }
  }
}
  • In einer mehrstufigen Mutation, z. B. mit mehreren _insert Feldern, enthält die response Bindung Teildaten unter response.<fieldName>.<fieldName>...., in diesem Fall 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,
  })
}

Die Bindung this

Die Bindung this wird zu dem Feld ausgewertet, an das die Direktive @check angehängt ist. In einem einfachen Fall können Sie Abfrageergebnisse mit einem einzelnen Wert auswerten.

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
  })
}

Wenn das zurückgegebene Feld mehrmals vorkommt, weil ein übergeordnetes Element eine Liste ist, wird jedes Vorkommen getestet, wobei this an jeden Wert gebunden ist.

Wenn ein übergeordnetes Element für einen bestimmten Pfad null oder [] ist, wird das Feld nicht erreicht und die CEL-Auswertung für diesen Pfad wird übersprungen. Mit anderen Worten: Die Auswertung erfolgt nur, wenn this null oder nicht null ist, aber nie undefined.

Wenn das Feld selbst eine Liste oder ein Objekt ist, folgt this derselben Struktur (einschließlich aller ausgewählten untergeordneten Elemente im Fall von Objekten), wie im folgenden Beispiel gezeigt.

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
  })
}

Syntax für komplexe Ausdrücke

Sie können komplexere Ausdrücke erstellen, indem Sie sie mit den && und || Operatoren kombinieren.

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

Im folgenden Abschnitt werden alle verfügbaren Operatoren beschrieben.

Operatoren und Operator-Vorrang

In der folgenden Tabelle finden Sie eine Referenz für Operatoren und ihren entsprechenden Vorrang.

Angenommen, es gibt beliebige Ausdrücke a und b, ein Feld f und einen Index i.

Operator Beschreibung Assoziativität
a[i] a() a.f Index, Aufruf, Feldzugriff von links nach rechts
!a -a Unäre Negation von rechts nach links
a/b a%b a*b Multiplikative Operatoren von links nach rechts
a+b a-b Additive Operatoren von links nach rechts
a>b a>=b a<b a<=b Relationale Operatoren von links nach rechts
a in b Vorhandensein in Liste oder Zuordnung von links nach rechts
type(a) == t Typvergleich, wobei t „bool“, „int“, „float“, „number“, „string“, „list“, „map“, „timestamp“ oder „duration“ sein kann von links nach rechts
a==b a!=b Vergleichsoperatoren von links nach rechts
a && b Bedingtes UND von links nach rechts
a || b Bedingtes ODER von links nach rechts
a ? true_value : false_value Ternärer Ausdruck von links nach rechts

Daten in Auth-Tokens

Das Objekt auth.token kann die folgenden Werte enthalten:

Feld Beschreibung
email Die mit dem Konto verknüpfte E‑Mail-Adresse, falls vorhanden.
email_verified true, wenn der Nutzer bestätigt hat, dass er Zugriff auf die email-Adresse hat. Einige Anbieter bestätigen automatisch E‑Mail-Adressen, die ihnen gehören.
phone_number Die mit dem Konto verknüpfte Telefonnummer, falls vorhanden.
name Der Anzeigename des Nutzers, falls festgelegt.
sub Die Firebase-UID des Nutzers. Sie ist innerhalb eines Projekts eindeutig.
firebase.identities Verzeichnis aller Identitäten, die mit dem Konto dieses Nutzers verknüpft sind. Die Schlüssel des Verzeichnisses können Folgendes sein: email, phone, google.com, facebook.com, github.com, twitter.com. Die Werte des Verzeichnisses sind Arrays eindeutiger IDs für jeden Identitätsanbieter, der mit dem Konto verknüpft ist. Beispielsweise enthält auth.token.firebase.identities["google.com"][0] die erste Google-Nutzer-ID, die mit dem Konto verknüpft ist.
firebase.sign_in_provider Der Anmeldeanbieter, der zum Abrufen dieses Tokens verwendet wurde. Kann einer der folgenden Strings sein: custom, password, phone, anonymous, google.com, facebook.com, github.com, twitter.com.
firebase.tenant Die mit dem Konto verknüpfte Tenant-ID, falls vorhanden. Beispiel: tenant2-m6tyz

Zusätzliche Felder in JWT-ID-Tokens

Sie können auch auf die folgenden auth.token-Felder zugreifen:

Benutzerdefinierte Token-Anforderungen
alg Algorithmus "RS256"
iss Aussteller E-Mail-Adresse des Dienstkontos Ihres Projekts
sub Betreff E-Mail-Adresse des Dienstkontos Ihres Projekts
aud Zielgruppe "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat Ausstellungszeit Die aktuelle Zeit in Sekunden seit der UNIX-Epoche
exp Ablaufzeit Die Zeit in Sekunden seit der UNIX-Epoche, zu der das Token abläuft. Dies kann maximal 3.600 Sekunden später als iat sein.
Beachten Sie, dass damit nur der Zeitpunkt gesteuert wird, zu dem das benutzerdefinierte Token selbst abläuft. Wenn Sie jedoch einen Nutzer mit signInWithCustomToken() anmelden, bleibt er so lange auf dem Gerät angemeldet, bis die Sitzung ungültig wird oder der Nutzer sich abmeldet.
<claims> (optional) Optionale benutzerdefinierte Anforderungen, die in das Token aufgenommen werden sollen und auf die in Ausdrücken über auth.token (oder request.auth.token) zugegriffen werden kann. Wenn Sie beispielsweise eine benutzerdefinierte Anforderung adminClaim erstellen, können Sie mit auth.token.adminClaim darauf zugreifen.