How do I pass a rendered persistent/esqueleto query to another query? - haskell

I'd like to use Persistent/Esqueleto to implement count estimates.
One approach recommended in this article is to define a function like this
CREATE FUNCTION count_estimate(query text) RETURNS integer AS $$
DECLARE
rec record;
rows integer;
BEGIN
FOR rec IN EXECUTE 'EXPLAIN ' || query LOOP
rows := substring(rec."QUERY PLAN" FROM ' rows=([[:digit:]]+)');
EXIT WHEN rows IS NOT NULL;
END LOOP;
RETURN rows;
END;
$$ LANGUAGE plpgsql VOLATILE STRICT;
and then use it like this
SELECT count_estimate('SELECT * FROM companies WHERE status = ''Active''');
In order to use the count_estimate function, I'll need (I think?) to render the query that Peristent/Equeleto generates, however when I try rendering the query with renderQuerySelect, I get something like this
SELECT "companies"."id", "companies"."name", "companies"."status"
FROM "companies"
WHERE "companies"."status" IN (?)
; [PersistText "Active"]
This of course can't be stuffed into the count_estimate, because it will syntax error on the ? placeholder. I also can't naïvely replace the ? with "Active", because it will syntax error on that first double quote.
How do I render the query in a way that my count_estimate function will accept?
I tried something like this, but it fails at runtime
getEstimate :: (Text, [PersistValue]) -> DB [Single Int]
getEstimate (query, params) = rawSql [st|
SELECT count_estimate('#{query}');
|] params

I managed to figure it out (mostly).
It's a matter of escaping the single quotes in both the query and the PersistValue parameters. I'm doing it like this at the moment, but escaping will need to be added back in otherwise I think it creates a SQL injection vulnerability. I may also need to handle the other PersistValue constructors in some specific way, but I haven't run into problems there yet.
import qualified Data.Text as T
import qualified Database.Persist as P
getEstimate :: (Text, [PersistValue]) -> DB (Maybe Int)
getEstimate (query, params) = fmap unSingle . listToMaybe <$> rawSql [st|
SELECT count_estimate('#{T.replace "'" "''" query}');
|] (map replace' params)
where literal a = PersistLiteral_ P.Unescaped ("''" <> a <> "''")
replace' = \case
PersistText t -> literal $ encodeUtf8 t
PersistDay d -> literal $ encodeUtf8 $ pack $ showGregorian d
a -> a

Related

How to create a Col datatype in selda?

I'm trying to write a function that does a LIKE sql query based on a parameter. I'm using Selda. I had this working before parameterizing the function:
selectBookQuery :: Query s (Row s GoodreadsBook)
selectBookQuery = do
book <- select goodreadsBooks
restrict ((book ! #title) `like` ("%Wheel of Time%"))
return book
But, when I try to use the t param, like this:
selectBookQuery :: String -> Query s (Row s GoodreadsBook)
selectBookQuery t = do
book <- select goodreadsBooks
restrict ((book ! #title) `like` (T.pack $ "%" ++ t ++ "%"))
return book
I get this error:
Couldn't match expected type ‘Col s Text’ with actual type ‘Text’
I think I have a rough idea of what's happening. The string literal that I'm using in the first example is being coerced through the magic of OverloadedStrings to a Col s Text, whereas once I make it a Text or String, it doesn't get coerced into a Col s Text.
Hoogle was really helpful here, when I realized I have a Text but needed a Col s Text, hoogling Text -> Col s Text gave me the text function from Selda. So all I had to change was:
restrict ((book ! #title) `like` S.text (T.pack $ "%" ++ t ++ "%"))
where S is a qualified import of Database.Selda.

Print contains data type how to disable

using gogol package,
follow example got
> exampleGetValue
-- ValueRange' {_vrValues = Just [String "2018/1/1",String "2018/1/2"], _vrRange = Just "'\24037\20316\34920\&1'!A1:1", _vrMajorDimension = Just VRMDRows}
> exampleGetValue >>= return . view vrValues
-- [String "2018/1/1",String "2018/1/2"]
> mapM_ (print) (exampleGetValue >>= return . view vrValues)
String "2018/1/1"
String "2018/1/2"
Why there will be a string of words
How to do I can only show
2018/1/1
2018/1/2
Take a look at
[String "2018/1/1",String "2018/1/2"]
the result of
> exampleGetValue >>= return . view vrValues
Here the strings you are interested in, like "2018/1/1" are contained in another datatype String, which has, I assume, an automatically derived show instance, which will print the name of the Data constructor String.
You need to unpack the strings somehow to get rid of the printing of the word String.
As this is stackoverflow, and we are considered to provide answers, I will give you one possibility now, but before you read it, try to do it yourself:
unpackString (String w) = w
mapM_ (print . unpackString) (exampleGetValue >>= return . view vrValues)
You have to determine the type signature for unpackString yourself, as you didn't provided any types.

Parsing a JSON document with a Monad to look for a specific value?

I am a beginner at Haskell and I am trying to use https://hackage.haskell.org/package/json-0.9.1/docs/Text-JSON.html to parse a JSON document.
In my task, i am given a JSON document, and I would like to return the value corresponding to "index" , for example in the following case:
{
"root": [
{
"root1": 157538
},
{
"root2": [
{
"leaf21": 3
}
]
},
{
"root3": [
{
"leaf31": "somestring"
},
{
"index": "foundit"
}
]
}
]
}
To be specific: if presented with a JSON document and a path like "root" -> "root3" -> "index" exists, I would like to return "foundit", else I would like to return Nothing. Everything else in the document is arbitrary: root3,root2,root1,root may or may not exist etc.
Now I can do this using lots of case statements and patterns matches, but having read https://wiki.haskell.org/All_About_Monads, I am wondering if there is a better way using something similar to the Maybe Monad and the sheep-cloning example, however i am not sure how to write the bind function ...
[in my real case the value I seek is actually 19-deep in the document so I have lots of case statements]
Please could you suggest how to use Monads to do this ?
Yes those case statements are not necessary
Your guesses are correct - but monads are not the correct answer in this case (no pun intended1).
This is a great job for Traversals, Prisms and Lenses - and of course the great aeson-library and lens-aeson.
{-# LANGUAGE OverloadedStrings #-}
module Test where
import Control.Lens
import Data.Aeson
import Data.Aeson.Lens
import Data.Monoid ((<>))
jsonString = "{\"root\":[{\"root1\":157538}"
<> ",{\"root2\":[{\"leaf21\":3}]}"
<> ",{\"root3\":[{\"leaf31\":\"somestring\"}"
<> ",{\"index\":\"foundit\"}]}]}"
val :: Maybe Value
val = decode jsonString
indexMaybe :: Maybe Value
indexMaybe = val ^? _Just . key "root" . values
. key "root3" . values
. key "index"
So what does this do?
decode transforms a ByteString into a Maybe Value - Maybe because parsing might fail!
then the (^?) operator previews a traversal - i.e. it goes through the JSON Object and follows the json path you give;
For this you have at least to know the path to "index", if this path is unknown, you'd have to invest a bit more research into lenses/prisms/traversals or do a simple tree search on the parsed object.
Here is a spoiler for those who lack time to implement a search for "index" in a json object:
search :: Text -> Value -> Maybe Value
search txt o#(Object o') = let f y#(Just x) _ = y
f _ v = search txt v
in case o ^? key txt of
Nothing -> foldl' f Nothing o'
x -> x
search txt a#(Array a') = let f y#(Just x) _ = y
f _ v = search txt v
in foldl' f Nothing a'
search _ _ = Nothing
Alternatives
As #MarkSeeman already mentioned - a simple text search, might be much more efficient.
1: okay maybe a little bit

How to search a pattern from a file/String in Haskell

** old**
Suppose we have a pattern ex. "1101000111001110".
Now I have a pattern to be searched ex. "1101". I am new to Haskell world, I am trying it at my end. I am able to do it in c but need to do it in Haskell.
Given Pattern := "1101000111001110"
Pattern To Be Searched :- "110
Desired Output:-"Pattern Found"`
** New**
import Data.List (isInfixOf)
main = do x <- readFile "read.txt"
putStr x
isSubb :: [Char] -> [Char] -> Bool
isSubb sub str = isInfixOf sub str
This code reads a file named "read", which contains the following string 110100001101. Using isInfixOf you can check the pattern "1101" in the string and result will be True.
But the problem is i am not able to search "1101" in the string present in "read.txt".
I need to compare the "read.txt" string with the user provided string. i.e
one string is their in the file "read.txt"
and second string user will provid (user defined) and we will perform search and find whether user defined string is present in the string present in "read.txt"
Answer to new:
To achieve this, you have to use readLn:
sub <- readLn
readLn accepts input until a \n is encountered and <- binds the result to sub. Watch out that if the input should be a string you have to explicitly type the "s around your string.
Alternatively if you do not feel like typing the quotation marks every time, you can use getLine in place of readLn which has the type IO String which becomes String after being bound to sub
For further information on all functions included in the standard libraries of Haskell see Hoogle. Using Hoogle you can search functions by various criteria and will often find functions which suit your needs.
Answer to old:
Use the isInfixOf function from Data.List to search for the pattern:
import Data.List (isInfixOf)
isInfixOf "1101" "1101000111001110" -- outputs true
It returns true if the first sequence exists in the second and false otherwise.
To read a file and get its contents use readFile:
contents <- readFile "filename.txt"
You will get the whole file as one string, which you can now perform standard functions on.
Outputting "Pattern found" should be trivial then.

Could I get help implementing a concept, "When a String changes, its type changes"

One day on #haskell, someone mentioned the concept of how a string's type should change when the string changes. This reminded me of some code I have in my project. It keeps bugging me, and I couldn't articulate why. The reason, I now surmise, is because I am not implementing this concept. Here's the code below, followed by some ideas of how I can begin to change it for the better. What I would like is some input to the effect of , "You're on the right track." or , "No, way off.", or "Here's this other thing you should be mindful of.".
> processHTML :: String -> [[String]]
> processHTML htmlFILE =
> let parsedHTML = parseTags htmlFILE
> allTagOpens = sections (~== TagOpen "a" [("href","")]) parsedHTML
> taggedTEXT = head $ map (filter isTagOpen) allTagOpens
> allHREFS = map (fromAttrib "href") taggedTEXT
> allPotentials = map (dropWhile (/= '?')) allHREFS
> removedNulls = filter (not . null) allPotentials
> removedQs = map (drop 1) removedNulls
> in map (splitOn "&") removedQs
The idea here is I'm taking raw HTML and filtering out everything I don't want until I get what I do want. Each let binding represents a stage in filtering. This could be the foundation of a data structure, like so:
> data Stage = Stage1 Foo
> | Stage2 Bar
> | Stage3 Baz
Where Foo Bar and Baz are the appropriate datatype; a String, or TagOpen for example, depending on what stage I am at in the filtering process. I could use this data type to get precise information when I add in the error handling code. Plus, it could help me keep track of what is happening when.
Feedback appreciated.
You're on the right track.
First of all, when you're building a long pipeline like this, you may prefer to compose functions directly:
> processHTML :: String -> [[String]]
> processHTML =
> parseTags
> >>> sections (~== TagOpen "a" [("href","")])
> >>> head $ map (filter isTagOpen)
> >>> map (fromAttrib "href")
> >>> map (dropWhile (/= '?'))
> >>> filter (not . null)
> >>> map (drop 1)
> >>> map (splitOn "&")
This uses Control.Category.(>>>), which is just (at least in this case) flipped function composition.
Now for your actual question, it looks like you're using the tagsoup package for parsing tags. This already does some type changing throughout the pipeline: parseTags generates a Tag, some functions operate on it, and then fromAttrib goes back to a String.
Depending on how much work you'll be doing, I might create a newtype:
newtype QueryElement = QE { unQE :: String } deriving (Eq, Show)
> processHTML :: String -> [[QueryElement]]
> processHTML =
> parseTags
> >>> sections (~== TagOpen "a" [("href","")])
> >>> head $ map (filter isTagOpen)
> >>> map (fromAttrib "href")
> >>> map (dropWhile (/= '?'))
> >>> filter (not . null)
> >>> map (drop 1)
> >>> map (splitOn "&" >>> map QE)
Only the last line has changed here, to add the QE newtype tags to each element.
Depending on your use case, you could take a difference approach. For example, you may want to add more information to the URI instead of just collecting the query variables. Or you might want to fold over the query items and produce a Map String String directly.
Finally, if you're trying to gain type safety, you usually wouldn't make a sum type such as your Stage. This is because each constructor creates a value of the same type, so the compiler can't do any extra checking. Instead you'd create a separate type for each stage:
data Stage1 = Stage1 Foo
data Stage2 = Stage2 Bar
data Stage3 = Stage3 Baz
doStage1 :: Stage1 -> Stage2
doStage2 :: Stage2 -> Stage3
It's easy to create very fine-grained classes and data structures, but at some point they get out of hand. For example, in your functions allPotentials, removedNulls, and removedQs, you may want to just work on Strings. There isn't a lot of semantic meaning that can be attached to the output of those stages, especially as they're partial steps within a slightly larger process.
This page talks about using types to enforce safety of operations, and causing common errors to show up at compile-time. I'm not sure, but I think this is along the lines of what you're trying to implement.
An example of the problem:
You're running a web application that needs to use a database. It generates an SQL query from the username and password (for example) and sends it off to the database server, gets a response, and presents it to the user. This works great for a while. But then a very rude user types in " OR 1 = 1; -- for the username. Can you imagine sending that string to the following query:
SELECT * FROM users WHERE password = "$" AND username = "$";
Disaster!
The basic solution:
1) create a type for strings that are safe to send to the database server (i.e. GoodSQLString)
2) make sure that all GoodSQLString's really are safe (perhaps the constructor passes the argument query string through an escaping function)
3) only allow GoodSQLString's to be sent to the database server from an application
That said, it's hard to say how that translates to your processHTML problem. Perhaps the type signature should be processHTML :: HTML -> [Tags] -- unless it's meaningful to pass in String's that are invalid HTML.

Resources