Relationships

GraphQLize identifies the relationships between database tables using their foreign keys, and generate appropriate relationship fields (connections) in the resulting GraphQL schema.

One to One

For the database table relationships like above, GraphQLize infers two one-to-one relationships.

  • An address is associated with a city via city_id column in the address table.

  • A city is associated with a country via country_id column in the city table.

GraphQLize then create two object relationships in the Address and the City type respectively.

type Address {
# ...
city: City!
}
type City {
# ...
country: Country!
}

The generated field name is the camelCase version of the corresponding column name with the id suffix (_id) removed.

Here are some of the examples.

Column Name GraphQL Field Name
actor_id actor
original_language_id originalLanguage
reports_to_employee_id reportsToEmployee

By default, GraphQLize assumes _id as the suffix for foreign keys in both Postgres and MySQL.

, GraphQLize will provide a configuration to override this default behavior.

One to Many

For the database table relationships like above, GraphQLize infers two one-to-many relationships.

  • A city has many address (addresses) via city_id column in the address table.

  • A country has many city (cities) via country_id column in the city table.

GraphQLize then create two array relationships in the City and the Country type respectively.

type City {
# ...
addresses: [Address]!
}
type Country {
# ...
cities: [City]!
}

The generated field name is the camelCase version of the corresponding target table's pluralized name.

If a table has multiple foreign keys to the same table as below,

CREATE TABLE language (
language_id serial PRIMARY KEY,
name character(20) NOT NULL
);
CREATE TABLE film (
film_id serial PRIMARY KEY,
title character varying(255) NOT NULL,
language_id smallint NOT NULL REFERENCES language(language_id),
original_language_id smallint REFERENCES language(language_id)
);

GraphQLize creates two one-to-many relationships between language and films.

  • The language has many film (films) via language_id column in the film table.
  • The language has many film (films) via original_language_id column in the film table.
type Language {
languageId: Int!
name: String!
films: [Film]!
originalLanguageFilms: [Film]!
}

The nomenclature used here to generate the field name follows the below logic.

If the column name (language_id) after the removal of the foreign key suffix (language) matches the source table name, then the resulting field name is the camelCase version of the pluralized form of the table (films).

If the column name (original_language_id) after the removal of the foreign key suffix (original_language) did not match the source table name, then GraphQLize removes the foreign key suffix and concatenate with the pluralized form of the target table and then convert it to its camelCase version (originalLanguageFilms).

Many to Many

The many-to-many relationship is a bit tricky to figure out.

GraphQLize traverses each table's metadata to figure out whether it is an associative table or not.

A table is considered as an associative table if it satisfies the following two criteria

  1. It should have a primary key made of two columns.
  2. These primary key columns should be a subset of the foreign key columns present in that table.

For the database table relationships like below,

The film_actor table is an associative table as

  1. It has actor_id and film_id as the primary keys.
  2. The primary keys {actor_id, film_id} is a subset of foreign keys {actor_id, film_id} of the film_actor table.

In this scenario, GraphQLize creates two array fields for these two many-to-many relationships.

type Film {
actors: [Actor]!
# ...
}
type Actor {
films: [Film]!
# ...
}

For the relationships between film & film_actor and film_actor & actor tables, GraphQLize creates the following fields.

type Film {
# ...
filmActors: [FilmActor]!
}
type FilmActor {
actor: Actor!
film: Film!
# ...
}
type Actor {
# ...
filmActors: [FilmActor]!
}

Foreign Key Without the Id Suffix

If the foreign key in question doesn't have the id suffix _id, then the GraphQLize follows a slightly different approach to name the fields.

Say, we have a below schema

CREATE TABLE continent (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE country (
id SERIAL PRIMARY KEY,
name TEXT NOT NULL,
continent_identifier int REFERENCES continent(id)
);

The continent_identifier column doesn't have the foreign key suffix (_id).

For the one-to-one relationship, GraphQLize creates a field with the name continentByContinentIdentifer. The convention is {targetTableName}By{FKeyColumnNameInPascalCase}.

type Country {
# ...
continentByContinentIdentifer : Continent!
}

On the one-to-many side, the field name is the concatenation of the camelCase version of the foreign key column name (continentIdentifer) with the pluralized form of the target table (Countries).

type Continent {
# ...
continentIdentiferCountries: [Country]!
}