refactor: merge Column list into Table
* Remove Table from Column * Correct OpenAPI test where the schema was appearing for the enum unnecessarily * Increase memory-tests consumption by 2M Seems the Hasql decoder consumes more memory now that the allTables results also have [Column] inside.
This commit is contained in:
committed by
Steve Chavez
parent
902e4e8921
commit
778b8d074d
@@ -485,7 +485,7 @@ handleOpenApi headersOnly tSchema (RequestContext conf@AppConfig{..} dbStructure
|
||||
lift $ case configOpenApiMode of
|
||||
OAFollowPriv ->
|
||||
OpenAPI.encode conf dbStructure
|
||||
<$> SQL.statement tSchema (DbStructure.accessibleTables ctxPgVersion configDbPreparedStatements)
|
||||
<$> SQL.statement [tSchema] (DbStructure.accessibleTables ctxPgVersion configDbPreparedStatements)
|
||||
<*> SQL.statement tSchema (DbStructure.accessibleProcs ctxPgVersion configDbPreparedStatements)
|
||||
<*> SQL.statement tSchema (DbStructure.schemaDescription configDbPreparedStatements)
|
||||
OAIgnorePriv ->
|
||||
|
||||
+108
-132
@@ -25,7 +25,6 @@ module PostgREST.DbStructure
|
||||
, accessibleProcs
|
||||
, findIfView
|
||||
, schemaDescription
|
||||
, tableCols
|
||||
) where
|
||||
|
||||
import qualified Data.Aeson as JSON
|
||||
@@ -43,7 +42,7 @@ import PostgREST.Config.PgVersion (PgVersion, pgVersion100,
|
||||
pgVersion110)
|
||||
import PostgREST.DbStructure.Identifiers (FieldName,
|
||||
QualifiedIdentifier (..),
|
||||
Schema, TableName)
|
||||
Schema)
|
||||
import PostgREST.DbStructure.Proc (PgType (..),
|
||||
ProcDescription (..),
|
||||
ProcParam (..),
|
||||
@@ -60,16 +59,11 @@ import Protolude
|
||||
|
||||
data DbStructure = DbStructure
|
||||
{ dbTables :: TablesMap
|
||||
, dbColumns :: [Column]
|
||||
, dbRelationships :: [Relationship]
|
||||
, dbProcs :: ProcsMap
|
||||
}
|
||||
deriving (Generic, JSON.ToJSON)
|
||||
|
||||
-- TODO Table could hold references to all its Columns
|
||||
tableCols :: DbStructure -> Schema -> TableName -> [Column]
|
||||
tableCols dbs tSchema tName = filter (\Column{colTable=Table{tableSchema=s, tableName=t}} -> s==tSchema && t==tName) $ dbColumns dbs
|
||||
|
||||
findIfView :: QualifiedIdentifier -> TablesMap -> Bool
|
||||
findIfView identifier tbls = maybe False tableIsView $ M.lookup identifier tbls
|
||||
|
||||
@@ -94,8 +88,7 @@ queryDbStructure :: [Schema] -> [Schema] -> Bool -> SQL.Transaction DbStructure
|
||||
queryDbStructure schemas extraSearchPath prepared = do
|
||||
SQL.sql "set local schema ''" -- This voids the search path. The following queries need this for getting the fully qualified name(schema.name) of every db object
|
||||
pgVer <- SQL.statement mempty pgVersionStatement
|
||||
tabs <- SQL.statement mempty $ allTables pgVer prepared
|
||||
cols <- SQL.statement schemas $ allColumns tabs prepared
|
||||
tabs <- SQL.statement schemas $ allTables pgVer prepared
|
||||
keyDeps <- SQL.statement (schemas, extraSearchPath) $ allViewsKeyDependencies prepared
|
||||
m2oRels <- SQL.statement mempty $ allM2ORels pgVer prepared
|
||||
procs <- SQL.statement schemas $ allProcs pgVer prepared
|
||||
@@ -105,7 +98,6 @@ queryDbStructure schemas extraSearchPath prepared = do
|
||||
|
||||
return $ removeInternal schemas $ DbStructure {
|
||||
dbTables = tabsWViewsPks
|
||||
, dbColumns = cols
|
||||
, dbRelationships = rels
|
||||
, dbProcs = procs
|
||||
}
|
||||
@@ -115,7 +107,6 @@ removeInternal :: [Schema] -> DbStructure -> DbStructure
|
||||
removeInternal schemas dbStruct =
|
||||
DbStructure {
|
||||
dbTables = M.filterWithKey (\(QualifiedIdentifier sch _) _ -> sch `elem` schemas) $ dbTables dbStruct
|
||||
, dbColumns = filter (\x -> tableSchema (colTable x) `elem` schemas) (dbColumns dbStruct)
|
||||
, dbRelationships = filter (\x -> qiSchema (relTable x) `elem` schemas &&
|
||||
qiSchema (relForeignTable x) `elem` schemas &&
|
||||
not (hasInternalJunction x)) $ dbRelationships dbStruct
|
||||
@@ -130,30 +121,24 @@ decodeTables :: HD.Result TablesMap
|
||||
decodeTables =
|
||||
M.fromList . map (\tbl@Table{tableSchema, tableName} -> (QualifiedIdentifier tableSchema tableName, tbl)) <$> HD.rowList tblRow
|
||||
where
|
||||
tblRow = Table <$> column HD.text
|
||||
<*> column HD.text
|
||||
<*> nullableColumn HD.text
|
||||
<*> column HD.bool
|
||||
<*> column HD.bool
|
||||
<*> column HD.bool
|
||||
<*> column HD.bool
|
||||
<*> arrayColumn HD.text
|
||||
|
||||
decodeColumns :: TablesMap -> HD.Result [Column]
|
||||
decodeColumns tables =
|
||||
mapMaybe (columnFromRow tables) <$> HD.rowList colRow
|
||||
where
|
||||
colRow =
|
||||
(,,,,,,,,)
|
||||
<$> column HD.text
|
||||
<*> column HD.text
|
||||
<*> column HD.text
|
||||
<*> nullableColumn HD.text
|
||||
<*> column HD.bool
|
||||
<*> column HD.text
|
||||
<*> nullableColumn HD.int4
|
||||
<*> nullableColumn HD.text
|
||||
<*> arrayColumn HD.text
|
||||
tblRow = Table
|
||||
<$> column HD.text
|
||||
<*> column HD.text
|
||||
<*> nullableColumn HD.text
|
||||
<*> column HD.bool
|
||||
<*> column HD.bool
|
||||
<*> column HD.bool
|
||||
<*> column HD.bool
|
||||
<*> arrayColumn HD.text
|
||||
<*> compositeArrayColumn
|
||||
(Column
|
||||
<$> compositeField HD.text
|
||||
<*> nullableCompositeField HD.text
|
||||
<*> compositeField HD.bool
|
||||
<*> compositeField HD.text
|
||||
<*> nullableCompositeField HD.int4
|
||||
<*> nullableCompositeField HD.text
|
||||
<*> compositeFieldArray HD.text)
|
||||
|
||||
decodeRels :: HD.Result [Relationship]
|
||||
decodeRels =
|
||||
@@ -330,9 +315,9 @@ schemaDescription =
|
||||
where
|
||||
n.nspname = $1 |]
|
||||
|
||||
accessibleTables :: PgVersion -> Bool -> SQL.Statement Schema TablesMap
|
||||
accessibleTables :: PgVersion -> Bool -> SQL.Statement [Schema] TablesMap
|
||||
accessibleTables pgVer =
|
||||
SQL.Statement sql (param HE.text) decodeTables
|
||||
SQL.Statement sql (arrayParam HE.text) decodeTables
|
||||
where
|
||||
sql = tablesSqlQuery False pgVer
|
||||
|
||||
@@ -403,9 +388,9 @@ addViewPrimaryKeys tabs keyDeps =
|
||||
maybe [] (\(ViewKeyDependency _ _ _ _ pkCols) -> snd <$> pkCols) $
|
||||
find (\(ViewKeyDependency _ viewQi _ dep _) -> dep == PKDep && viewQi == QualifiedIdentifier sch vw) keyDeps
|
||||
|
||||
allTables :: PgVersion -> Bool -> SQL.Statement () TablesMap
|
||||
allTables :: PgVersion -> Bool -> SQL.Statement [Schema] TablesMap
|
||||
allTables pgVer =
|
||||
SQL.Statement sql HE.noParams decodeTables
|
||||
SQL.Statement sql (arrayParam HE.text) decodeTables
|
||||
where
|
||||
sql = tablesSqlQuery True pgVer
|
||||
|
||||
@@ -417,6 +402,80 @@ tablesSqlQuery getAll pgVer =
|
||||
-- (pg_has_role(ss.relowner, 'USAGE'::text) OR has_column_privilege(ss.roid, a.attnum, 'SELECT, INSERT, UPDATE, REFERENCES'::text));
|
||||
[q|
|
||||
WITH
|
||||
columns AS (
|
||||
SELECT
|
||||
nc.nspname::name AS table_schema,
|
||||
c.relname::name AS table_name,
|
||||
a.attname::name AS column_name,
|
||||
d.description AS description,
|
||||
pg_get_expr(ad.adbin, ad.adrelid)::text AS column_default,
|
||||
not (a.attnotnull OR t.typtype = 'd' AND t.typnotnull) AS is_nullable,
|
||||
CASE
|
||||
WHEN t.typtype = 'd' THEN
|
||||
CASE
|
||||
WHEN bt.typelem <> 0::oid AND bt.typlen = (-1) THEN 'ARRAY'::text
|
||||
WHEN nbt.nspname = 'pg_catalog'::name THEN format_type(t.typbasetype, NULL::integer)
|
||||
ELSE format_type(a.atttypid, a.atttypmod)
|
||||
END
|
||||
ELSE
|
||||
CASE
|
||||
WHEN t.typelem <> 0::oid AND t.typlen = (-1) THEN 'ARRAY'::text
|
||||
WHEN nt.nspname = 'pg_catalog'::name THEN format_type(a.atttypid, NULL::integer)
|
||||
ELSE format_type(a.atttypid, a.atttypmod)
|
||||
END
|
||||
END::text AS data_type,
|
||||
information_schema._pg_char_max_length(
|
||||
information_schema._pg_truetypid(a.*, t.*),
|
||||
information_schema._pg_truetypmod(a.*, t.*)
|
||||
)::integer AS character_maximum_length,
|
||||
COALESCE(bt.typname, t.typname)::name AS udt_name,
|
||||
a.attnum::integer AS position
|
||||
FROM pg_attribute a
|
||||
LEFT JOIN pg_description AS d
|
||||
ON d.objoid = a.attrelid and d.objsubid = a.attnum
|
||||
LEFT JOIN pg_attrdef ad
|
||||
ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum
|
||||
JOIN (pg_class c JOIN pg_namespace nc ON c.relnamespace = nc.oid)
|
||||
ON a.attrelid = c.oid
|
||||
JOIN (pg_type t JOIN pg_namespace nt ON t.typnamespace = nt.oid)
|
||||
ON a.atttypid = t.oid
|
||||
LEFT JOIN (pg_type bt JOIN pg_namespace nbt ON bt.typnamespace = nbt.oid)
|
||||
ON t.typtype = 'd' AND t.typbasetype = bt.oid
|
||||
LEFT JOIN (pg_collation co JOIN pg_namespace nco ON co.collnamespace = nco.oid)
|
||||
ON a.attcollation = co.oid AND (nco.nspname <> 'pg_catalog'::name OR co.collname <> 'default'::name)
|
||||
WHERE
|
||||
NOT pg_is_other_temp_schema(nc.oid)
|
||||
AND a.attnum > 0
|
||||
AND NOT a.attisdropped
|
||||
AND c.relkind in ('r', 'v', 'f', 'm', 'p')
|
||||
AND nc.nspname = ANY($1)
|
||||
),
|
||||
columns_agg AS (
|
||||
SELECT DISTINCT
|
||||
info.table_schema AS table_schema,
|
||||
info.table_name AS table_name,
|
||||
array_agg(row(
|
||||
info.column_name,
|
||||
info.description,
|
||||
info.is_nullable::boolean,
|
||||
info.data_type,
|
||||
info.character_maximum_length,
|
||||
info.column_default,
|
||||
coalesce(enum_info.vals, '{}')) order by info.position) as columns
|
||||
FROM columns info
|
||||
LEFT OUTER JOIN (
|
||||
SELECT
|
||||
n.nspname AS s,
|
||||
t.typname AS n,
|
||||
array_agg(e.enumlabel ORDER BY e.enumsortorder) AS vals
|
||||
FROM pg_type t
|
||||
JOIN pg_enum e ON t.oid = e.enumtypid
|
||||
JOIN pg_namespace n ON n.oid = t.typnamespace
|
||||
GROUP BY s,n
|
||||
) AS enum_info ON info.udt_name = enum_info.n
|
||||
WHERE info.table_schema NOT IN ('pg_catalog', 'information_schema')
|
||||
GROUP BY info.table_schema, info.table_name
|
||||
),
|
||||
tbl_constraints AS (
|
||||
SELECT
|
||||
c.conname::name AS constraint_name,
|
||||
@@ -518,11 +577,13 @@ tablesSqlQuery getAll pgVer =
|
||||
AND (pg_relation_is_updatable(c.oid::regclass, TRUE) & 16) = 16
|
||||
)
|
||||
) AS deletable,
|
||||
coalesce(tpks.pk_cols, '{}') as pk_cols
|
||||
coalesce(tpks.pk_cols, '{}') as pk_cols,
|
||||
coalesce(cols_agg.columns, '{}') as columns
|
||||
FROM pg_class c
|
||||
JOIN pg_namespace n ON n.oid = c.relnamespace
|
||||
LEFT JOIN pg_description d on d.objoid = c.oid and d.objsubid = 0
|
||||
LEFT JOIN tbl_pk_cols tpks ON n.nspname = tpks.table_schema AND c.relname = tpks.table_name
|
||||
LEFT JOIN columns_agg cols_agg ON n.nspname = cols_agg.table_schema AND c.relname = cols_agg.table_name
|
||||
WHERE c.relkind IN ('v','r','m','f','p')
|
||||
AND n.nspname NOT IN ('pg_catalog', 'information_schema') |] <>
|
||||
relIsPartition <>
|
||||
@@ -530,7 +591,7 @@ tablesSqlQuery getAll pgVer =
|
||||
"ORDER BY table_schema, table_name"
|
||||
where
|
||||
fltTables = if getAll then mempty else [q|
|
||||
AND n.nspname = $1
|
||||
AND n.nspname = ANY($1)
|
||||
AND (
|
||||
pg_has_role(c.relowner, 'USAGE')
|
||||
or has_table_privilege(c.oid, 'SELECT, INSERT, UPDATE, DELETE, TRUNCATE, REFERENCES, TRIGGER')
|
||||
@@ -538,97 +599,6 @@ tablesSqlQuery getAll pgVer =
|
||||
)|]
|
||||
relIsPartition = if pgVer >= pgVersion100 then " AND not c.relispartition " else mempty
|
||||
|
||||
allColumns :: TablesMap -> Bool -> SQL.Statement [Schema] [Column]
|
||||
allColumns tabs =
|
||||
SQL.Statement sql (arrayParam HE.text) (decodeColumns tabs)
|
||||
where
|
||||
-- CTE based on information_schema.columns changed: remove the owner filter
|
||||
sql = [q|
|
||||
WITH
|
||||
columns AS (
|
||||
SELECT
|
||||
nc.nspname::name AS table_schema,
|
||||
c.relname::name AS table_name,
|
||||
a.attname::name AS column_name,
|
||||
d.description AS description,
|
||||
pg_get_expr(ad.adbin, ad.adrelid)::text AS column_default,
|
||||
not (a.attnotnull OR t.typtype = 'd' AND t.typnotnull) AS is_nullable,
|
||||
CASE
|
||||
WHEN t.typtype = 'd' THEN
|
||||
CASE
|
||||
WHEN bt.typelem <> 0::oid AND bt.typlen = (-1) THEN 'ARRAY'::text
|
||||
WHEN nbt.nspname = 'pg_catalog'::name THEN format_type(t.typbasetype, NULL::integer)
|
||||
ELSE format_type(a.atttypid, a.atttypmod)
|
||||
END
|
||||
ELSE
|
||||
CASE
|
||||
WHEN t.typelem <> 0::oid AND t.typlen = (-1) THEN 'ARRAY'::text
|
||||
WHEN nt.nspname = 'pg_catalog'::name THEN format_type(a.atttypid, NULL::integer)
|
||||
ELSE format_type(a.atttypid, a.atttypmod)
|
||||
END
|
||||
END::text AS data_type,
|
||||
information_schema._pg_char_max_length(
|
||||
information_schema._pg_truetypid(a.*, t.*),
|
||||
information_schema._pg_truetypmod(a.*, t.*)
|
||||
)::integer AS character_maximum_length,
|
||||
COALESCE(bt.typname, t.typname)::name AS udt_name,
|
||||
a.attnum::integer AS position
|
||||
FROM pg_attribute a
|
||||
LEFT JOIN pg_description AS d
|
||||
ON d.objoid = a.attrelid and d.objsubid = a.attnum
|
||||
LEFT JOIN pg_attrdef ad
|
||||
ON a.attrelid = ad.adrelid AND a.attnum = ad.adnum
|
||||
JOIN (pg_class c JOIN pg_namespace nc ON c.relnamespace = nc.oid)
|
||||
ON a.attrelid = c.oid
|
||||
JOIN (pg_type t JOIN pg_namespace nt ON t.typnamespace = nt.oid)
|
||||
ON a.atttypid = t.oid
|
||||
LEFT JOIN (pg_type bt JOIN pg_namespace nbt ON bt.typnamespace = nbt.oid)
|
||||
ON t.typtype = 'd' AND t.typbasetype = bt.oid
|
||||
LEFT JOIN (pg_collation co JOIN pg_namespace nco ON co.collnamespace = nco.oid)
|
||||
ON a.attcollation = co.oid AND (nco.nspname <> 'pg_catalog'::name OR co.collname <> 'default'::name)
|
||||
WHERE
|
||||
NOT pg_is_other_temp_schema(nc.oid)
|
||||
AND a.attnum > 0
|
||||
AND NOT a.attisdropped
|
||||
AND c.relkind in ('r', 'v', 'f', 'm', 'p')
|
||||
AND nc.nspname = ANY($1)
|
||||
)
|
||||
SELECT DISTINCT
|
||||
info.table_schema AS schema,
|
||||
info.table_name AS table_name,
|
||||
info.column_name AS name,
|
||||
info.description AS description,
|
||||
info.is_nullable::boolean AS nullable,
|
||||
info.data_type AS col_type,
|
||||
info.character_maximum_length AS max_len,
|
||||
info.column_default AS default_value,
|
||||
coalesce(enum_info.vals, '{}') AS enum,
|
||||
info.position
|
||||
FROM columns info
|
||||
LEFT OUTER JOIN (
|
||||
SELECT
|
||||
n.nspname AS s,
|
||||
t.typname AS n,
|
||||
array_agg(e.enumlabel ORDER BY e.enumsortorder) AS vals
|
||||
FROM pg_type t
|
||||
JOIN pg_enum e ON t.oid = e.enumtypid
|
||||
JOIN pg_namespace n ON n.oid = t.typnamespace
|
||||
GROUP BY s,n
|
||||
) AS enum_info ON (info.udt_name = enum_info.n)
|
||||
WHERE info.table_schema NOT IN ('pg_catalog', 'information_schema')
|
||||
ORDER BY schema, position;
|
||||
|]
|
||||
|
||||
columnFromRow :: TablesMap ->
|
||||
(Text, Text, Text,
|
||||
Maybe Text, Bool, Text,
|
||||
Maybe Int32, Maybe Text, [Text])
|
||||
-> Maybe Column
|
||||
columnFromRow tabs (s, t, n, desc, nul, typ, l, d, e) = buildColumn <$> table
|
||||
where
|
||||
buildColumn tbl = Column tbl n desc nul typ l d e
|
||||
table = M.lookup (QualifiedIdentifier s t) tabs
|
||||
|
||||
allM2ORels :: PgVersion -> Bool -> SQL.Statement () [Relationship]
|
||||
allM2ORels pgVer =
|
||||
SQL.Statement sql HE.noParams decodeRels
|
||||
@@ -834,6 +804,12 @@ compositeArrayColumn = arrayColumn . HD.composite
|
||||
compositeField :: HD.Value a -> HD.Composite a
|
||||
compositeField = HD.field . HD.nonNullable
|
||||
|
||||
nullableCompositeField :: HD.Value a -> HD.Composite (Maybe a)
|
||||
nullableCompositeField = HD.field . HD.nullable
|
||||
|
||||
compositeFieldArray :: HD.Value a -> HD.Composite [a]
|
||||
compositeFieldArray = HD.field . HD.nonNullable . HD.listArray . HD.nonNullable
|
||||
|
||||
column :: HD.Value a -> HD.Row a
|
||||
column = HD.column . HD.nonNullable
|
||||
|
||||
|
||||
@@ -28,6 +28,7 @@ data Table = Table
|
||||
, tableUpdatable :: Bool
|
||||
, tableDeletable :: Bool
|
||||
, tablePKCols :: [FieldName]
|
||||
, tableColumns :: [Column]
|
||||
}
|
||||
deriving (Show, Ord, Generic, JSON.ToJSON)
|
||||
|
||||
@@ -35,8 +36,7 @@ instance Eq Table where
|
||||
Table{tableSchema=s1,tableName=n1} == Table{tableSchema=s2,tableName=n2} = s1 == s2 && n1 == n2
|
||||
|
||||
data Column = Column
|
||||
{ colTable :: Table
|
||||
, colName :: FieldName
|
||||
{ colName :: FieldName
|
||||
, colDescription :: Maybe Text
|
||||
, colNullable :: Bool
|
||||
, colType :: Text
|
||||
@@ -44,9 +44,6 @@ data Column = Column
|
||||
, colDefault :: Maybe Text
|
||||
, colEnum :: [Text]
|
||||
}
|
||||
deriving (Ord, Generic, JSON.ToJSON)
|
||||
|
||||
instance Eq Column where
|
||||
Column{colTable=t1,colName=n1} == Column{colTable=t2,colName=n2} = t1 == t2 && n1 == n2
|
||||
deriving (Eq, Show, Ord, Generic, JSON.ToJSON)
|
||||
|
||||
type TablesMap = M.HashMap QualifiedIdentifier Table
|
||||
|
||||
+17
-24
@@ -26,8 +26,7 @@ import Data.Swagger
|
||||
|
||||
import PostgREST.Config (AppConfig (..), Proxy (..),
|
||||
isMalformedProxyUri, toURI)
|
||||
import PostgREST.DbStructure (DbStructure (..),
|
||||
tableCols)
|
||||
import PostgREST.DbStructure (DbStructure (..))
|
||||
import PostgREST.DbStructure.Identifiers (QualifiedIdentifier (..))
|
||||
import PostgREST.DbStructure.Proc (ProcDescription (..),
|
||||
ProcParam (..))
|
||||
@@ -47,7 +46,7 @@ encode conf dbStructure tables procs schemaDescription =
|
||||
postgrestSpec
|
||||
(dbRelationships dbStructure)
|
||||
(concat $ M.elems procs)
|
||||
(openApiTableInfo dbStructure <$> (snd <$> M.toList tables))
|
||||
(snd <$> M.toList tables)
|
||||
(proxyUri conf)
|
||||
schemaDescription
|
||||
|
||||
@@ -80,17 +79,17 @@ parseDefault colType colDefault =
|
||||
where
|
||||
wrapInQuotations text = "\"" <> text <> "\""
|
||||
|
||||
makeTableDef :: [Relationship] -> (Table, [Column]) -> (Text, Schema)
|
||||
makeTableDef rels (t, cs) =
|
||||
makeTableDef :: [Relationship] -> Table -> (Text, Schema)
|
||||
makeTableDef rels t =
|
||||
let tn = tableName t in
|
||||
(tn, (mempty :: Schema)
|
||||
& description .~ tableDescription t
|
||||
& type_ ?~ SwaggerObject
|
||||
& properties .~ fromList (fmap (makeProperty rels) cs)
|
||||
& required .~ fmap colName (filter (not . colNullable) cs))
|
||||
& properties .~ fromList (makeProperty t rels <$> tableColumns t)
|
||||
& required .~ fmap colName (filter (not . colNullable) $ tableColumns t))
|
||||
|
||||
makeProperty :: [Relationship] -> Column -> (Text, Referenced Schema)
|
||||
makeProperty rels col = (colName col, Inline s)
|
||||
makeProperty :: Table -> [Relationship] -> Column -> (Text, Referenced Schema)
|
||||
makeProperty tbl rels col = (colName col, Inline s)
|
||||
where
|
||||
e = if null $ colEnum col then Nothing else JSON.decode $ JSON.encode $ colEnum col
|
||||
fk :: Maybe Text
|
||||
@@ -107,7 +106,7 @@ makeProperty rels col = (colName col, Inline s)
|
||||
in
|
||||
(\(a, b) -> T.intercalate "" ["This is a Foreign Key to `", a, ".", b, "`.<fk table='", a, "' column='", b, "'/>"]) <$> fTblCol
|
||||
pk :: Bool
|
||||
pk = colName col `elem` tablePKCols (colTable col)
|
||||
pk = colName col `elem` tablePKCols tbl
|
||||
n = catMaybes
|
||||
[ Just "Note:"
|
||||
, if pk then Just "This is a Primary Key.<pk/>" else Nothing
|
||||
@@ -162,7 +161,7 @@ makeProcParam pd =
|
||||
, Ref $ Reference "preferParams"
|
||||
]
|
||||
|
||||
makeParamDefs :: [(Table, [Column])] -> [(Text, Param)]
|
||||
makeParamDefs :: [Table] -> [(Text, Param)]
|
||||
makeParamDefs ti =
|
||||
[ ("preferParams", makePreferParam ["params=single-object"])
|
||||
, ("preferReturn", makePreferParam ["return=representation", "return=minimal", "return=none"])
|
||||
@@ -218,8 +217,8 @@ makeParamDefs ti =
|
||||
& in_ .~ ParamQuery
|
||||
& type_ ?~ SwaggerString))
|
||||
]
|
||||
<> concat [ makeObjectBody (tableName t) : makeRowFilters (tableName t) cs
|
||||
| (t, cs) <- ti
|
||||
<> concat [ makeObjectBody (tableName t) : makeRowFilters (tableName t) (tableColumns t)
|
||||
| t <- ti
|
||||
]
|
||||
|
||||
makeObjectBody :: Text -> (Text, Param)
|
||||
@@ -244,8 +243,8 @@ makeRowFilter tn c =
|
||||
makeRowFilters :: Text -> [Column] -> [(Text, Param)]
|
||||
makeRowFilters tn = fmap (makeRowFilter tn)
|
||||
|
||||
makePathItem :: (Table, [Column]) -> (FilePath, PathItem)
|
||||
makePathItem (t, cs) = ("/" ++ T.unpack tn, p $ tableInsertable t || tableUpdatable t || tableDeletable t)
|
||||
makePathItem :: Table -> (FilePath, PathItem)
|
||||
makePathItem t = ("/" ++ T.unpack tn, p $ tableInsertable t || tableUpdatable t || tableDeletable t)
|
||||
where
|
||||
-- Use first line of table description as summary; rest as description (if present)
|
||||
-- We strip leading newlines from description so that users can include a blank line between summary and description
|
||||
@@ -279,7 +278,7 @@ makePathItem (t, cs) = ("/" ++ T.unpack tn, p $ tableInsertable t || tableUpdata
|
||||
p False = pr
|
||||
p True = pw
|
||||
tn = tableName t
|
||||
rs = [ T.intercalate "." ["rowFilter", tn, colName c ] | c <- cs ]
|
||||
rs = [ T.intercalate "." ["rowFilter", tn, colName c ] | c <- tableColumns t ]
|
||||
ref = Ref . Reference
|
||||
|
||||
makeProcPathItem :: ProcDescription -> (FilePath, PathItem)
|
||||
@@ -309,7 +308,7 @@ makeRootPathItem = ("/", p)
|
||||
pr = (mempty :: PathItem) & get ?~ getOp
|
||||
p = pr
|
||||
|
||||
makePathItems :: [ProcDescription] -> [(Table, [Column])] -> InsOrdHashMap FilePath PathItem
|
||||
makePathItems :: [ProcDescription] -> [Table] -> InsOrdHashMap FilePath PathItem
|
||||
makePathItems pds ti = fromList $ makeRootPathItem :
|
||||
fmap makePathItem ti ++ fmap makeProcPathItem pds
|
||||
|
||||
@@ -321,7 +320,7 @@ escapeHostName "*6" = "0.0.0.0"
|
||||
escapeHostName "!6" = "0.0.0.0"
|
||||
escapeHostName h = h
|
||||
|
||||
postgrestSpec :: [Relationship] -> [ProcDescription] -> [(Table, [Column])] -> (Text, Text, Integer, Text) -> Maybe Text -> Swagger
|
||||
postgrestSpec :: [Relationship] -> [ProcDescription] -> [Table] -> (Text, Text, Integer, Text) -> Maybe Text -> Swagger
|
||||
postgrestSpec rels pds ti (s, h, p, b) sd = (mempty :: Swagger)
|
||||
& basePath ?~ T.unpack b
|
||||
& schemes ?~ [s']
|
||||
@@ -379,9 +378,3 @@ proxyUri AppConfig{..} =
|
||||
(proxyScheme, proxyHost, proxyPort, proxyPath)
|
||||
Nothing ->
|
||||
("http", configServerHost, toInteger configServerPort, "/")
|
||||
|
||||
openApiTableInfo :: DbStructure -> Table -> (Table, [Column])
|
||||
openApiTableInfo dbStructure table =
|
||||
( table
|
||||
, tableCols dbStructure (tableSchema table) (tableName table)
|
||||
)
|
||||
|
||||
@@ -102,21 +102,21 @@ postJsonArrayTest(){
|
||||
|
||||
echo "Running memory usage tests.."
|
||||
|
||||
jsonKeyTest "1M" "POST" "/rpc/leak?columns=blob" "13M"
|
||||
jsonKeyTest "1M" "POST" "/leak?columns=blob" "13M"
|
||||
jsonKeyTest "1M" "PATCH" "/leak?id=eq.1&columns=blob" "13M"
|
||||
jsonKeyTest "1M" "POST" "/rpc/leak?columns=blob" "15M"
|
||||
jsonKeyTest "1M" "POST" "/leak?columns=blob" "15M"
|
||||
jsonKeyTest "1M" "PATCH" "/leak?id=eq.1&columns=blob" "15M"
|
||||
|
||||
jsonKeyTest "10M" "POST" "/rpc/leak?columns=blob" "41M"
|
||||
jsonKeyTest "10M" "POST" "/leak?columns=blob" "41M"
|
||||
jsonKeyTest "10M" "PATCH" "/leak?id=eq.1&columns=blob" "41M"
|
||||
jsonKeyTest "10M" "POST" "/rpc/leak?columns=blob" "43M"
|
||||
jsonKeyTest "10M" "POST" "/leak?columns=blob" "43M"
|
||||
jsonKeyTest "10M" "PATCH" "/leak?id=eq.1&columns=blob" "43M"
|
||||
|
||||
jsonKeyTest "50M" "POST" "/rpc/leak?columns=blob" "171M"
|
||||
jsonKeyTest "50M" "POST" "/leak?columns=blob" "171M"
|
||||
jsonKeyTest "50M" "PATCH" "/leak?id=eq.1&columns=blob" "171M"
|
||||
|
||||
postJsonArrayTest "1000" "/perf_articles?columns=id,body" "11M"
|
||||
postJsonArrayTest "10000" "/perf_articles?columns=id,body" "11M"
|
||||
postJsonArrayTest "100000" "/perf_articles?columns=id,body" "21M"
|
||||
postJsonArrayTest "1000" "/perf_articles?columns=id,body" "13M"
|
||||
postJsonArrayTest "10000" "/perf_articles?columns=id,body" "13M"
|
||||
postJsonArrayTest "100000" "/perf_articles?columns=id,body" "23M"
|
||||
|
||||
trap - int term exit
|
||||
|
||||
|
||||
@@ -523,7 +523,7 @@ spec actualPgVersion = describe "OpenAPI" $ do
|
||||
|
||||
types `shouldBe` Just [aesonQQ|
|
||||
{
|
||||
"format": "test.enum_menagerie_type",
|
||||
"format": "enum_menagerie_type",
|
||||
"type": "string",
|
||||
"enum": [
|
||||
"foo",
|
||||
|
||||
Reference in New Issue
Block a user