Firebase SQL Connect können Sie Connectors für Ihre PostgreSQL Instanzen erstellen, die mit Google Cloud SQL verwaltet werden. Diese Connectors sind Kombinationen aus Abfragen und Mutationen zur Verwendung Ihrer Daten aus Ihrem Schema.
In der Anleitung Erste Schritte wurde ein Schema für eine Film rezensions-App für PostgreSQL vorgestellt.
In dieser Anleitung wurden auch bereitstellbare und Ad-hoc-Verwaltungsvorgänge, einschließlich Mutationen, vorgestellt.
- Bereitstellbare Mutationen werden implementiert, um sie über Client-Apps in einem Connector mit von Ihnen definierten API-Endpunkten aufzurufen. SQL Connect integriert Authentifizierung und Autorisierung in diese Mutationen und generiert Client-SDKs basierend auf Ihrer API.
- Ad-hoc-Verwaltungsmutationen werden in privilegierten Umgebungen ausgeführt, um Tabellen zu füllen und zu verwalten. Sie können sie in der Firebase Konsole, in privilegierten Umgebungen mit dem Firebase Admin SDK, und in lokalen Entwicklungsumgebungen mit unserer SQL Connect VS Code-Erweiterung erstellen und ausführen.
In dieser Anleitung werden bereitstellbare Mutationen genauer betrachtet.
Funktionen von SQL Connect Mutationen
SQL Connect können Sie grundlegende Mutationen auf alle Arten ausführen, die Sie von einer PostgreSQL-Datenbank erwarten:
- CRUD-Vorgänge ausführen
- Mehrstufige Vorgänge mit Transaktionen verwalten
Mit den Erweiterungen von SQL Connect für GraphQL können Sie erweiterte Mutationen für schnellere und effizientere Apps implementieren:
- Verwenden Sie Schlüssel-Skalare , die von vielen Vorgängen zurückgegeben werden, um wiederholte Vorgänge für Datensätze zu vereinfachen.
- Verwenden Sie Serverwerte , um Daten mit Vorgängen zu füllen, die vom Server bereitgestellt werden.
- Führen Sie Abfragen im Rahmen von mehrstufigen Mutationsvorgängen aus, um Daten zu suchen. So sparen Sie Codezeilen und Roundtrips zum Server.
Generierte Felder zum Implementieren von Mutationen verwenden
Ihre SQL Connect Vorgänge erweitern eine Reihe von Feldern die automatisch von SQL Connect basierend auf den Typen und Typ Beziehungen in Ihrem Schema generiert werden. Diese Felder werden von lokalen Tools generiert, wenn Sie Ihr Schema bearbeiten.
Sie können generierte Felder verwenden, um Mutationen zu implementieren, von der Erstellung, Aktualisierung und Löschung einzelner Datensätze in einzelnen Tabellen bis hin zu komplexeren Aktualisierungen in mehreren Tabellen.Angenommen, Ihr Schema enthält einen Typ Movie und einen zugehörigen Typ Actor.
SQL Connect generiert die Felder movie_insert,
movie_update, movie_delete und mehr.
Mutation mit dem
movie_insert Feld
|
Das Feld |
Verwenden Sie dieses Feld, um einen einzelnen Film zu erstellen. mutation CreateMovie($data: Movie_Data!) { movie_insert(data: $data) { key } } |
Mutation mit dem
movie_update Feld
|
Das Feld |
Verwenden Sie dieses Feld, um einen einzelnen Film anhand seines Schlüssels zu aktualisieren. mutation UpdateMovie($myKey: Movie_Key!, $data: Movie_Data!) { movie_update(key: $myKey, data: $data) { key } } |
Mutation mit dem
movie_delete Feld
|
Das Feld |
Verwenden Sie dieses Feld, um einen einzelnen Film anhand seines Schlüssels zu löschen. mutation DeleteMovie($myKey: Movie_Key!) { movie_delete(key: $myKey) { key } } |
Wichtige Elemente einer Mutation
SQL Connect Mutationen sind GraphQL-Mutationen mit SQL Connect Erweiterungen. Wie bei einer regulären GraphQL-Mutation können Sie einen Vorgangsnamen und eine Liste von GraphQL-Variablen definieren.
SQL Connect erweitert GraphQL-Abfragen mit benutzerdefinierten Anweisungen wie
@auth und @transaction.
Die folgende Mutation hat also:
- Eine Typdefinition
mutation - Einen Namen für den Vorgang (die Mutation)
SignUp - Ein einzelnes Argument für den Vorgang
$username - Eine einzelne Anweisung,
@auth - Ein einzelnes Feld
user_insert.
mutation SignUp($username: String!) @auth(level: USER) {
user_insert(data: {
id_expr: "auth.uid"
username: $username
})
}
Für jedes Mutationsargument ist eine Typdeklaration erforderlich, entweder ein integrierter Typ wie String oder ein benutzerdefinierter, schemadefinierter Typ wie Movie.
Grundlegende Mutationen schreiben
Sie können mit dem Schreiben von Mutationen beginnen, um einzelne Datensätze in Ihrer Datenbank zu erstellen, zu aktualisieren und zu löschen.
Erstellen
Führen wir grundlegende Erstellungsvorgänge durch.
# Create a movie based on user input
mutation CreateMovie($title: String!, $releaseYear: Int!, $genre: String!, $rating: Int!) {
movie_insert(data: {
title: $title
releaseYear: $releaseYear
genre: $genre
rating: $rating
})
}
# Create a movie with default values
mutation CreateMovie2 {
movie_insert(data: {
title: "Sherlock Holmes"
releaseYear: 2009
genre: "Mystery"
rating: 5
})
}
Oder einen Upsert-Vorgang.
# Movie upsert using combination of variables and literals
mutation UpsertMovie($title: String!) {
movie_upsert(data: {
title: $title
releaseYear: 2009
genre: "Mystery"
rating: 5
genre: "Mystery/Thriller"
})
}
Aktualisierungen durchführen
Hier sind Aktualisierungen. Produzenten und Regisseure hoffen sicherlich, dass diese durchschnittlichen Bewertungen im Trend liegen.
Das Feld movie_update enthält ein erwartetes id-Argument zur Identifizierung eines Datensatzes und ein data-Feld, mit dem Sie Werte in dieser Aktualisierung festlegen können.
mutation UpdateMovie(
$id: UUID!,
$genre: String!,
$rating: Int!,
$description: String!
) {
movie_update(id: $id,
data: {
genre: $genre
rating: $rating
description: $description
})
}
Verwenden Sie das Feld movie_updateMany, um mehrere Aktualisierungen durchzuführen.
# Multiple updates (increase all ratings of a genre)
mutation IncreaseRatingForGenre($genre: String!, $rating: Int!) {
movie_updateMany(
where: { genre: { eq: $genre } },
data:
{
rating: $rating
})
}
Vorgänge zum Erhöhen, Verringern, Anhängen und Voranstellen mit _update verwenden
In _update und _updateMany Mutationen können Sie zwar Werte explizit in
data: festlegen, es ist jedoch oft sinnvoller, einen Operator wie „Erhöhen“ zu verwenden, um
Werte zu aktualisieren.
Wenn Sie das vorherige Beispiel für die Aktualisierung ändern möchten, nehmen wir an, Sie möchten die Bewertung eines bestimmten Films erhöhen. Sie können die Syntax rating_update mit dem Operator inc verwenden.
mutation UpdateMovie(
$id: UUID!,
$ratingIncrement: Int!
) {
movie_update(id: $id, data: {
rating_update: {
inc: $ratingIncrement
}
})
}
SQL Connect unterstützt die folgenden Operatoren für Feldaktualisierungen:
inczum Erhöhen der DatentypenInt,Int64,Float,DateundTimestampdeczum Verringern der DatentypenInt,Int64,Float,DateundTimestamp
Für Listen können Sie auch einzelne Werte oder Listen von Werten mit Folgendem aktualisieren:
addzum Anhängen von Elementen, wenn sie noch nicht in Listentypen vorhanden sind, außer bei Vektorlistenremovezum Entfernen aller Elemente, falls vorhanden, aus Listentypen, außer bei Vektorlistenappendzum Anhängen von Elementen an Listentypen, außer bei Vektorlistenprependzum Voranstellen von Elementen an Listentypen, außer bei Vektorlisten
Löschvorgänge durchführen
Sie können natürlich auch Filmdaten löschen. Filmkonservatoren möchten sicherlich, dass die physischen Filme so lange wie möglich erhalten bleiben.
# Delete by key
mutation DeleteMovie($id: UUID!) {
movie_delete(id: $id)
}
Hier können Sie _deleteMany verwenden.
# Multiple deletes
mutation DeleteUnpopularMovies($minRating: Int!) {
movie_deleteMany(where: { rating: { le: $minRating } })
}
Mutationen für Beziehungen schreiben
Sehen Sie sich an, wie Sie die implizite Mutation _upsert für eine Beziehung verwenden.
# Create or update a one to one relation
mutation MovieMetadataUpsert($movieId: UUID!, $director: String!) {
movieMetadata_upsert(
data: { movie: { id: $movieId }, director: $director }
)
}
Schemas für effiziente Mutationen entwerfen
SQL Connect bietet zwei wichtige Funktionen, mit denen Sie effizientere Mutationen schreiben und Roundtrips sparen können.
Schlüssel-Skalare sind prägnante Objekt-IDs, die SQL Connect automatisch aus Schlüsselfeldern in Ihren Schemas zusammensetzt. Schlüssel-Skalare dienen der Effizienz. Mit ihnen können Sie in einem einzigen Aufruf Informationen zur Identität und Struktur Ihrer Daten finden. Sie sind besonders nützlich, wenn Sie sequenzielle Aktionen für neue Datensätze ausführen möchten und eine eindeutige ID benötigen, die an nachfolgende Vorgänge übergeben werden soll, und auch, wenn Sie auf Beziehungsschlüssel zugreifen möchten, um weitere komplexere Vorgänge auszuführen.
Mit Serverwerten können Sie dem Server effektiv erlauben, Felder in Ihren Tabellen dynamisch mit gespeicherten oder leicht berechenbaren Werten gemäß bestimmten serverseitigen CEL-Ausdrücken im expr Argument zu füllen. Sie können beispielsweise ein Feld mit einem Zeitstempel definieren, der angewendet wird, wenn auf das Feld zugegriffen wird, und zwar mit der in einer Vorgangsanfrage gespeicherten Zeit: updatedAt: Timestamp!
@default(expr: "request.time").
Erweiterte Mutationen schreiben: SQL Connect Werte mit der Syntax field_expr bereitstellen lassen
Wie unter Schlüssel-Skalare und Serverwerte beschrieben,
können Sie Ihr Schema so entwerfen, dass der Server Werte für allgemeine
Felder wie ids und Datumsangaben als Reaktion auf Clientanfragen füllt.
Außerdem können Sie Daten wie Nutzer-IDs verwenden, die in
SQL Connect request Objekten von Client-Apps gesendet werden.
Wenn Sie Mutationen implementieren, verwenden Sie die Syntax field_expr, um serverseitig generierte Aktualisierungen auszulösen oder auf Daten aus Anfragen zuzugreifen. Wenn Sie beispielsweise die in einer Anfrage gespeicherte Autorisierung uid an einen _upsert Vorgang übergeben möchten, übergeben Sie
"auth.uid" im userId_expr Feld.
# Add a movie to the user's favorites list
mutation AddFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie_upsert(data: { userId_expr: "auth.uid", movieId: $movieId })
}
# Remove a movie from the user's favorites list
mutation DeleteFavoritedMovie($movieId: UUID!) @auth(level: USER) {
favorite_movie_delete(key: { userId_expr: "auth.uid", movieId: $movieId })
}
Oder in einer bekannten To-do-Listen-App könnten Sie beim Erstellen einer neuen To-do-Liste id_expr übergeben, um den Server anzuweisen, eine UUID für die Liste automatisch zu generieren.
mutation CreateTodoListWithFirstItem(
$listName: String!
) @transaction {
# Step 1
todoList_insert(data: {
id_expr: "uuidV4()", # <-- auto-generated. Or a column-level @default on `type TodoList` will also work
name: $listName,
})
}
Weitere Informationen finden Sie unter den _Expr Skalaren in der
Skalarreferenz.
Erweiterte Mutationen schreiben: Mehrstufige Vorgänge
Es gibt viele Situationen, in denen Sie mehrere Schreibfelder (z. B. Einfügungen) in eine Mutation aufnehmen möchten. Möglicherweise möchten Sie auch während der Ausführung einer Mutation Ihre Datenbank lesen, um vorhandene Daten zu suchen und zu überprüfen, bevor Sie beispielsweise Einfügungen oder Aktualisierungen vornehmen. Mit diesen Optionen sparen Sie Roundtrips und damit Kosten.
SQL Connect ermöglicht Ihnen die Ausführung mehrstufiger Logik in Ihren Mutationen durch Unterstützung von:
Mehrere Schreibfelder
Mehrere Lesefelder in Ihren Mutationen (mit dem Feld-Keyword
query).Die
@transactionAnweisung, die Transaktionsunterstützung bietet, die Sie von relationalen Datenbanken kennen.Die
@checkAnweisung, mit der Sie die Inhalte von Lesevorgängen mit CEL-Ausdrücken auswerten können und basierend auf den Ergebnissen dieser Auswertung:- Mit den durch eine Mutation definierten Erstellungs-, Aktualisierungs- und Löschvorgängen fortfahren
- Mit der Rückgabe der Ergebnisse eines Abfragefelds fortfahren
- Zurückgegebene Nachrichten verwenden, um die entsprechende Logik in Ihrem Clientcode auszuführen
Die
@redactAnweisung, mit der Sie Abfragefeldergebnisse aus den Ergebnissen des Wire-Protokolls entfernen können.Die CEL-Bindung
response, in der die kumulierten Ergebnisse aller Mutationen und Abfragen gespeichert werden, die in einem komplexen, mehrstufigen Vorgang ausgeführt wurden. Sie können auf die Bindungresponsezugreifen:- In
@check-Anweisungen über das Argumentexpr: - Mit Serverwerten über die Syntax
field_expr
- In
Die Anweisung @transaction
Die Unterstützung für mehrstufige Mutationen umfasst die Fehlerbehandlung mit Transaktionen.
Die Anweisung @transaction erzwingt, dass eine Mutation – entweder mit einem einzelnen Schreibfeld (z. B. _insert oder _update) oder mit mehreren Schreibfeldern – immer in einer Datenbanktransaktion ausgeführt wird.
Bei Mutationen ohne
@transactionwird jedes Stammfeld nacheinander in der Reihenfolge ausgeführt. Der Vorgang gibt alle Fehler als Teilfehler zurück, aber nicht die Auswirkungen der nachfolgenden Ausführungen.Bei Mutationen mit
@transactionwird garantiert, dass sie entweder vollständig erfolgreich sind oder vollständig fehlschlagen. Wenn eines der Felder in der Transaktion fehlschlägt, wird die gesamte Transaktion rückgängig gemacht.
Die Anweisungen @check und @redact
Die Anweisung @check prüft, ob die angegebenen Felder in den Abfrageergebnissen vorhanden sind. Ein CEL-Ausdruck (Common Expression Language) wird verwendet, um Feldwerte zu testen. Standardmäßig prüft die Anweisung, ob Knoten den Wert null oder [] (leere Listen) haben, und lehnt sie ab.
Die Anweisung @redact entfernt einen Teil der Antwort für den Client. Entfernte Felder werden weiterhin auf Nebeneffekte (einschließlich Datenänderungen und @check) ausgewertet und die Ergebnisse sind weiterhin für spätere Schritte in CEL-Ausdrücken verfügbar.
@check, @check(message:) und @redact verwenden
Eine wichtige Verwendung für @check und @redact ist das Suchen nach zugehörigen Daten, um zu entscheiden, ob bestimmte Vorgänge autorisiert werden sollen. Dabei wird die Suche in der Logik verwendet, aber vor Clients verborgen. Ihre Abfrage kann nützliche Nachrichten für die korrekte Verarbeitung im Clientcode zurückgeben.
query GetMovieEditors($movieId: UUID!) @auth(level: USER) {
moviePermission(key: { movieId: $movieId, userId_expr: "auth.uid" }) @redact {
role @check(expr: "this == 'admin'", message: "You must be an admin to view all editors of a movie.")
}
moviePermissions(where: { movieId: { eq: $movieId }, role: { eq: "editor" } }) {
user {
id
username
}
}
}
Weitere Informationen zu @check und @redact Anweisungen bei Autorisierungsprüfungen finden Sie unter der Diskussion der Autorisierungsdatensuche.
@check zum Validieren von Schlüsseln verwenden
Einige Mutationsfelder wie _update führen möglicherweise keine Aktion aus, wenn ein Datensatz mit einem angegebenen Schlüssel nicht vorhanden ist. Ebenso können Suchvorgänge „null“ oder eine leere Liste zurückgeben. Diese werden nicht als Fehler betrachtet und lösen daher keine Rollbacks aus.
Um dies zu verhindern, testen Sie mit der Anweisung @check, ob Schlüssel gefunden werden können.
# Delete by key, error if not found
mutation MustDeleteMovie($id: UUID!) @transaction {
movie_delete(id: $id) @check(expr: "this != null", message: "Movie not found, therefore nothing is deleted")
}
Die Bindung response verwenden, um mehrstufige Mutationen zu verketten
Der grundlegende Ansatz zum Erstellen verknüpfter Datensätze, z. B. eines neuen Movie und
eines zugehörigen MovieMetadata Eintrags, ist:
- Eine
_insert-Mutation fürMovieaufrufen - Den zurückgegebenen Schlüssel des erstellten Films speichern
- Dann eine zweite
_insert-Mutation aufrufen, um den DatensatzMovieMetadatazu erstellen.
Mit SQL Connect können Sie diesen häufigen Fall jedoch in einem einzigen
mehrstufigen Vorgang verarbeiten, indem Sie in der
zweiten _insert auf die Ergebnisse der ersten _insert zugreifen.
Eine erfolgreiche Filmrezensions-App zu erstellen, ist viel Arbeit. Verfolgen wir unsere To-do-Liste mit einem neuen Beispiel.
response verwenden, um Felder mit Serverwerten festzulegen
In der folgenden Mutation für die To-do-Liste gilt:
- Die Bindung
responsestellt das bisherige Teilantwortobjekt dar, das alle Mutationsfelder der obersten Ebene vor dem aktuellen enthält. - Auf die Ergebnisse des ersten Vorgangs
todoList_insert, der dasid(Schlüssel) zurückgibt, wird später inresponse.todoList_insert.idzugegriffen, damit wir sofort ein neues To-do-Element einfügen können.
mutation CreateTodoListWithFirstItem(
$listName: String!,
$itemContent: String!
) @transaction {
# Sub-step 1:
todoList_insert(data: {
id_expr: "uuidV4()", # <-- auto-generated. Or a column-level @default on `type TodoList` will also work
name: $listName,
})
# Sub-step 2:
todo_insert(data: {
listId_expr: "response.todoList_insert.id" # <-- Grab the newly generated ID from the partial response so far.
content: $itemContent,
})
}
response verwenden, um Felder mit @check zu validieren
response ist auch in @check(expr: "...") verfügbar, sodass Sie damit noch kompliziertere serverseitige Logik erstellen können. In Kombination mit query { … }-Schritten in Mutationen können Sie viel mehr erreichen, ohne zusätzliche Roundtrips zwischen Client und Server.
Beachten Sie im folgenden Beispiel, dass @check bereits Zugriff auf response.query hat, da @check immer nach dem Schritt ausgeführt wird, an den es angehängt ist.
mutation CreateTodoInNamedList(
$listName: String!,
$itemContent: String!
) @transaction {
# Sub-step 1: Look up List.id by its name
query
@check(expr: "response.query.todoLists.size() > 0", message: "No such TodoList with the name!")
@check(expr: "response.query.todoLists.size() < 2", message: "Ambiguous listName!") {
todoLists(where: { name: $listName }) {
id
}
}
# Sub-step 2:
todo_insert(data: {
listId_expr: "response.todoLists[0].id" # <-- Now we have the parent list ID to insert to
content: $itemContent,
})
}
Weitere Informationen zur response Bindung finden Sie in der
CEL-Referenz.
Unterbrochene Vorgänge mit @transaction und query @check
Bei mehrstufigen Mutationen können Fehler auftreten:
- Datenbankvorgänge können fehlschlagen.
- Die Logik von query
@checkkann Vorgänge beenden.
SQL Connect empfiehlt, die Anweisung @transaction mit
Ihren mehrstufigen Mutationen zu verwenden. Dies führt zu einer konsistenteren Datenbank und zu Mutationsergebnissen, die im Clientcode einfacher zu verarbeiten sind:
- Beim ersten Fehler oder bei der ersten fehlgeschlagenen
@checkwird der Vorgang beendet. Sie müssen also die Ausführung nachfolgender Felder oder die Auswertung von CEL nicht verwalten. - Rollbacks werden als Reaktion auf Datenbankfehler oder
@check-Logik ausgeführt, wodurch ein konsistenter Datenbankstatus entsteht. - Ein Rollback-Fehler wird immer an den Clientcode zurückgegeben.
Es gibt möglicherweise Anwendungsfälle, in denen Sie @transaction nicht verwenden möchten. Sie können sich beispielsweise für Eventual Consistency entscheiden, wenn Sie einen höheren Durchsatz, eine höhere Skalierbarkeit oder Verfügbarkeit benötigen. Sie müssen jedoch Ihre Datenbank und Ihren Clientcode so verwalten, dass die Ergebnisse berücksichtigt werden:
- Wenn ein Feld aufgrund von Datenbankvorgängen fehlschlägt, werden nachfolgende Felder weiterhin ausgeführt. Fehlgeschlagene
@check-Anweisungen beenden jedoch weiterhin den gesamten Vorgang. - Rollbacks werden nicht ausgeführt, was zu einem gemischten Datenbankstatus mit einigen erfolgreichen und einigen fehlgeschlagenen Aktualisierungen führt.
- Ihre Vorgänge mit
@checkkönnen zu inkonsistenteren Ergebnissen führen, wenn Ihre@check-Logik die Ergebnisse von Lese- und/oder Schreibvorgängen in einem vorherigen Schritt verwendet. - Das an den Clientcode zurückgegebene Ergebnis enthält eine komplexere Mischung aus Erfolgs- und Fehlerantworten, die verarbeitet werden müssen.
Anweisungen für SQL Connect Mutationen
Zusätzlich zu den Anweisungen, die Sie zum Definieren von Typen und Tabellen verwenden,
SQL Connect bietet die @auth, @check, @redact und
@transaction Anweisungen, um das Verhalten von Vorgängen zu erweitern.
| Anweisung | Anwendbar auf | Beschreibung |
|---|---|---|
@auth |
Abfragen und Mutationen | Definiert die Autorisierungsrichtlinie für eine Abfrage oder Mutation. Weitere Informationen finden Sie in der Anleitung zur Autorisierung und Attestierung. |
@check |
query-Felder in mehrstufigen Vorgängen |
Prüft, ob die angegebenen Felder in den Abfrageergebnissen vorhanden sind. Ein CEL-Ausdruck (Common Expression Language) wird verwendet, um Feldwerte zu testen. Weitere Informationen finden Sie unter Mehrstufige Vorgänge. |
@redact |
Abfragen | Entfernt einen Teil der Antwort für den Client. Weitere Informationen finden Sie unter Mehrstufige Vorgänge. |
@transaction |
Mutationen | Erzwingt, dass eine Mutation immer in einer Datenbanktransaktion ausgeführt wird. Weitere Informationen finden Sie unter Mehrstufige Vorgänge. |
Nächste Schritte
Folgendes könnte Sie auch interessieren:
- Mutationen für Ihre Apps mit KI-Unterstützungstools generieren
- Ihre Mutationen gemäß der Autorisierungsanleitung autorisieren
- Mutationen über Ihren Clientcode für Web, iOS, Android und Flutter aufrufen
- Bulk-Datenvorgänge mit Mutationen ausführen