New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add support of PostgreSQL-specific VALUES(..)
expression
#284
Conversation
scalar expression of values-list for `from` targets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is awesome, thank you!
Only thing is that I am pretty sure we can put this directly into esqueleto
proper instead of Esqueleto.Postgresql
. Can you try doing that and see if the tests all work out still?
src/Database/Esqueleto/PostgreSQL.hs
Outdated
@@ -363,3 +371,75 @@ filterWhere aggExpr clauseExpr = ERaw noMeta $ \_ info -> | |||
in ( aggBuilder <> " FILTER (WHERE " <> clauseBuilder <> ")" | |||
, aggValues <> clauseValues | |||
) | |||
|
|||
newtype PgValuesExprs a = PgValuesExprs { unPgValuesExprs :: NE.NonEmpty a } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is this a Postgres specific feature?
This article seems to indicate that it is a SQL-92
feature, and should be supported by all SQL databases.
MySQL supports VALUES
, as does SQLite. So I think we can move this into esqueleto
proper.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah sorry: my bad! Thanks for the links.
Sure, I can do that, but looks like other vendors requires different syntax, so I need to address that then :)
I will try to do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, if they require different syntax, then let's not bother. The current solution is to keep anything that varies in these separate modules.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In some basic detail:
- MySql wants keyword
ROW(..)
for one row of values; - SqLite requires some other placement of commas as far as I understand.. but worth to play a bit more.
I think consistency of API for vendors matters, so I am ready to try to cover other vendors as well.
But if you allow to go Postgres API earlier than other vendors - it would be awesome!
Otherwise - I could add necessary extensions for other vendors right here and ping you when it's ready :)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
esqueleto
doesn't currently do anything to differentiate the database provider - it's all Sqlbackend
as far as we're concerned. So I'd rather not try and do anything clever here and just support PG directly. If someone else wants MySQL support or Sqlite, then we can add those in vendor-specific modules, and if we really want to unify it, we can try and do that.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, understood: I also meant similar extensions in vendor-specific modules (like here) without unification (which probably also will present some code duplication but not a big deal I think).
Then I guess from Postgres perspective everything looks ok now? :)
src/Database/Esqueleto/PostgreSQL.hs
Outdated
-- pure (bound, count @Int $ user^.UserName) | ||
-- @ | ||
-- | ||
-- @since 3.5.2.3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🙌🏻 this is dope
@@ -1270,6 +1271,53 @@ testLateralQuery = do | |||
let _ = res :: [(Entity Lord, Value (Maybe Int))] | |||
asserting noExceptions | |||
|
|||
testValuesExpression :: SpecDb | |||
testValuesExpression = do |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
blessed tests ❤️
Try merging |
src/Database/Esqueleto/PostgreSQL.hs
Outdated
instance (ToSomeValues a, Ex.ToAliasReference a, Ex.ToAlias a) => Ex.ToFrom (PgValuesExprs a) a where | ||
toFrom = fromValues . unPgValuesExprs |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason why you are going through ToFrom
instead of just just making values === fromValues
?
ToFrom
is mostly there to support SqlSetOperation
as a restricted subset and backwards compatibility with the *Join
datatypes
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, no reasons, this is just a lack of my knowledge of code-base and how it works in day when I wrote that :)
Thanks a lot for note, this is more clear for me now!
I have fixed that :)
src/Database/Esqueleto/PostgreSQL.hs
Outdated
-- select $ do | ||
-- bound :& user <- from $ | ||
-- values ( (val (10 :: Int), val ("ten" :: Text)) | ||
-- :| [ (val 20, val "twenty") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wish the OverloadedList extension wasn't such a foot cannon with NonEmpty and actually just gave a compilation error.
Nothing to change here, just me 😞 in haskell
of `ToFrom` typeclass for postgres `values` expression.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding functionality is a minor bump - otherwise this is great and looks good to go 😄
I'll make the suggested modifications myself when I release for 3.5.3.0.
@@ -1,3 +1,9 @@ | |||
3.5.2.3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Adding a new feature is a minor bump, so
3.5.2.3 | |
3.5.3.0 |
@@ -1,7 +1,7 @@ | |||
cabal-version: 1.12 | |||
|
|||
name: esqueleto | |||
version: 3.5.2.2 | |||
version: 3.5.2.3 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
version: 3.5.2.3 | |
version: 3.5.3.0 |
At my company we really wanted to use
VALUES
Postgres expression to use it inside ofJOIN
between large db data-set with some smaller user-input data-set without loading of data into app-memory.
VALUES
allows us to do that and even gives performance benefit to our app.I think it is a relevant issue #231 :)
This PR tries to bring an ability to use like:
SQL :
SELECT * FROM (VALUES (a1), (a2) ...) as "vs"("v1")
Haskell:
select $ from $ values [val 1, val 2, val 3]
It also works for more than one columns as well (a bit doubting about aliases/refs assembling but works good so far). :)
I implemented it as part of
From
and thanks to latest refactoring fromGADTs to type-classes it was not so difficult :)
Few appropriate semi-integrational tests with other sql capabilities as join, sinigle/multicolumn were added as well.
Please, let me know if I made something in a wrong way - I am ready to try to fix :)
Thanks!
Before submitting your PR, check that you've:
@since
declarations to the Haddock.stylish-haskell
and otherwise adhered to the style guide.After submitting your PR: