Skip to content

Commit b139fd6

Browse files
authored
Merge pull request #131 from supabase/feat/function-options
feat: add additional function create options
2 parents 7cdfd93 + 03ac6d0 commit b139fd6

File tree

4 files changed

+56
-2
lines changed

4 files changed

+56
-2
lines changed

src/lib/PostgresMetaFunctions.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -82,21 +82,37 @@ export default class PostgresMetaFunctions {
8282
definition,
8383
rettype = 'void',
8484
language = 'sql',
85+
behavior = 'VOLATILE',
86+
security_definer = false,
87+
config_params,
8588
}: {
8689
name: string
8790
schema?: string
8891
args?: string[]
8992
definition: string
9093
rettype?: string
9194
language?: string
95+
behavior?: 'IMMUTABLE' | 'STABLE' | 'VOLATILE'
96+
security_definer?: boolean
97+
config_params: { [key: string]: string[] }
9298
}): Promise<PostgresMetaResult<PostgresFunction>> {
9399
const sql = `
94100
CREATE FUNCTION ${ident(schema)}.${ident(name)}(${args.join(', ')})
95101
RETURNS ${rettype}
96102
AS ${literal(definition)}
97103
LANGUAGE ${language}
104+
${behavior}
105+
${security_definer ? 'SECURITY DEFINER' : 'SECURITY INVOKER'}
106+
${Object.entries(config_params)
107+
.map(
108+
([param, values]) =>
109+
`SET ${param} ${
110+
values[0] === 'FROM CURRENT' ? 'FROM CURRENT' : 'TO ' + values.map(ident).join(',')
111+
}`
112+
)
113+
.join('\n')}
98114
RETURNS NULL ON NULL INPUT;
99-
`
115+
`
100116
const { error } = await this.query(sql)
101117
if (error) {
102118
return { data: null, error }

src/lib/sql/functions.sql

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,34 @@ SELECT
88
ELSE pg_get_functiondef(p.oid)
99
END AS definition,
1010
pg_get_function_arguments(p.oid) AS argument_types,
11-
t.typname AS return_type
11+
t.typname AS return_type,
12+
CASE
13+
WHEN p.provolatile = 'i' THEN 'IMMUTABLE'
14+
WHEN p.provolatile = 's' THEN 'STABLE'
15+
WHEN p.provolatile = 'v' THEN 'VOLATILE'
16+
END AS behavior,
17+
p.prosecdef AS security_definer,
18+
JSON_OBJECT_AGG(p_config.param, p_config.values)
19+
FILTER (WHERE p_config.param IS NOT NULL) AS config_params
1220
FROM
1321
pg_proc p
1422
LEFT JOIN pg_namespace n ON p.pronamespace = n.oid
1523
LEFT JOIN pg_language l ON p.prolang = l.oid
1624
LEFT JOIN pg_type t ON t.oid = p.prorettype
25+
LEFT JOIN (
26+
SELECT
27+
oid as id,
28+
(string_to_array(unnest(proconfig), '='))[1] AS param,
29+
string_to_array((string_to_array(unnest(proconfig), '='))[2], ', ') AS values
30+
FROM
31+
pg_proc
32+
) p_config ON p_config.id = p.oid
33+
GROUP BY
34+
p.oid,
35+
n.nspname,
36+
p.proname,
37+
l.lanname,
38+
p.prosrc,
39+
t.typname,
40+
p.provolatile,
41+
p.prosecdef

src/lib/types.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,13 @@ const postgresFunctionSchema = Type.Object({
7878
definition: Type.String(),
7979
argument_types: Type.String(),
8080
return_type: Type.String(),
81+
behavior: Type.Union([
82+
Type.Literal('IMMUTABLE'),
83+
Type.Literal('STABLE'),
84+
Type.Literal('VOLATILE'),
85+
]),
86+
security_definer: Type.Boolean(),
87+
config_params: Type.Union([Type.Dict(Type.Array(Type.String())), Type.Null()]),
8188
})
8289
export type PostgresFunction = Static<typeof postgresFunctionSchema>
8390

test/integration/index.spec.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,9 @@ describe('/functions', () => {
165165
definition: 'select $1 + $2',
166166
rettype: 'integer',
167167
language: 'sql',
168+
behavior: 'STABLE',
169+
security_definer: true,
170+
config_params: { search_path: ['hooks', 'auth'], role: ['postgres'] },
168171
}
169172
before(async () => {
170173
await axios.post(`${URL}/query`, {
@@ -212,6 +215,9 @@ describe('/functions', () => {
212215
assert.strictEqual(newFunc.schema, 'public')
213216
assert.strictEqual(newFunc.language, 'sql')
214217
assert.strictEqual(newFunc.return_type, 'int4')
218+
assert.strictEqual(newFunc.behavior, 'STABLE')
219+
assert.strictEqual(newFunc.security_definer, true)
220+
assert.deepStrictEqual(newFunc.config_params, { search_path: ['hooks', 'auth'], role: ['postgres'] })
215221
func.id = newFunc.id
216222
})
217223
it('PATCH', async () => {

0 commit comments

Comments
 (0)