Swiftpack.co - Package - IBM-Swift/Swift-Kuery-ORM

Kitura

APIDoc Build Status - Master macOS Linux Apache 2 Slack Status

Swift-Kuery-ORM

Swift-Kuery-ORM is an ORM (Object Relational Mapping) library built for Swift. Using it allows you to simplify persistence of model objects with your server.

Swift-Kuery-ORM is built on top of Swift-Kuery, which means that its possible to use Swift-Kuery to customize SQL queries made to the database, if the functionality of the ORM is insufficient.

The Model Protocol

The key component of Swift-Kuery-ORM is the protocol Model.

Let's propose a struct to use as an example. We can declare an object that looks like so:

struct Grade: Codable {
  var course: String
  var grade: Int
}

Thanks to Codable Routing in Kitura 2.0, we declare our struct to be Codable to simplify our RESTful routes for these objects on our server. The Model protocol extends what Codable does to work with the ORM. In your server application, you would extend your object like so:

extension Grade: Model { }

Now that your Grade struct conforms to Model, after you have set up your database connection pool and created a database table, you automatically have access to a slew of convenience functions for your object.

Need to retrieve all instances of Grade? You can implement:

Grade.findAll()

Need to add a new instance of Grade? Here's how:

grade.save()

The Model protocol is the key to using the ORM. Let's walk through how to fully set up an application to make use of the ORM.

Example

Follow Getting Started to create a Kitura server. In this example you'll be using the Swift Kuery PostgreSQL plugin, so you will need PostgreSQL running on your local machine, which you can install with brew install postgresql. The default port for PostgreSQL is 5432.

Update your Package.swift file

Add Swift-Kuery-ORM and Swift-Kuery-PostgreSQL to your application's Package.swift. Substitute "x.x.x" with the latest Swift-Kuery-ORM release and the latest Swift-Kuery-PostgreSQL release.

dependencies: [
    ...
    // Add these two lines
    .package(url: "https://github.com/IBM-Swift/Swift-Kuery-ORM.git", from: "x.x.x"),
    .package(url: "https://github.com/IBM-Swift/Swift-Kuery-PostgreSQL.git", from: "x.x.x"),
  ],
  targets: [
    .target(
      name: ...
      // Add these two modules to your target(s)
      dependencies: [..., "SwiftKueryORM", "SwiftKueryPostgreSQL"]),
  ]

Let's assume you want to add ORM functionality to a file called Application.swift. You'll need to add the following import statements at the top of the file:

import SwiftKueryORM
import SwiftKueryPostgreSQL

Create Your Database

As mentioned before, we recommend you use Homebrew to set up PostgreSQL on your machine. You can install PostgreSQL and set up your table like so:

brew install postgresql
brew services start postgresql
createdb school

Initialize your database in your Application.swift file:

let pool = PostgreSQLConnection.createPool(host: "localhost", port: 5432, options: [.databaseName("school")], poolOptions: ConnectionPoolOptions(initialCapacity: 10, maxCapacity: 50, timeout: 10000))
Database.default = Database(pool)

Set Up Your Object

Like before, assume you will work with a struct that looks like so:

struct Grade : Codable {
  var course: String
  var grade: Int
}

In your Application.swift file, extend Grade to conform to Model

extension Grade : Model {
    // here, you can add any server-side specific logic to your object
}

Now, you need to create your table. If you are configuring your database while you start up your server, you can use createTableSync(), which runs synchronously. If you want to use an asynchronous function, you can use createTable() elsewhere. You can implement either of these functions like so:

do {
  try Grade.createTableSync()
} catch let error {
  // Error
}

It's important to point out that if you've already created your table, this will throw an error here.

Your application is now ready to make use of all the functions available in the Model protocol. If you'd like to see a fully working example of the ORM using Codable Routing, visit our FoodTracker example.

Let's cover all the functionality you have available to you now.

Saving

If you'd like to save a new object to your database, you have to create the object and use the save() function:

let grade = Grade(course: "physics", grade: 80)
grade.save { grade, error in
  ...
}

You also optionally have the ability to pass the ID of the newly saved object into your closure. Add it to the collection of parameters like so:

grade.save { (id: Int?, grade: Grade?, error: RequestError?) in
  ...
}

Updating

If you have the id for an existing record of your object, and you'd like to update the record with an object, you can use the update() function to do so:

let grade = Grade(course: "physics", grade: 80)
grade.course = "maths"

grade.update(id: 1) { grade, error in
  ...
}

Retrieving

If you'd like to find a specific object, and you have its id, you can use the find() function to retrieve it:

Grade.find(id: 1) { result, error in
  ...
}

If you'd like to retrieve all instances of a particular object, you can make use of findAll() as a static function on the type you are trying to retrieve:

Grade.findAll { (result: [Grade]?, error: RequestError?) in
  ...
}

You also have the ability to form your results in different ways and formats, like so:

Grade.findAll { (result: [(Int, Grade)]?, error: RequestError?) in
  ...
}

Grade.findAll { (result: [Int: Grade]?, error: RequestError?) in
  ...
}

Deleting

If you'd like to delete an object, and you have its id, you can use the delete() function like so:

Grade.delete(id: 1) { error in
  ...
}

If you're feeling bold, and you'd like to remove all instances of an object from your database, you can use the static function deleteAll() with your type:

Grade.deleteAll { error in
  ...
}

Customization

The ORM uses Swift-Kuery which allows you to customize and execute your own queries without breaking any existing ORM functionality. You'll want to have access to the table for your object, which you can get with the getTable() function:

do {
  let table = Grade.getTable()
} catch {
  // Error
}

After you retrieve your table, you can create a Query object to specify what you want to execute on your database, and perform it like so:

executeQuery(query: Query) { (grade: Grade?, error: RequestError?) in
  ...
}

You can customize the parameters passed into your closure after you execute a Query like so:

executeQuery(query: Query) { grade, error in
  ...
}

executeQuery(query: Query) { error in
  ...
}

If you'd like to learn more about how you can customize queries, check out the Swift-Kuery repository for more information.

List of plugins

API Documentation

For more information visit our API reference.

Community

We love to talk server-side Swift, and Kitura. Join our Slack to meet the team!

License

This library is licensed under Apache 2.0. Full license text is available in LICENSE.

Github

link
Stars: 120
Help us keep the lights on

Releases

0.3.1 - Aug 9, 2018

Make fix for concurrent access to type info map avaialable.

0.3.0 - Jun 29, 2018

0.2.0 - Jun 11, 2018

  • Adding Date functionality

0.1.1 - Jun 1, 2018

  • Work around compiler crash with Swift 4.1

0.1.0 - Jun 1, 2018

  • Adds the new filtering functionalities from KituraContracts 1.0.0, such as:
    • GreaterThan, LowerThan , GreaterThanOrEqual, LowerThanOrEqual
    • InclusiveRange, ExclusiveRange
    • Ordering
    • Pagination
  • Prevent SQL Injections