Composition in Realm

Issue #13

There is time we have models that have some kind of inheritance, like Dog, Cat, Mouse can be Animal. We can use composition to imitate inheritance, we just need to make sure it has unique primary key

Cat and Dog

These are pretty much basic Realm objects

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class Dog: Object {
dynamic var id: Int = 0

required convenience init(json: [String: Any]) {
self.init()
id <- json.integer(key: "id")
}
}

class Cat: Object {
dynamic var id: Int = 0

required convenience init(json: [String: Any]) {
self.init()
id <- json.integer(key: "id")
}
}

Animal

Here Animal can contain either dog or cat, we can add more if there are many other “inheritance” of Animal. The required init makes sure Animal can only be init with 1 type of child class

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class Animal: Object {
dynamic var id: Int = 0

dynamic var cat: Cat?
dynamic var dog: Dog?

required convenience init(cat: Cat) {
self.init()
self.cat = cat
self.id = cat.id
}

required convenience init(dog: Dog) {
self.init()
self.dog = dog
self.id = dog.id
}
}

Primary key in Realm

Issue #4

Realm is great. But without primary key, it will duplicate the record, like https://github.com/realm/realm-java/issues/2730, http://stackoverflow.com/questions/32322460/should-i-define-the-primary-key-for-each-entity-in-realm, … So to force ourselves into the good habit of declaring primary key, we can leverage Swift protocol

Create primary constrain protocol like this

1
2
3
4
protocol PrimaryKeyAware {
var id: Int { get }
static func primaryKey() -> String?
}

and conform it in out Realm object

1
2
3
4
5
6
7
8
9
10
class Profile: Object, PrimaryKeyAware {

dynamic var firstName: String = ""
dynamic var lastName: String = ""
dynamic var id: Int = 0

override static func primaryKey() -> String? {
return "id"
}
}

This way, when using that object in out RealmStorage, we are safe to say that it has a primary key

1
2
3
4
5
6
7
8
9
10
11
12
13
class RealmStorage<T: Object> where T: PrimaryKeyAware {
let realm: Realm

init(realm: Realm = RealmProvider.realm()) {
self.realm = realm
}

func save(_ objects: [T]) {
try? realm.write {
realm.add(objects, update: true)
}
}
}

The usage is like this

1
2
3
let profile = Profile()
let storage = RealmStorage<Profile>()
storage.save([profile])