8000 feat(functions): add remaining functions routes (#117) · suryatmodulus/postgres-meta@0fa7587 · GitHub
[go: up one dir, main page]

Skip to content

Commit 0fa7587

Browse files
i-pipsoedirgo
andauthored
feat(functions): add remaining functions routes (#117)
* feat(/functions): add remaining functions routes functions list action is already implemented, adding the remaining actions (get, post, patch, delete). Beginning with this test for GET on /functions/:id * Adds implementation for GET /functions/:id * fix: get function by id or name instead of schema * Update src/lib/PostgresMetaFunctions.ts Co-authored-by: Bobbie Soedirgo <bobbie@soedirgo.dev>
1 parent 5be0c4e commit 0fa7587

File tree

3 files changed

+98
-22
lines changed

3 files changed

+98
-22
lines changed

src/lib/PostgresMetaFunctions.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,4 +20,41 @@ export default class PostgresMetaFunctions {
2020
)}));`
2121
return await this.query(sql)
2222
}
23+
24+
async retrieve({ id }: { id: number }): Promise<PostgresMetaResult<PostgresFunction>>
25+
async retrieve({ name }: { name: string }): Promise<PostgresMetaResult<PostgresFunction>>
26+
async retrieve({
27+
id,
28+
name,
29+
}: {
30+
id?: number
31+
name?: string
32+
}): Promise<PostgresMetaResult<PostgresFunction>> {
33+
if (id) {
34+
const sql = `${functionsSql} WHERE p.oid = ${literal(id)};`
35+
const { data, error } = await this.query(sql)
36+
if (error) {
37+
return { data, error }
38+
} else if (data.length === 0) {
39+
return { data: null, error: { message: `Cannot find a function with ID ${id}` } }
40+
} else {
41+
return { data: data[0], error }
42+
}
43+
} else if (name) {
44+
const sql = `${functionsSql} WHERE p.proname = ${literal(name)};`
45+
const { data, error } = await this.query(sql)
46+
if (error) {
47+
return { data, error }
48+
} else if (data.length === 0) {
49+
return {
50+
data: null,
51+
error: { message: `Cannot find a function named ${name}` },
52+
}
53+
} else {
54+
return { data: data[0], error }
55+
}
56+
} else {
57+
return { data: null, error: { message: 'Invalid parameters on function retrieve' } }
58+
}
59+
}
2360
}

src/server/routes/functions.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,25 @@ export default async (fastify: FastifyInstance) => {
2222

2323
return data
2424
})
25+
26+
fastify.get<{
27+
Headers: { pg: string }
28+
Params: {
29+
id: string
30+
}
31+
}>('/:id(\\d+)', async (request, reply) => {
32+
const connectionString = request.headers.pg
33+
const id = Number(request.params.id)
34+
35+
const pgMeta = new PostgresMeta({ connectionString, max: 1 })
36+
const { data, error } = await pgMeta.functions.retrieve({ id })
37+
await pgMeta.end()
38+
if (error) {
39+
request.log.error(JSON.stringify({ error, req: request.body }))
40+
reply.code(404)
41+
return { error: error.message }
42+
}
43+
44+
return data
45+
})
2546
}

test/integration/index.spec.js

Lines changed: 40 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,15 @@ describe('/functions', () => {
175175
assert.equal(true, !!datum)
176176
assert.equal(true, !!included)
177177
})
178+
it('GET single by ID', async () => {
179+
const functions = await axios.get(`${URL}/functions`)
180+
const functionFiltered = functions.data.find(
181+
(func) => `${func.schema}.${func.name}` === 'public.add'
182+
)
183+
const { data: functionById } = await axios.get(`${URL}/functions/${functionFiltered.id}`)
184+
185+
assert.deepStrictEqual(functionById, functionFiltered)
186+
})
178187
})
179188
describe('/tables', async () => {
180189
it('GET', async () => {
@@ -312,7 +321,7 @@ describe('/tables', async () => {
312321
type: 'int2',
313322
default_value: 42,
314323
is_nullable: false,
315-
comment: 'foo'
324+
comment: 'foo',
316325
})
317326

318327
const { data: columns } = await axios.get(`${URL}/columns`)
@@ -337,17 +346,16 @@ describe('/tables', async () => {
337346
})
338347

339348
// https://wiki.postgresql.org/wiki/Retrieve_primary_key_columns
340-
const { data: primaryKeys } = await axios.post(
341-
`${URL}/query`,
342-
{ query: `
349+
const { data: primaryKeys } = await axios.post(`${URL}/query`, {
350+
query: `
343351
SELECT a.attname
344352
FROM pg_index i
345353
JOIN pg_attribute a ON a.attrelid = i.indrelid
346354
AND a.attnum = ANY(i.indkey)
347355
WHERE i.indrelid = '${newTable.name}'::regclass
348356
AND i.indisprimary;
349-
` }
350-
)
357+
`,
358+
})
351359
assert.equal(primaryKeys.length, 1)
352360
assert.equal(primaryKeys[0].attname, 'bar')
353361

@@ -363,18 +371,17 @@ describe('/tables', async () => {
363371
is_unique: true,
364372
})
365373

366-
const { data: uniqueColumns } = await axios.post(
367-
`${URL}/query`,
368-
{ query: `
374+
const { data: uniqueColumns } = await axios.post(`${URL}/query`, {
375+
query: `
369376
SELECT a.attname
370377
FROM pg_index i
371378
JOIN pg_constraint c ON c.conindid = i.indexrelid
372379
JOIN pg_attribute a ON a.attrelid = i.indrelid
373380
AND a.attnum = ANY(i.indkey)
374381
WHERE i.indrelid = '${newTable.name}'::regclass
375382
AND i.indisunique;
376-
` }
377-
)
383+
`,
384+
})
378385
assert.equal(uniqueColumns.length, 1)
379386
assert.equal(uniqueColumns[0].attname, 'bar')
380387

@@ -423,16 +430,15 @@ describe('/tables', async () => {
423430
check: "description <> ''",
424431
})
425432

426-
const { data: constraints } = await axios.post(
427-
`${URL}/query`,
428-
{ query: `
433+
const { data: constraints } = await axios.post(`${URL}/query`, {
434+
query: `
429435
SELECT pg_get_constraintdef((
430436
SELECT c.oid
431437
FROM pg_constraint c
432438
WHERE c.conrelid = '${newTable.name}'::regclass
433439
));
434-
` }
435-
)
440+
`,
441+
})
436442
assert.equal(constraints.length, 1)
437443
assert.equal(constraints[0].pg_get_constraintdef, "CHECK ((description <> ''::text))")
438444

@@ -499,7 +505,7 @@ describe('/tables', async () => {
499505

500506
const { data: updatedColumn } = await axios.patch(`${URL}/columns/${newTable.id}.1`, {
501507
type: 'int4',
502-
default_value: 0
508+
default_value: 0,
503509
})
504510

505511
assert.strictEqual(updatedColumn.format, 'int4')
@@ -737,7 +743,10 @@ describe('/publications with tables', () => {
737743
assert.equal(newPublication.publish_update, publication.publish_update)
738744
assert.equal(newPublication.publish_delete, publication.publish_delete)
739745
assert.equal(newPublication.publish_truncate, publication.publish_truncate)
740-
assert.equal(newPublication.tables.some(table => `${table.schema}.${table.name}` === 'public.users'), true)
746+
assert.equal(
747+
newPublication.tables.some((table) => `${table.schema}.${table.name}` === 'public.users'),
748+
true
749+
)
741750
})
742751
it('GET', async () => {
743752
const res = await axios.get(`${URL}/publications`)
@@ -755,7 +764,10 @@ describe('/publications with tables', () => {
755764
})
756765
assert.equal(updated.name, 'b')
757766
assert.equal(updated.publish_insert, false)
758-
assert.equal(updated.tables.some(table => `${table.schema}.${table.name}` === 'public.users'), false)
767+
assert.equal(
768+
updated.tables.some((table) => `${table.schema}.${table.name}` === 'public.users'),
769+
false
770+
)
759771
})
760772
it('DELETE', async () => {
761773
const res = await axios.get(`${URL}/publications`)
@@ -768,9 +780,15 @@ describe('/publications with tables', () => {
768780
})
769781
it('/publications for tables with uppercase', async () => {
770782
const { data: table } = await axios.post(`${URL}/tables`, { name: 'T' })
771-
const { data: publication } = await axios.post(`${URL}/publications`, { name: 'pub', tables: ['T'] })
783+
const { data: publication } = await axios.post(`${URL}/publications`, {
784+
name: 'pub',
785+
tables: ['T'],
786+
})
772787
assert.equal(publication.name, 'pub')
773-
const { data: alteredPublication } = await axios.patch(`${URL}/publications/${publication.id}`, { tables: ['T'] })
788+
const { data: alteredPublication } = await axios.patch(
789+
`${URL}/publications/${publication.id}`,
790+
{ tables: ['T'] }
791+
)
774792
assert.equal(alteredPublication.name, 'pub')
775793

776794
await axios.delete(`${URL}/publications/${publication.id}`)
@@ -784,7 +802,7 @@ describe('/publications FOR ALL TABLES', () => {
784802
publish_insert: true,
785803
publish_update: true,
786804
publish_delete: true,
787-
publish_truncate: false
805+
publish_truncate: false,
788806
}
789807
it('POST', async () => {
790808
const { data: newPublication } = await axios.post(`${URL}/publications`, publication)

0 commit comments

Comments
 (0)
0