on master help sign in
Fix insertion of default values since broken by #85 (#121)

When printing the SQL, we analyse the `PrimExpr`s and `PrimQuery` to detect the case where `rows` is set to `rows = values _` and, if so, we output a bare `VALUES` statement instead of a `SELECT`, because `DEFAULT` is only syntactically valid in a bare `VALUES` clause.

commitadd7e77523207e12f2f40354e9031873ee025af4 authorShane <shane.obrien@circuithub.com> dateSat 17 Jul 2021, 09:47 (5 years ago) parent75d7b32
2 files changed+33−5
src/Rel8/Statement/Insert.hs+2−2 src/Rel8/Statement/Select.hs+31−3
src/Rel8/Statement/Insert.hs+2−2
@@ -35,7 +35,7 @@ import Rel8.Schema.Name ( Name, Selects, ppColumn )
3535import Rel8.Schema.Table ( TableSchema(..), ppTable )
3636import Rel8.Statement.OnConflict ( OnConflict, ppOnConflict )
3737import Rel8.Statement.Returning ( Returning, decodeReturning, ppReturning )
38−import Rel8.Statement.Select ( ppSelect )
38+import Rel8.Statement.Select ( ppRows )
3939import Rel8.Table ( Table )
4040import Rel8.Table.Name ( showNames )
4141
@@ -66,7 +66,7 @@ ppInsert :: Insert a -> Doc
6666ppInsert Insert {..} =
6767 text "INSERT INTO" <+>
6868 ppInto into $$
69− ppSelect rows $$
69+ ppRows rows $$
7070 ppOnConflict into onConflict $$
7171 ppReturning into returning
7272
src/Rel8/Statement/Select.hs+31−3
@@ -11,10 +11,13 @@ module Rel8.Statement.Select
1111
1212 , Optimized(..)
1313 , ppPrimSelect
14+ , ppRows
1415 )
1516where
1617
1718-- base
19+import Data.Foldable ( toList )
20+import Data.List.NonEmpty ( NonEmpty( (:|) ) )
1821import Data.Void ( Void )
1922import Prelude hiding ( undefined )
2023
@@ -24,12 +27,15 @@ import qualified Hasql.Encoders as Hasql
2427import qualified Hasql.Statement as Hasql
2528
2629-- opaleye
30+import qualified Opaleye.Internal.HaskellDB.PrimQuery as Opaleye
2731import qualified Opaleye.Internal.HaskellDB.Sql as Opaleye
32+import qualified Opaleye.Internal.HaskellDB.Sql.Print as Opaleye
2833import qualified Opaleye.Internal.PrimQuery as Opaleye
2934import qualified Opaleye.Internal.Print as Opaleye
3035import qualified Opaleye.Internal.Optimize as Opaleye
3136import qualified Opaleye.Internal.QueryArr as Opaleye hiding ( Select )
32−import qualified Opaleye.Internal.Sql as Opaleye
37+import qualified Opaleye.Internal.Sql as Opaleye hiding ( Values )
38+import qualified Opaleye.Internal.Tag as Opaleye
3339
3440-- pretty
3541import Text.PrettyPrint ( Doc )
@@ -45,6 +51,7 @@ import Rel8.Table ( Table )
4551import Rel8.Table.Cols ( toCols )
4652import Rel8.Table.Name ( namesFromLabels )
4753import Rel8.Table.Opaleye ( castTable, exprsWithNames )
54+import qualified Rel8.Table.Opaleye as T
4855import Rel8.Table.Serialize ( Serializable, parse )
4956import Rel8.Table.Undefined ( undefined )
5057
@@ -80,12 +87,33 @@ ppSelect query =
8087 never = pure (toPrimExpr false)
8188
8289
90+ppRows :: Table Expr a => Query a -> Doc
91+ppRows query = case optimize primQuery of
92+ -- Special case VALUES because we can't use DEFAULT inside a SELECT
93+ Optimized (Opaleye.Product ((_, Opaleye.Values symbols rows) :| []) [])
94+ | eqSymbols symbols (toList (T.exprs a)) ->
95+ Opaleye.ppValues_ (map Opaleye.sqlExpr <$> toList rows)
96+ _ -> ppSelect query
97+ where
98+ (a, primQuery, _) = Opaleye.runSimpleQueryArrStart (toOpaleye query) ()
99+
100+ eqSymbols (symbol : symbols) (Opaleye.AttrExpr symbol' : exprs)
101+ | eqSymbol symbol symbol' = eqSymbols symbols exprs
102+ | otherwise = False
103+ eqSymbols [] [] = True
104+ eqSymbols _ _ = False
105+
106+ eqSymbol
107+ (Opaleye.Symbol name (Opaleye.UnsafeTag tag))
108+ (Opaleye.Symbol name' (Opaleye.UnsafeTag tag'))
109+ = name == name' && tag == tag'
110+
111+
83112ppPrimSelect :: Query a -> (Optimized Doc, a)
84113ppPrimSelect query =
85114 (Opaleye.ppSql . primSelect <$> optimize primQuery, a)
86115 where
87− (a, primQuery, _) =
88− Opaleye.runSimpleQueryArrStart (toOpaleye query) ()
116+ (a, primQuery, _) = Opaleye.runSimpleQueryArrStart (toOpaleye query) ()
89117
90118
91119data Optimized a = Empty | Unit | Optimized a