Skip to content

Commit 9b8e6b4

Browse files
rakeshkkyshahidhk
authored andcommitted
functions can access session info via input arg (close hasura#2322) (hasura#3143)
1 parent 2d5cdab commit 9b8e6b4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

51 files changed

+798
-214
lines changed

cli/commands/migrate_test.go

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ query_collections: []
3737
remote_schemas: []
3838
tables:
3939
- array_relationships: []
40+
computed_fields: []
4041
configuration:
4142
custom_column_names: {}
4243
custom_root_fields:
@@ -88,12 +89,14 @@ tables:
8889
select_permissions: []
8990
table: test
9091
update_permissions: []
92+
version: 2
9193
`),
9294
"empty-metadata": []byte(`allowlist: []
9395
functions: []
9496
query_collections: []
9597
remote_schemas: []
9698
tables: []
99+
version: 2
97100
`),
98101
}
99102

@@ -283,7 +286,7 @@ func mustWriteFile(t testing.TB, dir, file string, body string) {
283286

284287
func compareMetadata(t testing.TB, metadataFile string, actualType string, serverVersion *semver.Version) {
285288
var actualData []byte
286-
c, err := semver.NewConstraint("<= v1.0.0-beta.9")
289+
c, err := semver.NewConstraint("<= v1.0.0-beta.10")
287290
if err != nil {
288291
t.Fatal(err)
289292
}

docs/graphql/manual/api-reference/schema-metadata-api/custom-functions.rst

Lines changed: 80 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,7 @@ track_function
1616
--------------
1717

1818
``track_function`` is used to add a custom SQL function to the GraphQL schema.
19-
20-
Currently, only functions which satisfy the following constraints can be exposed over the GraphQL API
21-
(*terminology from* `Postgres docs <https://www.postgresql.org/docs/current/sql-createfunction.html>`__):
22-
23-
- **Function behaviour**: ONLY ``STABLE`` or ``IMMUTABLE``
24-
- **Return type**: MUST be ``SETOF <table-name>``
25-
- **Argument modes**: ONLY ``IN``
19+
Also refer a note :ref:`here <note>`.
2620

2721
Add an SQL function ``search_articles``:
2822

@@ -40,6 +34,85 @@ Add an SQL function ``search_articles``:
4034
}
4135
}
4236
37+
.. _track_function_v2:
38+
39+
track_function v2
40+
-----------------
41+
42+
Version 2 of ``track_function`` is used to add a custom SQL function to the GraphQL schema with configuration.
43+
Also refer a note :ref:`here <note>`.
44+
45+
Add an SQL function called ``search_articles`` with a Hasura session argument.
46+
47+
.. code-block:: http
48+
49+
POST /v1/query HTTP/1.1
50+
Content-Type: application/json
51+
X-Hasura-Role: admin
52+
53+
{
54+
"type": "track_function",
55+
"version": 2,
56+
"args": {
57+
"function": {
58+
"schema": "public",
59+
"name": "search_articles"
60+
},
61+
"configuration": {
62+
"session_argument": "hasura_session"
63+
}
64+
}
65+
}
66+
67+
.. _track_function_args_syntax_v2:
68+
69+
Args syntax
70+
^^^^^^^^^^^
71+
72+
.. list-table::
73+
:header-rows: 1
74+
75+
* - Key
76+
- Required
77+
- Schema
78+
- Description
79+
* - function
80+
- true
81+
- :ref:`FunctionName <FunctionName>`
82+
- Name of the SQL function
83+
* - configuration
84+
- false
85+
- :ref:`Function Configuration <function_configuration>`
86+
- Configuration for the SQL function
87+
88+
.. _function_configuration:
89+
90+
Function Configuration
91+
^^^^^^^^^^^^^^^^^^^^^^
92+
93+
.. list-table::
94+
:header-rows: 1
95+
96+
* - Key
97+
- Required
98+
- Schema
99+
- Description
100+
* - session_argument
101+
- false
102+
- `String`
103+
- Function argument which accepts session info JSON
104+
105+
.. _note:
106+
107+
.. note::
108+
109+
Currently, only functions which satisfy the following constraints can be exposed over the GraphQL API
110+
(*terminology from* `Postgres docs <https://www.postgresql.org/docs/current/sql-createfunction.html>`__):
111+
112+
- **Function behaviour**: ONLY ``STABLE`` or ``IMMUTABLE``
113+
- **Return type**: MUST be ``SETOF <table-name>``
114+
- **Argument modes**: ONLY ``IN``
115+
43116
.. _untrack_function:
44117

45118
untrack_function

docs/graphql/manual/api-reference/schema-metadata-api/index.rst

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ The various types of queries are listed in the following table:
112112
- 1
113113
- Add an SQL function
114114

115+
* - :ref:`track_function`
116+
- :ref:`track_function_args <track_function_args_syntax_v2>`
117+
- 2
118+
- Add an SQL function with configuration
119+
115120
* - :ref:`untrack_function`
116121
- :ref:`FunctionName <FunctionName>`
117122
- 1

docs/graphql/manual/queries/custom-functions.rst

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -395,6 +395,51 @@ Search nearby landmarks with ``distance_kms`` default value which is 2 kms:
395395
}
396396

397397

398+
Accessing Hasura session variables in custom functions
399+
******************************************************
400+
401+
Use the v2 :ref:`track_function <track_function_v2>` to add a function by defining a session argument.
402+
The session argument will be a JSON object where keys are session variable names (in lower case) and values are strings.
403+
Use the ``->>`` JSON operator to fetch the value of a session variable as shown in the following example.
404+
405+
.. code-block:: plpgsql
406+
407+
-- single text column table
408+
CREATE TABLE text_result(
409+
result text
410+
);
411+
412+
-- simple function which returns the hasura role
413+
-- where 'hasura_session' will be session argument
414+
CREATE FUNCTION get_session_role(hasura_session json)
415+
RETURNS SETOF text_result AS $$
416+
SELECT q.* FROM (VALUES (hasura_session ->> 'x-hasura-role')) q
417+
$$ LANGUAGE sql STABLE;
418+
419+
420+
.. graphiql::
421+
:view_only:
422+
:query:
423+
query {
424+
get_session_role {
425+
result
426+
}
427+
}
428+
:response:
429+
{
430+
"data": {
431+
"get_session_role": [
432+
{
433+
"result": "admin"
434+
}
435+
]
436+
}
437+
}
438+
439+
.. note::
440+
441+
The specified session argument will not be included in the ``<function-name>_args`` input object in the GraphQL schema.
442+
398443
Permissions for custom function queries
399444
---------------------------------------
400445

server/graphql-engine.cabal

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ library
205205
, Hasura.RQL.Types.SchemaCache
206206
, Hasura.RQL.Types.SchemaCacheTypes
207207
, Hasura.RQL.Types.BoolExp
208+
, Hasura.RQL.Types.Function
208209
, Hasura.RQL.Types.Catalog
209210
, Hasura.RQL.Types.Column
210211
, Hasura.RQL.Types.Common

server/src-lib/Hasura/Db.hs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ module Hasura.Db
88
, runLazyTx
99
, runLazyTx'
1010
, withUserInfo
11+
, sessionInfoJsonExp
1112

1213
, RespTx
1314
, LazyRespTx
@@ -29,6 +30,8 @@ import Hasura.RQL.Types.Permission
2930
import Hasura.SQL.Error
3031
import Hasura.SQL.Types
3132

33+
import qualified Hasura.SQL.DML as S
34+
3235
data PGExecCtx
3336
= PGExecCtx
3437
{ _pecPool :: !Q.PGPool
@@ -88,8 +91,10 @@ setHeadersTx uVars =
8891
Q.unitQE defaultTxErrorHandler setSess () False
8992
where
9093
setSess = Q.fromText $
91-
"SET LOCAL \"hasura.user\" = " <>
92-
pgFmtLit (J.encodeToStrictText uVars)
94+
"SET LOCAL \"hasura.user\" = " <> toSQLTxt (sessionInfoJsonExp uVars)
95+
96+
sessionInfoJsonExp :: UserVars -> S.SQLExp
97+
sessionInfoJsonExp = S.SELit . J.encodeToStrictText
9398

9499
defaultTxErrorHandler :: Q.PGTxErr -> QErr
95100
defaultTxErrorHandler = mkTxErrorHandler (const False)

server/src-lib/Hasura/GraphQL/Execute/LiveQuery/Plan.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ resolveMultiplexedValue = \case
100100
pure $ fromResVars (PGTypeScalar $ pstType colVal) varJsonPath
101101
GR.UVSessVar ty sessVar -> pure $ fromResVars ty ["session", T.toLower sessVar]
102102
GR.UVSQL sqlExp -> pure sqlExp
103+
GR.UVSession -> pure $ fromResVars (PGTypeScalar PGJSON) ["session"]
103104
where
104105
fromResVars ty jPath =
105106
flip S.SETyAnn (S.mkTypeAnn ty) $ S.SEOpApp (S.SQLOp "#>>")

server/src-lib/Hasura/GraphQL/Execute/Query.hs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -158,12 +158,15 @@ prepareWithPlan = \case
158158
R.UVSessVar ty sessVar -> do
159159
let sessVarVal =
160160
S.SEOpApp (S.SQLOp "->>")
161-
[S.SEPrep 1, S.SELit $ T.toLower sessVar]
161+
[currentSession, S.SELit $ T.toLower sessVar]
162162
return $ flip S.SETyAnn (S.mkTypeAnn ty) $ case ty of
163163
PGTypeScalar colTy -> withConstructorFn colTy sessVarVal
164164
PGTypeArray _ -> sessVarVal
165165

166-
R.UVSQL sqlExp -> return sqlExp
166+
R.UVSQL sqlExp -> pure sqlExp
167+
R.UVSession -> pure currentSession
168+
where
169+
currentSession = S.SEPrep 1
167170

168171
queryRootName :: Text
169172
queryRootName = "query_root"

server/src-lib/Hasura/GraphQL/Explain.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ resolveVal userInfo = \case
6767
PGTypeScalar colTy -> withConstructorFn colTy sessVarVal
6868
PGTypeArray _ -> sessVarVal
6969
RS.UVSQL sqlExp -> return sqlExp
70+
RS.UVSession -> pure $ sessionInfoJsonExp $ userVars userInfo
7071

7172
getSessVarVal
7273
:: (MonadError QErr m)

server/src-lib/Hasura/GraphQL/Resolve.hs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,8 @@ import qualified Language.GraphQL.Draft.Syntax as G
2323

2424
import Hasura.GraphQL.Resolve.Context
2525
import Hasura.Prelude
26-
import Hasura.RQL.DML.Internal (sessVarFromCurrentSetting)
26+
import Hasura.RQL.DML.Internal (currentSession,
27+
sessVarFromCurrentSetting)
2728
import Hasura.RQL.Types
2829
import Hasura.SQL.Types
2930

@@ -82,6 +83,7 @@ queryFldToSQL fn fld = do
8283
UVPG annPGVal -> fn annPGVal
8384
UVSQL sqlExp -> return sqlExp
8485
UVSessVar colTy sessVar -> sessVarFromCurrentSetting colTy sessVar
86+
UVSession -> pure currentSession
8587
return $ RS.toPGQuery resolvedAST
8688

8789
mutFldToTx

0 commit comments

Comments
 (0)