Closed goolord closed 6 years ago
Thank you for the PR. The description of the core datatypes may be a bit lacking as it doesn't tell the best practices to work with the expressions or new datatypes.
The PersistValue
data type is meant for the types that be stored into a column and that any backend can support. For the complex types that are likely backend-specific there is PersistCustom
constructor, that can be seen as a catch-all one making extensions of the datatype unnecessary.
There may be several things in the project that are similar to your use case. The Postgresql backend has Array, Geometry and HStore. Postgresql Array can be used in raw queries and expressions. The Functions module has in_
and notIn_
that accept lists of expressions. If none of those are what you are looking for, they can serve as examples of making more complex expressions or datatypes.
Consider the type of
queryRaw :: (PersistBackend m, Conn m ~ conn) =>
Bool -- ^ keep in cache
-> String -- ^ query
-> [PersistValue] -- ^ positional parameters
-> m (RowStream [PersistValue])
I don't know if I'm just being obtuse, but I can't see a way to use Arrays in queries without expanding the PersistValue data type here. PersistCustom doesn't cut it for most backends here because the relevant instances call error. (for the postgresql backend):
toField (P (PersistCustom _ _)) = error "toField: unexpected PersistCustom"
How would I go about querying an array like this?
None of the libraries warn of incomplete pattern matches, so I am assuming that I covered each backend here.
If the advice here to is to rewrite the query without using queryRaw
, I will just close this PR, I'm not that attached to it.
None of the backends accepts PersistCustom
directly. It is rendered by the Sql module before getting to the backend. PersistCustom
was added ad-hoc to allow values that affect the query. break the existing API. The types could be improved to avoid the incomplete patterns. When PersistValue
gets to parameter substitution it is too late to update the query with PersistCustom
. I think that Groundhog should accommodate any use case without extending PersistValue
.
The raw queries are different from the others as they aren't going through the rendering pipeline. If they were, you could define, say, a newtype InlineList
and convert it into PersistCustom
. A lot of Groundhog flexibility isn't readily available for the raw queries.
As far as I understand, you have something this where the list length is unknown.
let list = map toPrimitivePersistValue ([1, 2, 3] :: [Int])
queryRaw "SELECT a FROM tbl WHERE b IN [?, ?, ?]" list
One way to get this work is to make a helper function that generates a part of the query. This is generic and keeps the core datatypes generic as well.
queryRaw ("SELECT a FROM tbl WHERE b IN " ++ listQuery list) list
Ok, as I thought. Thanks for taking the time to explain.
I needed this for a project I work on, this is useful to me for querying arrays in raw queries. I also added a cabal.project file in order to make working on it easier for me, as well as adding some entries to the .gitignore