-
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, our `Update` and `Delete` statements now support `FROM` and `USING` clauses respectively, allowing joining against other tables. Fourthly, `Returning` is now an `Applicative`, which means you can say `returning = pure ()` if you don't care about the number of rows affected. 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
b44ea81
commit 9e927c1
Showing
21 changed files
with
738 additions
and
319 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
Oops, something went wrong.