WIP on SQLite JSON documents
This commit is contained in:
@@ -66,26 +66,26 @@ open MyWebLog.Data
|
||||
open NodaTime.Text
|
||||
|
||||
/// Run a command that returns a count
|
||||
let count (cmd : SqliteCommand) = backgroundTask {
|
||||
let! it = cmd.ExecuteScalarAsync ()
|
||||
let count (cmd: SqliteCommand) = backgroundTask {
|
||||
let! it = cmd.ExecuteScalarAsync()
|
||||
return int (it :?> int64)
|
||||
}
|
||||
|
||||
/// Create a list of items from the given data reader
|
||||
let toList<'T> (it : SqliteDataReader -> 'T) (rdr : SqliteDataReader) =
|
||||
let toList<'T> (it: SqliteDataReader -> 'T) (rdr: SqliteDataReader) =
|
||||
seq { while rdr.Read () do it rdr }
|
||||
|> List.ofSeq
|
||||
|
||||
/// Verify that the web log ID matches before returning an item
|
||||
let verifyWebLog<'T> webLogId (prop : 'T -> WebLogId) (it : SqliteDataReader -> 'T) (rdr : SqliteDataReader) =
|
||||
if rdr.Read () then
|
||||
if rdr.Read() then
|
||||
let item = it rdr
|
||||
if prop item = webLogId then Some item else None
|
||||
else None
|
||||
|
||||
/// Execute a command that returns no data
|
||||
let write (cmd : SqliteCommand) = backgroundTask {
|
||||
let! _ = cmd.ExecuteNonQueryAsync ()
|
||||
let write (cmd: SqliteCommand) = backgroundTask {
|
||||
let! _ = cmd.ExecuteNonQueryAsync()
|
||||
()
|
||||
}
|
||||
|
||||
@@ -366,7 +366,26 @@ module Map =
|
||||
CreatedOn = getInstant "created_on" rdr
|
||||
LastSeenOn = tryInstant "last_seen_on" rdr
|
||||
}
|
||||
|
||||
/// Map from a document to a domain type, specifying the field name for the document
|
||||
let fromData<'T> ser rdr fieldName : 'T =
|
||||
Utils.deserialize<'T> ser (getString fieldName rdr)
|
||||
|
||||
/// Map from a document to a domain type
|
||||
let fromDoc<'T> ser rdr : 'T =
|
||||
fromData<'T> ser rdr "data"
|
||||
|
||||
/// Queries to assist with document manipulation
|
||||
module Query =
|
||||
|
||||
/// Fragment to add an ID condition to a WHERE clause
|
||||
let whereById =
|
||||
"data ->> 'Id' = @id"
|
||||
|
||||
/// Fragment to add a web log ID condition to a WHERE clause
|
||||
let whereWebLogId =
|
||||
"data ->> 'WebLogId' = @webLogId"
|
||||
|
||||
/// Add a web log ID parameter
|
||||
let addWebLogId (cmd: SqliteCommand) (webLogId: WebLogId) =
|
||||
cmd.Parameters.AddWithValue ("@webLogId", string webLogId) |> ignore
|
||||
cmd.Parameters.AddWithValue("@webLogId", string webLogId) |> ignore
|
||||
|
||||
@@ -4,9 +4,10 @@ open System.Threading.Tasks
|
||||
open Microsoft.Data.Sqlite
|
||||
open MyWebLog
|
||||
open MyWebLog.Data
|
||||
open Newtonsoft.Json
|
||||
|
||||
/// SQLite myWebLog category data implementation
|
||||
type SQLiteCategoryData(conn: SqliteConnection) =
|
||||
type SQLiteCategoryData(conn: SqliteConnection, ser: JsonSerializer) =
|
||||
|
||||
/// Add parameters for category INSERT or UPDATE statements
|
||||
let addCategoryParameters (cmd: SqliteCommand) (cat: Category) =
|
||||
@@ -34,8 +35,8 @@ type SQLiteCategoryData(conn: SqliteConnection) =
|
||||
|
||||
/// Count all categories for the given web log
|
||||
let countAll webLogId = backgroundTask {
|
||||
use cmd = conn.CreateCommand ()
|
||||
cmd.CommandText <- "SELECT COUNT(id) FROM category WHERE web_log_id = @webLogId"
|
||||
use cmd = conn.CreateCommand()
|
||||
cmd.CommandText <- $"SELECT COUNT(*) FROM {Table.Category} WHERE {whereWebLogId}"
|
||||
addWebLogId cmd webLogId
|
||||
return! count cmd
|
||||
}
|
||||
@@ -44,25 +45,27 @@ type SQLiteCategoryData(conn: SqliteConnection) =
|
||||
let countTopLevel webLogId = backgroundTask {
|
||||
use cmd = conn.CreateCommand ()
|
||||
cmd.CommandText <-
|
||||
"SELECT COUNT(id) FROM category WHERE web_log_id = @webLogId AND parent_id IS NULL"
|
||||
$"SELECT COUNT(*) FROM {Table.Category}
|
||||
WHERE {whereWebLogId} AND data ->> '{nameof Category.Empty.ParentId}' IS NULL"
|
||||
addWebLogId cmd webLogId
|
||||
return! count cmd
|
||||
}
|
||||
|
||||
// TODO: need to get SQLite in clause format for JSON documents
|
||||
/// Retrieve all categories for the given web log in a DotLiquid-friendly format
|
||||
let findAllForView webLogId = backgroundTask {
|
||||
use cmd = conn.CreateCommand ()
|
||||
cmd.CommandText <- "SELECT * FROM category WHERE web_log_id = @webLogId"
|
||||
use cmd = conn.CreateCommand()
|
||||
cmd.CommandText <- $"SELECT data FROM {Table.Category} WHERE {whereWebLogId}"
|
||||
addWebLogId cmd webLogId
|
||||
use! rdr = cmd.ExecuteReaderAsync ()
|
||||
use! rdr = cmd.ExecuteReaderAsync()
|
||||
let cats =
|
||||
seq {
|
||||
while rdr.Read () do
|
||||
Map.toCategory rdr
|
||||
while rdr.Read() do
|
||||
Map.fromDoc<Category> ser rdr
|
||||
}
|
||||
|> Seq.sortBy (fun cat -> cat.Name.ToLowerInvariant ())
|
||||
|> Seq.sortBy _.Name.ToLowerInvariant()
|
||||
|> List.ofSeq
|
||||
do! rdr.CloseAsync ()
|
||||
do! rdr.CloseAsync()
|
||||
let ordered = Utils.orderByHierarchy cats None None []
|
||||
let! counts =
|
||||
ordered
|
||||
@@ -71,7 +74,7 @@ type SQLiteCategoryData(conn: SqliteConnection) =
|
||||
let catSql, catParams =
|
||||
ordered
|
||||
|> Seq.filter (fun cat -> cat.ParentNames |> Array.contains it.Name)
|
||||
|> Seq.map (fun cat -> cat.Id)
|
||||
|> Seq.map _.Id
|
||||
|> Seq.append (Seq.singleton it.Id)
|
||||
|> List.ofSeq
|
||||
|> inClause "AND pc.category_id" "catId" id
|
||||
@@ -103,12 +106,12 @@ type SQLiteCategoryData(conn: SqliteConnection) =
|
||||
/// Find a category by its ID for the given web log
|
||||
let findById (catId: CategoryId) webLogId = backgroundTask {
|
||||
use cmd = conn.CreateCommand()
|
||||
cmd.CommandText <- "SELECT * FROM category WHERE id = @id"
|
||||
cmd.Parameters.AddWithValue ("@id", string catId) |> ignore
|
||||
cmd.CommandText <- $"SELECT * FROM {Table.Category} WHERE {Query.whereById}"
|
||||
cmd.Parameters.AddWithValue("@id", string catId) |> ignore
|
||||
use! rdr = cmd.ExecuteReaderAsync()
|
||||
return verifyWebLog<Category> webLogId (_.WebLogId) Map.toCategory rdr
|
||||
return verifyWebLog<Category> webLogId (_.WebLogId) (Map.fromDoc ser) rdr
|
||||
}
|
||||
|
||||
// TODO: stopped here
|
||||
/// Find all categories for the given web log
|
||||
let findByWebLog (webLogId: WebLogId) = backgroundTask {
|
||||
use cmd = conn.CreateCommand ()
|
||||
|
||||
Reference in New Issue
Block a user