RealmSessionStoreMigration.kt 12.7 KB
Newer Older
Valere's avatar
Valere committed
1
/*
2
 * Copyright 2020 The Matrix.org Foundation C.I.C.
Valere's avatar
Valere committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

Benoît Marty's avatar
Benoît Marty committed
17
package org.matrix.android.sdk.internal.database
Valere's avatar
Valere committed
18
19

import io.realm.DynamicRealm
Valere's avatar
Valere committed
20
import io.realm.FieldAttribute
Valere's avatar
Valere committed
21
import io.realm.RealmMigration
Valere's avatar
Valere committed
22
23
import org.matrix.android.sdk.api.session.events.model.EventType
import org.matrix.android.sdk.api.session.room.model.create.RoomCreateContent
Valere's avatar
Valere committed
24
import org.matrix.android.sdk.api.session.room.model.tag.RoomTag
Valere's avatar
Valere committed
25
import org.matrix.android.sdk.internal.database.model.CurrentStateEventEntityFields
26
27
import org.matrix.android.sdk.internal.database.model.EditAggregatedSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.EditionOfEventFields
Valere's avatar
Valere committed
28
import org.matrix.android.sdk.internal.database.model.EventEntityFields
Benoit Marty's avatar
Benoit Marty committed
29
import org.matrix.android.sdk.internal.database.model.HomeServerCapabilitiesEntityFields
30
import org.matrix.android.sdk.internal.database.model.PendingThreePidEntityFields
31
import org.matrix.android.sdk.internal.database.model.PreviewUrlCacheEntityFields
Benoit Marty's avatar
Benoit Marty committed
32
import org.matrix.android.sdk.internal.database.model.RoomEntityFields
33
import org.matrix.android.sdk.internal.database.model.RoomMembersLoadStatusType
Benoit Marty's avatar
Benoit Marty committed
34
import org.matrix.android.sdk.internal.database.model.RoomSummaryEntityFields
Valere's avatar
Valere committed
35
36
import org.matrix.android.sdk.internal.database.model.RoomTagEntityFields
import org.matrix.android.sdk.internal.database.model.TimelineEventEntityFields
Valere's avatar
Valere committed
37
38
import org.matrix.android.sdk.internal.database.model.SpaceChildSummaryEntityFields
import org.matrix.android.sdk.internal.database.model.SpaceParentSummaryEntityFields
Valere's avatar
Valere committed
39
import org.matrix.android.sdk.internal.di.MoshiProvider
Valere's avatar
Valere committed
40
41
42
43
44
import timber.log.Timber
import javax.inject.Inject

class RealmSessionStoreMigration @Inject constructor() : RealmMigration {

45
    companion object {
46
        const val SESSION_STORE_SCHEMA_VERSION = 11L
47
48
    }

Valere's avatar
Valere committed
49
50
51
52
    override fun migrate(realm: DynamicRealm, oldVersion: Long, newVersion: Long) {
        Timber.v("Migrating Realm Session from $oldVersion to $newVersion")

        if (oldVersion <= 0) migrateTo1(realm)
53
        if (oldVersion <= 1) migrateTo2(realm)
54
        if (oldVersion <= 2) migrateTo3(realm)
55
        if (oldVersion <= 3) migrateTo4(realm)
56
        if (oldVersion <= 4) migrateTo5(realm)
57
        if (oldVersion <= 5) migrateTo6(realm)
58
        if (oldVersion <= 6) migrateTo7(realm)
59
        if (oldVersion <= 7) migrateTo8(realm)
Valere's avatar
Valere committed
60
        if (oldVersion <= 8) migrateTo9(realm)
Valere's avatar
Valere committed
61
        if (oldVersion <= 9) migrateTo10(realm)
62
        if (oldVersion <= 10) migrateTo11(realm)
Valere's avatar
Valere committed
63
64
65
66
67
68
69
70
71
72
73
74
    }

    private fun migrateTo1(realm: DynamicRealm) {
        Timber.d("Step 0 -> 1")
        // Add hasFailedSending in RoomSummary and a small warning icon on room list

        realm.schema.get("RoomSummaryEntity")
                ?.addField(RoomSummaryEntityFields.HAS_FAILED_SENDING, Boolean::class.java)
                ?.transform { obj ->
                    obj.setBoolean(RoomSummaryEntityFields.HAS_FAILED_SENDING, false)
                }
    }
75
76
77
78

    private fun migrateTo2(realm: DynamicRealm) {
        Timber.d("Step 1 -> 2")
        realm.schema.get("HomeServerCapabilitiesEntity")
79
                ?.addField("adminE2EByDefault", Boolean::class.java)
80
                ?.transform { obj ->
81
                    obj.setBoolean("adminE2EByDefault", true)
82
83
                }
    }
84
85

    private fun migrateTo3(realm: DynamicRealm) {
Benoit Marty's avatar
Benoit Marty committed
86
        Timber.d("Step 2 -> 3")
87
        realm.schema.get("HomeServerCapabilitiesEntity")
88
                ?.addField("preferredJitsiDomain", String::class.java)
Benoit Marty's avatar
Benoit Marty committed
89
90
91
92
                ?.transform { obj ->
                    // Schedule a refresh of the capabilities
                    obj.setLong(HomeServerCapabilitiesEntityFields.LAST_UPDATED_TIMESTAMP, 0)
                }
93
    }
94
95
96
97
98
99
100
101
102
103
104

    private fun migrateTo4(realm: DynamicRealm) {
        Timber.d("Step 3 -> 4")
        realm.schema.create("PendingThreePidEntity")
                .addField(PendingThreePidEntityFields.CLIENT_SECRET, String::class.java)
                .setRequired(PendingThreePidEntityFields.CLIENT_SECRET, true)
                .addField(PendingThreePidEntityFields.EMAIL, String::class.java)
                .addField(PendingThreePidEntityFields.MSISDN, String::class.java)
                .addField(PendingThreePidEntityFields.SEND_ATTEMPT, Int::class.java)
                .addField(PendingThreePidEntityFields.SID, String::class.java)
                .setRequired(PendingThreePidEntityFields.SID, true)
Benoit Marty's avatar
Benoit Marty committed
105
                .addField(PendingThreePidEntityFields.SUBMIT_URL, String::class.java)
106
    }
107
108
109
110
111
112
113

    private fun migrateTo5(realm: DynamicRealm) {
        Timber.d("Step 4 -> 5")
        realm.schema.get("HomeServerCapabilitiesEntity")
                ?.removeField("adminE2EByDefault")
                ?.removeField("preferredJitsiDomain")
    }
114
115
116
117
118
119
120
121
122
123
124
125
126
127

    private fun migrateTo6(realm: DynamicRealm) {
        Timber.d("Step 5 -> 6")
        realm.schema.create("PreviewUrlCacheEntity")
                .addField(PreviewUrlCacheEntityFields.URL, String::class.java)
                .setRequired(PreviewUrlCacheEntityFields.URL, true)
                .addPrimaryKey(PreviewUrlCacheEntityFields.URL)
                .addField(PreviewUrlCacheEntityFields.URL_FROM_SERVER, String::class.java)
                .addField(PreviewUrlCacheEntityFields.SITE_NAME, String::class.java)
                .addField(PreviewUrlCacheEntityFields.TITLE, String::class.java)
                .addField(PreviewUrlCacheEntityFields.DESCRIPTION, String::class.java)
                .addField(PreviewUrlCacheEntityFields.MXC_URL, String::class.java)
                .addField(PreviewUrlCacheEntityFields.LAST_UPDATED_TIMESTAMP, Long::class.java)
    }
128
129
130
131

    private fun migrateTo7(realm: DynamicRealm) {
        Timber.d("Step 6 -> 7")
        realm.schema.get("RoomEntity")
Benoit Marty's avatar
Benoit Marty committed
132
                ?.addField(RoomEntityFields.MEMBERS_LOAD_STATUS_STR, String::class.java)
133
134
135
136
137
138
139
140
141
                ?.transform { obj ->
                    if (obj.getBoolean("areAllMembersLoaded")) {
                        obj.setString("membersLoadStatusStr", RoomMembersLoadStatusType.LOADED.name)
                    } else {
                        obj.setString("membersLoadStatusStr", RoomMembersLoadStatusType.NONE.name)
                    }
                }
                ?.removeField("areAllMembersLoaded")
    }
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160

    private fun migrateTo8(realm: DynamicRealm) {
        Timber.d("Step 7 -> 8")

        val editionOfEventSchema = realm.schema.create("EditionOfEvent")
                .addField(EditionOfEventFields.CONTENT, String::class.java)
                .addField(EditionOfEventFields.EVENT_ID, String::class.java)
                .setRequired(EditionOfEventFields.EVENT_ID, true)
                .addField(EditionOfEventFields.SENDER_ID, String::class.java)
                .setRequired(EditionOfEventFields.SENDER_ID, true)
                .addField(EditionOfEventFields.TIMESTAMP, Long::class.java)
                .addField(EditionOfEventFields.IS_LOCAL_ECHO, Boolean::class.java)

        realm.schema.get("EditAggregatedSummaryEntity")
                ?.removeField("aggregatedContent")
                ?.removeField("sourceEvents")
                ?.removeField("lastEditTs")
                ?.removeField("sourceLocalEchoEvents")
                ?.addRealmListField(EditAggregatedSummaryEntityFields.EDITIONS.`$`, editionOfEventSchema)
Benoit Marty's avatar
Benoit Marty committed
161
162
163
164

        // This has to be done once a parent use the model as a child
        // See https://github.com/realm/realm-java/issues/7402
        editionOfEventSchema.isEmbedded = true
165
    }
Valere's avatar
Valere committed
166

167
    private fun migrateTo9(realm: DynamicRealm) {
Valere's avatar
Valere committed
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
        Timber.d("Step 8 -> 9")

        realm.schema.get("RoomSummaryEntity")
                ?.addField(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, Long::class.java, FieldAttribute.INDEXED)
                ?.setNullable(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, true)
                ?.addIndex(RoomSummaryEntityFields.MEMBERSHIP_STR)
                ?.addIndex(RoomSummaryEntityFields.IS_DIRECT)
                ?.addIndex(RoomSummaryEntityFields.VERSIONING_STATE_STR)

                ?.addField(RoomSummaryEntityFields.IS_FAVOURITE, Boolean::class.java)
                ?.addIndex(RoomSummaryEntityFields.IS_FAVOURITE)
                ?.addField(RoomSummaryEntityFields.IS_LOW_PRIORITY, Boolean::class.java)
                ?.addIndex(RoomSummaryEntityFields.IS_LOW_PRIORITY)
                ?.addField(RoomSummaryEntityFields.IS_SERVER_NOTICE, Boolean::class.java)
                ?.addIndex(RoomSummaryEntityFields.IS_SERVER_NOTICE)

                ?.transform { obj ->
                    val isFavorite = obj.getList(RoomSummaryEntityFields.TAGS.`$`).any {
                        it.getString(RoomTagEntityFields.TAG_NAME) == RoomTag.ROOM_TAG_FAVOURITE
                    }
                    obj.setBoolean(RoomSummaryEntityFields.IS_FAVOURITE, isFavorite)

                    val isLowPriority = obj.getList(RoomSummaryEntityFields.TAGS.`$`).any {
                        it.getString(RoomTagEntityFields.TAG_NAME) == RoomTag.ROOM_TAG_LOW_PRIORITY
                    }

                    obj.setBoolean(RoomSummaryEntityFields.IS_LOW_PRIORITY, isLowPriority)

//                    XXX migrate last message origin server ts
                    obj.getObject(RoomSummaryEntityFields.LATEST_PREVIEWABLE_EVENT.`$`)
                            ?.getObject(TimelineEventEntityFields.ROOT.`$`)
                            ?.getLong(EventEntityFields.ORIGIN_SERVER_TS)?.let {
                                obj.setLong(RoomSummaryEntityFields.LAST_ACTIVITY_TIME, it)
                            }
                }
    }
Valere's avatar
Valere committed
204

205
    private fun migrateTo10(realm: DynamicRealm) {
Valere's avatar
Valere committed
206
        Timber.d("Step 9 -> 10")
Valere's avatar
Valere committed
207
208
209
210
211
212
        realm.schema.create("SpaceChildSummaryEntity")
                ?.addField(SpaceChildSummaryEntityFields.ORDER, String::class.java)
                ?.addField(SpaceChildSummaryEntityFields.CHILD_ROOM_ID, String::class.java)
                ?.addField(SpaceChildSummaryEntityFields.AUTO_JOIN, Boolean::class.java)
                ?.setNullable(SpaceChildSummaryEntityFields.AUTO_JOIN, true)
                ?.addRealmObjectField(SpaceChildSummaryEntityFields.CHILD_SUMMARY_ENTITY.`$`, realm.schema.get("RoomSummaryEntity")!!)
Valere's avatar
Valere committed
213
                ?.addRealmListField(SpaceChildSummaryEntityFields.VIA_SERVERS.`$`, String::class.java)
Valere's avatar
Valere committed
214
215
216
217
218
219

        realm.schema.create("SpaceParentSummaryEntity")
                ?.addField(SpaceParentSummaryEntityFields.PARENT_ROOM_ID, String::class.java)
                ?.addField(SpaceParentSummaryEntityFields.CANONICAL, Boolean::class.java)
                ?.setNullable(SpaceParentSummaryEntityFields.CANONICAL, true)
                ?.addRealmObjectField(SpaceParentSummaryEntityFields.PARENT_SUMMARY_ENTITY.`$`, realm.schema.get("RoomSummaryEntity")!!)
Valere's avatar
Valere committed
220
                ?.addRealmListField(SpaceParentSummaryEntityFields.VIA_SERVERS.`$`, String::class.java)
Valere's avatar
Valere committed
221

Valere's avatar
Valere committed
222
        val creationContentAdapter = MoshiProvider.providesMoshi().adapter(RoomCreateContent::class.java)
Valere's avatar
Valere committed
223
224
        realm.schema.get("RoomSummaryEntity")
                ?.addField(RoomSummaryEntityFields.ROOM_TYPE, String::class.java)
Valere's avatar
Valere committed
225
                ?.addField(RoomSummaryEntityFields.FLATTEN_PARENT_IDS, String::class.java)
Valere's avatar
Valere committed
226
                ?.addField(RoomSummaryEntityFields.GROUP_IDS, String::class.java)
Valere's avatar
Valere committed
227
                ?.transform { obj ->
Valere's avatar
Valere committed
228
229
230
231
232
233
234
235
236
237
238
239

                    val creationEvent = realm.where("CurrentStateEventEntity")
                            .equalTo(CurrentStateEventEntityFields.ROOM_ID, obj.getString(RoomSummaryEntityFields.ROOM_ID))
                            .equalTo(CurrentStateEventEntityFields.TYPE, EventType.STATE_ROOM_CREATE)
                            .findFirst()

                    val roomType = creationEvent?.getObject(CurrentStateEventEntityFields.ROOT.`$`)
                            ?.getString(EventEntityFields.CONTENT)?.let {
                                creationContentAdapter.fromJson(it)?.type
                            }

                    obj.setString(RoomSummaryEntityFields.ROOM_TYPE, roomType)
Valere's avatar
Valere committed
240
                }
Valere's avatar
Valere committed
241
242
                ?.addRealmListField(RoomSummaryEntityFields.PARENTS.`$`, realm.schema.get("SpaceParentSummaryEntity")!!)
                ?.addRealmListField(RoomSummaryEntityFields.CHILDREN.`$`, realm.schema.get("SpaceChildSummaryEntity")!!)
Valere's avatar
Valere committed
243
    }
244
245
246
247
248
249

    private fun migrateTo11(realm: DynamicRealm) {
        Timber.d("Step 10 -> 11")
        realm.schema.get("EventEntity")
                ?.addField(EventEntityFields.SEND_STATE_DETAILS, String::class.java)
    }
Valere's avatar
Valere committed
250
}