Haskell Persistent BackendFilter - haskell

I'm trying to use the match operator of Sqlite3 FTS3/4 tables with Persistent (in Yesod).
I've succeeded in creating my own match operator:
-- | Implements the `match` operator. This operator is specific to Sqlite3 and
-- is used to look for keywords in FTS3/4/5 tables.
match :: EntityField record Text -- ^ Field to filter on
-> Text -- ^ Text to compare with
-> Filter record -- ^ Resulting filter
match field val = Filter field (Left val) (BackendSpecificFilter "match")
It works fine but does not allow to use a very specific (strange?) feature of Sqlite3 FTS3/4 tables: you can specify the table name instead of just a column name. The effect is that the match operator will look for the searched terms in every column of the table.
It means you can write queries like:
SELECT *
FROM tablename
WHERE tablename MATCH "hello";
Such queries are described in the Sqlite3 FTS3/4 documentation https://sqlite.org/fts3.html#simple_fts_queries
Reading the Persistent documentation and the Filter definition, it might be possible to create this filter using a BackendFilter but I have not found any example of how actually using it.
What also puzzled me is the use of the type family BackendSpecificFilter which is used as a constructor in PersistFilter.
I would like to be able to write queries like:
mkPersist persistSettings [persist|
User
forename String
surname String
bio String
|]
users <- runDB $ selectList [ User `matchAll` searchedTerms ] []
Can someone show me the right way to use BackFilter in this case?
Thanks

From what I investigated, it is not possible to create a BackendFilter as easily as a BackendSpecificFilter. The first is meant to be interpreted specifically by the database layer meaning one would have to patch the persistent-sqlite package in order to allow what I described.

Related

Difficult in converting to strings from a list

I have a list which is in below format
A = [ "machine's code" ,"max's code"]
I want to convert to that list to string and pass it to a query. I am using python for this.
I am trying with below query and not giving required results
for i in A:query=Select * from table where name='"+str(A)+"'"
Expected code should be :
Select * from table where name="machine's code"
list_of_queries = []
for element in A:
query = f'Select * from table where name="{el}"'
list_of_queries.append(query)
as pointed out by others here, this pattern should be only used internally, as it creates some sql injection security risks.

SPARQL query to retrieve data with different datatype (string)

I am writing a SPARQL query to retrieve answers for the competency question. I want to retrieve all persons who have level of distress "not too disturbing".
select *
where
{
?person ocd:hasInsight ?insight;
ocd:hasThought ?thought;
ocd:hasEmotion ?emotion;
ocd:hasDistressLevel ?severitycontrol.
FILTER (?severitycontrol = ocd:Not too disturbing)
}
I am new at this and could not figure out how to fix that.
If the value is a string (e.g., "Not too disturbing"):
FILTER (?severitycontrol = "Not too disturbing") .
If the value is language-tagged in your RDF, you have to append that same language tag:
FILTER (?severitycontrol = "Not too disturbing"#en) .
String matching is case-sensitive. You can use ucase/lcase to make a string uppercase/lowercase.
If you only want to match a partial string, you can use strStarts/strEnds, contains, and more.

is there a difference between `quote_ident()` and parametized queries in psycopg2?

In python3 and postgresql12, is there a safety difference between parametizing SQL queries the "proper" way or just escaping potentially dangerous content using psycopg2.quote_ident()?
For example, consider these two options.
Option 1:
name = get_unsafe_input_from_web_form()
cursor.execute("SELECT * FROM students WHERE name = %s;", (name,))
Option 2:
from psycopg2.extensions import quote_ident
name = get_unsafe_input_from_web_form()
cursor.execute(f"SELECT * FROM students WHERE name = {quote_ident(name, cursor)};"
The documentation is not particularly explicit. Is Option 2 totally equivalent in terms of safety against injection attacks?
quote_ident() would be the wrong thing to use, as it is for identifiers e.g table, column names. You would want quote_literal() which does not exist in psycopg2.extensions. I would stick with the first option, but using the psycopg2.sql module:
https://www.psycopg.org/docs/sql.html
Safety-wise, both parameterized queries and quote_ident can safely handle untrusted input and will not open you to SQL injection issues. But you can't use quote_ident for values as you're trying to do in your example. The string you're passing to cursor.execute() will end up being (for name foobar) SELECT * FROM students WHERE name = "foobar";, which will try to find rows where the name column is equal to the foobar column, not where name is equal to the string 'foobar'.

Azure search query to filter JSON values

I'm trying to frame Azure search query. The field type is collection(Edm.String) in Azure search index. This is how my JSON data to be filtered looks like : ["A","B"].
When I try to filter using the query Alphabet in 'A' it brings all the entries that has "A" in it. But when I try to frame the same query in my code like "'A' in Alphabet" it throws an exception stating:
"Invalid expression: Expression contains an unsupported OData language feature. Please revise your query and try again.
Parameter name: $filter".
Is there any other Azure query which I can use to filter my JSON data?
Note : I could not use eq as my field is multi valued and eq can handle only single values.
if you want to filter a collection that need to include multiple values, ie , you want to query all result whose collection all has "A" and "B" try the filter expression below :
Let's assume your collection field name is "alphabet"
$filter=alphabet/any(s: s eq 'A') and alphabet/any(s: s eq 'B')
The solution for this is to use search.ismatch query like search.ismatch('A,B','Alphabet','simple','any'). So the result will have search results of all the records having either A or B or both.
Reference : https://learn.microsoft.com/en-us/azure/search/query-odata-filter-orderby-syntax

Updating a single field in a record with Haskell #

I need to update one field of a very large default record.
As the default may change I don't want to rebuild the entire record manually.
Now I have come across the following way of doing this, but I am not sure how it works:
unaggregate :: MyResult -> MyResult
unaggregate calc#MyResult{..} = calc{ the_defaults = the_override
`mappend` the_defaults }
where
the_override = create ("aggregation" := False)
I have tried searching for 'Haskell # operator' in Google but it does not return immediately useful information.
I saw somewhere calc#MyResult{..} does pattern matching on variables but I don't see what variable calc does for the MyResult record...
Also I have looked up mappend (and Monoids) and I am not sure how these work either...
Thank you for any help
The # symbol is called an "as-pattern". In the example above, you can use calc to mean the whole record. Usually you'd use it like this: calc#(MyResult someResult) -- so you can have both the whole thing and the pieces that you're matching. You can do the same thing with lists (myList#(myHead:myTail)) or tuples (myTuple#(myFst, mySnd). It's pretty handy!
MyResult{..} uses RecordWildcards. Which is a neat extension! BUT RecordWildcards doesn't help you update just one field of a record.
You can do this instead: calc { theFieldYouWantToUpdate = somethingNew }.

Resources