GraphQL Schema

... 2022-7-7 Ungefähr 4 min

# GraphQL Schema

# Definition von Entitäten

Die Datei schema.graphql definiert die verschiedenen GraphQL-Schemas. Aufgrund der Funktionsweise der GraphQL-Abfragesprache bestimmt die Schemadatei im Wesentlichen die Form Ihrer Daten aus SubQuery. Um mehr über das Schreiben in der GraphQL-Schemasprache zu erfahren, empfehlen wir Ihnen, sich Schemas und Typen (opens new window) anzusehen.

Wichtig: Wenn Sie Änderungen an der Schemadatei vornehmen, stellen Sie bitte sicher, dass Sie Ihr Typenverzeichnis mit dem folgenden Befehl yarn codegen . neu generieren

# Entitäten

Jede Entität muss ihre Pflichtfelder id mit dem Typ ID! definieren. Er wird als Primärschlüssel verwendet und ist unter allen Entitäten desselben Typs eindeutig.

Nicht-nullfähige Felder in der Entität werden durch ! gekennzeichnet. Bitte sehen Sie sich das folgende Beispiel an:

Beispiel @entity {
  id: ID! # id-Feld ist immer erforderlich und muss so aussehen
  name: String! # Das ist ein Pflichtfeld
  address: String # Das ist ein optionales Feld
}
1
2
3
4
5

# Unterstützte Skalare und Typen

Wir unterstützen derzeit folgende Skalartypen:

  • ID
  • Int
  • String
  • BigInt
  • Float
  • Datum
  • Boolean
  • <EntityName> für verschachtelte Beziehungsentitäten können Sie den Namen der definierten Entität als eines der Felder verwenden. Weitere Info finden Sie unter Entitätsbeziehungen.
  • JSON kann alternativ strukturierte Daten speichern, siehe JSON-Typ
  • <EnumName>-Typen sind eine spezielle Art von Aufzählungsskalaren, die auf einen bestimmten Satz zulässiger Werte beschränkt sind. Siehe Graphql Enum (opens new window)

# Indizierung nach Nicht-Primärschlüssel-Feld

Um die Abfrageleistung zu verbessern, indizieren Sie ein Entitätsfeld einfach durch Implementierung der Annotation @index in einem Nicht-Primärschlüsselfeld.

Wir gestatten Benutzern jedoch nicht, @index-Annotationen zu einem JSON-Objekt hinzuzufügen. Standardmäßig werden Indizes automatisch zu Fremdschlüsseln und für JSON-Felder in der Datenbank hinzugefügt, jedoch nur, um die Leistung des Abfragedienstes zu verbessern.

Hier ist ein Beispiel.

type User @entity {
  id: ID!
  name: String! @index(unique: true) # unique kann auf true oder false gesetzt werden
  title: Title! # Indizes werden automatisch zum Fremdschlüsselfeld hinzugefügt
}

type Title @entity {
  id: ID!  
  name: String! @index(unique:true)
}
1
2
3
4
5
6
7
8
9
10

Angenommen kennen wir den Namen dieses Benutzers, kennen aber nicht den genauen ID-Wert, anstatt alle Benutzer zu extrahieren und dann nach Namen zu filtern, können wir @index hinter dem Namensfeld hinzufügen. Dies macht die Abfrage viel schneller und wir können zusätzlich das unique: true übergeben, um die Eindeutigkeit sicherzustellen.

Wenn ein Feld nicht eindeutig ist, beträgt die maximale Ergebnissatzgröße 100

When code generation is run, this will automatically create a getByName under the User model, and the foreign key field title will create a getByTitleId method, which both can directly be accessed in the mapping function.

/* Bereiten Sie einen Datensatz für die Titelentität vor */
INSERT INTO titles (id, name) VALUES ('id_1', 'Captain')
1
2
// Handler in der Mapping-Funktion
import {User} from "../types/models/User"
import {Title} from "../types/models/Title"

const jack = await User.getByName('Jack Sparrow');

const captainTitle = await Title.getByName('Captain');

const pirateLords = await User.getByTitleId(captainTitle.id); // Liste aller Kapitäne
1
2
3
4
5
6
7
8
9

# Entitätsbeziehungen

Eine Entität hat oft verschachtelte Beziehungen mit anderen Entitäten. Das Festlegen des Feldwerts auf einen anderen Entitätsnamen definiert standardmäßig eine Eins-zu-Eins-Beziehung zwischen diesen beiden Entitäten.

Anhand der folgenden Beispiele können verschiedene Entitätsbeziehungen (eins-zu-eins, eins-zu-viele und viele-zu-viele) konfiguriert werden.

# Eins-zu-eins-Beziehungen

Eins-zu-eins-Beziehungen sind die Standardeinstellung, wenn nur eine einzelne Entität einer anderen zugeordnet wird.

Beispiel: Ein Reisepass gehört nur einer Person und eine Person hat nur einen Reisepass (in diesem Beispiel):

schreib Person @entity {
  id: ID!
}

schreib Passport @entity {
  id: ID!
  Besitzer: Person!
}
1
2
3
4
5
6
7
8

oder

schreib Person @entity {
  id: ID!
  Reisepass: Passport!
}

schreib Passport @entity {
  id: ID!
}
1
2
3
4
5
6
7
8

# One-to-Many-Beziehungen

Sie können eckige Klammern verwenden, um anzugeben, dass ein Feldtyp mehrere Entitäten enthält.

Beispiel: Eine Person kann mehrere Konten haben.

schreib Person @entity {
  id: ID!
  accounts: [Account]! @derivedFrom(field: "person") #This is virtual field 
}

type Account @entity {
  id: ID!
  Person: Person!
}
1
2
3
4
5
6
7
8
9

# Viele-zu-Viele-Beziehungen

Eine Viele-zu-Viele-Beziehung kann erreicht werden, indem eine Abbildungsentität implementiert wird, um die anderen beiden Entitäten zu verbinden.

Beispiel: Jede Person ist Teil mehrerer Gruppen (PersonGroup) und Gruppen haben mehrere verschiedene Personen (PersonGroup).

schreib Person @entity {
  id: ID!
  name: String!
}

type PersonGroup @entity {
  id: ID!
  Person: Person!
  Gruppe: Group!
}

schreib Group @entity {
  id: ID!
  name: String!
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

Es ist auch möglich, eine Verbindung derselben Entität in mehreren Feldern der mittleren Entität zu erstellen.

Ein Konto kann beispielsweise über mehrere Überweisungen verfügen und jede Überweisung hat ein Quell- und ein Zielkonto.

Dadurch wird eine bidirektionale Beziehung zwischen zwei Konten (von und zu) über die Transfertabelle hergestellt.

schreib Account @entity {
  id: ID!
  öffentliche Adresse: String!
}

schreib Transfer @entity {
  id: ID!
  Betrag: BigInt
   vom : Account!
  zu: Account!
}
1
2
3
4
5
6
7
8
9
10
11

# Reverse-Lookups

Um eine umgekehrte Suche einer Entität zu einer Beziehung zu ermöglichen, hängen Sie @derivedFrom an das Feld an und zeigen Sie auf ihr umgekehrtes Nachschlagefeld einer anderen Entität.

Dadurch wird ein virtuelles Feld auf der Entität erstellt, das abgefragt werden kann.

Auf die Überweisung "von" einem Konto kann von der Kontoentität aus zugegriffen werden, indem der Wert von sentTransfer oder ReceivedTransfer so eingestellt wird, dass ihr Wert aus den entsprechenden Feldern abgeleitet wird.

schreib Account @entity {
  id: ID!
  öffentliche Adresse: String!
  sentTransfers: [Transfer] @derivedFrom(field: "from")
  receivedTransfers: [Transfer] @derivedFrom(field: "to")
}

schreib Transfer @entity {
  id: ID!
  Betrag: BigInt
   vom : Account!
  zu: Account!
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# JSON-Typ

Wir unterstützen das Speichern von Daten als JSON-Typ, was eine schnelle Möglichkeit zum Speichern strukturierter Daten darstellt. Wir generieren automatisch entsprechende JSON-Schnittstellen zum Abfragen dieser Daten und sparen Ihnen Zeit beim Definieren und Verwalten von Entitäten.

Wir empfehlen Benutzern, den JSON-Typ in den folgenden Szenarien zu verwenden:

  • Das Speichern strukturierter Daten in einem einzelnen Feld ist einfacher zu verwalten als das Erstellen mehrerer separater Entitäten.
  • Das Speichern von beliebiger Schlüssel/Wert-Benutzereinstellungen (wobei der Wert boolesch, textuell oder numerisch sein kann und Sie keine separaten Spalten für verschiedene Datentypen haben möchten)
  • Das Schema ist flüchtig und ändert sich häufig

# JSON-Direktive definieren

Definieren Sie die Eigenschaft als JSON-Typ, indem Sie die Annotation jsonField in der Entität hinzufügen. Dadurch werden automatisch Schnittstellen für alle JSON-Objekte in Ihrem Projekt unter types/interfaces.ts generiert, auf die Sie in Ihrer Mapping-Funktion zugreifen können.

Im Gegensatz zur Entität erfordert das jsonField-Direktivenobjekt kein id-Feld. Ein JSON-Objekt kann auch mit anderen JSON-Objekten verschachtelt werden.

schreib Addresse-Details @jsonField {
  street: String!
  Bezirk: String!
}

schreib ContactCard @jsonField {
  Handy: String!
  Addresse: AddresseDetail # Nested JSON
}

schreib User @entity {
  id: ID! 
  contact: [ContactCard] # Speichern Sie eine Liste von JSON-Objekten
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# Abfragen von JSON-Feldern

Der Nachteil der Verwendung von JSON-Typen ist eine geringfügige Auswirkung auf die Abfrageeffizienz beim Filtern, da es sich bei jeder Textsuche um die gesamte Entität handelt.

Die Auswirkungen sind in unserem Abfrageservice jedoch noch akzeptabel. Hier ist ein Beispiel für die Verwendung des Operators enthält in der GraphQL-Abfrage für ein JSON-Feld, um die ersten fünf Benutzer zu finden, die eine Telefonnummer besitzen, die „0064“ enthält.

#Um die ersten 5 Benutzer zu finden, enthält die eigene Telefonnummer '0064'.

Anfrage{
   Nutzer(
     zuerst: 5,
     filtern: {
       Kontaktkarte: {
         enthält: [{ Telefon: "0064" }]
     }
}){
     Nodes{
       id
       Kontaktkarte
     }
   }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Zuletzt geändert: July 7, 2022 09:05