Skip to content

Commit 1f2b66f

Browse files
committed
Save PostViewerStatisticsEntity with viewingProfileId
1 parent 5982683 commit 1f2b66f

File tree

16 files changed

+2760
-267
lines changed

16 files changed

+2760
-267
lines changed

data-database/schemas/com.tunjid.heron.data.database.AppDatabase/19.json

Lines changed: 2327 additions & 0 deletions
Large diffs are not rendered by default.

data-database/src/commonMain/kotlin/com/tunjid/heron/data/database/AppDatabase.kt

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,8 @@ import com.tunjid.heron.data.database.entities.messageembeds.MessageFeedGenerato
5555
import com.tunjid.heron.data.database.entities.messageembeds.MessageListEntity
5656
import com.tunjid.heron.data.database.entities.messageembeds.MessagePostEntity
5757
import com.tunjid.heron.data.database.entities.messageembeds.MessageStarterPackEntity
58-
import com.tunjid.heron.data.database.entities.migrations.TimelineViewerMigration
58+
import com.tunjid.heron.data.database.entities.migrations.Migration17To18TimelineViewer
59+
import com.tunjid.heron.data.database.entities.migrations.Migration18To19PostViewerStatistics
5960
import com.tunjid.heron.data.database.entities.postembeds.ExternalEmbedEntity
6061
import com.tunjid.heron.data.database.entities.postembeds.ImageEntity
6162
import com.tunjid.heron.data.database.entities.postembeds.PostExternalEmbedEntity
@@ -69,7 +70,7 @@ import kotlinx.coroutines.Dispatchers
6970
import kotlinx.coroutines.IO
7071

7172
@Database(
72-
version = 18,
73+
version = 19,
7374
entities = [
7475
ExternalEmbedEntity::class,
7576
ImageEntity::class,
@@ -146,6 +147,7 @@ import kotlinx.coroutines.IO
146147
// Add LabelEntity and index uris for many entities
147148
AutoMigration(from = 16, to = 17),
148149
// Migration 17 - 18 is a manual migration
150+
// Migration 18 - 19 is a manual migration
149151
],
150152
exportSchema = true,
151153
)
@@ -186,7 +188,8 @@ fun RoomDatabase.Builder<AppDatabase>.configureAndBuild() =
186188
.addMigrations(
187189
NonNullPostUriAndAuthorMigration,
188190
FeedAndListsCreatedAtAutoMigration,
189-
TimelineViewerMigration,
191+
Migration17To18TimelineViewer,
192+
Migration18To19PostViewerStatistics,
190193
)
191194
.setDriver(BundledSQLiteDriver())
192195
.setQueryCoroutineContext(Dispatchers.IO)

data-database/src/commonMain/kotlin/com/tunjid/heron/data/database/daos/PostDao.kt

Lines changed: 42 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -90,48 +90,81 @@ interface PostDao {
9090
@Query(
9191
"""
9292
SELECT * FROM posts
93+
LEFT JOIN (
94+
SELECT * FROM postViewerStatistics
95+
WHERE viewingProfileId = :viewingProfileId
96+
)
97+
ON cid = postId
9398
WHERE cid IN (:postIds)
9499
"""
95100
)
96101
fun posts(
102+
viewingProfileId: String?,
97103
postIds: Collection<PostId>,
98104
): Flow<List<PopulatedPostEntity>>
99105

100106
@Transaction
101107
@Query(
102108
"""
103109
SELECT * FROM posts
110+
LEFT JOIN (
111+
SELECT * FROM postViewerStatistics
112+
WHERE viewingProfileId = :viewingProfileId
113+
)
114+
ON cid = postId
104115
WHERE uri IN (:postUris)
105116
"""
106117
)
107118
fun postEntitiesByUri(
119+
viewingProfileId: String?,
108120
postUris: Set<PostUri>,
109121
): Flow<List<PostEntity>>
110122

111123
@Transaction
112124
@Query(
113125
"""
114-
SELECT * FROM posts
115-
INNER JOIN postPosts
116-
ON cid = postPosts.embeddedPostId
117-
WHERE postId IN (:postIds)
126+
SELECT
127+
posts.*,
128+
postViewerStatistics.*,
129+
postPosts.postId AS parentPostId,
130+
postPosts.embeddedPostId AS embeddedPostId
131+
FROM posts AS posts
132+
LEFT JOIN (
133+
SELECT * FROM postViewerStatistics
134+
WHERE viewingProfileId = :viewingProfileId
135+
) AS postViewerStatistics
136+
ON posts.cid = postViewerStatistics.postId
137+
INNER JOIN postPosts AS postPosts
138+
ON posts.cid = postPosts.embeddedPostId
139+
WHERE postPosts.postId IN (:postIds)
118140
"""
119141
)
120142
fun embeddedPosts(
143+
viewingProfileId: String?,
121144
postIds: Collection<PostId>,
122145
): Flow<List<EmbeddedPopulatedPostEntity>>
123146

124147
@Transaction
125148
@Query(
126149
"""
127-
SELECT * FROM posts
128-
INNER JOIN postPosts
129-
ON cid = postPosts.embeddedPostId
130-
WHERE embeddedPostId = :quotedPostId
131-
ORDER BY indexedAt
150+
SELECT
151+
posts.*,
152+
postViewerStatistics.*,
153+
postPosts.postId AS parentPostId
154+
FROM posts AS posts
155+
LEFT JOIN (
156+
SELECT * FROM postViewerStatistics
157+
WHERE viewingProfileId = :viewingProfileId
158+
) AS postViewerStatistics
159+
ON posts.cid = postViewerStatistics.postId
160+
INNER JOIN postPosts AS postPosts
161+
ON posts.cid = postPosts.embeddedPostId
162+
WHERE postPosts.embeddedPostId = :quotedPostId
163+
ORDER BY posts.indexedAt
132164
"""
133165
)
134166
fun quotedPosts(
167+
viewingProfileId: String?,
135168
quotedPostId: String,
136169
): Flow<List<PopulatedPostEntity>>
137170

data-database/src/commonMain/kotlin/com/tunjid/heron/data/database/entities/PostEntity.kt

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,6 @@ import androidx.room.Junction
2323
import androidx.room.PrimaryKey
2424
import androidx.room.Relation
2525
import com.tunjid.heron.data.core.models.ImageList
26-
import com.tunjid.heron.data.core.models.Label
2726
import com.tunjid.heron.data.core.models.Post
2827
import com.tunjid.heron.data.core.models.fromBase64EncodedUrl
2928
import com.tunjid.heron.data.core.types.PostId
@@ -92,10 +91,7 @@ data class PopulatedPostEntity(
9291
entityColumn = "did"
9392
)
9493
val author: ProfileEntity?,
95-
@Relation(
96-
parentColumn = "cid",
97-
entityColumn = "postId",
98-
)
94+
@Embedded
9995
val viewerStats: PostViewerStatisticsEntity?,
10096
@Relation(
10197
parentColumn = "cid",
@@ -137,7 +133,7 @@ data class PopulatedPostEntity(
137133
data class EmbeddedPopulatedPostEntity(
138134
@Embedded
139135
val entity: PopulatedPostEntity,
140-
val postId: PostId,
136+
val parentPostId: PostId,
141137
val embeddedPostId: PostId,
142138
)
143139

data-database/src/commonMain/kotlin/com/tunjid/heron/data/database/entities/migrations/TimelineViewerMigration.kt renamed to data-database/src/commonMain/kotlin/com/tunjid/heron/data/database/entities/migrations/Migration17To18TimelineViewer.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import androidx.room.migration.Migration
2020
import androidx.sqlite.SQLiteConnection
2121
import androidx.sqlite.execSQL
2222

23-
internal object TimelineViewerMigration : Migration(17, 18) {
23+
internal object Migration17To18TimelineViewer : Migration(17, 18) {
2424
override fun migrate(connection: SQLiteConnection) {
2525
// Migrate timelineItems
2626

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
/*
2+
* Copyright 2024 Adetunji Dahunsi
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package com.tunjid.heron.data.database.entities.migrations
18+
19+
import androidx.room.migration.Migration
20+
import androidx.sqlite.SQLiteConnection
21+
import androidx.sqlite.execSQL
22+
23+
internal object Migration18To19PostViewerStatistics : Migration(18, 19) {
24+
override fun migrate(connection: SQLiteConnection) {
25+
// Migrate postViewerStatistics
26+
connection.execSQL(
27+
"""
28+
CREATE TABLE IF NOT EXISTS `postViewerStatistics_new` (
29+
`postId` TEXT NOT NULL,
30+
`viewingProfileId` TEXT NOT NULL,
31+
`likeUri` TEXT DEFAULT NULL,
32+
`repostUri` TEXT DEFAULT NULL,
33+
`threadMuted` INTEGER NOT NULL,
34+
`replyDisabled` INTEGER NOT NULL,
35+
`embeddingDisabled` INTEGER NOT NULL,
36+
`pinned` INTEGER NOT NULL,
37+
PRIMARY KEY(`postId`, `viewingProfileId`),
38+
FOREIGN KEY(`postId`)
39+
REFERENCES `posts`(`cid`)
40+
ON UPDATE NO ACTION
41+
ON DELETE CASCADE
42+
FOREIGN KEY(`viewingProfileId`)
43+
REFERENCES `profiles`(`did`)
44+
ON UPDATE NO ACTION
45+
ON DELETE CASCADE
46+
)
47+
""".trimIndent()
48+
)
49+
50+
// Remove the old table
51+
connection.execSQL("DROP TABLE postViewerStatistics")
52+
53+
// Change the table name to the correct one
54+
connection.execSQL("ALTER TABLE postViewerStatistics_new RENAME TO postViewerStatistics")
55+
}
56+
}

data-database/src/commonMain/kotlin/com/tunjid/heron/data/database/entities/profile/PostViewerStatisticsEntity.kt

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,22 +22,34 @@ import androidx.room.ForeignKey
2222
import androidx.room.PrimaryKey
2323
import com.tunjid.heron.data.core.types.GenericUri
2424
import com.tunjid.heron.data.core.types.PostId
25+
import com.tunjid.heron.data.core.types.ProfileId
2526
import com.tunjid.heron.data.database.entities.PostEntity
27+
import com.tunjid.heron.data.database.entities.ProfileEntity
2628

2729
@Entity(
2830
tableName = "postViewerStatistics",
31+
primaryKeys = [
32+
"postId",
33+
"viewingProfileId",
34+
],
2935
foreignKeys = [
3036
ForeignKey(
3137
entity = PostEntity::class,
3238
parentColumns = ["cid"],
3339
childColumns = ["postId"],
3440
onDelete = ForeignKey.CASCADE,
3541
),
42+
ForeignKey(
43+
entity = ProfileEntity::class,
44+
parentColumns = ["did"],
45+
childColumns = ["viewingProfileId"],
46+
onDelete = ForeignKey.CASCADE,
47+
),
3648
],
3749
)
3850
data class PostViewerStatisticsEntity(
39-
@PrimaryKey
4051
val postId: PostId,
52+
val viewingProfileId: ProfileId,
4153
@ColumnInfo(defaultValue = "NULL")
4254
val likeUri: GenericUri?,
4355
@ColumnInfo(defaultValue = "NULL")
@@ -49,19 +61,24 @@ data class PostViewerStatisticsEntity(
4961
) {
5062
sealed class Partial {
5163
abstract val postId: PostId
64+
abstract val viewingProfileId: ProfileId
65+
5266

5367
data class Like(
5468
override val postId: PostId,
69+
override val viewingProfileId: ProfileId,
5570
val likeUri: GenericUri?,
5671
) : Partial()
5772

5873
data class Repost(
5974
override val postId: PostId,
75+
override val viewingProfileId: ProfileId,
6076
val repostUri: GenericUri?,
6177
) : Partial()
6278

6379
fun asFull() = PostViewerStatisticsEntity(
6480
postId = postId,
81+
viewingProfileId = viewingProfileId,
6582
likeUri = when (this) {
6683
is Like -> likeUri
6784
is Repost -> null

data/src/commonMain/kotlin/com/tunjid/heron/data/network/models/PostConversions.kt

Lines changed: 28 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,9 @@ internal fun PostEntity.postExternalEmbedEntity(
7373
externalEmbedUri = embedEntity.uri,
7474
)
7575

76-
internal fun PostView.post(): Post {
76+
internal fun PostView.post(
77+
viewingProfileId: ProfileId?,
78+
): Post {
7779
val postEntity = postEntity()
7880
val quotedPostEntity = quotedPostEntity()
7981
val quotedPostProfileEntity = quotedPostProfileEntity()
@@ -82,7 +84,10 @@ internal fun PostView.post(): Post {
8284
profileEntity = profileEntity(),
8385
embeds = embedEntities(),
8486
viewerStatisticsEntity = viewer
85-
?.postViewerStatisticsEntity(postEntity.cid),
87+
?.postViewerStatisticsEntity(
88+
postId = postEntity.cid,
89+
viewingProfileId = viewingProfileId,
90+
),
8691
quote = if (quotedPostEntity != null && quotedPostProfileEntity != null) post(
8792
postEntity = quotedPostEntity,
8893
profileEntity = quotedPostProfileEntity,
@@ -224,19 +229,26 @@ internal fun PostView.embedEntities(): List<PostEmbed> =
224229

225230
internal fun ViewerState.postViewerStatisticsEntity(
226231
postId: PostId,
227-
) = PostViewerStatisticsEntity(
228-
postId = postId,
229-
likeUri = like?.atUri?.let(::GenericUri),
230-
repostUri = repost?.atUri?.let(::GenericUri),
231-
threadMuted = threadMuted == true,
232-
replyDisabled = replyDisabled == true,
233-
embeddingDisabled = embeddingDisabled == true,
234-
pinned = pinned == true,
235-
)
232+
viewingProfileId: ProfileId?,
233+
) =
234+
if (viewingProfileId == null) null
235+
else PostViewerStatisticsEntity(
236+
postId = postId,
237+
viewingProfileId = viewingProfileId,
238+
likeUri = like?.atUri?.let(::GenericUri),
239+
repostUri = repost?.atUri?.let(::GenericUri),
240+
threadMuted = threadMuted == true,
241+
replyDisabled = replyDisabled == true,
242+
embeddingDisabled = embeddingDisabled == true,
243+
pinned = pinned == true,
244+
)
236245

237-
internal fun ReplyRefRootUnion.postViewerStatisticsEntity() = when (this) {
246+
internal fun ReplyRefRootUnion.postViewerStatisticsEntity(
247+
viewingProfileId: ProfileId?,
248+
) = when (this) {
238249
is ReplyRefRootUnion.PostView -> value.viewer?.postViewerStatisticsEntity(
239250
postId = PostId(value.cid.cid),
251+
viewingProfileId = viewingProfileId,
240252
)
241253

242254
is ReplyRefRootUnion.BlockedPost,
@@ -245,9 +257,12 @@ internal fun ReplyRefRootUnion.postViewerStatisticsEntity() = when (this) {
245257
-> null
246258
}
247259

248-
internal fun ReplyRefParentUnion.postViewerStatisticsEntity() = when (this) {
260+
internal fun ReplyRefParentUnion.postViewerStatisticsEntity(
261+
viewingProfileId: ProfileId?,
262+
) = when (this) {
249263
is ReplyRefParentUnion.PostView -> value.viewer?.postViewerStatisticsEntity(
250264
postId = PostId(value.cid.cid),
265+
viewingProfileId = viewingProfileId,
251266
)
252267

253268
is ReplyRefParentUnion.BlockedPost,

0 commit comments

Comments
 (0)