diff --git a/migrations/base/02-post-setup.sql b/migrations/base/02-post-setup.sql deleted file mode 100644 index ddd1c267..00000000 --- a/migrations/base/02-post-setup.sql +++ /dev/null @@ -1,12 +0,0 @@ -ALTER ROLE postgres SET search_path TO "\$user",public,extensions; -CREATE OR REPLACE FUNCTION extensions.notify_api_restart() -RETURNS event_trigger -LANGUAGE plpgsql -AS $$ -BEGIN - NOTIFY pgrst, 'reload schema'; -END; -$$; -CREATE EVENT TRIGGER api_restart ON ddl_command_end -EXECUTE PROCEDURE extensions.notify_api_restart(); -COMMENT ON FUNCTION extensions.notify_api_restart IS 'Sends a notification to the API to restart. If your database schema has changed, this is required so that Supabase can rebuild the relationships.'; diff --git a/src/database/connection.ts b/src/database/connection.ts index 20070219..9a447c3c 100644 --- a/src/database/connection.ts +++ b/src/database/connection.ts @@ -35,7 +35,7 @@ export class TenantConnection { public readonly role: string protected constructor( - public readonly pool: Knex, + protected readonly pool: Knex, protected readonly options: TenantConnectionOptions ) { this.role = options.user.payload.role || 'anon' @@ -56,7 +56,7 @@ export class TenantConnection { let knexPool = connections.get(connectionString) if (knexPool) { - return new this(await knexPool, options) + return new this(knexPool, options) } const isExternalPool = Boolean(options.isExternalPool) @@ -67,7 +67,6 @@ export class TenantConnection { pool: { min: 0, max: isExternalPool ? 1 : options.maxConnections || databaseMaxConnections, - propagateCreateError: false, acquireTimeoutMillis: databaseConnectionTimeout, idleTimeoutMillis: isExternalPool ? 100 : databaseFreePoolAfterInactivity, reapIntervalMillis: isExternalPool ? 110 : undefined, @@ -115,15 +114,19 @@ export class TenantConnection { } } - transaction(instance?: Knex): Knex.TransactionProvider { - return async () => { - const pool = instance || this.pool - const tnx = await pool.transaction() + async transaction(instance?: Knex) { + const pool = instance || this.pool + const tnx = await pool.transaction() - if (!instance) { - await tnx.raw(`set search_path to ${searchPath.join(', ')}`) - } - return tnx + if (!instance && this.options.isExternalPool) { + await tnx.raw(`SELECT set_config('search_path', ?, true)`, [searchPath.join(', ')]) + } + return tnx + } + + transactionProvider(instance?: Knex): Knex.TransactionProvider { + return async () => { + return this.transaction(instance) } } diff --git a/src/storage/database/knex.ts b/src/storage/database/knex.ts index 5403de8a..b17b9e94 100644 --- a/src/storage/database/knex.ts +++ b/src/storage/database/knex.ts @@ -39,7 +39,7 @@ export class StorageKnexDB implements Database { transactionOptions?: TransactionOptions ) { try { - const tnx = await this.connection.transaction(this.options.tnx)() + const tnx = await this.connection.transactionProvider(this.options.tnx)() try { await this.connection.setScope(tnx) @@ -546,7 +546,7 @@ export class StorageKnexDB implements Database { const needsNewTransaction = !tnx || differentScopes if (!tnx || needsNewTransaction) { - tnx = await this.connection.transaction(this.options.tnx)() + tnx = await this.connection.transactionProvider(this.options.tnx)() tnx.on('query-error', (error: DatabaseError) => { throw DBError.fromDBError(error) }) diff --git a/src/test/object.test.ts b/src/test/object.test.ts index 579c3327..602db570 100644 --- a/src/test/object.test.ts +++ b/src/test/object.test.ts @@ -12,11 +12,13 @@ import { StorageBackendError } from '../storage' import { useMockObject, useMockQueue } from './common' import { getPostgresConnection } from '../database' import { getServiceKeyUser } from '../database/tenant' +import { Knex } from 'knex' dotenv.config({ path: '.env.test' }) const { anonKey, jwtSecret, serviceKey, tenantId } = getConfig() +let tnx: Knex.Transaction | undefined async function getSuperuserPostgrestClient() { const superUser = await getServiceKeyUser(tenantId) @@ -26,14 +28,19 @@ async function getSuperuserPostgrestClient() { tenantId, host: 'localhost', }) - const tnx = await conn.pool - + tnx = await conn.transaction() return tnx } useMockObject() useMockQueue() +afterEach(async () => { + if (tnx) { + await tnx.commit() + } +}) + /* * GET /object/:id */ diff --git a/src/test/rls.test.ts b/src/test/rls.test.ts index 8c698bf3..7bb22025 100644 --- a/src/test/rls.test.ts +++ b/src/test/rls.test.ts @@ -127,7 +127,7 @@ describe('RLS policies', () => { afterAll(async () => { await db.destroy() - await (storage.db as StorageKnexDB).connection.pool.destroy() + await (storage.db as StorageKnexDB).connection.dispose() }) testSpec.tests.forEach((_test, index) => { diff --git a/src/test/webhooks.test.ts b/src/test/webhooks.test.ts index bda4276a..f90b45d6 100644 --- a/src/test/webhooks.test.ts +++ b/src/test/webhooks.test.ts @@ -294,7 +294,7 @@ describe('Webhooks', () => { async function createObject(pg: TenantConnection, bucketId: string) { const objectName = Date.now() - const tnx = pg.pool + const tnx = await pg.transaction() const [data] = await tnx .from('objects') @@ -316,5 +316,7 @@ async function createObject(pg: TenantConnection, bucketId: string) { ]) .returning('*') + await tnx.commit() + return data as Obj }