Just Fluent 4.0: Manage Database Connections and Decode SQL Queries in Swift

4 min read Original article ↗

Maulik Shah

ORM — Object Relational Mapping is a layer of type-casting between the database and the programming language. Fluent is an open-source ORM library in Swift, which is a part of the Vapor project. Fluent can be used independently of Vapor to communicate with databases, though the Fluent-Vapor documentation gives an impression otherwise.

When I started my project to replace a legacy ORM with Fluent 4.0, I was worried that I would need to write a Rest or GraphQL based interface to use the Fluent library, and it would be a lot of work. Fortunately, this thread on Github gave me hope that I can survive without writing that big of bulk of code.

In this article, I want to share two things with you:

  1. Manage database connection just with Fluent Postgres Driver, and
  2. Write simple SQL queries and decode the results.

Both topics are not covered in the Fluent-Vapor documentation and would be handy tools when writing an Enterprise level API. Also, I’m referencing the Postgres database drivers here, but you can replace it with any other database driver.

Manage the Database Connections

FluentPostgresDriver allows you to connect to multiple databases at the same time. The Databases class (representation of a collection of databases and more..) enables you to connect to multiple Database (representation of a single database) objects using unique DatabaseIDs (a unique id attached to a Database). Following are the primary functions you need to implement to manage the database:

  1. Setup the Databases object by setting up an EventLoopGroup and a ThreadPool. The EventLoopGroup provides you a stream of EventLoop objects, being used to manage asynchronous transactions. On the other hand, ThreadPool, as the name suggests, manages the database threads.
  2. Use the DatabaseID, a Logger object, and database credentials to connect to a particular database. There is a bug in connecting the database that Fluent won’t give you an error for providing the wrong credentials, so I have tried to add a workaround to throw connection error.
  3. You must shut down the pools and databases before shutting down the program, otherwise Swift would cry out some errors at you.

Press enter or click to view image in full size

1. Functions for managing the database connections.

Decode SQL Queries

Fluent gives you an extensive set of functions to filter your tables and query the database. Still, writing a complex SQL query that joins five different tables is difficult with these functions. So, if you want to use complex queries with Fluent and are not able to find anything in the Fluent-Vapor documentation, this section would make your life easy.

FluentPostgresDriver provides simpleQuery function to execute your SQL queries and would return an array of PostgresRow. The below function gives you details about how to convert these query results into an array of dictionaries, saving some precious time on experiments. Though the use of wait() function makes things synchronous and simple, the code can be modified to use with asynchronous EventLoops as well.

Press enter or click to view image in full size

2. Decode the query results into an array of Dictionary

In the above function, each value in the returned type is a String, and you might like to typecast each field. You can use field.dataType in the above code to get the PostgresDataType and use it for Swift typecasting.

Let’s say the return type of your complex query maps to a Model class, and you already know the Model class’s type at compile time, you can directly decode the query results into your Model type.

Press enter or click to view image in full size

3. Decode the query results into a T:Model type

Here, knowing the type of class, which conforms to the Model protocol, is important, as the Model protocol is a PAT (Protocol with Associated Type) (For more about PAT: Alexis Gallagher — Protocols with Associated Types). You can not return a generic Model type in any function due to associated type requirements.

In conclusion, Fluent is a Vapor independent library and is capable enough to manage database connections on its own. The FluentPostgresDrivers provides some great functionalities to decode the SQL query results into dictionaries or Model types.

Thank you! Let me know your thoughts about this article!