Skip to content

Commit 667e6b6

Browse files
committed
refactor: factor out SQL on /roles
1 parent 745f529 commit 667e6b6

File tree

2 files changed

+80
-62
lines changed

2 files changed

+80
-62
lines changed

src/api/roles.ts

Lines changed: 74 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -19,14 +19,7 @@ const router = Router()
1919

2020
router.get('/', async (req, res) => {
2121
try {
22-
const sql = `
23-
WITH roles AS ( ${roles} ),
24-
grants AS ( ${grants} )
25-
SELECT
26-
*,
27-
${coalesceRowsToArray('grants', 'SELECT * FROM grants WHERE grants.grantee = roles.name')}
28-
FROM
29-
roles`
22+
const sql = getRolesSqlize(roles, grants)
3023
const { data } = await RunQuery(req.headers.pg, sql)
3124
const query: QueryParams = req.query
3225
const includeSystemSchemas = query?.includeSystemSchemas === 'true'
@@ -44,53 +37,7 @@ FROM
4437

4538
router.post('/', async (req, res) => {
4639
try {
47-
const {
48-
name,
49-
is_superuser = false,
50-
can_create_db = false,
51-
can_create_role = false,
52-
inherit_role = true,
53-
can_login = false,
54-
is_replication_role = false,
55-
can_bypass_rls = false,
56-
connection_limit = -1,
57-
password,
58-
valid_until,
59-
member_of,
60-
members,
61-
admins,
62-
} = req.body as {
63-
name: string
64-
is_superuser?: boolean
65-
can_create_db?: boolean
66-
can_create_role?: boolean
67-
inherit_role?: boolean
68-
can_login?: boolean
69-
is_replication_role?: boolean
70-
can_bypass_rls?: boolean
71-
connection_limit?: number
72-
password?: string
73-
valid_until?: string
74-
member_of?: string[]
75-
members?: string[]
76-
admins?: string[]
77-
}
78-
const sql = `
79-
CREATE ROLE ${name}
80-
WITH
81-
${is_superuser ? 'SUPERUSER' : 'NOSUPERUSER'}
82-
${can_create_db ? 'CREATEDB' : 'NOCREATEDB'}
83-
${can_create_role ? 'CREATEROLE' : 'NOCREATEROLE'}
84-
${inherit_role ? 'INHERIT' : 'NOINHERIT'}
85-
${can_login ? 'LOGIN' : 'NOLOGIN'}
86-
${is_replication_role ? 'REPLICATION' : 'NOREPLICATION'}
87-
${can_bypass_rls ? 'BYPASSRLS' : 'NOBYPASSRLS'}
88-
CONNECTION LIMIT ${connection_limit}
89-
${password === undefined ? '' : `PASSWORD '${password}'`}
90-
${valid_until === undefined ? '' : `VALID UNTIL '${valid_until}'`}
91-
${member_of === undefined ? '' : `IN ROLE ${member_of.join(',')}`}
92-
${members === undefined ? '' : `ROLE ${members.join(',')}`}
93-
${admins === undefined ? '' : `ADMIN ${admins.join(',')}`}`
40+
const sql = createRoleSqlize(req.body)
9441
const { data } = await RunQuery(req.headers.pg, sql)
9542
return res.status(200).json(data)
9643
} catch (error) {
@@ -100,6 +47,78 @@ WITH
10047
}
10148
})
10249

50+
const getRolesSqlize = (roles: string, grants: string) => {
51+
return `
52+
WITH roles AS ( ${roles} ),
53+
grants AS ( ${grants} )
54+
SELECT
55+
*,
56+
${coalesceRowsToArray('grants', 'SELECT * FROM grants WHERE grants.grantee = roles.name')}
57+
FROM
58+
roles`
59+
}
60+
const createRoleSqlize = ({
61+
name,
62+
isSuperuser = false,
63+
canCreateDb = false,
64+
canCreateRole = false,
65+
inheritRole = true,
66+
canLogin = false,
67+
isReplicationRole = false,
68+
canBypassRls = false,
69+
connectionLimit = -1,
70+
password,
71+
validUntil,
72+
memberOf,
73+
members,
74+
admins,
75+
}: {
76+
name: string
77+
isSuperuser?: boolean
78+
canCreateDb?: boolean
79+
canCreateRole?: boolean
80+
inheritRole?: boolean
81+
canLogin?: boolean
82+
isReplicationRole?: boolean
83+
canBypassRls?: boolean
84+
connectionLimit?: number
85+
password?: string
86+
validUntil?: string
87+
memberOf?: string[]
88+
members?: string[]
89+
admins?: string[]
90+
}) => {
91+
const isSuperuserSql = isSuperuser ? 'SUPERUSER' : 'NOSUPERUSER'
92+
const canCreateDbSql = canCreateDb ? 'CREATEDB' : 'NOCREATEDB'
93+
const canCreateRoleSql = canCreateRole ? 'CREATEROLE' : 'NOCREATEROLE'
94+
const inheritRoleSql = inheritRole ? 'INHERIT' : 'NOINHERIT'
95+
const canLoginSql = canLogin ? 'LOGIN' : 'NOLOGIN'
96+
const isReplicationRoleSql = isReplicationRole ? 'REPLICATION' : 'NOREPLICATION'
97+
const canBypassRlsSql = canBypassRls ? 'BYPASSRLS' : 'NOBYPASSRLS'
98+
const connectionLimitSql = `CONNECTION LIMIT ${connectionLimit}`
99+
const passwordSql = password === undefined ? '' : `PASSWORD '${password}'`
100+
const validUntilSql = validUntil === undefined ? '' : `VALID UNTIL '${validUntil}'`
101+
const memberOfSql = memberOf === undefined ? '' : `IN ROLE ${memberOf.join(',')}`
102+
const membersSql = members === undefined ? '' : `ROLE ${members.join(',')}`
103+
const adminsSql = admins === undefined ? '' : `ADMIN ${admins.join(',')}`
104+
105+
return `
106+
CREATE ROLE ${name}
107+
WITH
108+
${isSuperuserSql}
109+
${canCreateDbSql}
110+
${canCreateRoleSql}
111+
${inheritRoleSql}
112+
${canLoginSql}
113+
${isReplicationRoleSql}
114+
${canBypassRlsSql}
115+
${connectionLimitSql}
116+
${passwordSql}
117+
${validUntilSql}
118+
${memberOfSql}
119+
${membersSql}
120+
${adminsSql}`
121+
}
103122
const removeSystemSchemas = (data: Roles.Role[]) => {
104123
return data.map((role) => {
105124
let grants = role.grants.filter((x) => !DEFAULT_SYSTEM_SCHEMAS.includes(x.schema))
@@ -109,7 +128,6 @@ const removeSystemSchemas = (data: Roles.Role[]) => {
109128
}
110129
})
111130
}
112-
113131
const removeDefaultRoles = (data: Roles.Role[]) => {
114132
return data.filter((role) => !DEFAULT_ROLES.includes(role.name))
115133
}

test/integration/index.spec.js

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -324,12 +324,12 @@ describe('/roles', () => {
324324
it('POST', async () => {
325325
await axios.post(`${URL}/roles`, {
326326
name: 'test',
327-
is_superuser: true,
328-
can_create_db: true,
329-
is_replication_role: true,
330-
can_bypass_rls: true,
331-
connection_limit: 100,
332-
valid_until: '2020-01-01T00:00:00.000Z',
327+
isSuperuser: true,
328+
canCreateDb: true,
329+
isReplicationRole: true,
330+
canBypassRls: true,
331+
connectionLimit: 100,
332+
validUntil: '2020-01-01T00:00:00.000Z',
333333
})
334334
const { data: roles } = await axios.get(`${URL}/roles`)
335335
const test = roles.find((role) => role.name === 'test')

0 commit comments

Comments
 (0)