Skip to content

feat: CRUD on /roles & /extensions #30

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 6 commits into from
Jul 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 116 additions & 60 deletions src/api/columns.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,19 @@ router.get('/', async (req, res) => {

router.post('/', async (req, res) => {
try {
const { tableId, name, type } = req.body as {
tableId: number
name: string
type: string
}
const getTableQuery = SQL``.append(tables).append(SQL` AND c.oid = ${tableId}`)
const tableId: number = req.body.tableId
const name: string = req.body.name
const getTableQuery = getTableSqlize(tableId)
const { name: table, schema } = (await RunQuery(req.headers.pg, getTableQuery)).data[0]

const query = `ALTER TABLE "${schema}"."${table}" ADD COLUMN "${name}" "${type}"`
const addColumnArgs = req.body
delete addColumnArgs.tableId
addColumnArgs.table = table
addColumnArgs.schema = schema
const query = addColumnSqlize(addColumnArgs)
await RunQuery(req.headers.pg, query)

const getColumnQuery = SQL``
.append(columns)
.append(SQL` WHERE c.oid = ${tableId} AND column_name = ${name}`)
const getColumnQuery = getColumnSqlize(tableId, name)
const column = (await RunQuery(req.headers.pg, getColumnQuery)).data[0]

return res.status(200).json(column)
Expand All @@ -56,32 +55,16 @@ router.post('/', async (req, res) => {

router.patch('/:id', async (req, res) => {
try {
const [tableId, ordinalPos] = req.params.id.split('.')
const getColumnQuery = SQL``
.append(columns)
.append(SQL` WHERE c.oid = ${tableId} AND ordinal_position = ${ordinalPos}`)
const { schema, table, name: oldName } = (
await RunQuery(req.headers.pg, getColumnQuery)
).data[0]

const { name, type } = req.body as {
name?: string
type?: string
}

const query = `
BEGIN;
${
type === undefined
? ''
: `ALTER TABLE "${schema}"."${table}" ALTER COLUMN "${oldName}" SET DATA TYPE "${type}";`
}
${
name === undefined
? ''
: `ALTER TABLE "${schema}"."${table}" RENAME COLUMN "${oldName}" TO "${name}";`
}
COMMIT;`
const [tableId, ordinalPos] = req.params.id.split('.').map(Number)
const getColumnQuery = getColumnByPosSqlize(tableId, ordinalPos)
const column = (await RunQuery(req.headers.pg, getColumnQuery)).data[0]
const { schema, table, name: oldName } = column

const alterColumnArgs = req.body
alterColumnArgs.schema = schema
alterColumnArgs.table = table
alterColumnArgs.oldName = oldName
const query = alterColumnSqlize(alterColumnArgs)
await RunQuery(req.headers.pg, query)

const updated = (await RunQuery(req.headers.pg, getColumnQuery)).data[0]
Expand All @@ -94,15 +77,12 @@ COMMIT;`

router.delete('/:id', async (req, res) => {
try {
const [tableId, ordinalPos] = req.params.id.split('.')

const getColumnQuery = SQL``
.append(columns)
.append(SQL` WHERE c.oid = ${tableId} AND ordinal_position = ${ordinalPos} `)
const [tableId, ordinalPos] = req.params.id.split('.').map(Number)
const getColumnQuery = getColumnByPosSqlize(tableId, ordinalPos)
const column = (await RunQuery(req.headers.pg, getColumnQuery)).data[0]
const { schema, table, name } = column

const query = `ALTER TABLE "${schema}"."${table}" DROP COLUMN "${name}"`
const query = dropColumnSqlize(schema, table, name)
await RunQuery(req.headers.pg, query)

return res.status(200).json(column)
Expand All @@ -112,30 +92,106 @@ router.delete('/:id', async (req, res) => {
}
})

const removeSystemSchemas = (data: Tables.Column[]) => {
return data.filter((x) => !DEFAULT_SYSTEM_SCHEMAS.includes(x.schema))
const getTableSqlize = (id: number) => {
return SQL``.append(tables).append(SQL` AND c.oid = ${id}`)
}
const newColumnSql = ({
const addColumnSqlize = ({
schema,
table,
name,
default_value,
is_identity = false,
is_nullable = true,
is_primary_key = false,
data_type,
type,
defaultValue,
isIdentity = false,
isNullable = true,
isPrimaryKey = false,
isUnique = false,
}: {
schema: string
table: string
name: string
default_value?: string
is_identity?: boolean
is_nullable?: boolean
is_primary_key?: boolean
data_type: string
type: string
defaultValue?: any
isIdentity?: boolean
isNullable?: boolean
isPrimaryKey?: boolean
isUnique?: boolean
}) => {
const defaultValueSql = defaultValue === undefined ? '' : `DEFAULT ${defaultValue}`
const isIdentitySql = isIdentity ? 'GENERATED BY DEFAULT AS IDENTITY' : ''
const isNullableSql = isNullable ? 'NULL' : 'NOT NULL'
const isPrimaryKeySql = isPrimaryKey ? 'PRIMARY KEY' : ''
const isUniqueSql = isUnique ? 'UNIQUE' : ''

return `
ALTER TABLE "${schema}"."${table}" ADD COLUMN "${name}" "${type}"
${defaultValueSql}
${isIdentitySql}
${isNullableSql}
${isPrimaryKeySql}
${isUniqueSql}`
}
const getColumnSqlize = (tableId: number, name: string) => {
return SQL``.append(columns).append(SQL` WHERE c.oid = ${tableId} AND column_name = ${name}`)
}
const getColumnByPosSqlize = (tableId: number, ordinalPos: number) => {
return SQL``
.append(columns)
.append(SQL` WHERE c.oid = ${tableId} AND ordinal_position = ${ordinalPos}`)
}
const alterColumnSqlize = ({
schema,
table,
oldName,
name,
type,
dropDefault = false,
defaultValue,
isNullable,
}: {
schema: string
table: string
oldName: string
name?: string
type?: string
dropDefault?: boolean
defaultValue?: any
isNullable?: boolean
}) => {
const nameSql =
name === undefined
? ''
: `ALTER TABLE "${schema}"."${table}" RENAME COLUMN "${oldName}" TO "${name}";`
const typeSql =
type === undefined
? ''
: `ALTER TABLE "${schema}"."${table}" ALTER COLUMN "${oldName}" SET DATA TYPE "${type}";`
let defaultValueSql = ''
if (dropDefault) {
defaultValueSql = `ALTER TABLE "${schema}"."${table}" ALTER COLUMN "${oldName}" DROP DEFAULT;`
} else if (defaultValue !== undefined) {
defaultValueSql = `ALTER TABLE "${schema}"."${table}" ALTER COLUMN "${oldName}" SET DEFAULT ${defaultValue};`
}
let isNullableSql = ''
if (isNullable !== undefined) {
isNullableSql = isNullable
? `ALTER TABLE "${schema}"."${table}" ALTER COLUMN "${oldName}" DROP NOT NULL;`
: `ALTER TABLE "${schema}"."${table}" ALTER COLUMN "${oldName}" SET NOT NULL;`
}

// nameSql must be last.
return `
${name} ${data_type}
${default_value === undefined ? '' : `DEFAULT ${default_value}`}
${is_identity ? 'GENERATED BY DEFAULT AS IDENTITY' : ''}
${is_nullable ? '' : 'NOT NULL'}
${is_primary_key ? 'PRIMARY KEY' : ''}`
BEGIN;
${isNullableSql}
${defaultValueSql}
${typeSql}
${nameSql}
COMMIT;`
}
const dropColumnSqlize = (schema: string, table: string, name: string) => {
return `ALTER TABLE "${schema}"."${table}" DROP COLUMN "${name}"`
}
const removeSystemSchemas = (data: Tables.Column[]) => {
return data.filter((x) => !DEFAULT_SYSTEM_SCHEMAS.includes(x.schema))
}

export = router
113 changes: 109 additions & 4 deletions src/api/extensions.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,123 @@
import { Router } from 'express'

import SQL from 'sql-template-strings'
import sqlTemplates = require('../lib/sql')
const { extensions } = sqlTemplates
import { RunQuery } from '../lib/connectionPool'
import sql = require('../lib/sql')
const { extensions } = sql

const router = Router()

router.get('/', async (req, res) => {
try {
const { data } = await RunQuery(req.headers.pg, extensions)
const getExtensionsQuery = getExtensionsSqlize(extensions)
const { data } = await RunQuery(req.headers.pg, getExtensionsQuery)
return res.status(200).json(data)
} catch (error) {
console.log('throwing error')
res.status(500).json({ error: 'Database error', status: 500 })
}
})

router.post('/', async (req, res) => {
try {
const query = createExtensionSqlize(req.body)
await RunQuery(req.headers.pg, query)

const getExtensionQuery = singleExtensionSqlize(extensions, req.body.name)
const extension = (await RunQuery(req.headers.pg, getExtensionQuery)).data[0]

return res.status(200).json(extension)
} catch (error) {
console.log('throwing error')
res.status(500).json({ error: 'Database error', status: 500 })
}
})

router.patch('/:name', async (req, res) => {
try {
const name = req.params.name
req.body.name = name

const alterExtensionQuery = alterExtensionSqlize(req.body)
await RunQuery(req.headers.pg, alterExtensionQuery)

const getExtensionQuery = singleExtensionSqlize(extensions, name)
const updated = (await RunQuery(req.headers.pg, getExtensionQuery)).data[0]

return res.status(200).json(updated)
} catch (error) {
console.log('throwing error')
res.status(500).json({ error: 'Database error', status: 500 })
}
})

router.delete('/:name', async (req, res) => {
try {
const name = req.params.name
const cascade = req.query.cascade === 'true'

const getExtensionQuery = singleExtensionSqlize(extensions, name)
const deleted = (await RunQuery(req.headers.pg, getExtensionQuery)).data[0]

const query = dropExtensionSqlize(name, cascade)
await RunQuery(req.headers.pg, query)

return res.status(200).json(deleted)
} catch (error) {
console.log('throwing error')
res.status(500).json({ error: 'Database error', status: 500 })
}
})

const getExtensionsSqlize = (extensions: string) => {
return `${extensions} ORDER BY name ASC`
}
const createExtensionSqlize = ({
name,
schema,
version,
cascade = false,
}: {
name: string
schema?: string
version?: string
cascade?: boolean
}) => {
return `
CREATE EXTENSION "${name}"
${schema === undefined ? '' : `SCHEMA ${schema}`}
${version === undefined ? '' : `VERSION '${version}'`}
${cascade ? 'CASCADE' : ''}`
}
const singleExtensionSqlize = (extensions: string, name: string) => {
return SQL``.append(extensions).append(SQL` WHERE name = ${name}`)
}
const alterExtensionSqlize = ({
name,
update = false,
version,
schema,
}: {
name: string
update?: boolean
version?: string
schema?: string
}) => {
let updateSql = ''
if (update) {
updateSql = `ALTER EXTENSION "${name}" UPDATE ${version === undefined ? '' : version};`
}
const schemaSql = schema === undefined ? '' : `ALTER EXTENSION "${name}" SET SCHEMA "${schema}";`

return `
BEGIN;
${updateSql}
${schemaSql}
COMMIT;`
}
const dropExtensionSqlize = (name: string, cascade: boolean) => {
return `
DROP EXTENSION ${name}
${cascade ? 'CASCADE' : 'RESTRICT'}`
}

export = router
Loading