Skip to content
This repository was archived by the owner on Oct 18, 2021. It is now read-only.

Code Quotations Spec

Max Hirschhorn edited this page Aug 28, 2013 · 20 revisions

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 |> ignore

Query Selectors

Comparison

$all
module Query =
    let all (x : 'a list) (y : 'a list) : bool = invalidOp "not implemented"

bson <@ fun (x : BsonDocument) -> x?tags |> Query.all [ "appliances"; "school"; "book" ] @>
$eq

There is no actual $eq operator, but you get the idea...

bson <@ fun (x : BsonDocument) -> x?qty = 20 @>
$gt
bson <@ fun (x : BsonDocument) -> x?qty > 20 @>
$gte
bson <@ fun (x : BsonDocument) -> x?qty >= 20 @>
$in

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 ] @>
$lt
bson <@ fun (x : BsonDocument) -> x?qty < 20 @>
$lte
bson <@ fun (x : BsonDocument) -> x?qty <= 20 @>
$ne
bson <@ fun (x : BsonDocument) -> x?qty <> 20 @>
$nin
module Query =
    let nin (x : 'a list) (y : 'a) : bool = invalidOp "not implemented"

bson <@ fun (x : BsonDocument) -> x?qty |> Query.nin [ 5; 15 ] @>

Logical

$or
bson <@ fun x -> x?price = 1.99 && (x?qty < 20 || x?sale = true) @>
$and
bson <@ fun x -> x?price = 1.99 && x?qty < 20 && x?sale = true @>
$not
bson <@ fun x -> not (x?price > 1.99) @>
$nor
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 ] @>

Element

$exists

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 ] @>
$mod
bson <@ fun (x : BsonDocument) -> x?qty % 4 = 0 @>
$type

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 @>

JavaScript

$where
module Query =
    let where (x : string) y : bool = invalidOp "not implemented"

bson <@ fun (x : BsonDocument) -> x |> Query.where "this.credits == this.debits" @>
$regex
let (=~) input pattern =
    System.Text.RegularExpressions.Regex.IsMatch(input, pattern)

bson <@ fun (x : BsonDocument) -> x?desc?short =~ "/acme.*corp/i" @>

Array

$elemMatch
module Query =
    let elemMatch x y : bool = invalidOp "not implemented"

bson <@ fun (x : BsonDocument) ->
    x?sizes |> Query.elemMatch (bson <@ fun (y : BsonDocument) -> y?length = 1 && y?width > 1 @>) @>
$size
module Query =
    let size (x : int) y : bool = invalidOp "not implemented"

bson <@ fun (x : BsonDocument) -> x?tags |> Query.size 2 @>

Update Operators

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.

Fields

$inc
bson <@ fun (x : BsonDocument) -> [ x?qty <- (+) 1 ] @>

bson <@ fun (x : BsonDocument) -> [ x?qty <- (-) 2 ] @>
$rename
module Update =
    let rename (x : (string * string) list) (y : 'a) : 'a = invalidOp "not implemented"

bson <@ fun (x : BsonDocument) -> [ x |> Update.rename [ ("nickname", "alias"); ("cell", "mobile") ] |> ignore ] @>
$setOnInsert
module Update =
    let setOnInsert (x : unit list) (y : 'a) : 'a = invalidOp "not implemented"

bson <@ fun (x : BsonDocument) -> [ x |> Update.setOnInsert [ x?defaultQty <- 100 ] |> ignore ] @>
$set

Should we also use an option type here, i.e. Some x, to parallel the $unset operator?

bson <@ fun (x : BsonDocument) -> [ x?qty <- 10 ] @>
$unset
bson <@ fun (x : BsonDocument) -> [ x?option <- None ] @>

Array

Operators
$
bson <@ fun (x : BsonDocument) -> [ x ? grades ? ``$`` <- 82 ] @>
$addToSet
module Update =
    let addToSet (x : 'a) (y : 'a list) : 'a list = invalidOp "not implemented"

bson <@ fun (x : BsonDocument) -> [ x?tags <- Update.addToSet "toaster" ] @>
$pop

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?sizes <- Update.popleft ] @>
bson <@ fun (x : BsonDocument) -> [ x?sizes <- Update.popright ] @>
$pull
module Update =
    let pull (x : 'a) (y : 'b list) : 'b list = invalidOp "not implemented"

bson <@ fun (x : BsonDocument) -> [ x?sizes <- Update.pull (bson <@ fun (y : BsonDocument) -> y?height = 75 @>) ] @>
$pullAll
module Update =
    let pullAll (x : 'a list) (y : 'a list) : 'a list = invalidOp "not implemented"

bson <@ fun (x : BsonDocument) -> [ x?tags <- Update.pullAll [ "appliances"; "school"; "book" ] ] @>
$push
module Update =
    let push (x : 'a) (y : 'a list) : 'a list = invalidOp "not implemented"

bson <@ fun (x : BsonDocument) -> [ x?tags <- Update.push "toaster" ] @>
Modifiers
$each
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?tags <- Update.each Update.addToSet [ "appliances"; "school"; "book" ] ] @>
bson <@ fun (x : BsonDocument) -> [ x?tags <- Update.each Update.push [ "appliances"; "school"; "book" ] ] @>
$slice
module Update =
    let slice (x : int) (y : 'a list) : 'a list = invalidOp "not implemented"

bson <@ fun (x : BsonDocument) -> [ x?tags <- Update.each Update.push [ "appliances"; "school"; "book" ]
                                           >> Update.slice -5 ] @>
$sort
module Update =
    let sort (x : 'a) (y : 'b list) : 'b list = invalidOp "not implemented"

bson <@ fun (x : BsonDocument) -> [ x?sizes <- Update.each Update.push [ { length = 3; width = 8; height = 1 }
                                                                         { length = 4; width = 7; height = 2 }
                                                                         { length = 5; width = 6; height = 4 } ]
                                            >> Update.sort (bson <@ fun (y : BsonDocument) -> y?width = 1 @>)
                                            >> Update.slice -5 } @>

Bitwise

$bit
bson <@ fun (x : BsonDocument) -> [ x?qty <- (&&&) 5 ] @>
bson <@ fun (x : BsonDocument) -> [ x?qty <- (|||) 5 ] @>