Intend to support all selectors and operators listed here in one form or another.
let (?) (doc : BsonDocument) (field : string) =
unbox doc.[field]
let (?<-) (doc : BsonDocument) (field : string) value =
doc.[field] = unbox value |> ignoremodule Query =
let all (x : 'a list) (y : 'a list) : bool = invalidOp "not implemented"
bson <@ fun (x : BsonDocument) -> x?tags |> Query.all [ "appliances"; "school"; "book" ] @>There is no actual $eq operator, but you get the idea...
bson <@ fun (x : BsonDocument) -> x?qty = 20 @>bson <@ fun (x : BsonDocument) -> x?qty > 20 @>bson <@ fun (x : BsonDocument) -> x?qty >= 20 @>Decided to add single-quote after identifier to avoid name conflict.
module Query =
let in' (x : 'a list) (y : 'a) : bool = invalidOp "not implemented"
bson <@ fun (x : BsonDocument) -> x?qty |> Query.in' [ 5; 15 ] @>bson <@ fun (x : BsonDocument) -> x?qty < 20 @>bson <@ fun (x : BsonDocument) -> x?qty <= 20 @>bson <@ fun (x : BsonDocument) -> x?qty <> 20 @>module Query =
let nin (x : 'a list) (y : 'a) : bool = invalidOp "not implemented"
bson <@ fun (x : BsonDocument) -> x?qty |> Query.nin [ 5; 15 ] @>bson <@ fun x -> x?price = 1.99 && (x?qty < 20 || x?sale = true) @>bson <@ fun x -> x?price = 1.99 && x?qty < 20 && x?sale = true @>bson <@ fun x -> not (x?price > 1.99) @>module Query =
let nor (x : bool list) : bool = invalidOp "not implemented"
bson <@ fun x -> Query.nor [ x?price = 1.99; x?qty < 20; x?sale = true ] @>Could define a pair of functions n/exists, or use a similar semantic of { $exists: <bool> }.
module Query =
let exists x : bool = invalidOp "not implemented"
let nexists x : bool = invalidOp "not implemented"
bson <@ fun (x : BsonDocument) -> x?qty |> Query.exists && x?qty |> Query.nin [ 5; 15 ] @>
bson <@ fun (x : BsonDocument) -> x?qty |> Query.nexists || x?qty |> Query.in [ 5; 15 ] @>bson <@ fun (x : BsonDocument) -> x?qty % 4 = 0 @>All BsonValue instances have a BsonType property, which could be used to perform the check with regard to an enum (that has meaningful names). Doing so requires an explicit upcast, however.
bson <@ fun (x : BsonDocument) -> (x?price :> BsonValue).BsonType = BsonType.Double @>The alternative is to define a function that would take an integer or type.
module Query =
let type' (x : BsonType) y : bool = invalidOp "not implemented"
bson <@ fun (x : BsonDocument) -> x?price |> Query.type' BsonType.Double @>module Query =
let where (x : string) y : bool = invalidOp "not implemented"
bson <@ fun (x : BsonDocument) -> x |> Query.where "this.credits == this.debits" @>let (=~) input pattern =
System.Text.RegularExpressions.Regex.IsMatch(input, pattern)
bson <@ fun (x : BsonDocument) -> x?field =~ "/acme.*corp/i" @>module Query =
let elemMatch x y : bool = invalidOp "not implemented"
bson <@ fun (x : BsonDocument) ->
x?array |> Query.elemMatch (bson <@ fun (y : BsonDocument) -> y?value1 = 1 && y?value2 > 1 @>) @>module Query =
let size (x : int) y : bool = invalidOp "not implemented"
bson <@ fun (x : BsonDocument) -> x?field |> Query.size 2 @>Since the update command is able to affect multiple fields with different operations, the return type of the function should be a unit list rather than a bool.
bson <@ fun (x : BsonDocument) -> [ x?age <- (+) 1 ] @>TODO
TODO
Should we also use an option type here, i.e. Some x, to parallel the $unset operator?
bson <@ fun (x : BsonDocument) -> [ x?age <- 1 ] @>bson <@ fun (x : BsonDocument) -> [ x?age <- None ] @>bson <@ fun (x : BsonDocument) -> [ x ? grades ? ``$`` <- 82 ] @>module Update =
let addToSet (x : 'a) (y : 'a list) : 'a list = invalidOp "not implemented"
bson <@ (x : BsonDocument) -> [ x?scores <- Update.addToSet 89 ] @>Could define as two separate operators: popleft and popright, or use a similar semantic of { $pop: { field: +/- 1 } }.
module Update =
let popleft (x : 'a list) : 'a list = invalidOp "not implemented"
let popright (x : 'a list) : 'a list = invalidOp "not implemented"
bson <@ fun (x : BsonDocument) -> [ x?field <- Update.popleft ] @>
bson <@ fun (x : BsonDocument) -> [ x?field <- Update.popright ] @>module Update =
let pullAll (x : 'a list) (y : 'a list) : 'a list = invalidOp "not implemented"
bson <@ fun (x : BsonDocument) -> [ x?field1 <- Update.pullAll [ value1; value2; value3 ] ] @>module Update =
let push (x : 'a) (y : 'a list) : 'a list = invalidOp "not implemented"
bson <@ (x : BsonDocument) -> [ x?scores <- Update.push 89 ] @>module Update =
let each (x : 'a -> 'a list -> 'a list) (y : 'a list) (z : 'a list) : 'a list = invalidOp "not implemented"
bson <@ fun (x : BsonDocument) -> [ x?field <- Update.each Update.addToSet [ value1; value2; ... ] ] @>
bson <@ fun (x : BsonDocument) -> [ x?field <- Update.each Update.push [ value1; value2; ... ] ] @>module Update =
let slice (x : int) (y : 'a list) : 'a list = invalidOp "not implemented"
bson <@ fun (x : BsonDocument) -> [ x?grades <- Update.each Update.push [ 80; 78; 86 ] >> Update.slide -5 ] @>module Update =
let sort (x : 'a) (y : 'b list) : 'b list = invalidOp "not implemented"
bson <@ fun (x : BsonDocument) ->
[ x?quizzes <- Update.each Update.push [ { Id = 3; Score = 8 }
{ Id = 4; Score = 7 }
{ Id = 5; Score = 6 } ]
>> Update.sort (bson <@ fun (y : BsonDocument) -> y?score = 1 @>)
>> Update.slice -5 ] @>bson <@ (x : BsonDocument) -> [ x?field <- (&&&) 5 ] @>
bson <@ (x : BsonDocument) -> [ x?field <- (|||) 5 ] @>