Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update to LiteDB5.0 #61

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 19 additions & 1 deletion LiteDB.FSharp.Tests/Tests.DBRef.fs
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,31 @@ open LiteDB
open LiteDB.FSharp
open LiteDB.FSharp.Experimental
open Tests.Types
open LiteDB.FSharp.Linq
open LiteDB.FSharp.Extensions
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Linq.RuntimeHelpers
open System.Linq.Expressions


let pass() = Expect.isTrue true "passed"
let fail() = Expect.isTrue false "failed"



module Linq =
let convertExpr (expr : Expr<'a -> 'b>) =
let linq = LeafExpressionConverter.QuotationToExpression expr
let call = linq :?> MethodCallExpression
let lambda = call.Arguments.[0] :?> LambdaExpression
Expression.Lambda<Func<'a, 'b>>(lambda.Body, lambda.Parameters)

[<RequireQualifiedAccess>]
type Expr =
static member prop(exp:Expression<Func<'T,'a>>) = exp


open Linq

let useDataBase (mapper:FSharpBsonMapper) (f: LiteRepository -> unit) =
mapper.DbRef<Order,_>(fun c -> c.Company)
mapper.DbRef<Order,_>(fun c -> c.EOrders)
Expand Down
1 change: 0 additions & 1 deletion LiteDB.FSharp.Tests/Tests.InheritedType.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ open System.IO
open LiteDB
open LiteDB.FSharp
open Tests.Types
open LiteDB.FSharp.Linq
open LiteDB.FSharp.Extensions
open LiteDB.FSharp.Experimental

Expand Down
15 changes: 8 additions & 7 deletions LiteDB.FSharp.Tests/Tests.LiteDatabase.fs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ let liteDatabaseUsage mapper =
let records = db.GetCollection<RecordWithSingleCaseId>("documents")
let record = { Id = SingleCaseDU 20; Value = "John" }
records.Insert(record) |> ignore

records.findOne (fun document -> document.Id = SingleCaseDU 20)
|> function
| { Id = SingleCaseDU 20; Value = "John" } -> pass()
Expand Down Expand Up @@ -553,8 +554,8 @@ let liteDatabaseUsage mapper =
values.Insert({ Id = 1; HasValue = true }) |> ignore
values.Insert({ Id = 2; HasValue = false }) |> ignore

let query = values.where <@ fun value -> value.HasValue @> id
values.Find(query)
let results = values.where <@ fun value -> value.HasValue @> id
results
|> Seq.length
|> function
| 1 -> pass()
Expand All @@ -566,8 +567,8 @@ let liteDatabaseUsage mapper =
values.Insert({ Id = 1; HasValue = true }) |> ignore
values.Insert({ Id = 2; HasValue = false }) |> ignore

let query = values.where <@ fun value -> value.Id @> (fun id -> id = 1 || id = 2)
values.Find(query)
let results = values.where <@ fun value -> value.Id @> (fun id -> id = 1 || id = 2)
results
|> Seq.length
|> function
| 2 -> pass()
Expand Down Expand Up @@ -620,15 +621,15 @@ let liteDatabaseUsage mapper =
let record = { Id = 1; Shape = shape }

records.Insert(record) |> ignore
let searchQuery =
Query.Where("Shape", fun bsonValue ->
let results =
records.FullSearch("Shape", fun bsonValue ->
let shapeValue = Bson.deserializeField<Shape> bsonValue
match shapeValue with
| Composite [ Circle 2.0; other ] -> true
| otherwise -> false
)

records.Find(searchQuery)
results
|> Seq.length
|> function
| 1 -> pass()
Expand Down
2 changes: 1 addition & 1 deletion LiteDB.FSharp.sln
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 16
VisualStudioVersion = 16.0.31025.194
VisualStudioVersion = 16.0.31025.218
MinimumVisualStudioVersion = 10.0.40219.1
Project("{6EC3EE1D-3C4E-46DD-8F32-0CC8E7565705}") = "LiteDB.FSharp", "LiteDB.FSharp\LiteDB.FSharp.fsproj", "{9A8AA256-B139-4AEA-9CEF-460BA8045617}"
EndProject
Expand Down
26 changes: 12 additions & 14 deletions LiteDB.FSharp/Bson.fs
Original file line number Diff line number Diff line change
@@ -1,32 +1,31 @@
namespace LiteDB.FSharp

open System
open System.Globalization

open FSharp.Reflection
open Newtonsoft.Json
open LiteDB
open LiteDB


/// Utilities to convert between BSON document and F# types
[<RequireQualifiedAccess>]
module Bson =
/// Returns the value of entry in the BsonDocument by it's key
let read key (doc: BsonDocument) =
let read (key: string) (doc: BsonDocument) =

doc.[key]

/// Reads a property from a BsonDocument by it's key as a string
let readStr key (doc: BsonDocument) =
let readStr (key: string) (doc: BsonDocument) =
doc.[key].AsString

/// Reads a property from a BsonDocument by it's key and converts it to an integer
let readInt key (doc: BsonDocument) =
doc.[key].AsString |> int
let readInt (key: string) (doc: BsonDocument) =
doc.[key].AsInt32

/// Reads a property from a BsonDocument by it's key and converts it to an integer
let readBool key (doc: BsonDocument) =
doc.[key].AsString |> bool.Parse
let readBool (key: string) (doc: BsonDocument) =
doc.[key].AsBoolean

/// Adds an entry to a `BsonDocument` given a key and a BsonValue
let withKeyValue key value (doc: BsonDocument) =
Expand All @@ -35,19 +34,18 @@ module Bson =

/// Reads a field from a BsonDocument as DateTime
let readDate (key: string) (doc: BsonDocument) =
let date = doc.[key].AsDateTime
if date.Kind = DateTimeKind.Local
then date.ToUniversalTime()
else date
doc.[key].AsDateTime


/// Removes an entry (property) from a `BsonDocument` by the key of that property
let removeEntryByKey (key:string) (doc: BsonDocument) =
let internal removeEntryByKey (key:string) (doc: BsonDocument) =
if (doc.ContainsKey key)
then doc.Remove(key) |> ignore
doc

let private fsharpJsonConverter = FSharpJsonConverter()
let mutable internal converters : JsonConverter[] = [| fsharpJsonConverter |]

let private converters : JsonConverter[] = [| fsharpJsonConverter |]

/// Converts a typed entity (normally an F# record) to a BsonDocument.
/// Assuming there exists a field called `Id` or `id` of the record that will be mapped to `_id` in the BsonDocument, otherwise an exception is thrown.
Expand Down
95 changes: 56 additions & 39 deletions LiteDB.FSharp/Extensions.fs
Original file line number Diff line number Diff line change
Expand Up @@ -5,12 +5,16 @@ open System.Linq.Expressions
open System
open Quotations.Patterns
open FSharp.Reflection
open Microsoft.FSharp.Quotations.DerivedPatterns
open Microsoft.FSharp.Quotations
open Microsoft.FSharp.Quotations.Patterns
open System
open Patterns

module Extensions =
open Microsoft.FSharp.Quotations

type LiteCollection<'t> with
type ILiteCollection<'t> with
/// Tries to find a document using the Id of the document.
member collection.TryFindById(id: BsonValue) =
let result : 't = collection.FindById(id)
Expand All @@ -19,7 +23,7 @@ module Extensions =
| _ -> Some result

/// Tries to find a document using the given query
member collection.TryFind (query: Query) =
member collection.TryFind (query: BsonExpression) =
let skipped = 0
let limit = 1
collection.Find(query, skipped, limit)
Expand All @@ -42,44 +46,57 @@ module Extensions =
collection.Find(query)

/// Executes a full search using the Where query
member collection.fullSearch<'t, 'u> (expr: Expr<'t -> 'u>) (pred: 'u -> bool) =
match expr with
| Lambda(_, PropertyGet(_, propInfo, [])) ->
let propName =
match propInfo.Name with
| ("Id" | "id" | "ID") -> "_id"
| _ -> propInfo.Name
let query =
Query.Where(propName, fun bsonValue ->
bsonValue
|> Bson.deserializeField<'u>
|> pred)
collection.Find(query)
| _ ->
member private collection.FullSearch<'t, 'u> (propNames: string seq, pred: BsonValue -> bool) =
collection.Query().ToDocuments()
|> Seq.filter(fun doc ->
let bsonValue =
((doc :> BsonValue) ,propNames)
||> Seq.fold(fun doc propName ->
doc.[propName]
)
pred bsonValue
)
|> Seq.map (Bson.deserialize<'t>)

/// Executes a full search using the Where query
member collection.FullSearch<'t, 'u> (propName: string, pred: BsonValue -> bool) =
collection.FullSearch<'t, 'u>(propName.Split '.', pred)

/// Executes a full search using the Where query
member collection.FullSearch<'t, 'u> (expr: Expr<'t -> 'u>, pred: BsonValue -> bool) =
match expr with
| Lambda(_, NestedPropertyNamesGetter propNames) ->
let propNames =
match propNames with
| [ "Id" | "id" | "ID" ] -> ["_id"]
| _ -> propNames

collection.FullSearch<'t, 'u>(propNames, pred)
| _ ->
let expression = sprintf "%A" expr
failwithf "Could not recognize the given expression \n%s\n, it should a simple lambda to select a property, for example: <@ fun record -> record.property @>" expression



/// Executes a full search using the Where query
member collection.fullSearch<'t, 'u> (expr: Expr<'t -> 'u>) (pred: 'u -> bool) =
collection.FullSearch<'t, 'u> (expr, (fun (bsonValue: BsonValue) ->
Bson.deserializeField bsonValue
|> pred
))


/// Creates a Query for a full search using a selector expression like `<@ fun record -> record.Name @>` and predicate
member collection.where<'t, 'u> (expr: Expr<'t -> 'u>) (pred: 'u -> bool) =
match expr with
| Lambda(_, PropertyGet(_, propInfo, [])) ->
let propName =
match propInfo.Name with
| ("Id" | "id" | "ID") -> "_id"
| _ -> propInfo.Name

Query.Where(propName, fun bsonValue ->
bsonValue
|> Bson.deserializeField<'u>
|> pred)
| _ ->
let expression = sprintf "%A" expr
failwithf "Could not recognize the given expression \n%s\n, it should a simple lambda to select a property, for example: <@ fun record -> record.property @>" expression
collection.FullSearch<'t, 'u> (expr, (fun (bsonValue: BsonValue) ->
Bson.deserializeField bsonValue
|> pred
))

/// Remove all document based on quoted expression query. Returns removed document counts
member collection.delete<'t> ([<ReflectedDefinition>] expr: Expr<'t -> bool>) =
let query = Query.createQueryFromExpr expr
collection.Delete(query)
collection.DeleteMany(query)

type LiteRepository with
///Create a new permanent index in all documents inside this collections if index not exists already.
Expand Down Expand Up @@ -111,28 +128,28 @@ module Extensions =
[<RequireQualifiedAccess>]
type LiteQueryable =
///Include DBRef field in result query execution
static member ``include`` (exp: Expression<Func<'a,'b>>) (query: LiteQueryable<'a>) =
static member ``include`` (exp: Expression<Func<'a,'b>>) (query: ILiteQueryable<'a>) =
query.Include(exp)

///Include DBRef field in result query execution
static member expand (exp: Expression<Func<'a,'b>>) (query: LiteQueryable<'a>) =
static member expand (exp: Expression<Func<'a,'b>>) (query: ILiteQueryable<'a>) =
query.Include(exp)

static member first (query: LiteQueryable<'a>) =
static member first (query: ILiteQueryable<'a>) =
query.First()

static member toList (query: LiteQueryable<'a>) =
static member toList (query: ILiteQueryable<'a>) =
query.ToEnumerable() |> List.ofSeq

///Add new Query filter when query will be executed. This filter use database index
static member where (exp: Expression<Func<'a,bool>>) (query: LiteQueryable<'a>) =
static member where (exp: Expression<Func<'a,bool>>) (query: ILiteQueryable<'a>) =
query.Where exp

static member find (exp: Expression<Func<'a,bool>>) (query: LiteQueryable<'a>) =
static member find (exp: Expression<Func<'a,bool>>) (query: ILiteQueryable<'a>) =
query |> LiteQueryable.where exp |> LiteQueryable.first

static member tryFirst (query: LiteQueryable<'a>) =
static member tryFirst (query: ILiteQueryable<'a>) =
query.ToEnumerable() |> Seq.tryHead

static member tryFind (exp: Expression<Func<'a,bool>>) (query: LiteQueryable<'a>) =
static member tryFind (exp: Expression<Func<'a,bool>>) (query: ILiteQueryable<'a>) =
query |> LiteQueryable.where exp |> LiteQueryable.tryFirst
4 changes: 2 additions & 2 deletions LiteDB.FSharp/FSharpBsonMapper.fs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ type FSharpBsonMapper() =
( fun _ types -> types.Add(t2) |> ignore; types )
) |> ignore

static member UseCustomJsonConverters(converters: JsonConverter[]) =
Bson.converters <- converters



override self.ToObject(entityType: System.Type, entity: BsonDocument) = Bson.deserializeByType entity entityType
override self.ToObject<'t>(entity: BsonDocument) = Bson.deserialize<'t> entity
Expand Down
Loading