Fix #1182, fix subselect view embedding for pg10
This commit is contained in:
committed by
Steve Chávez
parent
b48824bddd
commit
dc834572d6
+1
-2
@@ -5,12 +5,11 @@ module Main where
|
||||
|
||||
import PostgREST.App (postgrest)
|
||||
import PostgREST.Config (AppConfig (..),
|
||||
minimumPgVersion,
|
||||
prettyVersion, readOptions)
|
||||
import PostgREST.DbStructure (getDbStructure, getPgVersion)
|
||||
import PostgREST.Error (encodeError)
|
||||
import PostgREST.OpenAPI (isMalformedProxyUri)
|
||||
import PostgREST.Types (DbStructure, Schema, PgVersion(..))
|
||||
import PostgREST.Types (DbStructure, Schema, PgVersion(..), minimumPgVersion)
|
||||
import Protolude hiding (hPutStrLn, replace)
|
||||
|
||||
|
||||
|
||||
+1
-14
@@ -18,9 +18,6 @@ module PostgREST.Config ( prettyVersion
|
||||
, docsVersion
|
||||
, readOptions
|
||||
, corsPolicy
|
||||
, minimumPgVersion
|
||||
, pgVersion95
|
||||
, pgVersion96
|
||||
, AppConfig (..)
|
||||
)
|
||||
where
|
||||
@@ -52,7 +49,7 @@ import Network.Wai.Middleware.Cors (CorsResourcePolicy (..))
|
||||
import Options.Applicative hiding (str)
|
||||
import Paths_postgrest (version)
|
||||
import PostgREST.Parsers (pRoleClaimKey)
|
||||
import PostgREST.Types (PgVersion(..), ApiRequestError(..),
|
||||
import PostgREST.Types (ApiRequestError(..),
|
||||
JSPath, JSPathExp(..))
|
||||
import Protolude hiding (hPutStrLn, take,
|
||||
intercalate, (<>))
|
||||
@@ -233,13 +230,3 @@ pathParser =
|
||||
strArgument $
|
||||
metavar "FILENAME" <>
|
||||
help "Path to configuration file"
|
||||
|
||||
-- | Tells the minimum PostgreSQL version required by this version of PostgREST
|
||||
minimumPgVersion :: PgVersion
|
||||
minimumPgVersion = PgVersion 90400 "9.4"
|
||||
|
||||
pgVersion96 :: PgVersion
|
||||
pgVersion96 = PgVersion 90600 "9.6"
|
||||
|
||||
pgVersion95 :: PgVersion
|
||||
pgVersion95 = PgVersion 90500 "9.5"
|
||||
|
||||
@@ -26,7 +26,7 @@ import Data.Text (split, strip,
|
||||
import qualified Data.Text as T
|
||||
import qualified Hasql.Session as H
|
||||
import PostgREST.Types
|
||||
import Text.InterpolatedString.Perl6 (q)
|
||||
import Text.InterpolatedString.Perl6 (q, qc)
|
||||
|
||||
import GHC.Exts (groupWith)
|
||||
import Protolude
|
||||
@@ -36,7 +36,7 @@ getDbStructure :: Schema -> PgVersion -> H.Session DbStructure
|
||||
getDbStructure schema pgVer = do
|
||||
tabs <- H.statement () allTables
|
||||
cols <- H.statement schema $ allColumns tabs
|
||||
syns <- H.statement schema $ allSynonyms cols
|
||||
syns <- H.statement schema $ allSynonyms cols pgVer
|
||||
childRels <- H.statement () $ allChildRelations tabs cols
|
||||
keys <- H.statement () $ allPrimaryKeys tabs
|
||||
procs <- H.statement schema allProcs
|
||||
@@ -685,68 +685,71 @@ pkFromRow :: [Table] -> (Schema, Text, Text) -> Maybe PrimaryKey
|
||||
pkFromRow tabs (s, t, n) = PrimaryKey <$> table <*> pure n
|
||||
where table = find (\tbl -> tableSchema tbl == s && tableName tbl == t) tabs
|
||||
|
||||
allSynonyms :: [Column] -> H.Statement Schema [Synonym]
|
||||
allSynonyms cols =
|
||||
allSynonyms :: [Column] -> PgVersion -> H.Statement Schema [Synonym]
|
||||
allSynonyms cols pgVer =
|
||||
H.Statement sql (HE.param HE.text) (decodeSynonyms cols) True
|
||||
-- query explanation at https://gist.github.com/steve-chavez/7ee0e6590cddafb532e5f00c46275569
|
||||
where sql = [q|
|
||||
with
|
||||
views as (
|
||||
where
|
||||
subselectRegex :: Text
|
||||
subselectRegex | pgVer < pgVersion100 = ":subselect {.*?:constraintDeps <>} :location"
|
||||
| otherwise = ":subselect {.*?:stmt_len 0} :location"
|
||||
sql = [qc|
|
||||
with
|
||||
views as (
|
||||
select
|
||||
n.nspname as view_schema,
|
||||
c.relname as view_name,
|
||||
r.ev_action as view_definition
|
||||
from pg_class c
|
||||
join pg_namespace n on n.oid = c.relnamespace
|
||||
join pg_rewrite r on r.ev_class = c.oid
|
||||
where (c.relkind = 'v'::char) and n.nspname = $1
|
||||
),
|
||||
removed_subselects as(
|
||||
select
|
||||
view_schema, view_name,
|
||||
regexp_replace(view_definition, '{subselectRegex}', '', 'g') as x
|
||||
from views
|
||||
),
|
||||
target_lists as(
|
||||
select
|
||||
view_schema, view_name,
|
||||
regexp_split_to_array(x, 'targetList') as x
|
||||
from removed_subselects
|
||||
),
|
||||
last_target_list_wo_tail as(
|
||||
select
|
||||
view_schema, view_name,
|
||||
(regexp_split_to_array(x[array_upper(x, 1)], ':onConflict'))[1] as x
|
||||
from target_lists
|
||||
),
|
||||
target_entries as(
|
||||
select
|
||||
view_schema, view_name,
|
||||
unnest(regexp_split_to_array(x, 'TARGETENTRY')) as entry
|
||||
from last_target_list_wo_tail
|
||||
),
|
||||
results as(
|
||||
select
|
||||
view_schema, view_name,
|
||||
substring(entry from ':resname (.*?) :') as view_colum_name,
|
||||
substring(entry from ':resorigtbl (.*?) :') as resorigtbl,
|
||||
substring(entry from ':resorigcol (.*?) :') as resorigcol
|
||||
from target_entries
|
||||
)
|
||||
select
|
||||
n.nspname as view_schema,
|
||||
c.relname as view_name,
|
||||
r.ev_action as view_definition
|
||||
from pg_class c
|
||||
join pg_namespace n on n.oid = c.relnamespace
|
||||
join pg_rewrite r on r.ev_class = c.oid
|
||||
where (c.relkind = 'v'::char) and n.nspname = $1
|
||||
),
|
||||
removed_subselects as(
|
||||
select
|
||||
view_schema, view_name,
|
||||
regexp_replace(view_definition, ':subselect {.*?:constraintDeps <>} :location', '', 'g') as x
|
||||
from views
|
||||
),
|
||||
target_lists as(
|
||||
select
|
||||
view_schema, view_name,
|
||||
regexp_split_to_array(x, 'targetList') as x
|
||||
from removed_subselects
|
||||
),
|
||||
last_target_list_wo_tail as(
|
||||
select
|
||||
view_schema, view_name,
|
||||
(regexp_split_to_array(x[array_upper(x, 1)], ':onConflict'))[1] as x
|
||||
from target_lists
|
||||
),
|
||||
target_entries as(
|
||||
select
|
||||
view_schema, view_name,
|
||||
unnest(regexp_split_to_array(x, 'TARGETENTRY')) as entry
|
||||
from last_target_list_wo_tail
|
||||
),
|
||||
results as(
|
||||
select
|
||||
view_schema, view_name,
|
||||
substring(entry from ':resname (.*?) :') as view_colum_name,
|
||||
substring(entry from ':resorigtbl (.*?) :') as resorigtbl,
|
||||
substring(entry from ':resorigcol (.*?) :') as resorigcol
|
||||
from target_entries
|
||||
)
|
||||
select
|
||||
sch.nspname as table_schema,
|
||||
tbl.relname as table_name,
|
||||
col.attname as table_column_name,
|
||||
res.view_schema,
|
||||
res.view_name,
|
||||
res.view_colum_name
|
||||
from results res
|
||||
join pg_class tbl on tbl.oid::text = res.resorigtbl
|
||||
join pg_attribute col on col.attrelid = tbl.oid and col.attnum::text = res.resorigcol
|
||||
join pg_namespace sch on sch.oid = tbl.relnamespace
|
||||
where resorigtbl <> '0'
|
||||
order by view_schema, view_name, view_colum_name;
|
||||
|]
|
||||
sch.nspname as table_schema,
|
||||
tbl.relname as table_name,
|
||||
col.attname as table_column_name,
|
||||
res.view_schema,
|
||||
res.view_name,
|
||||
res.view_colum_name
|
||||
from results res
|
||||
join pg_class tbl on tbl.oid::text = res.resorigtbl
|
||||
join pg_attribute col on col.attrelid = tbl.oid and col.attnum::text = res.resorigcol
|
||||
join pg_namespace sch on sch.oid = tbl.relnamespace
|
||||
where resorigtbl <> '0'
|
||||
order by view_schema, view_name, view_colum_name; |]
|
||||
|
||||
synonymFromRow :: [Column] -> (Text,Text,Text,Text,Text,Text) -> Maybe Synonym
|
||||
synonymFromRow allCols (s1,t1,c1,s2,t2,c2) = (,) <$> col1 <*> col2
|
||||
|
||||
@@ -32,7 +32,6 @@ import qualified Hasql.Decoders as HD
|
||||
|
||||
import qualified Data.Aeson as JSON
|
||||
|
||||
import PostgREST.Config (pgVersion96)
|
||||
import PostgREST.RangeQuery (rangeLimit, rangeOffset, allRange)
|
||||
import qualified Data.HashMap.Strict as HM
|
||||
import Data.Maybe
|
||||
|
||||
+17
-1
@@ -317,7 +317,23 @@ toMime (CTOther ct) = ct
|
||||
data PgVersion = PgVersion {
|
||||
pgvNum :: Int32
|
||||
, pgvName :: Text
|
||||
} deriving (Eq, Ord, Show)
|
||||
} deriving (Eq, Show)
|
||||
|
||||
instance Ord PgVersion where
|
||||
(PgVersion v1 _) `compare` (PgVersion v2 _) = v1 `compare` v2
|
||||
|
||||
-- | Tells the minimum PostgreSQL version required by this version of PostgREST
|
||||
minimumPgVersion :: PgVersion
|
||||
minimumPgVersion = PgVersion 90400 "9.4"
|
||||
|
||||
pgVersion95 :: PgVersion
|
||||
pgVersion95 = PgVersion 90500 "9.5"
|
||||
|
||||
pgVersion96 :: PgVersion
|
||||
pgVersion96 = PgVersion 90600 "9.6"
|
||||
|
||||
pgVersion100 :: PgVersion
|
||||
pgVersion100 = PgVersion 100000 "10"
|
||||
|
||||
sourceCTEName :: SqlFragment
|
||||
sourceCTEName = "pg_source"
|
||||
|
||||
+1
-2
@@ -6,9 +6,8 @@ import SpecHelper
|
||||
import qualified Hasql.Pool as P
|
||||
|
||||
import PostgREST.App (postgrest)
|
||||
import PostgREST.Config (pgVersion95, pgVersion96)
|
||||
import PostgREST.DbStructure (getDbStructure, getPgVersion)
|
||||
import PostgREST.Types (DbStructure(..))
|
||||
import PostgREST.Types (DbStructure(..), pgVersion95, pgVersion96)
|
||||
import Control.AutoUpdate (defaultUpdateSettings, mkAutoUpdate, updateAction)
|
||||
import Data.Function (id)
|
||||
import Data.IORef
|
||||
|
||||
Reference in New Issue
Block a user