F#: record to query string - serialization

I'm searching for an existing solution to serialize records to query strings but found nothing. I know about F#'s pretty printing, but I have no idea how to access it manually.
In common I want something like this:
type Person = {first:string; last:string}
type Group = {name:string; size:int}
let person = {first="Mary"; last="Smith"}
let personQueryString = Something.toQueryString person
let group = {name="Full"; size=345}
let groupQueryString = Something.toQueryString group
where
personQueryString -> "first=Mary&last=Smith"
groupQueryString -> "name=Full&size=345"

I don't think such a function exists, but you can write one that uses Reflection:
open System.Reflection
module Something =
let toQueryString x =
let formatElement (pi : PropertyInfo) =
sprintf "%s=%O" pi.Name <| pi.GetValue x
x.GetType().GetProperties()
|> Array.map formatElement
|> String.concat "&"
Since it uses Reflection, it's not as efficient as specialised functions that know about the types in advance, so whether or not this is sufficient for your needs, only you know.
It produces the desired result, though:
> let person = {first="Mary"; last="Smith"};;
val person : Person = {first = "Mary";
last = "Smith";}
> let personQueryString = Something.toQueryString person;;
val personQueryString : string = "first=Mary&last=Smith"
> let group = {name="Full"; size=345};;
val group : Group = {name = "Full";
size = 345;}
> let groupQueryString = Something.toQueryString group;;
val groupQueryString : string = "name=Full&size=345"

Related

Interpolated strings in F#

I am trying to use the Entity Framework Core interpolated SQL query function in F# which requires a FormattableString. However to my surprise it doesn't function as I cannot find a way to convert a regular F# string to that type. I figured just doing what you do in C# would work but it doesn't. Here is the code I currently have:
let fromDbUser (u : Entity.User) =
{
name = u.Name
age = u.Age
phone = u.Phone
}
let mname = "Foo"
let ctx = new Entity.DatabaseContext()
ctx.User.FromSqlInterpolated($"Select * FROM User Where name = {mname};")
|> Seq.map(fromDbUser)
|> printfn "%A"
Running that block of code yields a compile error:
This token is reserved for future use
I have been trying to google around but I was unable to find any way to get this to work, any help would be most appreciated!
When this was asked, F# didn't have string interpolation.
Today though, there is an RFC for it that is merged in in F# 5.0 allowing string interpolation in F#.
The error was because the $ symbol is reserved (for 6 years+ as of writing), and will probably be used for string interpolation when it is added.
As Dave pointed out, interpolation isn't implemented yet.
But for methods that absolutely require an FormattableString or an IFormattable, you can use FormattableStringFactory.Create
let query (sql: FormattableString) =
printfn "%s" (sql.ToString(null, null))
let mname = "Foo"
let fstr = FormattableStringFactory.Create("Select * FROM User Where name = {0};", mname)
query fstr
It's available from F# 5.0.
> let mname = "Foo" ;;
val mname : string = "Foo"
> let str = $"Select * FROM User Where name = {mname};" ;;
val str : string = "Select * FROM User Where name = Foo;"
Check this out. https://learn.microsoft.com/en-us/dotnet/fsharp/whats-new/fsharp-50#string-interpolation

Easiest way of defining and using of Global Variable

"first part" &&&& fun _ ->
let ident
"second part" &&&& fun _ ->
ident ....
I need to use variable "ident".
I just need to pass value of variable from first part of test to second one...
I want to ask you if there is any easy way how to define and use global variable or even if you have better (and easy) idea of doing that
Keep in mind, please, that I am a beginner, so I would prefer easier ones.
Global variables will often make your code difficult to work with - particularly if they are mutable.
Instead, consider returning the values you need to keep track of as composite values. An easy data type to start with would be a tuple:
let ``first part`` id =
let someOtherValue = "Foo"
someOtherValue, id + 1
This function takes an int (the current ID) as input, and returns string * int (a tuple where the first element is a string, and the second element and int) as output.
You can call it like this:
> let other, newId = ``first part`` 42;;
val other : string = "Foo"
val newId : int = 43
Notice that you can use pattern matching to immediately destructure the values into two named symbols: other and newId.
Your second function could also take an ID as input:
let ``second part`` id otherArgument =
// use id here, if you need it
"Bar"
You can call it like this, with the newId value from above:
> let result = ``second part`` newId "Baz";;
val result : string = "Bar"
If you find yourself doing this a lot, you can define a record for the purpose:
type Identifiable<'a> = { Id : int; Value : 'a }
Now you can begin to define higher-order functions to deal with such a type, such as e.g. a map function:
module Identifiable =
let map f x = { Id = x.Id; Value = f x.Value }
// Other functions go here...
This is a function that maps the Value of an Identifiable from one value to another, but preserves the identity.
Here's a simple example of using it:
> let original = { Id = 42; Value = "1337" };;
val original : Identifiable<string> = {Id = 42;
Value = "1337";}
> let result' = original |> Identifiable.map System.Int32.Parse;;
val result' : Identifiable<int> = {Id = 42;
Value = 1337;}
As you can see, it preserves the value 42, but changes the Value from a string to an int.
You can still change the ID explicitly, if you want to do that:
> let result'' = { result' with Id = 7 };;
val result'' : Identifiable<int> = {Id = 7;
Value = 1337;}
Since this was getting out of hand for comments this is how I would do it for an example
let mutable t = 0
let first =
t <- 1 + 1
//other stuff
let second =
//can use t here and it will have a value of 2
In some cases you have to use a ref:
let t = ref 0
let first =
t := 1 + 1
//other stuff
let second =
//can use t here and it will have a value of 2 -
// you use "!t" to get the value
If you define ident at the top of your file like this :
let ident = "foo"
// rest of your code using ident
ident are global and you can use in the next part of your file.
EDIT :
If ident wil change in the next part of your code, use this :
let ident = ref "foo"

What local-storage tooling does WebSharper provide?

In looking at the documentation for WebSharper's local storage, the SetItem item is string * string -> unit (and GetItem is string -> string).
This means that I'll need to convert anything I want to store into strings and do the reverse to retrieve them. Or, to put it in another way, I'll need to serialize and de-serialize them. Is there a way to use the behind-the-scenes conversion that WebSharper already does for RPC calls, or am I stuck with using a server-side library like FsPicker?
Not built in yet, I have been using this helper module to make local storage usable the same way as a ref cell:
open IntelliFactory.WebSharper
// Helper for handling localstorage, making a stored value work like a ref cell.
[<JavaScript; AutoOpen>]
module LocalStorage =
open IntelliFactory.WebSharper.Html5
let localStorage = Window.Self.LocalStorage
type IValue<'T> =
abstract Value: 'T with get, set
let [<Inline>] ( ! ) (x: IValue<_>) = x.Value
let [<Inline>] ( := ) (x: IValue<_>) v = x.Value <- v
// Redefining Ref to use IValue
type Ref<'T> (value: 'T) =
let mutable v = value
interface IValue<'T> with
member this.Value
with get() = v
and set value = v <- value
let [<Inline>] ref v = Ref v
let incr i = i := !i + 1
let decr i = i := !i - 1
type IStorageItem<'T> =
inherit IValue<'T>
abstract Save: unit -> unit
abstract Delete: unit -> unit
type JSONStorageItem<'T>(key, defaultVal) =
let mutable value = None
let getValue() =
match value with
| Some v -> v
| _ ->
let v =
match localStorage.GetItem key with
| null -> defaultVal
| s ->
Json.Parse s :?> _
value <- Some v
v
interface IStorageItem<'T> with
member this.Value
with get() = getValue()
and set v =
try localStorage.SetItem(key, Json.Stringify v)
value <- Some v
with _ -> JavaScript.Alert "Saving data to storage failed."
member this.Save() =
try localStorage.SetItem(key, Json.Stringify (getValue()))
with _ -> JavaScript.Alert "Saving data to storage failed."
member this.Delete() =
localStorage.RemoveItem key
value <- None
let [<Inline>] getJSONStorage key defaultVal = JSONStorageItem<_>(key, defaultVal) :> IStorageItem<_>
However this can currently only stringify/parse straight data objects: record, list, array, tuple and union types are ok, but no prototypes are restored.

F# dynamic operator giving access both to function and function name

Given a number of functions test1, test2, ... belonging to a module:
module Checks =
let test1 x = ...
let test2 x = ...
...
how can the (?) operator be used to give access to both the function name and the function itself? The result should look like:
let name, func = Checks?test1
assert(name = "test1")
assert(func(x) = Checks.test1(x)) //whatever x is (test1 is known to be pure)
You cannot use the ? operator to access functions in a module, because the construct Checks?test1 is not syntactically correct (this would be translated to (?) Checks "test" and you cannot use module names as values).
However, it should be possible to do this for members of a type using an instance of the object (e.g. obj?test). Alternatively you could write a "fake" object instance (that knows the name of the module). The implementation of ? would then look for the module and search static members in the module.
The simplest implementation (of the first case) would look like this:
let (?) obj s =
let memb = obj.GetType().GetMethod(s)
// Return name and a function that runs the method
s, (fun args -> memb.Invoke(obj, args))
// Type that contains tests as members
type Check() =
member x.test1 () = 32
// We need to create instance in order to use '?'
let ch = Check()
let s,f = ch?test1
// Function 'f' takes array of objects as an argument and
// returns object, so the call is not as elegant as it could be
let n = ((f [| |]) :?> int)
You could also add some wrapping to make the function 'f' a little bit nicer, but I hope this demonstrates the idea. Unfortunately, this cannot work for modules.
Here's some sample code that shows off some of this. I use D as the 'dynamic' access of the Checks module plus function name.
module Checks =
let test1(x) = printfn "test1 %d" x
let test2(x,y) = printfn "test2 %s %d" x y
type MyDynamic() = class end
let D = new MyDynamic()
let (?) (md:MyDynamic) fname : (string * ('a -> 'r)) =
let a = md.GetType().Assembly
let t = a.GetType("Program+Checks")
let m = t.GetMethod(fname)
let f arg =
let at = arg.GetType()
let fsharpArgs =
if at.IsGenericType && at.GetGenericTypeDefinition().FullName.StartsWith("System.Tuple`") then
Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields(arg)
else
[| box arg |]
unbox(m.Invoke(null, fsharpArgs))
fname, f
let Main() =
let x = 42
let s = "foo"
let name, func = D?test1
assert(name = "test1")
assert(func(x) = Checks.test1(x))
let name, func = D?test2
assert(name = "test2")
assert(func(s,x) = Checks.test2(s,x))
System.Console.ReadKey()
Main()

More FP-correct way to create an update sql query

I am working on access a database using F# and my initial attempt at creating a function to create the update query is flawed.
let BuildUserUpdateQuery (oldUser:UserType) (newUser:UserType) =
let buf = new System.Text.StringBuilder("UPDATE users SET ");
if (oldUser.FirstName.Equals(newUser.FirstName) = false) then buf.Append("SET first_name='").Append(newUser.FirstName).Append("'" ) |> ignore
if (oldUser.LastName.Equals(newUser.LastName) = false) then buf.Append("SET last_name='").Append(newUser.LastName).Append("'" ) |> ignore
if (oldUser.UserName.Equals(newUser.UserName) = false) then buf.Append("SET username='").Append(newUser.UserName).Append("'" ) |> ignore
buf.Append(" WHERE id=").Append(newUser.Id).ToString()
This doesn't properly put a , between any update parts after the first, for example:
UPDATE users SET first_name='Firstname', last_name='lastname' WHERE id=...
I could put in a mutable variable to keep track when the first part of the set clause is appended, but that seems wrong.
I could just create an list of tuples, where each tuple is oldtext, newtext, columnname, so that I could then loop through the list and build up the query, but it seems that I should be passing in a StringBuilder to a recursive function, returning back a boolean which is then passed as a parameter to the recursive function.
Does this seem to be the best approach, or is there a better one?
UPDATE:
Here is what I am using as my current solution, as I wanted to make it more generalized, so I just need to write an abstract class for my entities to derive from and they can use the same function. I chose to split up how I do the function so I can pass in how to create the SET part of the update so I can test with different ideas.
let BuildUserUpdateQuery3 (oldUser:UserType) (newUser:UserType) =
let properties = List.zip3 oldUser.ToSqlValuesList newUser.ToSqlValuesList oldUser.ToSqlColumnList
let init = false, new StringBuilder()
let anyChange, (formatted:StringBuilder) =
properties |> Seq.fold (fun (anyChange, sb) (oldVal, newVal, name) ->
match(oldVal=newVal) with
| true -> anyChange, sb
| _ ->
match(anyChange) with
| true -> true, sb.AppendFormat(",{0} = '{1}'", name, newVal)
| _ -> true, sb.AppendFormat("{0} = '{1}'", name, newVal)
) init
formatted.ToString()
let BuildUserUpdateQuery (oldUser:UserType) (newUser:UserType) (updatequery:UserType->UserType->String) =
let buf = StringBuilder("UPDATE users SET ");
buf.AppendFormat(" {0} WHERE id={1}", (updatequery oldUser newUser), newUser.Id)
let UpdateUser conn (oldUser:UserType) (newUser:UserType) =
let query = BuildUserUpdateQuery oldUser newUser BuildUserUpdateQuery3
execNonQuery conn (query.ToString())
Is this the tuple solution you had in mind?
let BuildUserUpdateQuery (oldUser:UserType) (newUser:UserType) =
let buf = StringBuilder("UPDATE users set ")
let properties =
[(oldUser.FirstName, newUser.FirstName, "first_name")
(oldUser.LastName, newUser.LastName, "last_name")
(oldUser.UserName, newUser.UserName, "username")]
|> Seq.map (fun (oldV, newV, field) ->
if oldV <> newV
then sprintf "%s='%s'" field newV
else null)
|> Seq.filter (fun p -> p <> null)
|> Seq.toArray
if properties.Length = 0
then None
else
bprintf buf "%s" (String.Join(", ", properties))
bprintf buf " where id=%d" newUser.Id
Some <| buf.ToString()
I don't see how the recursive solution could be simpler than this...
BTW I would strongly advise to use proper SQL parameters instead of just concatenating the values, you might become vulnerable to injection attacks...
Just for completeness, here is a version that does the same thing directly using the fold function. This can be done quite elegantly, because methods of StringBuilder return the StringBuilder (which allows you to chain them in C#). This can be also used nicely for folding.
Let's assume that we have the list of tuples from the solution by Mauricio:
let properties =
[ (oldUser.FirstName, newUser.FirstName, "first_name")
(oldUser.LastName, newUser.LastName, "last_name")
(oldUser.UserName, newUser.UserName, "username") ]
Now you can write the following code (it also returns a flag whether anything has changed):
let init = false, new StringBuilder()
let anyChange, formatted =
properties |> Seq.fold (fun (anyChange, sb) (oldVal, newVal, name) ->
if (oldVal = newVal) anyChange, sb
else true, sb.AppendFormat("{0} = '{1}'", name, newVal)) init
The state kept during folding has type bool * StringBuilder and we start with an initial value containing empty string builder and false. In each step, we either return the original state (if value is the same as previous) or a new state containing true and a new version of the StringBuilder returned by AppendFormat.
Using recursion explicitly would also work, but when you can use some built-in F# function, it is usually easier to use this approach. If you needed to process nested entities of each entity, you could use the Seq.collect function together with recursion to get a list of properties that you need to process using fold. Pseudo-code might look like this:
let rec processEntities list names =
// Pair matching entity with the name from the list of names
List.zip list names
|> List.collect (fun (entity, name) ->
// Current element containing old value, new value and property name
let current = (entity.OldValue, entity.NewValue, name)
// Recursively proces nested entitites
let nested = processEntities entity.Nested
current::nested)
This can be more elegantly written using sequence expressions:
let rec processEntities list =
seq { for entity, name in List.zip list names do
yield (entity.OldValue, entity.NewValue, name)
yield! processEntities entity.Nested }
Then you could simply call processEntities which returns a flat list of entities and process the entities using fold as in the first case.
I like both Mauricio's and Tomas's solutions, but perhaps this is more like what you originally envisioned?
let sqlFormat (value:'a) = //'
match box value with
| :? int | :? float -> value.ToString()
| _ -> sprintf "'%A'" value // this should actually use database specific escaping logic to make it safe
let appendToQuery getProp (sqlName:string) (oldEntity,newEntity,statements) =
let newStatements =
if (getProp oldEntity <> getProp newEntity) then (sprintf "%s=%s" sqlName (sqlFormat (getProp newEntity)))::statements
else statements
(oldEntity, newEntity, newStatements)
let createUserUpdate (oldUser:UserType) newUser =
let (_,_,statements) =
(oldUser,newUser,[])
|> appendToQuery (fun u -> u.FirstName) "first_name"
|> appendToQuery (fun u -> u.LastName) "last_name"
|> appendToQuery (fun u -> u.UserName) "username"
// ...
let statementArr = statements |> List.toArray
if (statementArr.Length > 0) then
let joinedStatements = System.String.Join(", ", statementArr)
Some(sprintf "UPDATE users SET %s WHERE ID=%i" joinedStatements newUser.ID)
else
None
If you have lots of properties to check, this may be a bit more concise. One benefit to this approach is that it works even if you're checking properties of multiple types, whereas the other approaches require all properties to have the same type (since they're stored in a list).