@@ -2,7 +2,7 @@ import { Router } from 'express'
22import SQL from 'sql-template-strings'
33import sqlTemplates = require( '../lib/sql' )
44const { columns, grants, policies, primary_keys, relationships, tables } = sqlTemplates
5- import { coalesceRowsToArray } from '../lib/helpers'
5+ import { coalesceRowsToArray , toTransaction } from '../lib/helpers'
66import { RunQuery } from '../lib/connectionPool'
77import { DEFAULT_SYSTEM_SCHEMAS } from '../lib/constants'
88import { Tables } from '../lib/interfaces'
@@ -18,7 +18,7 @@ const router = Router()
1818
1919router . get ( '/' , async ( req , res ) => {
2020 try {
21- const sql = getTablesSqlize ( { tables, columns, grants, policies, primary_keys, relationships } )
21+ const sql = getTablesSql ( { tables, columns, grants, policies, primary_keys, relationships } )
2222 const { data } = await RunQuery ( req . headers . pg , sql )
2323 const query : QueryParams = req . query
2424 const includeSystemSchemas = query ?. includeSystemSchemas === 'true'
@@ -40,7 +40,9 @@ router.post('/', async (req, res) => {
4040
4141 // Create the table
4242 const createTableSql = createTable ( name , schema )
43- await RunQuery ( req . headers . pg , createTableSql )
43+ const alterSql = alterTableSql ( req . body )
44+ const transaction = toTransaction ( [ createTableSql , alterSql ] )
45+ await RunQuery ( req . headers . pg , transaction )
4446
4547 // Return fresh details
4648 const getTable = selectSingleByName ( schema , name )
@@ -57,23 +59,26 @@ router.post('/', async (req, res) => {
5759router . patch ( '/:id' , async ( req , res ) => {
5860 try {
5961 const id : number = parseInt ( req . params . id )
62+ if ( ! ( id > 0 ) ) throw new Error ( 'id is required' )
63+
6064 const name : string = req . body . name
65+ const payload : any = { ...req . body }
6166
6267 // Get table
6368 const getTableSql = selectSingleSql ( id )
6469 const { data : getTableResults } = await RunQuery ( req . headers . pg , getTableSql )
6570 let previousTable : Tables . Table = getTableResults [ 0 ]
6671
67- // Update fields
68- // NB: Run name updates last
69- if ( name ) {
70- const updateName = alterTableName ( previousTable . name , name , previousTable . schema )
71- await RunQuery ( req . headers . pg , updateName )
72- }
72+ // Update fields and name
73+ const nameSql = ! name ? '' : alterTableName ( previousTable . name , name , previousTable . schema )
74+ if ( ! name ) payload . name = previousTable . name
75+ const alterSql = alterTableSql ( payload )
76+ const transaction = toTransaction ( [ nameSql , alterSql ] )
77+ await RunQuery ( req . headers . pg , transaction )
7378
7479 // Return fresh details
75- const { data : updatedResults } = await RunQuery ( req . headers . pg , getTableSql )
76- let updated : Tables . Table = updatedResults [ 0 ]
80+ const { data : freshTableData } = await RunQuery ( req . headers . pg , getTableSql )
81+ let updated : Tables . Table = freshTableData [ 0 ]
7782 return res . status ( 200 ) . json ( updated )
7883 } catch ( error ) {
7984 // For this one, we always want to give back the error to the customer
@@ -90,7 +95,7 @@ router.delete('/:id', async (req, res) => {
9095 const { name, schema } = table
9196
9297 const cascade = req . query . cascade === 'true'
93- const query = dropTableSqlize ( schema , name , cascade )
98+ const query = dropTableSql ( schema , name , cascade )
9499 await RunQuery ( req . headers . pg , query )
95100
96101 return res . status ( 200 ) . json ( table )
@@ -100,7 +105,7 @@ router.delete('/:id', async (req, res) => {
100105 }
101106} )
102107
103- const getTablesSqlize = ( {
108+ const getTablesSql = ( {
104109 tables,
105110 columns,
106111 grants,
@@ -142,24 +147,51 @@ SELECT
142147 OR (relationships.target_table_schema = tables.schema AND relationships.target_table_name = tables.name)`
143148 ) }
144149FROM
145- tables`
150+ tables;` . trim ( )
146151}
147152const selectSingleSql = ( id : number ) => {
148- return SQL `` . append ( tables ) . append ( SQL ` and c.oid = ${ id } ` )
153+ return ` ${ tables } and c.oid = ${ id } ;` . trim ( )
149154}
150155const selectSingleByName = ( schema : string , name : string ) => {
151- return SQL `` . append ( tables ) . append ( SQL ` and table_schema = ${ schema } and table_name = ${ name } ` )
156+ return ` ${ tables } and table_schema = ' ${ schema } ' and table_name = ' ${ name } ';` . trim ( )
152157}
153158const createTable = ( name : string , schema : string = 'postgres' ) => {
154- const query = SQL `` . append ( `CREATE TABLE "${ schema } "."${ name } " ()` )
155- return query
159+ return `CREATE TABLE IF NOT EXISTS "${ schema } "."${ name } " ();` . trim ( )
156160}
157161const alterTableName = ( previousName : string , newName : string , schema : string ) => {
158- const query = SQL `` . append ( `ALTER TABLE "${ schema } "."${ previousName } " RENAME TO "${ newName } "` )
159- return query
162+ return `ALTER TABLE "${ schema } "."${ previousName } " RENAME TO "${ newName } ";` . trim ( )
163+ }
164+ const alterTableSql = ( {
165+ schema = 'public' ,
166+ name,
167+ rls_enabled,
168+ rls_forced,
169+ } : {
170+ schema ?: string
171+ name : string
172+ rls_enabled ?: boolean
173+ rls_forced ?: boolean
174+ } ) => {
175+ let alter = `ALTER table "${ schema } "."${ name } "`
176+ let enableRls = ''
177+ if ( rls_enabled !== undefined ) {
178+ let enable = `${ alter } ENABLE ROW LEVEL SECURITY;`
179+ let disable = `${ alter } DISABLE ROW LEVEL SECURITY;`
180+ enableRls = rls_enabled ? enable : disable
181+ }
182+ let forceRls = ''
183+ if ( rls_forced !== undefined ) {
184+ let enable = `${ alter } FORCE ROW LEVEL SECURITY;`
185+ let disable = `${ alter } NO FORCE ROW LEVEL SECURITY;`
186+ forceRls = rls_forced ? enable : disable
187+ }
188+ return `
189+ ${ enableRls }
190+ ${ forceRls }
191+ ` . trim ( )
160192}
161- const dropTableSqlize = ( schema : string , name : string , cascade : boolean ) => {
162- return `DROP TABLE "${ schema } "."${ name } " ${ cascade ? 'CASCADE' : 'RESTRICT' } `
193+ const dropTableSql = ( schema : string , name : string , cascade : boolean ) => {
194+ return `DROP TABLE "${ schema } "."${ name } " ${ cascade ? 'CASCADE' : 'RESTRICT' } ;` . trim ( )
163195}
164196const removeSystemSchemas = ( data : Tables . Table [ ] ) => {
165197 return data . filter ( ( x ) => ! DEFAULT_SYSTEM_SCHEMAS . includes ( x . schema ) )
0 commit comments