@@ -109,6 +109,7 @@ module Store =
109109 let private openConn () =
110110 let conn = new SqliteConnection($"Data Source={dbPath}")
111111 conn.Open()
112+ conn.Execute("PRAGMA busy_timeout = 5000") |> ignore
112113 conn
113114
114115 type private ByteArrayOptionHandler() =
@@ -130,6 +131,7 @@ module Store =
130131 OptionTypes.register ()
131132 SqlMapper.AddTypeHandler(ByteArrayOptionHandler())
132133 use conn = openConn ()
134+ conn.Execute("PRAGMA journal_mode=WAL") |> ignore
133135
134136 conn.Execute(
135137 "CREATE TABLE IF NOT EXISTS profile (Id TEXT PRIMARY KEY, DisplayName TEXT NOT NULL DEFAULT '', Bio TEXT NOT NULL DEFAULT '', Photo BLOB)"
@@ -170,11 +172,9 @@ module Store =
170172 log $"schema version check: {ex.Message}"
171173 0
172174
173− // Future migrations:
174− // if dbVersion < 2 then
175− // conn.Execute("ALTER TABLE ...") |> ignore
176−
177− ignore dbVersion
175+ if dbVersion < 2 then
176+ conn.Execute("CREATE INDEX IF NOT EXISTS idx_messages_conv ON messages(ConversationId)")
177+ |> ignore
178178
179179 conn.Execute(
180180 "INSERT OR REPLACE INTO schema_meta (key, value) VALUES ('schema_version', @v)",
@@ -288,11 +288,9 @@ module Store =
288288 |> Map.ofSeq
289289
290290 let! messageRows =
291− select {
292− for m in messageTable do
293− selectAll
294− }
295− |> conn.SelectAsync<MessageRow>
291+ conn.QueryAsync<MessageRow>(
292+ "SELECT Id, ConversationId, Body, TimestampUnix, IsOutgoing, Status FROM (SELECT *, ROW_NUMBER() OVER (PARTITION BY ConversationId ORDER BY TimestampUnix DESC) AS rn FROM messages) WHERE rn <= 200"
293+ )
296294 |> Async.AwaitTask
297295
298296 let messages =
@@ -334,6 +332,7 @@ module Store =
334332 async {
335333 try
336334 use conn = openConn ()
335+ use tx = conn.BeginTransaction()
337336
338337 for c in data.Contacts.Values do
339338 do!
@@ -343,7 +342,8 @@ module Store =
343342 Nickname = c.Nickname
344343 DisplayName = c.DisplayName
345344 Bio = c.Bio
346− Photo = c.Photo |}
345+ Photo = c.Photo |},
346+ tx
347347 )
348348 |> Async.AwaitTask
349349 |> Async.Ignore
@@ -364,7 +364,8 @@ module Store =
364364 Body = m.Body
365365 TimestampUnix = m.Timestamp.ToUnixTimeMilliseconds()
366366 IsOutgoing = isOutgoing
367− Status = status |}
367+ Status = status |},
368+ tx
368369 )
369370 |> Async.AwaitTask
370371 |> Async.Ignore
@@ -374,10 +375,13 @@ module Store =
374375 "INSERT OR REPLACE INTO settings (Id, ServerUrl, PollCursor) VALUES (@Id, @ServerUrl, @PollCursor)",
375376 {| Id = Constants.settingsId
376377 ServerUrl = data.ServerUrl
377− PollCursor = data.PollCursor |}
378+ PollCursor = data.PollCursor |},
379+ tx
378380 )
379381 |> Async.AwaitTask
380382 |> Async.Ignore
383+
384+ tx.Commit()
381385 with ex ->
382386 log $"saveData error: {ex.Message}"
383387 }
@@ -440,3 +444,37 @@ module Store =
440444 with ex ->
441445 log $"dequeueOutbox error: {ex.Message}"
442446 }
447+
448+ let loadMessagesForConversation (conversationId: string) =
449+ async {
450+ try
451+ use conn = openConn ()
452+
453+ let! rows =
454+ conn.QueryAsync<MessageRow>(
455+ "SELECT Id, ConversationId, Body, TimestampUnix, IsOutgoing, Status FROM messages WHERE ConversationId = @convId ORDER BY TimestampUnix",
456+ {| convId = conversationId |}
457+ )
458+ |> Async.AwaitTask
459+
460+ return
461+ rows
462+ |> Seq.map (fun m ->
463+ { Id = m.Id
464+ Body = m.Body
465+ Timestamp = DateTimeOffset.FromUnixTimeMilliseconds m.TimestampUnix
466+ Direction =
467+ if not m.IsOutgoing then
468+ Incoming
469+ else
470+ Outgoing(
471+ if m.Status = 1 then
472+ DeliveryStatus.Delivered
473+ else
474+ DeliveryStatus.Sent
475+ ) })
476+ |> Seq.toList
477+ with ex ->
478+ log $"loadMessagesForConversation error: {ex.Message}"
479+ return []
480+ }