Riferimento alla sintassi di Common Expression Language per Data Connect

Queste guide di riferimento illustrano la sintassi di Common Expression Language (CEL) pertinente alla creazione di espressioni per le direttive @auth(expr:) e @check(expr:).

Le informazioni di riferimento complete per CEL sono fornite nella specifica CEL.

Prova le variabili passate in query e mutazioni

La sintassi @auth(expr) ti consente di accedere e testare le variabili da query e mutazione.

Ad esempio, puoi includere una variabile di operazione, come $status, utilizzando vars.status.

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

Dati disponibili per le espressioni: request, response, this

Utilizzi i dati per:

  • Valutazione con espressioni CEL nelle direttive @auth(expr:) e @check(expr:)
  • Assegnazione utilizzando espressioni server, <field>_expr.

Sia le espressioni CEL @auth(expr:) che @check(expr:) possono valutare quanto segue:

  • request.operationName
  • vars (alias per request.variables)
  • auth (alias per request.auth)

Nelle mutazioni, puoi accedere e assegnare i contenuti di:

  • response (per controllare i risultati parziali nella logica a più passaggi)

Inoltre, le espressioni @check(expr:) possono valutare:

  • this (il valore del campo corrente)
  • response (per controllare i risultati parziali nella logica a più passaggi)

L'associazione request.operationName

Il vincolo request.operarationName memorizza il tipo di operazione, query o mutazione.

Il binding vars (request.vars)

L'associazione vars consente alle espressioni di accedere a tutte le variabili passate nella query o nella mutazione.

Puoi utilizzare vars.<variablename> in un'espressione come alias per il valore request.variables.<variablename> completamente qualificato:

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

Il binding auth (request.auth)

Authentication identifica gli utenti che richiedono l'accesso ai tuoi dati e fornisce queste informazioni come una definizione su cui puoi basare le tue espressioni.

Nei filtri e nelle espressioni, puoi utilizzare auth come alias per request.auth.

Il vincolo di autenticazione contiene le seguenti informazioni:

  • uid: un ID utente univoco assegnato all'utente che effettua la richiesta.
  • token: una mappa dei valori raccolti da Authentication.

Per maggiori dettagli sui contenuti di auth.token, consulta Dati nei token di autenticazione

L'associazione response

Il vincolo response contiene i dati assemblati dal server in risposta a una query o a una mutazione durante l'assemblaggio.

Man mano che l'operazione procede e ogni passaggio viene completato correttamente, response contiene i dati di risposta dei passaggi completati correttamente.

Il vincolo response è strutturato in base alla forma dell'operazione associata, inclusi (più) campi nidificati e (se applicabile) query incorporate.

Tieni presente che quando accedi ai dati di risposta della query incorporata, i campi possono contenere qualsiasi tipo di dato, a seconda dei dati richiesti nella query incorporata. Quando accedi ai dati restituiti dai campi di mutazione come _insert e _delete, questi possono contenere chiavi UUID, numero di eliminazioni, valori null (consulta la documentazione di riferimento sulle mutazioni).

Ad esempio:

  • In una mutazione che contiene una query incorporata, il vincolo response contiene i dati di ricerca in response.query.<fieldName>.<fieldName>...., in questo caso response.query.todoList e 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 una mutazione in più passaggi, ad esempio con più campi _insert, il vincolo response contiene dati parziali in response.<fieldName>.<fieldName>...., in questo caso 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,
  })
}

L'associazione this

L'associazione this restituisce il campo a cui è associata l'istruzione @check. In un caso di base, potresti valutare risultati della query a valore singolo.

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

Se il campo restituito si verifica più volte perché un qualsiasi antenato è un elenco, ogni occorrenza viene testata con this associato a ciascun valore.

Per un determinato percorso, se un antenato è null o [], il campo non verrà raggiunto e la valutazione CEL verrà saltata per quel percorso. In altre parole, la valutazione avviene solo quando this è null o non null, ma mai undefined.

Quando il campo stesso è un elenco o un oggetto, this segue la stessa struttura (inclusi tutti i discendenti selezionati in caso di oggetti), come illustrato nell' esempio seguente.

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

Sintassi delle espressioni complesse

Puoi scrivere espressioni più complesse combinandole con gli operatori && e ||.

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

La sezione seguente descrive tutti gli operatori disponibili.

Operatori e precedenza degli operatori

Utilizza la seguente tabella come riferimento per gli operatori e la relativa precedenza.

Dati espressioni arbitrarie a e b, un campo f e un indice i.

Operatore Descrizione Associatività
a[i] a() a.f Indice, chiamata, accesso ai campi da sinistra a destra
!a -a Negazione unaria da destra a sinistra
a/b a%b a*b Operatori moltiplicativi da sinistra a destra
a+b a-b Operatori additivi da sinistra a destra
a>b a>=b a<b a<=b Operatori relazionali da sinistra a destra
a in b Presenza in un elenco o in una mappa da sinistra a destra
type(a) == t Confronto di tipo, dove t può essere bool, int, float, number, string, list, map, timestamp o duration da sinistra a destra
a==b a!=b Operatori di confronto da sinistra a destra
a && b E condizionale da sinistra a destra
a || b OR condizionale da sinistra a destra
a ? true_value : false_value Espressione ternaria da sinistra a destra

Dati nei token di autenticazione

L'oggetto auth.token può contenere i seguenti valori:

Campo Descrizione
email L'indirizzo email associato all'account, se presente.
email_verified true se l'utente ha verificato di avere accesso all'indirizzo email. Alcuni provider verificano automaticamente gli indirizzi email di loro proprietà.
phone_number Il numero di telefono associato all'account, se presente.
name Il nome visualizzato dell'utente, se impostato.
sub L'UID Firebase dell'utente. Deve essere univoco all'interno di un progetto.
firebase.identities Dizionario di tutte le identità associate all'account di questo utente. Le chiavi del dizionario possono essere una delle seguenti: email, phone, google.com, facebook.com, github.com, twitter.com. I valori del dizionario sono array di identificatori univoci per ogni provider di identità associato all'account. Ad esempio, auth.token.firebase.identities["google.com"][0] contiene il primo ID utente Google associato all'account.
firebase.sign_in_provider Il provider di accesso utilizzato per ottenere questo token. Può essere una delle seguenti stringhe: custom, password, phone, anonymous, google.com, facebook.com, github.com, twitter.com.
firebase.tenant Il tenantId associato all'account, se presente. Ad esempio, tenant2-m6tyz

Campi aggiuntivi nei token ID JWT

Puoi anche accedere ai seguenti campi auth.token:

Attestazioni token personalizzate
alg Algoritmo "RS256"
iss Emittente L'indirizzo email dell'account di servizio del progetto
sub Oggetto L'indirizzo email dell'account di servizio del progetto
aud Pubblico "https://identitytoolkit.googleapis.com/google.identity.identitytoolkit.v1.IdentityToolkit"
iat Data/ora di emissione L'ora corrente, in secondi dall'epoca UNIX
exp Scadenza La data e l'ora in cui scade il token, espresse in secondi dall'epoca UNIX. Deve essere al massimo 3600 secondi dopo il valore iat.
Nota: questo controlla solo la data di scadenza del token personalizzato stesso. Tuttavia, dopo che un utente ha eseguito l'accesso utilizzando signInWithCustomToken(), l'accesso rimarrà attivo sul dispositivo finché la sessione non viene invalidata o l'utente non si disconnette.
<claims> (facoltativo) Dichiarazioni personalizzate facoltative da includere nel token, a cui è possibile accedere tramite auth.token (o request.auth.token) nelle espressioni. Ad esempio, se crei un reclamo personalizzato adminClaim, puoi accedervi con auth.token.adminClaim.