Reading data
With your API data in a Postgres database, reading from APIs like Salesforce or HubSpot has never been easier.
You can use a Postgres GUI client like TablePlus or Postico to connect to your database and get a sense of the tables, columns, and their values. GUI clients are also great ways to perform one-off workflows on your API data (“how many Salesforce leads did we add in the last 30 days?”).
When you’re ready to start building your integration, you’ll need to configure the Postgres adapter you’re using. While you can use a simple Postgres adapter and build your integration with raw SQL, ORMs often provide a superior interface.
Configuring your ORM
Object–relational mapping libraries (ORMs) are the best way to bring your Sequin-synced data into your application. ORMs let us write expressive queries for our data using our programming language. This ORM query for Prisma generates a complex SQL query under the hood:
Migrations
Most ORMs come with a migration tool. The migration tool lets you define a database migration in a file. That migration might add a new table or drop a column.
When using Sequin-synced tables, Sequin is the “owner” of those tables. That means that all migrations are taken care of for you. If you want to add a table, add the table in Sequin’s console and Sequin will add the table to your database.
Most developers connect Sequin to the databases that they use in both production and development. This means managing migrations is not necessary for those environments.
However, if you want to write automated tests against your Sequin tables, you’ll likely need to add migrations to make Sequin’s tables and columns available to your test code.
Defining ORM models
In an ORM, a model is a class that represents a table in the database. It serves as the link between your code and your relational database.
A model typically corresponds to a single table in the database. The attributes or properties of the model class correspond to the columns of the table. An instance of the model represents a single row in the database table.
Each ORM requires some effort to setup these models. Some, like Prisma, require a full schema definition which describes the database structure in an ORM-specific format (the ORM’s DSL or domain-specific language). Others, like ActiveRecord, only require that you setup the relationships between tables.
In general, the process for setting up an ORM is:
- For each table, list the schema
- Paste each table’s schema into your ORM schema definitions, translating to your ORM’s DSL
- Setup the relationships between tables
- Set the primary key type for your ORM to the right type
For ORMs like ActiveRecord that don’t require a schema definition, you can skip steps 1 & 2. Compiled or statically-typed languages typically require a schema definition.
1. List the schema for your tables
For each table you want to create an ORM schema for, you can use the schema in Postgres to bootstrap your schema definition. For example, to list the schema for the table customer
, you can run:
2. Paste and translate
In your codebase, create the schema definition file. Paste in the schema definition from Postgres. Then tweak it into a valid declaration according to your language’s DSL.
For example, if setting up an Elixir/Ecto schema for a Stripe customer
, you might paste in a schema definition that looks like this:
Using some text editor wizardry, you can quickly:
- Reformat each line into a valid declaration
- Swap out data types as necessary
Like so:
Delete any fields that are references, as you’ll handle those in the next step.
3. Setup relationships
Next you need to declare relationships between entities, such as “has one” or “belongs to” relationships. Again, in Elixir, that would look like this:
That means there’s a customer_id
on subscription
which references a customer
. With this field in place, we can now call subscription.customer
on any subscription to retrieve its corresponding customer. This is called a forward reference and is a key value that ORMs provide.
The easiest approach is to setup the relationship on the child first, as the field for the relationship lives there. Then you can add the corresponding field on the parent later. All forward references end in _id
, so an easy way to see which tables a given table is the child of is to run this query:
4. Set the primary key type for your ORM
The last step required by many ORMs is to set the type for the primary key of the IDs on your synced tables. Sometimes IDs are declared along with other fields, other times they’re declared separately. You’ll need to set the primary key type to text
, as that’s the ID type used by all of Sequin’s sources.
info
You may be able to skip some of these steps if your ORM has a schema generator. While it’s worth a Google search to see if your ORM has one, you’ll usually still want to take a manual pass of the auto-generated files. Some of these generators miss relationships between tables or give odd names to back-refs or forward-refs.
Notes for specific ORMs
Below are setup notes for a few different ORMs. Even if you don’t see your ORM below, many of the configuration notes apply across ORMs:
Ecto (Elixir)
Ecto does not have schema generator. But fortunately Ecto declarations are concise and easy to generate (see above).
You’ll want to set three module attributes for each one of your Ecto schemas:
In Ecto, you need to specify the type for both the primary key and foreign keys as types string
. If you’re syncing to a Postgres schema other than public
, you’ll also want to set the @schema_prefix
.
If you’re generating many schemas, you can roll some of these module attributes up to a shared module like this:
ActiveRecord (Ruby)
ActiveRecord does not require schema definitions. So, for each table, you just need to:
- Declare a model
- Specify the table’s name (with the schema)
- Establish relationships between tables
Here’s an example:
Prisma (JavaScript)
While Prisma has a schema generator, there are two considerations:
- Verbose default names for forward-refs and back-refs.
- No support for querying across schemas
1. Verbose default names for forward-refs and back-refs.
Prisma has a schema generator. But for our more complex syncs like Stripe, its default names for forward-refs and back-refs aren’t ideal. For example, you’ll see some crazy field names like this:
We have some scripts we use to clean these up. We’re happy to provide Prisma schemas on demand. Just reach out.
2. No support for querying across schemas
Prisma does not support querying across schemas. This is a bummer, but we’re hoping this will change soon.
In the meantime, we can sync to an existing schema in your database, but with a prefix. For example, if you’re syncing Stripe to your database, we’d sync all tables with the stripe_
prefix, like stripe_customer
and stripe_subscription
. This feature is not exposed in our UI at the moment, so just get in touch if you need it.