diff --git a/src/PostgREST/App.hs b/src/PostgREST/App.hs index a7b3174ed..b959fdcd2 100644 --- a/src/PostgREST/App.hs +++ b/src/PostgREST/App.hs @@ -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 -> diff --git a/src/PostgREST/DbStructure.hs b/src/PostgREST/DbStructure.hs index 09f80f492..91787ac9c 100644 --- a/src/PostgREST/DbStructure.hs +++ b/src/PostgREST/DbStructure.hs @@ -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 diff --git a/src/PostgREST/DbStructure/Table.hs b/src/PostgREST/DbStructure/Table.hs index 0fdc7c7de..ed2302a91 100644 --- a/src/PostgREST/DbStructure/Table.hs +++ b/src/PostgREST/DbStructure/Table.hs @@ -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 diff --git a/src/PostgREST/OpenAPI.hs b/src/PostgREST/OpenAPI.hs index 76aa3a6d6..2ade86b6b 100644 --- a/src/PostgREST/OpenAPI.hs +++ b/src/PostgREST/OpenAPI.hs @@ -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, "`."]) <$> 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." 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) - ) diff --git a/test/memory/memory-tests.sh b/test/memory/memory-tests.sh index 1ecbd2e43..032ef9786 100755 --- a/test/memory/memory-tests.sh +++ b/test/memory/memory-tests.sh @@ -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 diff --git a/test/spec/Feature/OpenApi/OpenApiSpec.hs b/test/spec/Feature/OpenApi/OpenApiSpec.hs index 1fb06bcff..50d14ea46 100644 --- a/test/spec/Feature/OpenApi/OpenApiSpec.hs +++ b/test/spec/Feature/OpenApi/OpenApiSpec.hs @@ -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",