How to convert op to query in jena? - jena

My code is:
String s="";//some query
Query query = QueryFactory.create(s);
Op op = Algebra.compile(query) ;
op = Algebra.optimize(op) ;
How can I convert the op back to query? I tried:
query=OpAsQuery.asQuery(op);
but it doesn't work.

Related

Replace the value of one item of single case discriminated union?

See I have a single case discriminated union
type R = R of string * int * sting option * .....
And I got a value of R.
let r: R = getAValue ()
Now I need to replace the first item of r to an empty string and keep all other value. How to do it? Record type has the with construct
let r' = { r with Item1 = "" }
I know it can use 'pattern match' to extract all the items and create a new one. But it seems very cumbersome.
I assume you do not want to involve reflection, do you?
Then, I believe your only option would be using pattern matching. The (quite limited) burden would be defining the r-ity of your type Ras a pattern for matching.
Let's assume, for example, that your R wraps a tuple of 3 elements, i.e. has r-ity 3:
type R = R of string * int * string option
In this case all you need is to do define the following function:
let modR = function
| R(x,y,z) -> R("",y,z)
The signature of modR is R -> R, a quick check of your scenario:
let r = R("abc",1,None)
modR r
in fsi brings back
>
val it : R = R ("",1,None)
All you would need for applying the above to your specific R is set the actual r-ity of your type into the pattern.
UPDATE: As Fyodor Soikin pointed, a matching function isn't needed at all for unwrapping a single-case DU (see the docs). The sought convertion function definition may be defined as simple as
let modR (R(_,y,z)) = R("",y,z)
UPDATE2: While considering the comment from ca9163d9 I recalled just another flavor of pattern matching, namely as Pattern. Using it while implementing the sought conversion in the form of DU member gives:
type R = R of string * int * string option with
member self.modR() = let R(_,b,c) as x = self in R("",b,c)
Also #FyodorSoikin and #kaefer have pointed out in the comments that as x form isn't required for the simple DU unwrapping, similarly to terser modR function definition above:
member self.modR() = let (R(_,b,c)) = self in R("",b,c)

F# SqlCommand Output Parameters

In F# best way to set up a SQLCommand with parameters
some very neat solutions were given for constructing SQLCommand input parameters. Now I need to do some output parameters for calling a stored procedure that returns two output parameters.
So far I have:
let cmd = (createSqlCommand query conn)
let pec = (new SqlParameter("#errorCode", SqlDbType.Int))
pec.Direction <- ParameterDirection.Output
ignore (cmd.Parameters.Add(pec))
let pet = new SqlParameter("#errorMessage", SqlDbType.VarChar, 2000)
pet.Direction <- ParameterDirection.Output
ignore (cmd.Parameters.Add(pet))
let rc = cmd.ExecuteNonQuery()
let errorCode = cmd.Parameters.Item("#errorCode").Value.ToString()
let errorText = cmd.Parameters.Item("#errorMessage").Value.ToString()
Which works, but I find it ugly and too imperative. How can I expand the solutions in the previous example, (especially Tomas, which I'm now using) to handle output parameters too? So input and output in the same command to be issued.
So I tried this:
type Command =
{ Query : string
Timeout : int
Parameters : (string * Parameter) list
OutParameters : Option<(string * OutParameter)> list}
followed by this:
let createSqlCommand cmd connection =
let sql = new SqlCommand(cmd.Query, connection)
sql.CommandTimeout <- cmd.Timeout
for name, par in cmd.Parameters do
let sqlTyp, value =
match par with
| Int n -> SqlDbType.Int, box n
| VarChar s -> SqlDbType.VarChar, box s
| Text s -> SqlDbType.Text, box s
| DateTime dt -> SqlDbType.DateTime, box dt
sql.Parameters.Add(name, sqlTyp).Value <- value
match cmd.OutParameters with
| Some <string * OutParameter> list ->
for name, par in list do
let sqlParameter =
match par with
| OutInt -> new SqlParameter(name, SqlDbType.Int)
| OutVarChar len -> new SqlParameter(name, SqlDbType.VarChar, len)
sqlParameter.Direction <- ParameterDirection.Output
sql.Parameters.Add sqlParameter |> ignore
| _ -> ()
But I can't work out the syntax for the match near the end. I tried:
Some list -> and got
Error 52 This expression was expected to have type
Option list but here has type
'a option
Then I tried:
| Some Option<string * OutParameter> list ->
got the same error, So I tried:
| Some <string * OutParameter> list ->
got a different error:
Error 53 Unexpected identifier in pattern. Expected infix operator,
quote symbol or other token.
Then tried:
| Some <(string * OutParameter)> list ->
got the error:
Error 53 Unexpected symbol '(' in pattern. Expected infix operator,
quote symbol or other token.
Finally tried:
| Some (string * OutParameter) list ->
and got the first error again.
Then, I gave up.
What syntax is needed here?
Thought up a new one:
| Some list : (string * OutParameter) ->
for name, par in list do
but that errors on "for"
Error 53 Unexpected keyword 'for' in type
New Attempt:
I thought maybe I could define a function to build a sql command expecting output parameters and still use the first createSqlCommand function. I tried this:
type OutCommand =
{ Query : string
Timeout : int
Parameters : (string * Parameter) list
OutParameters : (string * OutParameter) list
}
let createSqlCommandOut (cmd : OutCommand) connection =
let sql = createSqlCommand {cmd.Query; cmd.Timeout; cmd.Parameters} connection
for name, par in cmd.OutParameters do
let sqlParameter =
match par with
| OutInt -> new SqlParameter(name, SqlDbType.Int)
| OutVarChar len -> new SqlParameter(name, SqlDbType.VarChar, len)
sqlParameter.Direction <- ParameterDirection.Output
sql.Parameters.Add sqlParameter |> ignore
sql
The idea is to grab the parameters passed in and send them on to the original function to do the work. You probably guessed that this doesn't work. I get the errors;
Error 53 Invalid object, sequence or record expression
On the call to createSqlCommand in the new function. Is this kind of thing possible? Can I make a Command record using the members of an OutCommand record? If so, how do I do the casting? (It seems to be neither an upcast downcast)
Tomas is of course much better qualified to answer this, but I'll give it a try. If he does answer, It'll be interesting to see if I'm on the right track. I guess I'm slightly off.
Bear with me if this doesn't quite run well, since I won't test it. I will base this on the code Tomas gave us.
I think we need a new OutParameter type.
type OutParameter =
| OutInt
| OutVarChar of int // the length is needed?
In the Command type we add an extra field named OutParameters.
type Command =
{ Query : string
Timeout : int
Parameters : (string * Parameter) list
OutParameters : (string * OutParameter) list }
In the cmd function, this must be added.
OutParameters =
[ "#errorCode", OutInt
"#errorMessage", OutVarChar 2000 ]
The function createSqlCommand must now also handle OutParameters. The last for-loop is the only modification here.
let createSqlCommand cmd connection =
let sql = new SqlCommand(cmd.Query, connection)
sql.CommandTimeout <- cmd.Timeout
for name, par in cmd.Parameters do
let sqlTyp, value =
match par with
| Int n -> SqlDbType.Int, box n
| VarChar s -> SqlDbType.VarChar, box s
| Text s -> SqlDbType.Text, box s
| DateTime dt -> SqlDbType.DateTime, box dt
sql.Parameters.Add(name, sqlTyp).Value <- value
for name, par in cmd.OutParameters do
let sqlParameter =
match par with
| OutInt -> new SqlParameter(name, SqlDbType.Int)
| OutVarChar len -> new SqlParameter(name, SqlDbType.VarChar, len)
sqlParameter.Direction <- ParameterDirection.Output
sql.Parameters.Add sqlParameter |> ignore
sql
After you have run your ExecuteNonQuery, you can again take advantage of your list of OutParameters to parse the output.
Now a function to extract the values.
let extractOutParameters (cmd: SqlCommand) (outParms: (string * OutParameter) list) =
outParms
|> List.map (fun (name, outType) ->
match outType with
| OutInt -> cmd.Parameters.Item(name).Value :?> int |> Int
| OutVarChar _ -> cmd.Parameters.Item(name).Value.ToString() |> VarChar
)
I am not at all sure that casting the values like this is good, and you probably should match on the type instead, to handle errors properly. Test it. But that's a minor issue not much related to what I'm trying to demonstrate.
Notice that this function uses the Parameter type for returning the values, rather than the OutParameter type. At this point I would consider changing the names of one or both types, to better reflect their use.
UPDATE
You can use this to create specific functions for commands and queries. Here is a slightly pseudo-codish F# snippet.
type UserInfo = { UserName: string; Name: string; LastLogin: DateTime }
let getUserInfo con userName : UserInfo =
let cmd = {
Query = "some sql to get the data"
Timeout = 1000
Parameters = ... the user name here
OutParameters = ... the userName, Name and LastLogin here
}
let sqlCommand = createSqlCommand cmd con
... run the ExecuteNonQuery or whatever here
let outs = extractOutParameters sqlCommand cmd.OutParameters
{
UserName = getValOfParam outs "#userName"
Name = getValOfParam outs "#name"
LastLogin = getValOfParam outs "#lastLogin"
}
You will have to create the function getValOfParam, which just searches outs for the parameter with the correct name, and returns its value.
You can then use getUserInfo like this.
let userInfo = getUserInfo con "john_smith"
Even if there were ten fields returned, you'd get them in one record, so it's simple to ignore the fields you don't want.
And if you had built another function with results you weren't interested in at all when calling it, you'd call it like this.
startEngineAndGetStatus con "mainEngine" |> ignore

Construct Query to database dynamically

I am currently using FSharp.Data.SqlClient, but I am interested in any solution of my task.
I have a web client and the backend written in F#. In the web client user can set 10-20 filters and make the GET request to my F# backend. The URL looks like:
http://mybackend.com/get/1/0/34/ ....
Any number in this URL is a filter. There is no filter on the corresponding field if the value of corresponding filter is zero.
Now I need to construct the SQL query in my backend. While the number of possible filters was 3-4 I was using pattern matching:
type GetEObyOrg1Org2AsutpParent = SqlCommandProvider<"SELECT * FROM ITEM WHERE ORGID1 = #org1 AND ORGID2 = #org2 AND ASUTPID = #asutp AND PARENTAUTOINCID = #parent", "name=MobileConnectionProvider", ResultType.Tuples>
type GetEObyOrg1Org2Org3AsutpParent = SqlCommandProvider<"SELECT * FROM ITEM WHERE ORGID1 = #org1 AND ORGID2 = #org2 AND ORGID3 = #org3 AND ASUTPID = #asutp AND PARENTAUTOINCID = #parent", "name=MobileConnectionProvider", ResultType.Tuples>
match (asutpid, orgId1, orgId2, orgId3) with
| "0", _, "0", "0" ->
let cmd = new GetEObyOrg1Org2AsutpParent()
cmd.Execute(org1 = orgId1, parent = parentAid)
| "0", _, _ , "0" ->
let cmd = new GetEObyOrg1Org2Org3AsutpParent()
cmd.Execute(org1 = orgId1, org2 = orgId2, parent = parentAid)
But when the number of filters is greater then 3-4 it is very difficult to write pattern matching for all combinations of the parameters.
I think I need to construct the SQL query dynamically. Each non-zero parameter in the URL must add AND Field = Value expression to SQL statement. But I can not do it:
type GetEObyOrg1AsutpParent = SqlCommandProvider<Query, "name=MobileConnectionProvider", ResultType.Tuples>
Query paramter is this expression must be Literal, and I can not to construct literal expression dinamically:
[<Literal>]
let q1 = "SELECT * FROM ITEM WHERE ORGID1 = #org1 AND ASUTPID = #asutp"
[<Literal>]
let q2 = " AND PARENTAUTOINCID = #parent"
let f a =
match a with
| 1 -> q1 + q2
| _ -> q1
[<Literal>]
let q3 = f()
What is the best way of doing it in my case ?
I think in a case like this the core library's SqlDataConnection type provider might be a better fit. Then you should be able to use standard IQueryable operations to dynamically add additional WHERE clauses, something like:
type MyDb = SqlDataConnection<...>
let items = MyDb.GetContext().Item
let q1 = if asutpid = 0 then items else items.Where(fun i -> i.Asutpid = asutpid)
let q2 = if orgId1 = 0 then q1 else q1.Where(fun i -> i.OrgId1 = orgid1)
...

How do I parse/skip specific characters in attrparsec?

I'm trying to learn how to use the attrparsec module and so am practicing by parsing one of my log files.
I have the following code for the beginning of a line parser:
lineParser :: Parser LogEntry
lineParser = do
theMonth <- monthParser
skipSpace
theDate <- decimal
skipSpace
theHour <- decimal
skipColon
theMinute <- decimal
skipColon
theSecond <- decimal
return LogEntry { monthOfYear = theMonth, dayOfMonth = theDate,
hourOfDay = theHour, minuteOfHour = theMinute, secondOfMinute = theSecond}
but I'm having trouble with the skipColon function. I've tried various versions such as
skipColon = isColon
where isColon c = c == ':'
but I just get type errors
I would have liked to have simply written something like
skipChar ':'
but haven't been able to figure that out either.
Ran into all sorts of type errors around Char vs Word8 but most search results where about converting Word8 to Char, not the other way round.
Would appreciate some guidance. Many thanks.
AJFarmer posted the best answer.
Simply use
char ':'
However, you'll get a warning about a discarded value so to avoid that warning write
_ <- char ':'
Thanks for answering.

Pattern matching for custom read function

I am writing a custom read function for one of the data types in my module. For eg, when I do read "(1 + 1)" :: Data, I want it to return Plus 1 1. My data declaration is data Data = Plus Int Int. Thanks
This sounds like something better suited to a parser; Parsec is a powerful Haskell parser combinator library, which I would recommend.
I'd like to second the notion of using a parser. However, if you absolutely have to use a pattern-matching, go like this:
import Data.List
data Expr = Plus Int Int | Minus Int Int deriving Show
test = [ myRead "(1 + 1)", myRead "(2-1)" ]
myRead = match . lexer
where
match ["(",a,"+",b,")"] = Plus (read a) (read b)
match ["(",a,"-",b,")"] = Minus (read a) (read b)
match garbage = error $ "Cannot parse " ++ show garbage
lexer = unfoldr next_lexeme
where
next_lexeme "" = Nothing
next_lexeme str = Just $ head $ lex str
You could use GHC's ReadP.

Resources