v2 RC2 #33
|
@ -6,9 +6,11 @@
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.7" />
|
<PackageReference Include="Microsoft.Data.Sqlite" Version="6.0.7" />
|
||||||
|
<PackageReference Include="Microsoft.Extensions.Caching.Abstractions" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
|
<PackageReference Include="Microsoft.Extensions.Configuration.Abstractions" Version="6.0.0" />
|
||||||
<PackageReference Include="Microsoft.FSharpLu.Json" Version="0.11.7" />
|
<PackageReference Include="Microsoft.FSharpLu.Json" Version="0.11.7" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
|
||||||
|
<PackageReference Include="NodaTime" Version="3.1.2" />
|
||||||
<PackageReference Include="Npgsql" Version="6.0.6" />
|
<PackageReference Include="Npgsql" Version="6.0.6" />
|
||||||
<PackageReference Include="Npgsql.FSharp" Version="5.3.0" />
|
<PackageReference Include="Npgsql.FSharp" Version="5.3.0" />
|
||||||
<PackageReference Include="RethinkDb.Driver" Version="2.3.150" />
|
<PackageReference Include="RethinkDb.Driver" Version="2.3.150" />
|
||||||
|
@ -31,16 +33,17 @@
|
||||||
<Compile Include="SQLite\SQLiteWebLogData.fs" />
|
<Compile Include="SQLite\SQLiteWebLogData.fs" />
|
||||||
<Compile Include="SQLite\SQLiteWebLogUserData.fs" />
|
<Compile Include="SQLite\SQLiteWebLogUserData.fs" />
|
||||||
<Compile Include="SQLiteData.fs" />
|
<Compile Include="SQLiteData.fs" />
|
||||||
<Compile Include="PostgreSql\PostgreSqlHelpers.fs" />
|
<Compile Include="Postgres\PostgresHelpers.fs" />
|
||||||
<Compile Include="PostgreSql\PostgreSqlCategoryData.fs" />
|
<Compile Include="Postgres\PostgresCache.fs" />
|
||||||
<Compile Include="PostgreSql\PostgreSqlPageData.fs" />
|
<Compile Include="Postgres\PostgresCategoryData.fs" />
|
||||||
<Compile Include="PostgreSql\PostgreSqlPostData.fs" />
|
<Compile Include="Postgres\PostgresPageData.fs" />
|
||||||
<Compile Include="PostgreSql\PostgreSqlTagMapData.fs" />
|
<Compile Include="Postgres\PostgresPostData.fs" />
|
||||||
<Compile Include="PostgreSql\PostgreSqlThemeData.fs" />
|
<Compile Include="Postgres\PostgresTagMapData.fs" />
|
||||||
<Compile Include="PostgreSql\PostgreSqlUploadData.fs" />
|
<Compile Include="Postgres\PostgresThemeData.fs" />
|
||||||
<Compile Include="PostgreSql\PostgreSqlWebLogData.fs" />
|
<Compile Include="Postgres\PostgresUploadData.fs" />
|
||||||
<Compile Include="PostgreSql\PostgreSqlWebLogUserData.fs" />
|
<Compile Include="Postgres\PostgresWebLogData.fs" />
|
||||||
<Compile Include="PostgreSqlData.fs" />
|
<Compile Include="Postgres\PostgresWebLogUserData.fs" />
|
||||||
|
<Compile Include="PostgresData.fs" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
216
src/MyWebLog.Data/Postgres/PostgresCache.fs
Normal file
216
src/MyWebLog.Data/Postgres/PostgresCache.fs
Normal file
|
@ -0,0 +1,216 @@
|
||||||
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
|
open System.Threading
|
||||||
|
open System.Threading.Tasks
|
||||||
|
open Microsoft.Extensions.Caching.Distributed
|
||||||
|
open NodaTime
|
||||||
|
open Npgsql
|
||||||
|
open Npgsql.FSharp
|
||||||
|
|
||||||
|
/// Helper types and functions for the cache
|
||||||
|
[<AutoOpen>]
|
||||||
|
module private Helpers =
|
||||||
|
|
||||||
|
/// The cache entry
|
||||||
|
type Entry =
|
||||||
|
{ /// The ID of the cache entry
|
||||||
|
Id : string
|
||||||
|
|
||||||
|
/// The value to be cached
|
||||||
|
Payload : byte[]
|
||||||
|
|
||||||
|
/// When this entry will expire
|
||||||
|
ExpireAt : Instant
|
||||||
|
|
||||||
|
/// The duration by which the expiration should be pushed out when being refreshed
|
||||||
|
SlidingExpiration : Duration option
|
||||||
|
|
||||||
|
/// The must-expire-by date/time for the cache entry
|
||||||
|
AbsoluteExpiration : Instant option
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Run a task synchronously
|
||||||
|
let sync<'T> (it : Task<'T>) = it |> (Async.AwaitTask >> Async.RunSynchronously)
|
||||||
|
|
||||||
|
/// Get the current instant
|
||||||
|
let getNow () = SystemClock.Instance.GetCurrentInstant ()
|
||||||
|
|
||||||
|
/// Create a parameter for the expire-at time
|
||||||
|
let expireParam (it : Instant) =
|
||||||
|
"@expireAt", Sql.parameter (NpgsqlParameter ("@expireAt", it))
|
||||||
|
|
||||||
|
/// Create a parameter for a possibly-missing NodaTime type
|
||||||
|
let optParam<'T> name (it : 'T option) =
|
||||||
|
let p = NpgsqlParameter ($"@%s{name}", if Option.isSome it then box it.Value else null)
|
||||||
|
p.ParameterName, Sql.parameter p
|
||||||
|
|
||||||
|
|
||||||
|
/// A distributed cache implementation in PostgreSQL used to handle sessions for myWebLog
|
||||||
|
type DistributedCache (connStr : string) =
|
||||||
|
|
||||||
|
// ~~~ INITIALIZATION ~~~
|
||||||
|
|
||||||
|
do
|
||||||
|
task {
|
||||||
|
let! exists =
|
||||||
|
Sql.connect connStr
|
||||||
|
|> Sql.query $"
|
||||||
|
SELECT EXISTS
|
||||||
|
(SELECT 1 FROM pg_tables WHERE schemaname = 'public' AND tablename = 'session')
|
||||||
|
AS {existsName}"
|
||||||
|
|> Sql.executeRowAsync Map.toExists
|
||||||
|
if not exists then
|
||||||
|
let! _ =
|
||||||
|
Sql.connect connStr
|
||||||
|
|> Sql.query
|
||||||
|
"CREATE TABLE session (
|
||||||
|
id TEXT NOT NULL PRIMARY KEY,
|
||||||
|
payload BYETA NOT NULL,
|
||||||
|
expire_at TIMESTAMPTZ NOT NULL,
|
||||||
|
sliding_expiration INTERVAL,
|
||||||
|
absolute_expiration TIMESTAMPTZ);
|
||||||
|
CREATE INDEX idx_session_expiration ON session (expire_at)"
|
||||||
|
|> Sql.executeNonQueryAsync
|
||||||
|
()
|
||||||
|
} |> sync
|
||||||
|
|
||||||
|
// ~~~ SUPPORT FUNCTIONS ~~~
|
||||||
|
|
||||||
|
/// Get an entry, updating it for sliding expiration
|
||||||
|
let getEntry key = backgroundTask {
|
||||||
|
let idParam = "@id", Sql.string key
|
||||||
|
let! tryEntry =
|
||||||
|
Sql.connect connStr
|
||||||
|
|> Sql.query "SELECT * FROM session WHERE id = @id"
|
||||||
|
|> Sql.parameters [ idParam ]
|
||||||
|
|> Sql.executeAsync (fun row ->
|
||||||
|
{ Id = row.string "id"
|
||||||
|
Payload = row.bytea "payload"
|
||||||
|
ExpireAt = row.fieldValue<Instant> "expire_at"
|
||||||
|
SlidingExpiration = row.fieldValueOrNone<Duration> "sliding_expiration"
|
||||||
|
AbsoluteExpiration = row.fieldValueOrNone<Instant> "absolute_expiration" })
|
||||||
|
|> tryHead
|
||||||
|
match tryEntry with
|
||||||
|
| Some entry ->
|
||||||
|
let now = getNow ()
|
||||||
|
let slideExp = defaultArg entry.SlidingExpiration Duration.MinValue
|
||||||
|
let absExp = defaultArg entry.AbsoluteExpiration Instant.MinValue
|
||||||
|
let needsRefresh, item =
|
||||||
|
if entry.ExpireAt = absExp then false, entry
|
||||||
|
elif slideExp = Duration.MinValue && absExp = Instant.MinValue then false, entry
|
||||||
|
elif absExp > Instant.MinValue && entry.ExpireAt.Plus slideExp > absExp then
|
||||||
|
true, { entry with ExpireAt = absExp }
|
||||||
|
else true, { entry with ExpireAt = now.Plus slideExp }
|
||||||
|
if needsRefresh then
|
||||||
|
let! _ =
|
||||||
|
Sql.connect connStr
|
||||||
|
|> Sql.query "UPDATE session SET expire_at = @expireAt WHERE id = @id"
|
||||||
|
|> Sql.parameters [ expireParam item.ExpireAt; idParam ]
|
||||||
|
|> Sql.executeNonQueryAsync
|
||||||
|
()
|
||||||
|
return if item.ExpireAt > now then Some entry else None
|
||||||
|
| None -> return None
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The last time expired entries were purged (runs every 30 minutes)
|
||||||
|
let mutable lastPurge = Instant.MinValue
|
||||||
|
|
||||||
|
/// Purge expired entries every 30 minutes
|
||||||
|
let purge () = backgroundTask {
|
||||||
|
let now = getNow ()
|
||||||
|
if lastPurge.Plus (Duration.FromMinutes 30L) < now then
|
||||||
|
let! _ =
|
||||||
|
Sql.connect connStr
|
||||||
|
|> Sql.query "DELETE FROM session WHERE expire_at < @expireAt"
|
||||||
|
|> Sql.parameters [ expireParam now ]
|
||||||
|
|> Sql.executeNonQueryAsync
|
||||||
|
lastPurge <- now
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove a cache entry
|
||||||
|
let removeEntry key = backgroundTask {
|
||||||
|
let! _ =
|
||||||
|
Sql.connect connStr
|
||||||
|
|> Sql.query "DELETE FROM session WHERE id = @id"
|
||||||
|
|> Sql.parameters [ "@id", Sql.string key ]
|
||||||
|
|> Sql.executeNonQueryAsync
|
||||||
|
()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Save an entry
|
||||||
|
let saveEntry (opts : DistributedCacheEntryOptions) key payload = backgroundTask {
|
||||||
|
let now = getNow ()
|
||||||
|
let expireAt, slideExp, absExp =
|
||||||
|
if opts.SlidingExpiration.HasValue then
|
||||||
|
let slide = Duration.FromTimeSpan opts.SlidingExpiration.Value
|
||||||
|
now.Plus slide, Some slide, None
|
||||||
|
elif opts.AbsoluteExpiration.HasValue then
|
||||||
|
let exp = Instant.FromDateTimeOffset opts.AbsoluteExpiration.Value
|
||||||
|
exp, None, Some exp
|
||||||
|
elif opts.AbsoluteExpirationRelativeToNow.HasValue then
|
||||||
|
let exp = now.Plus (Duration.FromTimeSpan opts.AbsoluteExpirationRelativeToNow.Value)
|
||||||
|
exp, None, Some exp
|
||||||
|
else
|
||||||
|
// Default to 1 hour sliding expiration
|
||||||
|
let slide = Duration.FromHours 1
|
||||||
|
now.Plus slide, Some slide, None
|
||||||
|
let! _ =
|
||||||
|
Sql.connect connStr
|
||||||
|
|> Sql.query
|
||||||
|
"INSERT INTO session (
|
||||||
|
id, payload, expire_at, sliding_expiration, absolute_expiration
|
||||||
|
) VALUES (
|
||||||
|
@id, @payload, @expireAt, @slideExp, @absExp
|
||||||
|
) ON CONFLICT (id) DO UPDATE
|
||||||
|
SET payload = EXCLUDED.payload,
|
||||||
|
expire_at = EXCLUDED.expire_at,
|
||||||
|
sliding_expiration = EXCLUDED.sliding_expiration,
|
||||||
|
absolute_expiration = EXCLUDED.absolute_expiration"
|
||||||
|
|> Sql.parameters
|
||||||
|
[ "@id", Sql.string key
|
||||||
|
"@payload", Sql.bytea payload
|
||||||
|
expireParam expireAt
|
||||||
|
optParam "slideExp" slideExp
|
||||||
|
optParam "absExp" absExp ]
|
||||||
|
|> Sql.executeNonQueryAsync
|
||||||
|
()
|
||||||
|
}
|
||||||
|
|
||||||
|
// ~~~ IMPLEMENTATION FUNCTIONS ~~~
|
||||||
|
|
||||||
|
/// Retrieve the data for a cache entry
|
||||||
|
let get key (_ : CancellationToken) = backgroundTask {
|
||||||
|
match! getEntry key with
|
||||||
|
| Some entry ->
|
||||||
|
do! purge ()
|
||||||
|
return entry.Payload
|
||||||
|
| None -> return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Refresh an entry
|
||||||
|
let refresh key (cancelToken : CancellationToken) = backgroundTask {
|
||||||
|
let! _ = get key cancelToken
|
||||||
|
()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove an entry
|
||||||
|
let remove key (_ : CancellationToken) = backgroundTask {
|
||||||
|
do! removeEntry key
|
||||||
|
do! purge ()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set an entry
|
||||||
|
let set key value options (_ : CancellationToken) = backgroundTask {
|
||||||
|
do! saveEntry options key value
|
||||||
|
do! purge ()
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IDistributedCache with
|
||||||
|
member this.Get key = get key CancellationToken.None |> sync
|
||||||
|
member this.GetAsync (key, token) = get key token
|
||||||
|
member this.Refresh key = refresh key CancellationToken.None |> sync
|
||||||
|
member this.RefreshAsync (key, token) = refresh key token
|
||||||
|
member this.Remove key = remove key CancellationToken.None |> sync
|
||||||
|
member this.RemoveAsync (key, token) = remove key token
|
||||||
|
member this.Set (key, value, options) = set key value options CancellationToken.None |> sync
|
||||||
|
member this.SetAsync (key, value, options, token) = set key value options token
|
|
@ -1,11 +1,12 @@
|
||||||
namespace MyWebLog.Data.PostgreSql
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
open Npgsql
|
open Npgsql
|
||||||
open Npgsql.FSharp
|
open Npgsql.FSharp
|
||||||
|
|
||||||
type PostgreSqlCategoryData (conn : NpgsqlConnection) =
|
/// PostgreSQL myWebLog category data implementation
|
||||||
|
type PostgresCategoryData (conn : NpgsqlConnection) =
|
||||||
|
|
||||||
/// Count all categories for the given web log
|
/// Count all categories for the given web log
|
||||||
let countAll webLogId =
|
let countAll webLogId =
|
|
@ -1,6 +1,6 @@
|
||||||
/// Helper functions for the PostgreSQL data implementation
|
/// Helper functions for the PostgreSQL data implementation
|
||||||
[<AutoOpen>]
|
[<AutoOpen>]
|
||||||
module MyWebLog.Data.PostgreSql.PostgreSqlHelpers
|
module MyWebLog.Data.Postgres.PostgresHelpers
|
||||||
|
|
||||||
open System.Threading.Tasks
|
open System.Threading.Tasks
|
||||||
open MyWebLog
|
open MyWebLog
|
|
@ -1,4 +1,4 @@
|
||||||
namespace MyWebLog.Data.PostgreSql
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
|
@ -7,7 +7,7 @@ open Npgsql
|
||||||
open Npgsql.FSharp
|
open Npgsql.FSharp
|
||||||
|
|
||||||
/// PostgreSQL myWebLog page data implementation
|
/// PostgreSQL myWebLog page data implementation
|
||||||
type PostgreSqlPageData (conn : NpgsqlConnection) =
|
type PostgresPageData (conn : NpgsqlConnection) =
|
||||||
|
|
||||||
// SUPPORT FUNCTIONS
|
// SUPPORT FUNCTIONS
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
namespace MyWebLog.Data.PostgreSql
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open System
|
open System
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
|
@ -8,7 +8,7 @@ open Npgsql
|
||||||
open Npgsql.FSharp
|
open Npgsql.FSharp
|
||||||
|
|
||||||
/// PostgreSQL myWebLog post data implementation
|
/// PostgreSQL myWebLog post data implementation
|
||||||
type PostgreSqlPostData (conn : NpgsqlConnection) =
|
type PostgresPostData (conn : NpgsqlConnection) =
|
||||||
|
|
||||||
// SUPPORT FUNCTIONS
|
// SUPPORT FUNCTIONS
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
namespace MyWebLog.Data.PostgreSql
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
|
@ -6,7 +6,7 @@ open Npgsql
|
||||||
open Npgsql.FSharp
|
open Npgsql.FSharp
|
||||||
|
|
||||||
/// PostgreSQL myWebLog tag mapping data implementation
|
/// PostgreSQL myWebLog tag mapping data implementation
|
||||||
type PostgreSqlTagMapData (conn : NpgsqlConnection) =
|
type PostgresTagMapData (conn : NpgsqlConnection) =
|
||||||
|
|
||||||
/// Find a tag mapping by its ID for the given web log
|
/// Find a tag mapping by its ID for the given web log
|
||||||
let findById tagMapId webLogId =
|
let findById tagMapId webLogId =
|
|
@ -1,4 +1,4 @@
|
||||||
namespace MyWebLog.Data.PostgreSql
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
|
@ -6,7 +6,7 @@ open Npgsql
|
||||||
open Npgsql.FSharp
|
open Npgsql.FSharp
|
||||||
|
|
||||||
/// PostreSQL myWebLog theme data implementation
|
/// PostreSQL myWebLog theme data implementation
|
||||||
type PostgreSqlThemeData (conn : NpgsqlConnection) =
|
type PostgresThemeData (conn : NpgsqlConnection) =
|
||||||
|
|
||||||
/// Retrieve all themes (except 'admin'; excludes template text)
|
/// Retrieve all themes (except 'admin'; excludes template text)
|
||||||
let all () = backgroundTask {
|
let all () = backgroundTask {
|
||||||
|
@ -135,7 +135,7 @@ type PostgreSqlThemeData (conn : NpgsqlConnection) =
|
||||||
|
|
||||||
|
|
||||||
/// PostreSQL myWebLog theme data implementation
|
/// PostreSQL myWebLog theme data implementation
|
||||||
type PostgreSqlThemeAssetData (conn : NpgsqlConnection) =
|
type PostgresThemeAssetData (conn : NpgsqlConnection) =
|
||||||
|
|
||||||
/// Get all theme assets (excludes data)
|
/// Get all theme assets (excludes data)
|
||||||
let all () =
|
let all () =
|
|
@ -1,4 +1,4 @@
|
||||||
namespace MyWebLog.Data.PostgreSql
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
|
@ -6,7 +6,7 @@ open Npgsql
|
||||||
open Npgsql.FSharp
|
open Npgsql.FSharp
|
||||||
|
|
||||||
/// PostgreSQL myWebLog uploaded file data implementation
|
/// PostgreSQL myWebLog uploaded file data implementation
|
||||||
type PostgreSqlUploadData (conn : NpgsqlConnection) =
|
type PostgresUploadData (conn : NpgsqlConnection) =
|
||||||
|
|
||||||
/// The INSERT statement for an uploaded file
|
/// The INSERT statement for an uploaded file
|
||||||
let upInsert =
|
let upInsert =
|
|
@ -1,4 +1,4 @@
|
||||||
namespace MyWebLog.Data.PostgreSql
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
|
@ -6,7 +6,7 @@ open Npgsql
|
||||||
open Npgsql.FSharp
|
open Npgsql.FSharp
|
||||||
|
|
||||||
/// PostgreSQL myWebLog web log data implementation
|
/// PostgreSQL myWebLog web log data implementation
|
||||||
type PostgreSqlWebLogData (conn : NpgsqlConnection) =
|
type PostgresWebLogData (conn : NpgsqlConnection) =
|
||||||
|
|
||||||
// SUPPORT FUNCTIONS
|
// SUPPORT FUNCTIONS
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
namespace MyWebLog.Data.PostgreSql
|
namespace MyWebLog.Data.Postgres
|
||||||
|
|
||||||
open MyWebLog
|
open MyWebLog
|
||||||
open MyWebLog.Data
|
open MyWebLog.Data
|
||||||
|
@ -6,7 +6,7 @@ open Npgsql
|
||||||
open Npgsql.FSharp
|
open Npgsql.FSharp
|
||||||
|
|
||||||
/// PostgreSQL myWebLog user data implementation
|
/// PostgreSQL myWebLog user data implementation
|
||||||
type PostgreSqlWebLogUserData (conn : NpgsqlConnection) =
|
type PostgresWebLogUserData (conn : NpgsqlConnection) =
|
||||||
|
|
||||||
/// The INSERT statement for a user
|
/// The INSERT statement for a user
|
||||||
let userInsert =
|
let userInsert =
|
|
@ -1,24 +1,24 @@
|
||||||
namespace MyWebLog.Data
|
namespace MyWebLog.Data
|
||||||
|
|
||||||
open Microsoft.Extensions.Logging
|
open Microsoft.Extensions.Logging
|
||||||
open MyWebLog.Data.PostgreSql
|
open MyWebLog.Data.Postgres
|
||||||
open Npgsql
|
open Npgsql
|
||||||
open Npgsql.FSharp
|
open Npgsql.FSharp
|
||||||
|
|
||||||
/// Data implementation for PostgreSQL
|
/// Data implementation for PostgreSQL
|
||||||
type PostgreSqlData (conn : NpgsqlConnection, log : ILogger<PostgreSqlData>) =
|
type PostgresData (conn : NpgsqlConnection, log : ILogger<PostgresData>) =
|
||||||
|
|
||||||
interface IData with
|
interface IData with
|
||||||
|
|
||||||
member _.Category = PostgreSqlCategoryData conn
|
member _.Category = PostgresCategoryData conn
|
||||||
member _.Page = PostgreSqlPageData conn
|
member _.Page = PostgresPageData conn
|
||||||
member _.Post = PostgreSqlPostData conn
|
member _.Post = PostgresPostData conn
|
||||||
member _.TagMap = PostgreSqlTagMapData conn
|
member _.TagMap = PostgresTagMapData conn
|
||||||
member _.Theme = PostgreSqlThemeData conn
|
member _.Theme = PostgresThemeData conn
|
||||||
member _.ThemeAsset = PostgreSqlThemeAssetData conn
|
member _.ThemeAsset = PostgresThemeAssetData conn
|
||||||
member _.Upload = PostgreSqlUploadData conn
|
member _.Upload = PostgresUploadData conn
|
||||||
member _.WebLog = PostgreSqlWebLogData conn
|
member _.WebLog = PostgresWebLogData conn
|
||||||
member _.WebLogUser = PostgreSqlWebLogUserData conn
|
member _.WebLogUser = PostgresWebLogUserData conn
|
||||||
|
|
||||||
member _.StartUp () = backgroundTask {
|
member _.StartUp () = backgroundTask {
|
||||||
|
|
|
@ -60,10 +60,10 @@ module DataImplementation =
|
||||||
let conn = await (rethinkCfg.CreateConnectionAsync log)
|
let conn = await (rethinkCfg.CreateConnectionAsync log)
|
||||||
upcast RethinkDbData (conn, rethinkCfg, log)
|
upcast RethinkDbData (conn, rethinkCfg, log)
|
||||||
elif hasConnStr "PostgreSQL" then
|
elif hasConnStr "PostgreSQL" then
|
||||||
let log = sp.GetRequiredService<ILogger<PostgreSqlData>> ()
|
let log = sp.GetRequiredService<ILogger<PostgresData>> ()
|
||||||
let conn = new NpgsqlConnection (connStr "PostgreSQL")
|
let conn = new NpgsqlConnection (connStr "PostgreSQL")
|
||||||
log.LogInformation $"Using PostgreSQL database {conn.Host}:{conn.Port}/{conn.Database}"
|
log.LogInformation $"Using PostgreSQL database {conn.Host}:{conn.Port}/{conn.Database}"
|
||||||
PostgreSqlData (conn, log)
|
PostgresData (conn, log)
|
||||||
else
|
else
|
||||||
upcast createSQLite "Data Source=./myweblog.db;Cache=Shared"
|
upcast createSQLite "Data Source=./myweblog.db;Cache=Shared"
|
||||||
|
|
||||||
|
@ -144,13 +144,13 @@ let rec main args =
|
||||||
// Use SQLite for caching as well
|
// Use SQLite for caching as well
|
||||||
let cachePath = defaultArg (Option.ofObj (cfg.GetConnectionString "SQLiteCachePath")) "./session.db"
|
let cachePath = defaultArg (Option.ofObj (cfg.GetConnectionString "SQLiteCachePath")) "./session.db"
|
||||||
builder.Services.AddSqliteCache (fun o -> o.CachePath <- cachePath) |> ignore
|
builder.Services.AddSqliteCache (fun o -> o.CachePath <- cachePath) |> ignore
|
||||||
| :? PostgreSqlData ->
|
| :? PostgresData ->
|
||||||
// ADO.NET connections are designed to work as per-request instantiation
|
// ADO.NET connections are designed to work as per-request instantiation
|
||||||
let cfg = sp.GetRequiredService<IConfiguration> ()
|
let cfg = sp.GetRequiredService<IConfiguration> ()
|
||||||
builder.Services.AddScoped<NpgsqlConnection> (fun sp ->
|
builder.Services.AddScoped<NpgsqlConnection> (fun sp ->
|
||||||
new NpgsqlConnection (cfg.GetConnectionString "PostgreSQL"))
|
new NpgsqlConnection (cfg.GetConnectionString "PostgreSQL"))
|
||||||
|> ignore
|
|> ignore
|
||||||
builder.Services.AddScoped<IData, PostgreSqlData> () |> ignore
|
builder.Services.AddScoped<IData, PostgresData> () |> ignore
|
||||||
// Use SQLite for caching (for now)
|
// Use SQLite for caching (for now)
|
||||||
let cachePath = defaultArg (Option.ofObj (cfg.GetConnectionString "SQLiteCachePath")) "./session.db"
|
let cachePath = defaultArg (Option.ofObj (cfg.GetConnectionString "SQLiteCachePath")) "./session.db"
|
||||||
builder.Services.AddSqliteCache (fun o -> o.CachePath <- cachePath) |> ignore
|
builder.Services.AddSqliteCache (fun o -> o.CachePath <- cachePath) |> ignore
|
||||||
|
|
Loading…
Reference in New Issue
Block a user