8000 feat(/functions): adds POST /functions and DELETE /functions · DavraYoung/postgres-meta@2f6ab96 · GitHub
[go: up one dir, main page]

Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 2f6ab96

Browse files
committed
feat(/functions): adds POST /functions and DELETE /functions
implements missing routes and (POST & DELETE) supabase#115
1 parent e74514a commit 2f6ab96

File tree

3 files changed

+125
-2
lines changed

3 files changed

+125
-2
lines changed

src/lib/PostgresMetaFunctions.ts

Lines changed: 58 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { literal } from 'pg-format'
1+
import { ident, literal } from 'pg-format'
22
import { DEFAULT_SYSTEM_SCHEMAS } from './constants'
33
import { functionsSql } from './sql'
44
import { PostgresMetaResult, PostgresFunction } from './types'
@@ -22,7 +22,13 @@ export default class PostgresMetaFunctions {
2222
}
2323

2424
async retrieve({ id }: { id: number }): Promise<PostgresMetaResult<PostgresFunction>>
25-
async retrieve({ name }: { name: string }): Promise<PostgresMetaResult<PostgresFunction>>
25+
async retrieve({
26+
name,
27+
schema,
28+
}: {
29+
name: string
30+
schema: string
31+
}): Promise<PostgresMetaResult<PostgresFunction>>
2632
async retrieve({
2733
id,
2834
name,
@@ -57,4 +63,54 @@ export default class PostgresMetaFunctions {
5763
return { data: null, error: { message: 'Invalid parameters on function retrieve' } }
5864
}
5965
}
66+
67+
async create({
68+
name,
69+
schema = 'public',
70+
params,
71+
definition,
72+
rettype = 'void',
73+
language = 'sql',
74+
}: {
75+
name: string
76+
schema?: string
77+
params?: string[]
78+
definition: string
79+
rettype?: string
80+
language?: string
81+
}): Promise<PostgresMetaResult<PostgresFunction>> {
82+
const sql = `
83+
CREATE FUNCTION ${ident(schema)}.${ident(name)}
84+
${params && params.length ? `(${params.join(',')})` : '()'}
85+
RETURNS ${rettype || 'void'}
86+
AS '${definition}'
87+
LANGUAGE ${language}
88+
RETURNS NULL ON NULL INPUT;
89+
`
90+
const { error } = await this.query(sql)
91+
if (error) {
92+
return { data: null, error }
93+
}
94+
return await this.retrieve({ name, schema })
95+
}
96+
97+
async remove(
98+
id: number,
99+
{ cascade = false } = {}
100+
): Pr 8000 omise<PostgresMetaResult<PostgresFunction>> {
101+
const { data: func, error } = await this.retrieve({ id })
102+
if (error) {
103+
return { data: null, error }
104+
}
105+
const sql = `DROP FUNCTION ${ident(func!.schema)}.${ident(func!.name)} ${
106+
cascade ? 'CASCADE' : 'RESTRICT'
107+
};`
108+
{
109+
const { error } = await this.query(sql)
110+
if (error) {
111+
return { data: null, error }
112+
}
113+
}
114+
return { data: func!, error: null }
115+
}
60116
}

src/server/routes/functions.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,42 @@ export default async (fastify: FastifyInstance) => {
4343

4444
return data
4545
})
46+
47+
fastify.post<{
48+
Headers: { pg: string }
49+
Body: any
50+
}>('/', async (request, reply) => {
51+
const connectionString = request.headers.pg
52+
53+
const pgMeta = new PostgresMeta({ connectionString, max: 1 })
54+
const { data, error } = await pgMeta.functions.create(request.body)
55+
await pgMeta.end()
56+
if (error) {
57+
request.log.error(JSON.stringify({ error, req: request.body }))
58+
reply.code(400)
59+
return { error: error.message }
60+
}
61+
return data
62+
})
63+
64+
fastify.delete<{
65+
Headers: { pg: string }
66+
Params: {
67+
id: string
68+
}
69+
}>('/:id(\\d+)', async (request, reply) => {
70+
const connectionString = request.headers.pg
71+
const id = Number(request.params.id)
72+
73+
const pgMeta = new PostgresMeta({ connectionString, max: 1 })
74+
const { data, error } = await pgMeta.functions.remove(id)
75+
await pgMeta.end()
76+
if (error) {
77+
request.log.error(JSON.stringify({ error, req: request.body }))
78+
reply.code(400)
79+
if (error.message.startsWith('Cannot find')) reply.code(404)
80+
return { error: error.message }
81+
}
82+
return data
83+
})
4684
}

test/integration/index.spec.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,20 @@ describe('/types', () => {
157157
})
158158
})
159159
describe('/functions', () => {
160+
var func = {
161+
id: null,
162+
name: 'test_func',
163+
schema: 'public',
164+
params: ['integer', 'integer'],
165+
definition: 'select $1 + $2',
166+
rettype: 'integer',
167+
language: 'sql',
168+
}
169+
before(async () => {
170+
await axios.post(`${URL}/query`, {
171+
query: `DROP FUNCTION IF EXISTS "${func.name}";`,
172+
})
173+
})
160174
it('GET', async () => {
161175
const res = await axios.get(`${URL}/functions`)
162176
// console.log('res.data', res.data)
@@ -184,7 +198,22 @@ describe('/functions', () => {
184198

185199
assert.deepStrictEqual(functionById, functionFiltered)
186200
})
201+
it('POST', async () => {
202+
const { data: newFunc } = await axios.post(`${URL}/functions`, func)
203+
assert.equal(newFunc.name, 'test_func')
204+
assert.equal(newFunc.schema, 'public')
205+
assert.equal(newFunc.language, 'sql')
206+
assert.equal(newFunc.return_type, 'int4')
207+
func.id = newFunc.id
208+
})
209+
it('DELETE', async () => {
210+
await axios.delete(`${URL}/functions/${func.id}`)
211+
const { data: functions } = await axios.get(`${URL}/functions`)
212+
const stillExists = functions.some((x) => func.id === x.id)
213+
assert.equal(stillExists< 5B81 /span>, false, 'Function is deleted')
214+
})
187215
})
216+
188217
describe('/tables', async () => {
189218
it('GET', async () => {
190219
const tables = await axios.get(`${URL}/tables`)

0 commit comments

Comments
 (0)
0