Skip to content

Commit 0bb5757

Browse files
committed
feature: create roles and tables from endpoints
1 parent 1ce02fa commit 0bb5757

File tree

4 files changed

+94
-2
lines changed

4 files changed

+94
-2
lines changed

src/api/roles.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,43 @@ FROM
3636
res.status(500).json({ error: 'Database error', status: 500 })
3737
}
3838
})
39+
router.post('/', async (req, res) => {
40+
try {
41+
const {
42+
name,
43+
is_super_user = false,
44+
has_create_db_privileges = false,
45+
has_replication_privileges = false,
46+
can_bypass_rls = false,
47+
connections = -1,
48+
valid_until,
49+
} = req.body as {
50+
name: string
51+
is_super_user?: boolean
52+
has_create_db_privileges?: boolean
53+
has_replication_privileges?: boolean
54+
can_bypass_rls?: boolean
55+
connections?: number
56+
valid_until?: string
57+
}
58+
const sql = `
59+
CREATE ROLE ${name}
60+
WITH
61+
${is_super_user ? 'SUPERUSER' : 'NOSUPERUSER'}
62+
${has_create_db_privileges ? 'CREATEDB' : 'NOCREATEDB'}
63+
${has_replication_privileges ? 'REPLICATION' : 'NOREPLICATION'}
64+
${can_bypass_rls ? 'BYPASSRLS' : 'NOBYPASSRLS'}
65+
CONNECTION LIMIT ${connections}
66+
${valid_until === undefined ? '' : `VALID UNTIL '${valid_until}'`}`
67+
console.log(sql)
68+
const { data } = await RunQuery(req.headers.pg, sql)
69+
return res.status(200).json(data)
70+
} catch (error) {
71+
// For this one, we always want to give back the error to the customer
72+
console.log('Soft error!', error)
73+
res.status(200).json([{ error: error.toString() }])
74+
}
75+
})
3976

4077
const removeSystemSchemas = (data: Roles.Role[]) => {
4178
return data.map((role) => {

src/api/tables.ts

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { Router } from 'express'
22

33
import sql = require('../lib/sql')
44
const { columns, grants, primary_keys, relationships, tables } = sql
5-
import { coalesceRowsToArray } from '../lib/helpers'
5+
import { coalesceRowsToArray, formatColumns } from '../lib/helpers'
66
import { RunQuery } from '../lib/connectionPool'
77
import { DEFAULT_SYSTEM_SCHEMAS } from '../lib/constants/schemas'
88
import { Tables } from '../lib/interfaces'
@@ -49,6 +49,26 @@ FROM
4949
res.status(500).json({ error: 'Database error', status: 500 })
5050
}
5151
})
52+
router.post('/', async (req, res) => {
53+
try {
54+
const { schema = 'public', name, columns, primary_keys = [] } = req.body as {
55+
schema?: string
56+
name: string
57+
columns: Tables.Column[]
58+
primary_keys?: Tables.PrimaryKey[]
59+
}
60+
const sql = `
61+
CREATE TABLE ${schema}.${name} (
62+
${formatColumns({ columns, primary_keys })}
63+
)`
64+
const { data } = await RunQuery(req.headers.pg, sql)
65+
return res.status(200).json(data)
66+
} catch (error) {
67+
// For this one, we always want to give back the error to the customer
68+
console.log('Soft error!', error)
69+
res.status(200).json([{ error: error.toString() }])
70+
}
71+
})
5272

5373
export = router
5474

src/lib/connectionPool.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import pg = require('pg')
55
pg.types.setTypeParser(20, 'text', parseInt)
66
const { Pool } = pg
77

8-
export const RunQuery = async (connectionString, sql) => {
8+
export const RunQuery = async (connectionString: any, sql: string) => {
99
const pool = new Pool({ connectionString })
1010
try {
1111
const results = await pool.query(sql)

src/lib/helpers.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import { Tables } from '../lib/interfaces'
2+
13
export const coalesceRowsToArray = (source: string, joinQuery: string) => {
24
return `
35
COALESCE(
@@ -10,3 +12,36 @@ COALESCE(
1012
'[]'
1113
) AS ${source}`
1214
}
15+
16+
export const formatColumns = ({
17+
columns,
18+
primary_keys,
19+
}: {
20+
columns: Tables.Column[]
21+
primary_keys: Tables.PrimaryKey[]
22+
}) => {
23+
const pkey_columns = primary_keys.map((primary_key) => primary_key.name)
24+
return columns
25+
.map((column) => {
26+
const {
27+
name,
28+
default_value,
29+
is_identity = false,
30+
is_nullable = true,
31+
data_type,
32+
} = column as {
33+
name: string
34+
default_value?: string
35+
is_identity?: boolean
36+
is_nullable?: boolean
37+
data_type: string
38+
}
39+
return `
40+
${name} ${data_type}
41+
${default_value === undefined ? '' : `DEFAULT ${default_value}`}
42+
${is_identity ? 'GENERATED BY DEFAULT AS IDENTITY' : ''}
43+
${is_nullable ? '' : 'NOT NULL'}
44+
${pkey_columns.includes(name) ? 'PRIMARY KEY' : ''}`
45+
})
46+
.join(',')
47+
}

0 commit comments

Comments
 (0)