Skip to content

2.2 Using Sourcery with models

Dmitry edited this page Feb 22, 2018 · 1 revision

Introduction

Sourcery is a code generator for Swift, built on top of Apple's own SourceKit. It’s an open-source project created by Krzysztof Zabłocki

Sourcery allows you to generate boilerplate code automatically. It parses your code and gives you detailed information about it (variables, methods, their types, names, etc.), that can be used to generate boilerplate code and to get rid of repetitive tasks.

Sourcery works with stencil templates. (also with swift and javascript)

Why we use it

Because Vapor models have a lot of convenient protocols that they can conform, there’re a lot of same code, that could be generated for us automatically.

AutoModelGeneratable.stencil template has been created for that purpose.

Installation

Open terminal and run this command to install Sourcery using Mint.

Download Mint Package manager

brew tap yonaskolb/Mint https://github.com/yonaskolb/Mint.git
brew install mint

Download latest Sourcery package with Mint

mint install krzysztofzablocki/Sourcery

Usage

Sourcery uses annotations for passing arguments in template. This makes using sourcery really flexible.

In order to tell sourcery that we want to generate code for our Vapor model, add this annotations above class definition:

// sourcery: AutoModelGeneratable
// sourcery: toJSON, fromJSON, Updateable, Preparation
class SomeClass: Model {

}

AutoModelGeneratable annotation is required and will generate code for Keys structure, static var entity property(for DB table name) and RowRepresentable protocol. toJSON, fromJSON, Updateable, Preparation, ResponseRepresentable, Timestampable are optional and will generate appropriate protocols for each annotation.

If model has relations, we can explicitly add annotation to emphasise relation details or it will be done implicitly, for relation properties annotations are optional:

Example 1: property connected to User model, and is also unique

 // sourcery: relatedModel = User, unique = true 
 var userId: Identifier 

Example 2: property connected to City model(if not added explicitly in annotation, it will be taken from property name), not unique and also can be NULL as it's optional

var cityId: Identifier?

Handling nested JSON Fields

Model JSON representation can have nested JSON fields for its relations. For this purpose we have nestedJSONField and nestedJSONRepresentableField annotations.

  • nestedJSONField for primitive types(String, [String], Int and so on...)
  • nestedJSONRepresentableField for types that conform JSONRepresentable protocol([SomeModel], SomeModel so on...)

Template will use place as field name. If function is called registrationForm, field name will be snakecased automatically("registration_form"):

// sourcery: nestedJSONRepresentableField
func place() throws -> Place? {
  return try parent(id: placeId).get()
}

Or field like this("speakers_photos": ["test", "test", "test"])

// sourcery: nestedJSONField
func speakersPhotos() throws -> [String] {
  return ["test", "test", "test"]
}

Ignoring fields in JSON

Sometimes we don't need some properties to be generated in makeJSON() implementation. For example if we use "place" from example above property "place_id" make no sense there, so we ignore it.

// sourcery: ignoreInJSON
var placeId: Identifier

Auto enum generation support

Also if model has enums they can also be generated. For example, enum variable with two cases: video and slide, would be annotated like this:

// sourcery: enum, video, slide 
var type: ContentType

Time to generate code

After this, run SourceryGenerator.command script that will generate code in new file and will place it in model's folder.(Model must have necessary variables and initializer for them)

If you use Xcode, do not forget to add generated file to project and choose App as target membership for it.

Clone this wiki locally