mirror of
https://github.com/hasura/graphql-engine.git
synced 2024-12-13 19:33:55 +03:00
server: fix issue with tracking custom functions that return SETOF
materialized view (close #5294) (#5945)
https://github.com/hasura/graphql-engine/pull/5945
This commit is contained in:
parent
ee940b4a84
commit
b72fc6922a
@ -79,6 +79,7 @@ This release contains the [PDV refactor (#4111)](https://github.com/hasura/graph
|
||||
- server: limit the length of event trigger names (close #5786)
|
||||
**NOTE:** If you have event triggers with names greater than 42 chars, then you should update their names to avoid running into Postgres identifier limit bug (#5786)
|
||||
- server: validate remote schema queries (fixes #4143)
|
||||
- server: fix issue with tracking custom functions that return `SETOF` materialized view (close #5294) (#5945)
|
||||
- console: allow user to cascade Postgres dependencies when dropping Postgres objects (close #5109) (#5248)
|
||||
- console: mark inconsistent remote schemas in the UI (close #5093) (#5181)
|
||||
- cli: add missing global flags for seed command (#5565)
|
||||
|
@ -222,8 +222,8 @@ handleMultipleFunctions qf = \case
|
||||
throw400 NotSupported $
|
||||
"function " <> qf <<> " is overloaded. Overloaded functions are not supported"
|
||||
|
||||
fetchRawFunctioInfo :: MonadTx m => QualifiedFunction -> m RawFunctionInfo
|
||||
fetchRawFunctioInfo qf@(QualifiedObject sn fn) =
|
||||
fetchRawFunctionInfo :: MonadTx m => QualifiedFunction -> m RawFunctionInfo
|
||||
fetchRawFunctionInfo qf@(QualifiedObject sn fn) =
|
||||
handleMultipleFunctions qf =<< map (Q.getAltJ . runIdentity) <$> fetchFromDatabase
|
||||
where
|
||||
fetchFromDatabase = liftTx $
|
||||
|
@ -195,30 +195,34 @@ instance ToTxt TableName where
|
||||
data TableType
|
||||
= TTBaseTable
|
||||
| TTView
|
||||
| TTMaterializedView
|
||||
| TTForeignTable
|
||||
| TTLocalTemporary
|
||||
deriving (Eq)
|
||||
|
||||
tableTyToTxt :: TableType -> T.Text
|
||||
tableTyToTxt TTBaseTable = "BASE TABLE"
|
||||
tableTyToTxt TTView = "VIEW"
|
||||
tableTyToTxt TTForeignTable = "FOREIGN TABLE"
|
||||
tableTyToTxt TTLocalTemporary = "LOCAL TEMPORARY"
|
||||
tableTyToTxt TTBaseTable = "BASE TABLE"
|
||||
tableTyToTxt TTView = "VIEW"
|
||||
tableTyToTxt TTMaterializedView = "MATERIALIZED VIEW"
|
||||
tableTyToTxt TTForeignTable = "FOREIGN TABLE"
|
||||
tableTyToTxt TTLocalTemporary = "LOCAL TEMPORARY"
|
||||
|
||||
instance Show TableType where
|
||||
show = T.unpack . tableTyToTxt
|
||||
|
||||
instance Q.FromCol TableType where
|
||||
fromCol bs = flip Q.fromColHelper bs $ PD.enum $ \case
|
||||
"BASE TABLE" -> Just TTBaseTable
|
||||
"VIEW" -> Just TTView
|
||||
"FOREIGN TABLE" -> Just TTForeignTable
|
||||
"LOCAL TEMPORARY" -> Just TTLocalTemporary
|
||||
_ -> Nothing
|
||||
"BASE TABLE" -> Just TTBaseTable
|
||||
"VIEW" -> Just TTView
|
||||
"MATERIALIZED VIEW" -> Just TTMaterializedView
|
||||
"FOREIGN TABLE" -> Just TTForeignTable
|
||||
"LOCAL TEMPORARY" -> Just TTLocalTemporary
|
||||
_ -> Nothing
|
||||
|
||||
isView :: TableType -> Bool
|
||||
isView TTView = True
|
||||
isView _ = False
|
||||
isView TTView = True
|
||||
isView TTMaterializedView = True
|
||||
isView _ = False
|
||||
|
||||
newtype ConstraintName
|
||||
= ConstraintName { getConstraintTxt :: T.Text }
|
||||
|
@ -1 +1 @@
|
||||
39
|
||||
40
|
||||
|
@ -568,33 +568,42 @@ CREATE VIEW hdb_catalog.hdb_function_info_agg AS (
|
||||
(
|
||||
SELECT
|
||||
e
|
||||
FROM
|
||||
(
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
description,
|
||||
has_variadic,
|
||||
function_type,
|
||||
return_type_schema,
|
||||
return_type_name,
|
||||
return_type_type,
|
||||
returns_set,
|
||||
input_arg_types,
|
||||
input_arg_names,
|
||||
default_args,
|
||||
exists(
|
||||
SELECT
|
||||
description,
|
||||
has_variadic,
|
||||
function_type,
|
||||
return_type_schema,
|
||||
return_type_name,
|
||||
return_type_type,
|
||||
returns_set,
|
||||
input_arg_types,
|
||||
input_arg_names,
|
||||
default_args,
|
||||
exists(
|
||||
SELECT
|
||||
1
|
||||
FROM
|
||||
information_schema.tables
|
||||
WHERE
|
||||
table_schema = return_type_schema
|
||||
AND table_name = return_type_name
|
||||
) AS returns_table
|
||||
) AS e
|
||||
1
|
||||
FROM
|
||||
information_schema.tables
|
||||
WHERE
|
||||
table_schema = return_type_schema
|
||||
AND table_name = return_type_name
|
||||
)
|
||||
OR exists(
|
||||
SELECT
|
||||
1
|
||||
FROM
|
||||
pg_matviews
|
||||
WHERE
|
||||
schemaname = return_type_schema
|
||||
AND matviewname = return_type_name
|
||||
) AS returns_table
|
||||
) AS e
|
||||
)
|
||||
) AS "function_info"
|
||||
FROM
|
||||
hdb_catalog.hdb_function_agg
|
||||
FROM
|
||||
hdb_catalog.hdb_function_agg
|
||||
);
|
||||
|
||||
CREATE OR REPLACE FUNCTION
|
||||
|
46
server/src-rsr/migrations/39_to_40.sql
Normal file
46
server/src-rsr/migrations/39_to_40.sql
Normal file
@ -0,0 +1,46 @@
|
||||
CREATE
|
||||
OR REPLACE VIEW hdb_catalog.hdb_function_info_agg AS (
|
||||
SELECT
|
||||
function_name,
|
||||
function_schema,
|
||||
row_to_json (
|
||||
(
|
||||
SELECT
|
||||
e
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
description,
|
||||
has_variadic,
|
||||
function_type,
|
||||
return_type_schema,
|
||||
return_type_name,
|
||||
return_type_type,
|
||||
returns_set,
|
||||
input_arg_types,
|
||||
input_arg_names,
|
||||
default_args,
|
||||
exists(
|
||||
SELECT
|
||||
1
|
||||
FROM
|
||||
information_schema.tables
|
||||
WHERE
|
||||
table_schema = return_type_schema
|
||||
AND table_name = return_type_name
|
||||
)
|
||||
OR exists(
|
||||
SELECT
|
||||
1
|
||||
FROM
|
||||
pg_matviews
|
||||
WHERE
|
||||
schemaname = return_type_schema
|
||||
AND matviewname = return_type_name
|
||||
) AS returns_table
|
||||
) AS e
|
||||
)
|
||||
) AS "function_info"
|
||||
FROM
|
||||
hdb_catalog.hdb_function_agg
|
||||
);
|
37
server/src-rsr/migrations/40_to_39.sql
Normal file
37
server/src-rsr/migrations/40_to_39.sql
Normal file
@ -0,0 +1,37 @@
|
||||
CREATE
|
||||
OR REPLACE VIEW hdb_catalog.hdb_function_info_agg AS (
|
||||
SELECT
|
||||
function_name,
|
||||
function_schema,
|
||||
row_to_json (
|
||||
(
|
||||
SELECT
|
||||
e
|
||||
FROM
|
||||
(
|
||||
SELECT
|
||||
description,
|
||||
has_variadic,
|
||||
function_type,
|
||||
return_type_schema,
|
||||
return_type_name,
|
||||
return_type_type,
|
||||
returns_set,
|
||||
input_arg_types,
|
||||
input_arg_names,
|
||||
default_args,
|
||||
exists(
|
||||
SELECT
|
||||
1
|
||||
FROM
|
||||
information_schema.tables
|
||||
WHERE
|
||||
table_schema = return_type_schema
|
||||
AND table_name = return_type_name
|
||||
) AS returns_table
|
||||
) AS e
|
||||
)
|
||||
) AS "function_info"
|
||||
FROM
|
||||
hdb_catalog.hdb_function_agg
|
||||
);
|
@ -0,0 +1,18 @@
|
||||
description: Custom GraphQL query using search_author_mview function which returns results from a materialized view
|
||||
url: /v1/graphql
|
||||
status: 200
|
||||
response:
|
||||
data:
|
||||
search_author_mview:
|
||||
- first_name: franz
|
||||
last_name: kafka
|
||||
query:
|
||||
query: |
|
||||
query {
|
||||
search_author_mview(
|
||||
args: {query: "kafka"}
|
||||
) {
|
||||
first_name
|
||||
last_name
|
||||
}
|
||||
}
|
@ -176,3 +176,45 @@ args:
|
||||
name: get_session_var
|
||||
configuration:
|
||||
session_argument: hasura_session
|
||||
|
||||
# track & query functions that return SETOF materialized views
|
||||
- type: run_sql
|
||||
args:
|
||||
sql: |
|
||||
CREATE TABLE author(
|
||||
id SERIAL PRIMARY KEY,
|
||||
first_name TEXT,
|
||||
last_name TEXT
|
||||
);
|
||||
|
||||
INSERT INTO author(first_name, last_name) VALUES
|
||||
('enid', 'blyton'),
|
||||
('ruskin', 'bond'),
|
||||
('franz', 'kafka');
|
||||
|
||||
CREATE MATERIALIZED VIEW author_mat_view AS
|
||||
SELECT * FROM author;
|
||||
|
||||
CREATE FUNCTION search_author_mview(query text)
|
||||
RETURNS SETOF author_mat_view AS $FUNCTION$
|
||||
SELECT * FROM author_mat_view WHERE
|
||||
first_name = query OR
|
||||
last_name = query
|
||||
$FUNCTION$ LANGUAGE sql STABLE;
|
||||
|
||||
- type: track_table
|
||||
args:
|
||||
name: author
|
||||
schema: public
|
||||
|
||||
- type: track_table
|
||||
args:
|
||||
name: author_mat_view
|
||||
schema: public
|
||||
|
||||
- type: track_function
|
||||
version: 2
|
||||
args:
|
||||
function:
|
||||
schema: public
|
||||
name: search_author_mview
|
||||
|
@ -9,4 +9,6 @@ args:
|
||||
DROP TABLE integer_column cascade;
|
||||
DROP TABLE "user" cascade;
|
||||
DROP TABLE text_result cascade;
|
||||
DROP TABLE author cascade;
|
||||
DROP MATERIALIZED VIEW IF EXISTS author_mat_view cascade;
|
||||
cascade: true
|
||||
|
@ -544,6 +544,10 @@ class TestGraphQLQueryFunctions:
|
||||
@pytest.mark.parametrize("transport", ['http', 'websocket'])
|
||||
def test_query_get_test_session_id(self, hge_ctx, transport):
|
||||
check_query_f(hge_ctx, self.dir() + '/query_get_test_session_id.yaml')
|
||||
|
||||
@pytest.mark.parametrize("transport", ['http', 'websocket'])
|
||||
def test_query_search_author_mview(self, hge_ctx, transport):
|
||||
check_query_f(hge_ctx, self.dir() + '/query_search_author_mview.yaml')
|
||||
|
||||
@classmethod
|
||||
def dir(cls):
|
||||
|
Loading…
Reference in New Issue
Block a user