-
Notifications
You must be signed in to change notification settings - Fork 40
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add upsert support and allow arbitrary queries in INSERT, UPDATE and …
…DELETE This PR makes several changes to our "manipulation" functions (`insert`, `update`, `delete`). Firstly, we now support `ON CONFLICT DO UPDATE`, aka "upsert". Secondly, we now allow the insertion of arbitrary queries (not just static `VALUES`). `values` recovers the old behaviour. Thirdly, the `WHERE` clauses of `UPDATE` and `DELETE` are now also arbitrary queries (allowing joining against other tables and the use of functions like `absent` and `present`). `where_` recovers the old behaviour. In terms of generating the SQL to implement these features, it was unfortunately significantly less work to roll our own here than to add this upstream to Opaleye proper, because it would have required more refactoring than I felt comfortable doing.
- Loading branch information
1 parent
032242f
commit 9747d8b
Showing
18 changed files
with
452 additions
and
237 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,75 +1,21 @@ | ||
{-# language FlexibleContexts #-} | ||
{-# language TypeFamilies #-} | ||
{-# language ViewPatterns #-} | ||
{-# language MonoLocalBinds #-} | ||
|
||
module Rel8.Query.SQL | ||
( showQuery | ||
, sqlForQuery, sqlForQueryWithNames | ||
) | ||
where | ||
|
||
-- base | ||
import Data.Foldable ( fold ) | ||
import Data.Functor.Const ( Const( Const ), getConst ) | ||
import Data.Void ( Void ) | ||
import Prelude | ||
|
||
-- opaleye | ||
import qualified Opaleye.Internal.HaskellDB.Sql as Opaleye | ||
import qualified Opaleye.Internal.PrimQuery as Opaleye | ||
import qualified Opaleye.Internal.Print as Opaleye | ||
import qualified Opaleye.Internal.Optimize as Opaleye | ||
import qualified Opaleye.Internal.QueryArr as Opaleye hiding ( Select ) | ||
import qualified Opaleye.Internal.Sql as Opaleye | ||
|
||
-- rel8 | ||
import Rel8.Expr ( Expr ) | ||
import Rel8.Expr.Opaleye ( toPrimExpr ) | ||
import Rel8.Query ( Query ) | ||
import Rel8.Query.Opaleye ( toOpaleye ) | ||
import Rel8.Schema.Name ( Name( Name ), Selects ) | ||
import Rel8.Schema.HTable ( htabulateA, hfield ) | ||
import Rel8.Table ( Table, toColumns ) | ||
import Rel8.Table.Cols ( toCols ) | ||
import Rel8.Table.Name ( namesFromLabels ) | ||
import Rel8.Table.Opaleye ( castTable ) | ||
import Rel8.Statement.Select ( ppSelect ) | ||
import Rel8.Table ( Table ) | ||
|
||
|
||
-- | Convert a query to a 'String' containing the query as a @SELECT@ | ||
-- statement. | ||
-- | Convert a 'Query' to a 'String' containing a @SELECT@ statement. | ||
showQuery :: Table Expr a => Query a -> String | ||
showQuery = fold . sqlForQuery | ||
|
||
|
||
sqlForQuery :: Table Expr a | ||
=> Query a -> Maybe String | ||
sqlForQuery = sqlForQueryWithNames namesFromLabels . fmap toCols | ||
|
||
|
||
sqlForQueryWithNames :: Selects names exprs | ||
=> names -> Query exprs -> Maybe String | ||
sqlForQueryWithNames names query = | ||
show . Opaleye.ppSql . selectFrom names exprs <$> optimize primQuery | ||
where | ||
(exprs, primQuery, _) = | ||
Opaleye.runSimpleQueryArrStart (toOpaleye query) () | ||
|
||
|
||
optimize :: Opaleye.PrimQuery' a -> Maybe (Opaleye.PrimQuery' Void) | ||
optimize = Opaleye.removeEmpty . Opaleye.optimize | ||
|
||
|
||
selectFrom :: Selects names exprs | ||
=> names -> exprs -> Opaleye.PrimQuery' Void -> Opaleye.Select | ||
selectFrom (toColumns -> names) (toColumns . castTable -> exprs) query = | ||
Opaleye.SelectFrom $ Opaleye.newSelect | ||
{ Opaleye.attrs = Opaleye.SelectAttrs attributes | ||
, Opaleye.tables = Opaleye.oneTable select | ||
} | ||
where | ||
select = Opaleye.foldPrimQuery Opaleye.sqlQueryGenerator query | ||
attributes = getConst $ htabulateA $ \field -> case hfield names field of | ||
Name name -> case hfield exprs field of | ||
expr -> Const (pure (makeAttr name (toPrimExpr expr))) | ||
makeAttr label expr = | ||
(Opaleye.sqlExpr expr, Just (Opaleye.SqlColumn label)) | ||
showQuery = foldMap show . ppSelect |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.