Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JsonProvider<...>.Root does not have null as proper value

Tags:

f#

f#-data

I am trying to query results of the parsed Json and if I cannot find I want to do something else.

[
  {
    "orderId": 136,
    "quantity": 5,
    "price": 3.75
  },
  {
    "orderId": 129,
    "quantity": 9,
    "price": 3.55
  },
  {
    "orderId": 113,
    "quantity": 11,
    "price": 3.75
  }
]

My code is like:

type OrdersProvider = JsonProvider<"Orders.json">
let orders = OrdersProvider.GetSamples()

let test id =
    let res = query{
                    for i in orders do
                        where (i.OrderId = id)
                        select i
                        headOrDefault
                }

    if isNull(res)
        then NOT_FOUND("")
        else OK(res.JsonValue.ToString())
    )

However I am getting compiler error "JsonProvider<...>.Root does not have null as proper value". Which is kinda makes sense except I still want to catch the case when id is not in the file. I guess I could change headOrDefault to head and trap the exception but wonder if there is something better.

Update #1: Following one of the links in comments I was able to get away with

    if obj.ReferenceEquals(res,null)
        then NOT_FOUND("")
        else OK(res.JsonValue.ToString())
    )

Update #2: While mentioned code works but still feels unnatural for the language. Accepted answer looks more natural.

like image 629
AlexanderM Avatar asked Jun 29 '26 13:06

AlexanderM


1 Answers

I think the headOrDefault operation was designed for compatibility with LINQ to SQL, which is why it returns null in the default case - this is not something you'd normally want in well behaved F# code, so using it in the way your query does is not a good idea.

Fortunately, headOrDefault will work with F# option type - if you return Some from your select clause then headOrDefault returns None when the value is not available:

let res = 
  query {
    for i in orders do
    where (i.OrderId = id)
    select (Some i)
    headOrDefault }

Now you can handle the missing case with pattern matching:

match res with
| None -> NOT_FOUND("")
| Some order -> OK(order.JsonValue.ToString())
like image 149
Tomas Petricek Avatar answered Jul 03 '26 10:07

Tomas Petricek



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!