diff --git a/src/PostgREST/Plan.hs b/src/PostgREST/Plan.hs index e1fcf0f66a2..6b625448e64 100644 --- a/src/PostgREST/Plan.hs +++ b/src/PostgREST/Plan.hs @@ -118,9 +118,9 @@ resolveTableField :: Table -> Field -> CoercibleField resolveTableField table (fieldName, []) = resolveTableFieldName table fieldName -- If the field is known and a JSON path is given, always assume the JSON type. But don't assume a type for entirely unknown fields. resolveTableField table (fieldName, jp) = - case resolveTableFieldName table fieldName of - tf@CoercibleField{tfIRType=""} -> tf{tfJsonPath=jp} - tf -> tf{tfJsonPath=jp, tfIRType="json"} + case resolveTableFieldName table fieldName of + tf@CoercibleField{tfIRType=""} -> tf{tfJsonPath=jp} + tf -> tf{tfJsonPath=jp, tfIRType="json"} -- | Resolve a type within the context based on the given field name and JSON path. Although there are situations where failure to resolve a field is considered an error (see `resolveOrError`), there are also situations where we allow it (RPC calls). If it should be an error and `resolveOrError` doesn't fit, ensure to check the `tfIRType` isn't empty. resolveTypeOrUnknown :: ResolverContext -> Field -> CoercibleField @@ -172,12 +172,12 @@ readPlan qi@QualifiedIdentifier{..} AppConfig{configDbMaxRows} SchemaCache{dbTab validateSpreadEmbeds =<< addRelatedOrders =<< addRels qiSchema (iAction apiRequest) dbRelationships Nothing =<< - addLogicTrees ctx apiRequest =<< + addLogicTrees ctx apiRequest =<< addRanges apiRequest =<< addOrders apiRequest =<< addDataRepresentationAliases =<< - expandStarsForDataRepresentations ctx =<< - addFilters ctx apiRequest (initReadRequest ctx $ QueryParams.qsSelect $ iQueryParams apiRequest) + expandStarsForDataRepresentations ctx =<< + addFilters ctx apiRequest (initReadRequest ctx $ QueryParams.qsSelect $ iQueryParams apiRequest) -- Build the initial read plan tree initReadRequest :: ResolverContext -> [Tree SelectItem] -> ReadPlanTree @@ -525,12 +525,12 @@ mutatePlan mutation qi ApiRequest{..} SchemaCache{dbTables, dbRepresentations} r if iPreferRepresentation == None then [] else inferColsEmbedNeeds readReq pkCols - pkCols = maybe mempty tablePKCols $ HM.lookup qi dbTables + tbl = HM.lookup qi dbTables + pkCols = maybe mempty tablePKCols tbl logic = map (resolveLogicTree ctx . snd) qsLogic rootOrder = maybe [] snd $ find (\(x, _) -> null x) qsOrder combinedLogic = foldr (addFilterToLogicForest . resolveFilter ctx) logic qsFiltersRoot body = payRaw <$> iPayload -- the body is assumed to be json at this stage(ApiRequest validates) - tbl = HM.lookup qi dbTables typedColumnsOrError = resolveOrError ctx tbl `traverse` S.toList iColumns resolveOrError :: ResolverContext -> Maybe Table -> FieldName -> Either ApiRequestError CoercibleField diff --git a/src/PostgREST/SchemaCache.hs b/src/PostgREST/SchemaCache.hs index 6efc9294fc6..de98537ace7 100644 --- a/src/PostgREST/SchemaCache.hs +++ b/src/PostgREST/SchemaCache.hs @@ -156,7 +156,7 @@ removeInternal schemas dbStruct = , dbRelationships = filter (\r -> qiSchema (relForeignTable r) `elem` schemas && not (hasInternalJunction r)) <$> HM.filterWithKey (\(QualifiedIdentifier sch _, _) _ -> sch `elem` schemas ) (dbRelationships dbStruct) , dbProcs = dbProcs dbStruct -- procs are only obtained from the exposed schemas, no need to filter them. - , dbRepresentations = dbRepresentations dbStruct -- it's expected to use internal schemas for casting functions; we don't expose these functions through the API, we only use them + , dbRepresentations = dbRepresentations dbStruct -- no need to filter, not directly exposed through the API } where hasInternalJunction ComputedRelationship{} = False @@ -296,21 +296,21 @@ dataRepresentations = SQL.Statement sql (arrayParam HE.text) decodeRepresentatio where sql = [q| SELECT - c.castsource::regtype::text, - c.casttarget::regtype::text, - c.castfunc::regproc::text + c.castsource::regtype::text, + c.casttarget::regtype::text, + c.castfunc::regproc::text FROM pg_catalog.pg_cast c JOIN pg_catalog.pg_type src_t - ON c.castsource::oid = src_t.oid - JOIN pg_catalog.pg_type dst_t - ON c.casttarget::oid = dst_t.oid + ON c.castsource::oid = src_t.oid + JOIN pg_catalog.pg_type dst_t + ON c.casttarget::oid = dst_t.oid WHERE c.castcontext = 'i' AND c.castmethod = 'f' AND has_function_privilege(c.castfunc, 'execute') AND ((src_t.typtype = 'd' AND c.casttarget IN ('json'::regtype::oid , 'text'::regtype::oid)) - OR (dst_t.typtype = 'd' AND c.castsource IN ('json'::regtype::oid , 'text'::regtype::oid))) + OR (dst_t.typtype = 'd' AND c.castsource IN ('json'::regtype::oid , 'text'::regtype::oid))) |] allProcs :: PgVersion -> Bool -> SQL.Statement [Schema] ProcsMap diff --git a/src/PostgREST/SchemaCache/Representations.hs b/src/PostgREST/SchemaCache/Representations.hs index 234cc2b62b8..027365f6df9 100644 --- a/src/PostgREST/SchemaCache/Representations.hs +++ b/src/PostgREST/SchemaCache/Representations.hs @@ -12,11 +12,12 @@ import qualified Data.HashMap.Strict as HM import Protolude --- Supporting information for how to receive and return data in API endpoints. This structure answers questions like: +-- | Data representations allow user customisation of how to present and receive data through APIs, per field. +-- This structure is used for the library of available transforms. It answers questions like: -- - What function, if any, should be used to present a certain field that's been selected for API output? -- - How do we parse incoming data for a certain field type when inserting or updating? -- - And similarly, how do we parse textual data in a query string to be used as a filter? --- In the future it's likely this functionality will be extended to cover the outputs and inputs of procedures for RPC. +-- -- Support for outputting special formats like CSV and binary data would fit into the same system. data DataRepresentation = DataRepresentation { drSourceType :: Text @@ -24,6 +25,5 @@ data DataRepresentation = DataRepresentation , drFunction :: Text } deriving (Eq, Show, Generic, JSON.ToJSON, JSON.FromJSON) --- The representation map maps from (source type, target type) to a DR. The absence of a pair here means use the default --- PostgreSQL type conversion. +-- The representation map maps from (source type, target type) to a DR. type RepresentationsMap = HM.HashMap (Text, Text) DataRepresentation