Diseña esquemas de SQL Connect

Con Firebase SQL Connect, diseñas un esquema de GraphQL que representa el modelo de datos que requiere tu aplicación. SQL Connect convierte este esquema en la instancia de Cloud SQL para PostgreSQL que respalda tu app. Luego, crearás consultas y mutaciones para interactuar con el backend y agruparás estas operaciones en conectores para usar tus datos desde el código del cliente.

SQL Connect ofrece herramientas de IA para ayudarte a diseñar e implementar tus esquemas. En esta guía, se presentan conceptos importantes del diseño de esquemas para respaldar y complementar tus flujos de trabajo estándar y asistidos por IA cuando comienzas a desarrollar una app y más allá.

En la guía de introducción, se presentó un esquema de app de opiniones sobre películas para PostgreSQL.

En esta guía, se desarrolla aún más ese esquema y se proporciona una lista de SQL equivalente al esquema final de la app de opiniones sobre películas.

El esquema de una app de opiniones sobre películas

Imagina que quieres compilar un servicio que permita a los usuarios enviar y ver opiniones sobre películas.

Necesitas un esquema inicial para que una app de este tipo admita consultas básicas. Más adelante, extenderás este esquema para crear consultas relacionales complejas.

En SQL Connect, definirás tipos de GraphQL para definir la forma de los datos que tus clientes pueden consultar y manipular. Cuando escribes tu esquema, tus tipos se traducen a Cloud SQL para las tablas de PostgreSQL, con mayor frecuencia en una relación directa entre los tipos de GraphQL y las tablas de la base de datos, aunque es posible realizar otras asignaciones. En esta guía, se muestran algunos ejemplos, desde los más básicos hasta los más avanzados.

Define un tipo básico de Movie

Puedes comenzar con un tipo Movie.

El esquema de Movie contiene directivas principales como las siguientes:

  • @table(name) y @col(name) para personalizar los nombres de las tablas y columnas de SQL SQL Connect genera nombres en minúsculas con guiones bajos si no se especifica.
  • @col(dataType) para personalizar los tipos de columnas de SQL.
  • @default para configurar los valores predeterminados de las columnas de SQL durante la inserción.

Para obtener más detalles, consulta los documentos de referencia de @table, @col y @default.

# Movies
type Movie @table(name: "movie", key: "id") {
  id: UUID! @col(name: "movie_id") @default(expr: "uuidV4()")
  title: String!
  releaseYear: Int
  genre: String @col(dataType: "varchar(20)")
  rating: Int
  description: String
}

Almacena datos importantes del usuario automáticamente en un tipo User

Tu app hará un seguimiento de los usuarios, por lo que necesitas un tipo User.

La directiva @default es especialmente útil en este caso. El campo id aquí puede obtener automáticamente el ID del usuario de la autenticación: observa el uso de @default(expr: "auth.uid") en el siguiente ejemplo.

# Users
# Suppose a user can leave reviews for movies
type User @table {
  id: String! @default(expr: "auth.uid")
  username: String! @col(dataType: "varchar(50)")
}

Escalares de claves y valores del servidor

Antes de analizar más la app de opiniones sobre películas, es importante presentar los escalares clave y los valores del servidor de SQL Connect.

Los escalares clave son identificadores de objetos concisos que SQL Connect ensambla automáticamente a partir de campos clave en tus esquemas. Los escalares clave se relacionan con la eficiencia, ya que te permiten encontrar en una sola llamada información sobre la identidad y la estructura de tus datos. Son útiles, en especial, cuando quieres realizar acciones secuenciales en registros nuevos y necesitas un identificador único para pasar a las próximas operaciones, y también cuando quieres acceder a claves relacionales para realizar operaciones adicionales más complejas.

Con los valores del servidor, puedes permitir que el servidor complete de forma dinámica los campos de tus tablas con valores almacenados o que se puedan calcular con facilidad según expresiones de CEL particulares del servidor en el argumento expr. Por ejemplo, puedes definir un campo con una marca de tiempo que se aplique cuando se acceda al campo con la hora almacenada en una solicitud de operación, updatedAt: Timestamp! @default(expr: "request.time").

Controlar las relaciones de varios a varios en los tipos Actor y MovieActor

Una vez que hayas controlado los usuarios, puedes volver a modelar los datos de las películas.

A continuación, quieres que los actores protagonicen tus películas.

La tabla Actor es bastante sencilla.

# Actors
# Suppose an actor can participate in multiple movies and movies can have multiple actors
# Movie - Actors (or vice versa) is a many to many relationship
type Actor @table {
  id: UUID! @default(expr: "uuidV4()")
  name: String! @col(dataType: "varchar(30)")
}

Si quieres que los actores participen en varias películas y que las películas tengan varios actores, necesitarás una "tabla de unión".

La tabla MovieActor controla la relación varios a varios, y su clave primaria es una combinación de [movie, actor] (los campos de clave externa de movie y actor).

# Join table for many-to-many relationship for movies and actors
# The 'key' param signifies the primary keys of this table
# In this case, the keys are [movieId, actorId], the foreign key fields of the reference fields [movie, actor]
type MovieActor @table(key: ["movie", "actor"]) {
  movie: Movie!
  # movieId: UUID! <- implicitly added foreign key field
  actor: Actor!
  # actorId: UUID! <- implicitly added foreign key field
  role: String! # "main" or "supporting"
  # optional other fields
}

Cuando defines una relación de SQL en la tabla con una restricción de clave externa, SQL Connect genera automáticamente el campo correspondiente en el otro lado. No es necesario definir el campo de asignación inversa (p.ej., de Actor a MovieActor).

Controla las relaciones uno a uno en un tipo MovieMetadata

Ahora, haz un seguimiento de los directores de películas y configura una relación uno a uno con Movie.

Puedes usar la directiva @ref para personalizar las restricciones de clave externa:

  • @ref(fields) especifica qué campos de clave externa se deben usar.
  • @ref(references) especifica los campos a los que se hace referencia en la tabla de destino (el valor predeterminado es la clave primaria, pero los campos @unique también funcionan). Esta es una opción más avanzada; SQL Connect suele inferir esto por ti.

Para obtener más detalles, consulta los documentos de referencia de @ref.

# Movie Metadata
# Movie - MovieMetadata is a one-to-one relationship
type MovieMetadata @table {
  # @unique ensures that each Movie only has one MovieMetadata.
  movie: Movie! @unique
  # Since it references to another table type, it adds a foreign key constraint.
  #  movie: Movie! @unique @ref(fields: "movieId", references: "id")
  #  movieId: UUID! <- implicitly added foreign key field
  director: String
}

Usa los campos generados a partir de tu esquema para crear operaciones

Tus operaciones SQL Connect extenderán un conjunto de campos generados automáticamente por SQL Connect según los tipos y las relaciones de tipos en tu esquema. Las herramientas locales generan estos campos cada vez que editas tu esquema.

Supongamos que tu esquema contiene un tipo Movie y un tipo Actor asociado. SQL Connect genera los campos movie, movies, actors_on_movies y más.

Consulta con el campo
movie

El campo movie representa un solo registro en la tabla Movie.

Usa este campo para consultar una sola película por su clave.

query GetMovie($myKey: Movie_Key!) {
  movie(key: $myKey) { title }
}

Consulta con el campo
movies

El campo movies representa una lista de registros en la tabla Movie.

Usa este campo para consultar varias películas, por ejemplo, todas las películas de un año determinado.

query GetMovies($myYear: Int!) {
  movies(where: { year: { eq: $myYear } }) { title }
}

Consulta con el campo
actors_on_movies

El campo actors_on_movies representa una lista de registros que conectan las tablas Actor y Movie. Usa este campo para consultar todos los actores asociados con una película determinada.

Usa este campo para consultar todos los actores asociados con una película determinada.

  query GetActorsOnMovie($myKey: Movie_Key!) {
    actors_on_movies(where: { movie: { key: { eq: $myKey } } }) {
      actor { name }
    }
  }

Con esto en mente, puedes leer cómo implementar operaciones con estos campos en la guía para implementar consultas y la guía para implementar mutaciones.

Conceptos de esquemas más avanzados

Campos de enumeración

SQL Connect admite campos de enumeración que se asignan a tipos enumerados de PostgreSQL. Los Enums te permiten definir rápidamente una lista de valores estáticos y predefinidos con un orden específico.

Para agregar un enum a tu esquema, decláralo y sus valores predefinidos, luego, haz referencia a él en tu tipo.

enum AspectRatio {
   ACADEMY
   WIDESCREEN
   ANAMORPHIC
   IMAX
   "No information available on aspect ratio"
   UNAVAILABLE
}

type Movie
  @table {
  title: String! 
  genre: String
  description: String
  originalAspectRatio: AspectRatio! @default(value: WIDESCREEN)
  otherAspectRatios: [AspectRatio!]
  tags: [String]
  rating: Float
  imageUrl: String!
  releaseYear: Int
}

En el tipo Movie, agregamos un campo de tipo enum originalAspectRatio para la relación de aspecto en la que se filmó la película y otro campo otherAspectRatios para una lista de otras relaciones de aspecto disponibles.

Administra los cambios en los campos de enumeración

Puedes agregar valores nuevos a tu enum, pero el orden de la lista de enum es muy significativo, por lo que debes insertar los valores nuevos con cuidado. El único cambio totalmente retrocompatible en un enum es agregar un valor nuevo al final de la lista de valores. En particular, insertar un valor nuevo entre enumeraciones publicadas anteriormente o reordenar los valores existentes cambia el orden relativo cuando se usan operadores relativos, como "menor que", en las consultas. Quitar o cambiar el nombre de los valores siempre es un cambio incompatible con versiones anteriores.

Nunca debes reordenar los valores de la lista de valores de la enumeración; el orden es importante, ya que cambia la forma en que se aplica el filtrado.

Los ajustes en los valores de enum deben realizarse con cuidado para no dañar las versiones anteriores de tu operación o código de cliente. Cuando quites o cambies el nombre de un valor de enum, asegúrate de que no queden instancias en tu base de datos actual.

Usa tus campos de tipo enum en operaciones y en el código del cliente

Ahora que agregaste un campo de tipo enum a tu esquema, puedes usarlo en consultas y código de cliente.

Obtén más información para escribir consultas con enums y cómo escribir un cliente que permita ajustes en tus enums en la guía de consultas.

Otros conceptos avanzados

Para ir más allá de los tipos y las relaciones básicos, pero útiles, consulta los ejemplos en la documentación de referencia.

Tipos de datos admitidos

SQL Connect admite los siguientes tipos de datos escalares, con asignaciones a tipos de PostgreSQL con @col(dataType:).

Tipo SQL Connect Tipo integrado de GraphQL o
SQL Connect tipo personalizado
Tipo de PostgreSQL predeterminado Tipos de PostgreSQL admitidos
(alias entre paréntesis)
String GraphQL texto text
bit(n), varbit(n)
char(n), varchar(n)
Int GraphQL int Int2 (smallint, smallserial),
int4 (integer, int, serial)
Número de punto flotante GraphQL float8 float4 (real)
float8 (precisión doble)
numeric (decimal)
Booleano GraphQL booleano booleano
UUID Personalizado uuid uuid
Int64 Personalizado bigint int8 (bigint, bigserial)
numeric (decimal)
Fecha Personalizado date fecha
Marca de tiempo Personalizado timestamptz

timestamptz

Nota: No se almacena la información de la zona horaria local.
PostgreSQL convierte y almacena esas marcas de tiempo como UTC.

Enumeration Personalizado enum

enum

Vector Personalizado vector

vector

Consulta Realiza una búsqueda de similitud de vectores con Vertex AI.

  • El List de GraphQL se asigna a un array unidimensional.
    • Por ejemplo, [Int] se asigna a int5[], [Any] se asigna a jsonb[].
    • SQL Connect no admite arrays anidados.

Esquema de SQL equivalente

-- Movies Table
CREATE TABLE Movies (
    movie_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    title VARCHAR(255) NOT NULL,
    release_year INT,
    genre VARCHAR(30),
    rating INT,
    description TEXT,
    tags TEXT[]
);
-- Movie Metadata Table
CREATE TABLE MovieMetadata (
    movie_id UUID REFERENCES Movies(movie_id) UNIQUE,
    director VARCHAR(255) NOT NULL,
    PRIMARY KEY (movie_id)
);
-- Actors Table
CREATE TABLE Actors (
    actor_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    name VARCHAR(30) NOT NULL
);
-- MovieActor Join Table for Many-to-Many Relationship
CREATE TABLE MovieActor (
    movie_id UUID REFERENCES Movies(movie_id),
    actor_id UUID REFERENCES Actors(actor_id),
    role VARCHAR(50) NOT NULL, # "main" or "supporting"
    PRIMARY KEY (movie_id, actor_id),
    FOREIGN KEY (movie_id) REFERENCES Movies(movie_id),
    FOREIGN KEY (actor_id) REFERENCES Actors(actor_id)
);
-- Users Table
CREATE TABLE Users (
    user_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    user_auth VARCHAR(255) NOT NULL
    username VARCHAR(30) NOT NULL
);
-- Reviews Table
CREATE TABLE Reviews (
    review_id UUID DEFAULT uuid_generate_v4() PRIMARY KEY,
    user_id UUID REFERENCES Users(user_id),
    movie_id UUID REFERENCES Movies(movie_id),
    rating INT,
    review_text TEXT,
    review_date TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE (movie_id, user_id)
    FOREIGN KEY (user_id) REFERENCES Users(user_id),
    FOREIGN KEY (movie_id) REFERENCES Movies(movie_id)
);
-- Self Join Example for Movie Sequel Relationship
ALTER TABLE Movies
ADD COLUMN sequel_to UUID REFERENCES Movies(movie_id);

Próximos pasos

Tal vez te interese: