diff --git a/.changeset/swift-clocks-cry.md b/.changeset/swift-clocks-cry.md new file mode 100644 index 0000000000..8f37a2e340 --- /dev/null +++ b/.changeset/swift-clocks-cry.md @@ -0,0 +1,5 @@ +--- +'@backstage/backend-common': patch +--- + +Add knexConfig config section diff --git a/packages/backend-common/config.d.ts b/packages/backend-common/config.d.ts index bdc7740c13..fe3c7a5bec 100644 --- a/packages/backend-common/config.d.ts +++ b/packages/backend-common/config.d.ts @@ -96,6 +96,12 @@ export interface Config { * @default database */ pluginDivisionMode?: 'database' | 'schema'; + /** + * Arbitrary config object to pass to knex when initializing + * (https://knexjs.org/#Installation-client). Most notable is the debug + * and asyncStackTraces booleans + */ + knexConfig?: object; /** Plugin specific database configuration and client override */ plugin?: { [pluginId: string]: { @@ -111,6 +117,14 @@ export interface Config { * Defaults to base config if unspecified. */ ensureExists?: boolean; + /** + * Arbitrary config object to pass to knex when initializing + * (https://knexjs.org/#Installation-client). Most notable is the + * debug and asyncStackTraces booleans. + * + * This is merged recursively into the base knexConfig + */ + knexConfig?: object; }; }; }; diff --git a/packages/backend-common/src/database/DatabaseManager.test.ts b/packages/backend-common/src/database/DatabaseManager.test.ts index f2fe855234..1d2ff58b41 100644 --- a/packages/backend-common/src/database/DatabaseManager.test.ts +++ b/packages/backend-common/src/database/DatabaseManager.test.ts @@ -505,5 +505,42 @@ describe('DatabaseManager', () => { 'database_name_overriden', ); }); + + it('fetches and merges additional knex config', async () => { + const testManager = DatabaseManager.fromConfig( + new ConfigReader({ + backend: { + database: { + client: 'pg', + connection: { + host: 'localhost', + database: 'foodb', + }, + knexConfig: { + something: false, + }, + plugin: { + testdbname: { + knexConfig: { + debug: true, + }, + }, + }, + }, + }, + }), + ); + await testManager.forPlugin('testdbname').getClient(); + + const mockCalls = mocked(createDatabaseClient).mock.calls.splice(-1); + const [baseConfig] = mockCalls[0]; + + expect(baseConfig.data).toEqual( + expect.objectContaining({ + debug: true, + something: false, + }), + ); + }); }); }); diff --git a/packages/backend-common/src/database/DatabaseManager.ts b/packages/backend-common/src/database/DatabaseManager.ts index cf5e801d66..a3f31e98f2 100644 --- a/packages/backend-common/src/database/DatabaseManager.ts +++ b/packages/backend-common/src/database/DatabaseManager.ts @@ -14,20 +14,20 @@ * limitations under the License. */ -import { Knex } from 'knex'; -import { omit } from 'lodash'; import { Config, ConfigReader } from '@backstage/config'; import { JsonObject } from '@backstage/types'; +import { Knex } from 'knex'; +import { merge, omit } from 'lodash'; +import { mergeDatabaseConfig } from './config'; import { - createNameOverride, - ensureDatabaseExists, - normalizeConnection, - createSchemaOverride, - ensureSchemaExists, createDatabaseClient, + createNameOverride, + createSchemaOverride, + ensureDatabaseExists, + ensureSchemaExists, + normalizeConnection, } from './connection'; import { PluginDatabaseManager } from './types'; -import { mergeDatabaseConfig } from './config'; /** * Provides a config lookup path for a plugin's config block. @@ -138,6 +138,24 @@ export class DatabaseManager { }; } + /** + * Provides the knexConfig which should be used for a given plugin. + * + * @param pluginId Plugin to get the knexConfig for + * @returns the merged kexConfig value or undefined if it isn't specified + */ + private getAdditionalKnexConfig(pluginId: string): JsonObject | undefined { + const pluginConfig = this.config + .getOptionalConfig(`${pluginPath(pluginId)}.knexConfig`) + ?.get(); + + const baseConfig = this.config + .getOptionalConfig('knexConfig') + ?.get(); + + return merge(baseConfig, pluginConfig); + } + private getEnsureExistsConfig(pluginId: string): boolean { const baseConfig = this.config.getOptionalBoolean('ensureExists') ?? true; return ( @@ -200,6 +218,7 @@ export class DatabaseManager { const { client } = this.getClientType(pluginId); return { + ...this.getAdditionalKnexConfig(pluginId), client, connection: this.getConnectionConfig(pluginId), };