refactor: move accessibleTables to SqlFragment

This commit is contained in:
steve-chavez
2025-09-04 09:35:33 -05:00
committed by Steve Chavez
parent 1ace298a1a
commit 9c07070263
4 changed files with 33 additions and 38 deletions
+12 -2
View File
@@ -205,8 +205,8 @@ actionQuery (MayUseDb plan@InspectPlan{ipSchema=tSchema}) AppConfig{..} _ sCache
mainActionQuery = lift $
case configOpenApiMode of
OAFollowPriv -> do
tableAccess <- SQL.statement [tSchema] (SchemaCache.accessibleTables configDbPreparedStatements)
schDesc <- SQL.statement mempty (SQL.dynamicallyParameterized (SqlFragment.schemaDescription tSchema) decodeSchemaDesc configDbPreparedStatements)
tableAccess <- SQL.statement mempty $ SQL.dynamicallyParameterized (SqlFragment.accessibleTables tSchema) decodeAccessibleIdentifiers configDbPreparedStatements
schDesc <- SQL.statement mempty $ SQL.dynamicallyParameterized (SqlFragment.schemaDescription tSchema) decodeSchemaDesc configDbPreparedStatements
MaybeDbResult plan . Just <$> ((,,)
(HM.filterWithKey (\qi _ -> S.member qi tableAccess) $ SchemaCache.dbTables sCache)
@@ -214,6 +214,7 @@ actionQuery (MayUseDb plan@InspectPlan{ipSchema=tSchema}) AppConfig{..} _ sCache
<*> pure schDesc)
OAIgnorePriv -> do
schDesc <- SQL.statement mempty (SQL.dynamicallyParameterized (SqlFragment.schemaDescription tSchema) decodeSchemaDesc configDbPreparedStatements)
let tbls = HM.filterWithKey (\(QualifiedIdentifier sch _) _ -> sch == tSchema) (SchemaCache.dbTables sCache)
routs = HM.filterWithKey (\(QualifiedIdentifier sch _) _ -> sch == tSchema) (SchemaCache.dbRoutines sCache)
@@ -224,6 +225,15 @@ actionQuery (MayUseDb plan@InspectPlan{ipSchema=tSchema}) AppConfig{..} _ sCache
decodeSchemaDesc :: HD.Result (Maybe Text)
decodeSchemaDesc = join <$> HD.rowMaybe (nullableColumn HD.text)
decodeAccessibleIdentifiers :: HD.Result (S.Set QualifiedIdentifier)
decodeAccessibleIdentifiers =
let
row = QualifiedIdentifier
<$> column HD.text
<*> column HD.text
in
S.fromList <$> HD.rowList row
-- Makes sure the querystring pk matches the payload pk
-- e.g. PUT /items?id=eq.1 { "id" : 1, .. } is accepted,
-- PUT /items?id=eq.14 { "id" : 2, .. } is rejected.
+20
View File
@@ -41,6 +41,7 @@ module PostgREST.Query.SqlFragment
, escapeIdent
, escapeIdentList
, schemaDescription
, accessibleTables
) where
import qualified Data.Aeson as JSON
@@ -597,3 +598,22 @@ schemaDescription schema =
"SELECT pg_catalog.obj_description(" <> encoded <> "::regnamespace, 'pg_namespace')"
where
encoded = SQL.encoderAndParam (HE.nonNullable HE.unknown) $ encodeUtf8 schema
accessibleTables :: Text -> SQL.Snippet
accessibleTables schema = SQL.sql (encodeUtf8 [trimming|
SELECT
n.nspname AS table_schema,
c.relname AS table_name
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('v','r','m','f','p')
AND c.relnamespace = |]) <> encodedSchema <> "::regnamespace " <> SQL.sql (encodeUtf8 [trimming|
AND (
pg_has_role(c.relowner, 'USAGE')
or has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER')
or has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES')
)
AND not c.relispartition
ORDER BY table_schema, table_name|])
where
encodedSchema = SQL.encoderAndParam (HE.nonNullable HE.text) schema
+1 -32
View File
@@ -21,7 +21,6 @@ These queries are executed once at startup or when PostgREST is reloaded.
module PostgREST.SchemaCache
( SchemaCache(..)
, querySchemaCache
, accessibleTables
, accessibleFuncs
, showSummary
) where
@@ -46,7 +45,7 @@ import PostgREST.Config (AppConfig (..))
import PostgREST.Config.Database (TimezoneNames,
toIsolationLevel)
import PostgREST.Query.SqlFragment (escapeIdent)
import PostgREST.SchemaCache.Identifiers (AccessSet, FieldName,
import PostgREST.SchemaCache.Identifiers (FieldName,
QualifiedIdentifier (..),
RelIdentifier (..),
Schema, isAnyElement)
@@ -208,14 +207,6 @@ removeInternal schemas dbStruct =
M2M Junction{junTable} -> qiSchema junTable `notElem` schemas
_ -> False
decodeAccessibleIdentifiers :: HD.Result AccessSet
decodeAccessibleIdentifiers =
S.fromList <$> HD.rowList row
where
row = QualifiedIdentifier
<$> column HD.text
<*> column HD.text
decodeTables :: HD.Result TablesMap
decodeTables =
HM.fromList . map (\tbl@Table{tableSchema, tableName} -> (QualifiedIdentifier tableSchema tableName, tbl)) <$> HD.rowList tblRow
@@ -473,28 +464,6 @@ funcsSqlQuery = encodeUtf8 [trimming|
WHERE t.oid <> 'trigger'::regtype AND COALESCE(a.callable, true)
AND prokind = 'f'
AND p.pronamespace = ANY($$1::regnamespace[]) |]
accessibleTables :: Bool -> SQL.Statement [Schema] AccessSet
accessibleTables =
SQL.Statement sql params decodeAccessibleIdentifiers
where
params = map escapeIdent >$< arrayParam HE.text
sql = encodeUtf8 [trimming|
SELECT
n.nspname AS table_schema,
c.relname AS table_name
FROM pg_class c
JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE c.relkind IN ('v','r','m','f','p')
AND c.relnamespace = ANY($$1::regnamespace[])
AND (
pg_has_role(c.relowner, 'USAGE')
or has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER')
or has_any_column_privilege(c.oid, 'SELECT, INSERT, UPDATE, REFERENCES')
)
AND not c.relispartition
ORDER BY table_schema, table_name|]
{-
Adds M2O and O2O relationships for views to tables, tables to views, and views to views. The example below is taken from the test fixtures, but the views names/colnames were modified.
-4
View File
@@ -8,13 +8,11 @@ module PostgREST.SchemaCache.Identifiers
, Schema
, TableName
, FieldName
, AccessSet
, dumpQi
, toQi
) where
import qualified Data.Aeson as JSON
import qualified Data.Set as S
import qualified Data.Text as T
import Protolude
@@ -51,5 +49,3 @@ toQi txt = case T.drop 1 <$> T.breakOn "." txt of
type Schema = Text
type TableName = Text
type FieldName = Text
type AccessSet = S.Set QualifiedIdentifier