@@ -13,7 +13,7 @@ module Store =
1313 Nickname: string
1414 DisplayName: string
1515 Bio: string
16− Photo: byte[] }
16+ Photo: byte[] option }
1717
1818 type Profile =
1919 { DisplayName: string
@@ -111,20 +111,48 @@ module Store =
111111
112112 type private ByteArrayOptionHandler() =
113113 inherit SqlMapper.TypeHandler<byte[] option>()
114+
114115 override _.SetValue(p, value) =
115− p.Value <- match value with Some v -> box v | None -> box DBNull.Value
116+ p.Value <-
117+ match value with
118+ | Some v -> box v
119+ | None -> box DBNull.Value
120+
116121 override _.Parse(value) =
117− if value = null || value :? DBNull then None else Some(value :?> byte[])
122+ if value = null || value :? DBNull then
123+ None
124+ else
125+ Some(value :?> byte[])
118126
119127 do
120128 OptionTypes.register ()
121129 SqlMapper.AddTypeHandler(ByteArrayOptionHandler())
122130 use conn = openConn ()
123− conn.Execute("CREATE TABLE IF NOT EXISTS profile (Id TEXT PRIMARY KEY, DisplayName TEXT NOT NULL DEFAULT '', Bio TEXT NOT NULL DEFAULT '', Photo BLOB)") |> ignore
124− conn.Execute("CREATE TABLE IF NOT EXISTS contacts (Pubkey TEXT PRIMARY KEY, Nickname TEXT NOT NULL DEFAULT '', DisplayName TEXT NOT NULL DEFAULT '', Bio TEXT NOT NULL DEFAULT '', Photo BLOB)") |> ignore
125− conn.Execute("CREATE TABLE IF NOT EXISTS messages (Id TEXT PRIMARY KEY, ConversationId TEXT NOT NULL, Body TEXT NOT NULL DEFAULT '', TimestampUnix INTEGER NOT NULL, IsOutgoing INTEGER NOT NULL DEFAULT 0, Status INTEGER NOT NULL DEFAULT 0)") |> ignore
126− conn.Execute("CREATE TABLE IF NOT EXISTS settings (Id TEXT PRIMARY KEY, ServerUrl TEXT NOT NULL DEFAULT '', PollCursor INTEGER NOT NULL DEFAULT 0)") |> ignore
127− conn.Execute("CREATE TABLE IF NOT EXISTS outbox (Id INTEGER PRIMARY KEY AUTOINCREMENT, RecipientHex TEXT NOT NULL, EnvelopeJson TEXT NOT NULL, CreatedAt INTEGER NOT NULL)") |> ignore
131+
132+ conn.Execute(
133+ "CREATE TABLE IF NOT EXISTS profile (Id TEXT PRIMARY KEY, DisplayName TEXT NOT NULL DEFAULT '', Bio TEXT NOT NULL DEFAULT '', Photo BLOB)"
134+ )
135+ |> ignore
136+
137+ conn.Execute(
138+ "CREATE TABLE IF NOT EXISTS contacts (Pubkey TEXT PRIMARY KEY, Nickname TEXT NOT NULL DEFAULT '', DisplayName TEXT NOT NULL DEFAULT '', Bio TEXT NOT NULL DEFAULT '', Photo BLOB)"
139+ )
140+ |> ignore
141+
142+ conn.Execute(
143+ "CREATE TABLE IF NOT EXISTS messages (Id TEXT PRIMARY KEY, ConversationId TEXT NOT NULL, Body TEXT NOT NULL DEFAULT '', TimestampUnix INTEGER NOT NULL, IsOutgoing INTEGER NOT NULL DEFAULT 0, Status INTEGER NOT NULL DEFAULT 0)"
144+ )
145+ |> ignore
146+
147+ conn.Execute(
148+ "CREATE TABLE IF NOT EXISTS settings (Id TEXT PRIMARY KEY, ServerUrl TEXT NOT NULL DEFAULT '', PollCursor INTEGER NOT NULL DEFAULT 0)"
149+ )
150+ |> ignore
151+
152+ conn.Execute(
153+ "CREATE TABLE IF NOT EXISTS outbox (Id INTEGER PRIMARY KEY AUTOINCREMENT, RecipientHex TEXT NOT NULL, EnvelopeJson TEXT NOT NULL, CreatedAt INTEGER NOT NULL)"
154+ )
155+ |> ignore
128156
129157 let private identityPath = Path.Combine(appDataDir, "identity.key")
130158
@@ -153,12 +181,18 @@ module Store =
153181 try
154182 use conn = openConn ()
155183
156− select { for p in profileTable do where (p.Id = "me") }
184+ select {
185+ for p in profileTable do
186+ where (p.Id = "me")
187+ }
157188 |> conn.SelectAsync<ProfileRow>
158189 |> Async.AwaitTask
159190 |> Async.RunSynchronously
160191 |> Seq.tryHead
161− |> Option.map (fun p -> { DisplayName = p.DisplayName; Bio = p.Bio; Photo = p.Photo })
192+ |> Option.map (fun p ->
193+ { DisplayName = p.DisplayName
194+ Bio = p.Bio
195+ Photo = p.Photo })
162196 with _ ->
163197 None
164198
@@ -168,8 +202,11 @@ module Store =
168202
169203 conn.Execute(
170204 "INSERT OR REPLACE INTO profile (Id, DisplayName, Bio, Photo) VALUES (@Id, @DisplayName, @Bio, @Photo)",
171− {| Id = "me"; DisplayName = profile.DisplayName; Bio = profile.Bio
172− Photo = profile.Photo |> Option.defaultValue null |})
205+ {| Id = "me"
206+ DisplayName = profile.DisplayName
207+ Bio = profile.Bio
208+ Photo = profile.Photo |> Option.defaultValue null |}
209+ )
173210 |> ignore
174211 with _ ->
175212 ()
@@ -179,7 +216,10 @@ module Store =
179216 use conn = openConn ()
180217
181218 let settings =
182− select { for s in settingsTable do where (s.Id = "settings") }
219+ select {
220+ for s in settingsTable do
221+ where (s.Id = "settings")
222+ }
183223 |> conn.SelectAsync<SettingsRow>
184224 |> Async.AwaitTask
185225 |> Async.RunSynchronously
@@ -188,7 +228,10 @@ module Store =
188228 settings
189229 |> Option.map (fun s ->
190230 let contacts =
191− select { for c in contactTable do selectAll }
231+ select {
232+ for c in contactTable do
233+ selectAll
234+ }
192235 |> conn.SelectAsync<ContactRow>
193236 |> Async.AwaitTask
194237 |> Async.RunSynchronously
@@ -198,13 +241,16 @@ module Store =
198241 Nickname = c.Nickname
199242 DisplayName = c.DisplayName
200243 Bio = c.Bio
201− Photo = c.Photo |> Option.defaultValue [||] }
244+ Photo = c.Photo }
202245
203246 c.Pubkey, contact)
204247 |> Map.ofSeq
205248
206249 let messages =
207− select { for m in messageTable do selectAll }
250+ select {
251+ for m in messageTable do
252+ selectAll
253+ }
208254 |> conn.SelectAsync<MessageRow>
209255 |> Async.AwaitTask
210256 |> Async.RunSynchronously
@@ -217,8 +263,15 @@ module Store =
217263 Body = m.Body
218264 Timestamp = DateTimeOffset.FromUnixTimeMilliseconds m.TimestampUnix
219265 Direction =
220− if not m.IsOutgoing then Incoming
221− else Outgoing(if m.Status = 1 then DeliveryStatus.Delivered else DeliveryStatus.Sent) })
266+ if not m.IsOutgoing then
267+ Incoming
268+ else
269+ Outgoing(
270+ if m.Status = 1 then
271+ DeliveryStatus.Delivered
272+ else
273+ DeliveryStatus.Sent
274+ ) })
222275 |> Seq.sortBy _.Timestamp
223276 |> Seq.toList)
224277 |> Map.ofSeq
@@ -237,8 +290,12 @@ module Store =
237290 for c in data.Contacts.Values do
238291 conn.Execute(
239292 "INSERT OR REPLACE INTO contacts (Pubkey, Nickname, DisplayName, Bio, Photo) VALUES (@Pubkey, @Nickname, @DisplayName, @Bio, @Photo)",
240− {| Pubkey = c.Pubkey; Nickname = c.Nickname; DisplayName = c.DisplayName; Bio = c.Bio
241− Photo = if c.Photo = null || c.Photo.Length = 0 then null else c.Photo |})
293+ {| Pubkey = c.Pubkey
294+ Nickname = c.Nickname
295+ DisplayName = c.DisplayName
296+ Bio = c.Bio
297+ Photo = c.Photo |}
298+ )
242299 |> ignore
243300
244301 data.Messages
@@ -252,28 +309,37 @@ module Store =
252309
253310 conn.Execute(
254311 "INSERT OR REPLACE INTO messages (Id, ConversationId, Body, TimestampUnix, IsOutgoing, Status) VALUES (@Id, @ConversationId, @Body, @TimestampUnix, @IsOutgoing, @Status)",
255− {| Id = m.Id; ConversationId = convId; Body = m.Body
312+ {| Id = m.Id
313+ ConversationId = convId
314+ Body = m.Body
256315 TimestampUnix = m.Timestamp.ToUnixTimeMilliseconds()
257− IsOutgoing = isOutgoing; Status = status |})
316+ IsOutgoing = isOutgoing
317+ Status = status |}
318+ )
258319 |> ignore)
259320
260321 conn.Execute(
261322 "INSERT OR REPLACE INTO settings (Id, ServerUrl, PollCursor) VALUES (@Id, @ServerUrl, @PollCursor)",
262− {| Id = "settings"; ServerUrl = data.ServerUrl; PollCursor = data.PollCursor |})
323+ {| Id = "settings"
324+ ServerUrl = data.ServerUrl
325+ PollCursor = data.PollCursor |}
326+ )
263327 |> ignore
264328 with _ ->
265329 ()
266330
267331 let enqueueOutbox (recipientHex: string) (envelopeJson: string) =
268332 use conn = openConn ()
333+
269334 insert {
270335 for o in outboxTable do
271− value
272− { Id = 0L
273− RecipientHex = recipientHex
274− EnvelopeJson = envelopeJson
275− CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }
276− excludeColumn o.Id
336+ value
337+ { Id = 0L
338+ RecipientHex = recipientHex
339+ EnvelopeJson = envelopeJson
340+ CreatedAt = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds() }
341+
342+ excludeColumn o.Id
277343 }
278344 |> conn.InsertAsync
279345 |> Async.AwaitTask
@@ -282,9 +348,10 @@ module Store =
282348
283349 let peekOutbox () : OutboxRow option =
284350 use conn = openConn ()
351+
285352 select {
286353 for o in outboxTable do
287− orderBy o.Id
354+ orderBy o.Id
288355 }
289356 |> conn.SelectAsync<OutboxRow>
290357 |> Async.AwaitTask
@@ -293,9 +360,10 @@ module Store =
293360
294361 let dequeueOutbox (id: int64) =
295362 use conn = openConn ()
363+
296364 delete {
297365 for o in outboxTable do
298− where (o.Id = id)
366+ where (o.Id = id)
299367 }
300368 |> conn.DeleteAsync
301369 |> Async.AwaitTask