From 00a0d8b9b7af366d4deaa881a64beb507004c906 Mon Sep 17 00:00:00 2001 From: steve-chavez Date: Sun, 10 Feb 2019 14:15:39 -0500 Subject: [PATCH] Remove pjType from QueryBuilder Insert/Update * Refactor Insert onConflict --- src/PostgREST/DbRequestBuilder.hs | 4 +-- src/PostgREST/QueryBuilder.hs | 46 ++++++++++++++++--------------- src/PostgREST/Types.hs | 6 ++-- 3 files changed, 29 insertions(+), 27 deletions(-) diff --git a/src/PostgREST/DbRequestBuilder.hs b/src/PostgREST/DbRequestBuilder.hs index 2cd92dc89..767565fbf 100644 --- a/src/PostgREST/DbRequestBuilder.hs +++ b/src/PostgREST/DbRequestBuilder.hs @@ -321,7 +321,7 @@ addProperty f (targetNodeName:remainingPath, a) (Node rn forest) = mutateRequest :: ApiRequest -> TableName -> [Text] -> [FieldName] -> Either Response MutateRequest mutateRequest apiRequest tName pkCols fldNames = mapLeft apiRequestError $ case action of - ActionCreate -> Right $ Insert tName pkCols payload (iPreferResolution apiRequest) [] returnings + ActionCreate -> Right $ Insert tName payload ((,) <$> iPreferResolution apiRequest <*> Just pkCols) [] returnings ActionUpdate -> Update tName payload <$> combinedLogic <*> pure returnings ActionSingleUpsert -> (\flts -> @@ -331,7 +331,7 @@ mutateRequest apiRequest tName pkCols fldNames = mapLeft apiRequestError $ all (\case Filter _ (OpExpr False (Op "eq" _)) -> True _ -> False) flts - then Insert tName pkCols payload (Just MergeDuplicates) <$> combinedLogic <*> pure returnings + then Insert tName payload (Just (MergeDuplicates, pkCols)) <$> combinedLogic <*> pure returnings else Left InvalidFilters) =<< filters ActionDelete -> Delete tName <$> combinedLogic <*> pure returnings diff --git a/src/PostgREST/QueryBuilder.hs b/src/PostgREST/QueryBuilder.hs index 8ba5f3179..1406faede 100644 --- a/src/PostgREST/QueryBuilder.hs +++ b/src/PostgREST/QueryBuilder.hs @@ -263,44 +263,46 @@ requestToQuery schema isParent (DbRead (Node (Select colSelects tbl tblAlias imp --getQueryParts is not total but requestToQuery is called only after addJoinConditions which ensures the only --posible relations are Child Parent Many getQueryParts _ _ = witness -requestToQuery schema _ (DbMutate (Insert mainTbl pkCols p@(PayloadJSON _ pType pKeys) onConflct logicForest returnings)) = +requestToQuery schema _ (DbMutate (Insert mainTbl p@(PayloadJSON _ _ pKeys) onConflct putConditions returnings)) = unwords [ - ("WITH " <> ignoredBody) `emptyOnFalse` not payloadIsEmpty, + "WITH payload AS (SELECT $1::json AS json_data),", + "vals AS (", + unwords [ + "SELECT json_data AS val FROM payload WHERE json_typeof(json_data) = 'array'", + "UNION ALL", + "SELECT json_build_array(json_data) AS val FROM payload WHERE json_typeof(json_data) = 'object')"], "INSERT INTO ", fromQi qi, if payloadIsEmpty then " " else "(" <> cols <> ")", - case (pType, payloadIsEmpty) of - (PJArray _, True) -> "SELECT null WHERE false" - (PJObject, True) -> "DEFAULT VALUES" - _ -> unwords [ - "SELECT " <> cols <> " FROM", - case pType of - PJObject -> "json_populate_record" - PJArray _ -> "json_populate_recordset", "(null::", fromQi qi, ", $1) _", - -- Only used for PUT - ("WHERE " <> intercalate " AND " (pgFmtLogicTree (QualifiedIdentifier "" "_") <$> logicForest)) `emptyOnFalse` null logicForest], - maybe "" (\x -> ( - "ON CONFLICT(" <> intercalate ", " (pgFmtIdent <$> pkCols) <> ") " <> case x of + unwords [ + "SELECT " <> cols <> " FROM", + "json_populate_recordset", "(null::", fromQi qi, ", (select val from vals)) _", + -- Only used for PUT + ("WHERE " <> intercalate " AND " (pgFmtLogicTree (QualifiedIdentifier "" "_") <$> putConditions)) `emptyOnFalse` null putConditions], + maybe "" (\(oncDo, oncCols) -> ( + "ON CONFLICT(" <> intercalate ", " (pgFmtIdent <$> oncCols) <> ") " <> case oncDo of IgnoreDuplicates -> "DO NOTHING" MergeDuplicates -> "DO UPDATE SET " <> intercalate ", " (pgFmtIdent <> const " = EXCLUDED." <> pgFmtIdent <$> S.toList pKeys) - ) `emptyOnFalse` null pkCols) onConflct, + ) `emptyOnFalse` null oncCols) onConflct, ("RETURNING " <> intercalate ", " (map (pgFmtColumn qi) returnings)) `emptyOnFalse` null returnings] where qi = QualifiedIdentifier schema mainTbl cols = intercalate ", " $ pgFmtIdent <$> S.toList pKeys payloadIsEmpty = pjIsEmpty p -requestToQuery schema _ (DbMutate (Update mainTbl p@(PayloadJSON _ pType keys) logicForest returnings)) = +requestToQuery schema _ (DbMutate (Update mainTbl p@(PayloadJSON _ _ keys) logicForest returnings)) = if pjIsEmpty p then "WITH " <> ignoredBody <> "SELECT ''" else unwords [ + "WITH payload AS (SELECT $1::json AS json_data),", + "vals AS (", + "SELECT json_data AS val FROM payload WHERE json_typeof(json_data) = 'array'", + "UNION ALL", + "SELECT json_build_array(json_data) AS val FROM payload WHERE json_typeof(json_data) = 'object')", "UPDATE " <> fromQi qi <> " SET " <> cols, - "FROM (SELECT * FROM ", - case pType of - PJObject -> " json_populate_record" - PJArray _ -> " json_populate_recordset", "(null::", fromQi qi, ", $1)) _ ", - ("WHERE " <> intercalate " AND " (map (pgFmtLogicTree qi) logicForest)) `emptyOnFalse` null logicForest, - ("RETURNING " <> intercalate ", " (map (pgFmtColumn qi) returnings)) `emptyOnFalse` null returnings + "FROM (SELECT * FROM json_populate_recordset", "(null::", fromQi qi, ", (select val from vals))) _ ", + ("WHERE " <> intercalate " AND " (pgFmtLogicTree qi <$> logicForest)) `emptyOnFalse` null logicForest, + ("RETURNING " <> intercalate ", " (pgFmtColumn qi <$> returnings)) `emptyOnFalse` null returnings ] where qi = QualifiedIdentifier schema mainTbl diff --git a/src/PostgREST/Types.hs b/src/PostgREST/Types.hs index e2d27a2e9..77008dcdc 100644 --- a/src/PostgREST/Types.hs +++ b/src/PostgREST/Types.hs @@ -115,7 +115,7 @@ newtype ForeignKey = ForeignKey { fkCol :: Column } deriving (Show, Eq, Ord) data Column = Column { colTable :: Table - , colName :: Text + , colName :: ColumnName , colDescription :: Maybe Text , colPosition :: Int32 , colNullable :: Bool @@ -134,6 +134,7 @@ instance Eq Column where -- | A view column that refers to a table column type Synonym = (Column, ViewColumn) type ViewColumn = Column +type ColumnName = Text data PrimaryKey = PrimaryKey { pkTable :: Table @@ -329,9 +330,8 @@ data ReadQuery = Select { data MutateQuery = Insert { in_ :: TableName - , insPkCols :: [Text] , qPayload :: PayloadJSON - , onConflict :: Maybe PreferResolution + , onConflict :: Maybe (PreferResolution, [ColumnName]) , where_ :: [LogicTree] , returning :: [FieldName] }|