diff --git a/packages/cli/src/commands/pg/settings/auto-explain.ts b/packages/cli/src/commands/pg/settings/auto-explain.ts index 6f5270d504..6100e4bc39 100644 --- a/packages/cli/src/commands/pg/settings/auto-explain.ts +++ b/packages/cli/src/commands/pg/settings/auto-explain.ts @@ -19,14 +19,14 @@ export default class AutoExplain extends PGSettingsCommand { } static args = { - database: Args.string(), - value: Args.string(), + database: Args.string({optional: true}), + value: Args.string({optional: true}), } static strict = false protected settingKey: SettingKey = 'auto_explain' - + protected invariant = this.booleanInvariant protected convertValue(val: BooleanAsString): boolean { return booleanConverter(val) } diff --git a/packages/cli/src/commands/pg/settings/auto-explain/log-analyze.ts b/packages/cli/src/commands/pg/settings/auto-explain/log-analyze.ts index debd1fcd37..c5e3fa39d8 100644 --- a/packages/cli/src/commands/pg/settings/auto-explain/log-analyze.ts +++ b/packages/cli/src/commands/pg/settings/auto-explain/log-analyze.ts @@ -13,12 +13,12 @@ export default class LogAnalyze extends PGSettingsCommand { `) static args = { - database: Args.string(), - value: Args.string(), + database: Args.string({optional: true}), + value: Args.string({optional: true}), } protected settingKey = 'auto_explain.log_analyze' as SettingKey - + protected invariant = this.booleanInvariant protected convertValue(val: BooleanAsString): boolean { return booleanConverter(val) } diff --git a/packages/cli/src/commands/pg/settings/auto-explain/log-buffers.ts b/packages/cli/src/commands/pg/settings/auto-explain/log-buffers.ts index e5f27a57c7..ce539a8995 100644 --- a/packages/cli/src/commands/pg/settings/auto-explain/log-buffers.ts +++ b/packages/cli/src/commands/pg/settings/auto-explain/log-buffers.ts @@ -11,12 +11,12 @@ export default class LogBuffersWaits extends PGSettingsCommand { `) static args = { - database: Args.string(), - value: Args.string(), + database: Args.string({optional: true}), + value: Args.string({optional: true}), } protected settingKey: SettingKey = 'auto_explain.log_buffers' - + protected invariant = this.booleanInvariant protected convertValue(val: BooleanAsString): boolean { return booleanConverter(val) } diff --git a/packages/cli/src/commands/pg/settings/auto-explain/log-min-duration.ts b/packages/cli/src/commands/pg/settings/auto-explain/log-min-duration.ts index 00d19bbab5..b109cc5806 100644 --- a/packages/cli/src/commands/pg/settings/auto-explain/log-min-duration.ts +++ b/packages/cli/src/commands/pg/settings/auto-explain/log-min-duration.ts @@ -11,12 +11,12 @@ export default class LogMinDuration extends PGSettingsCommand { `) static args = { - database: Args.string(), - value: Args.string(), + database: Args.string({optional: true}), + value: Args.string({optional: true}), } protected settingKey: SettingKey = 'auto_explain.log_min_duration' - + protected invariant = this.numberInvariant protected convertValue(val: string): number { return numericConverter(val) } diff --git a/packages/cli/src/commands/pg/settings/auto-explain/log-nested-statements.ts b/packages/cli/src/commands/pg/settings/auto-explain/log-nested-statements.ts index 8248095958..2b2f84cc84 100644 --- a/packages/cli/src/commands/pg/settings/auto-explain/log-nested-statements.ts +++ b/packages/cli/src/commands/pg/settings/auto-explain/log-nested-statements.ts @@ -6,12 +6,12 @@ export default class LogNestedStatements extends PGSettingsCommand { static description = "Nested statements are included in the execution plan's log." static args = { - database: Args.string(), - value: Args.string(), + database: Args.string({optional: true}), + value: Args.string({optional: true}), } protected settingKey: SettingKey = 'auto_explain.log_nested_statements' - + protected invariant = this.booleanInvariant protected convertValue(val: unknown): boolean { return booleanConverter(val as BooleanAsString) } diff --git a/packages/cli/src/commands/pg/settings/auto-explain/log-triggers.ts b/packages/cli/src/commands/pg/settings/auto-explain/log-triggers.ts index 5091468621..827661a95c 100644 --- a/packages/cli/src/commands/pg/settings/auto-explain/log-triggers.ts +++ b/packages/cli/src/commands/pg/settings/auto-explain/log-triggers.ts @@ -11,12 +11,12 @@ export default class LogTriggers extends PGSettingsCommand { `) static args = { - database: Args.string(), - value: Args.string(), + database: Args.string({optional: true}), + value: Args.string({optional: true}), } protected settingKey = 'auto_explain.log_triggers' as SettingKey - + protected invariant = this.booleanInvariant protected convertValue(val: BooleanAsString): boolean { return booleanConverter(val) } diff --git a/packages/cli/src/commands/pg/settings/auto-explain/log-verbose.ts b/packages/cli/src/commands/pg/settings/auto-explain/log-verbose.ts index e1eceb5ba9..8adbfdd7ef 100644 --- a/packages/cli/src/commands/pg/settings/auto-explain/log-verbose.ts +++ b/packages/cli/src/commands/pg/settings/auto-explain/log-verbose.ts @@ -16,8 +16,8 @@ export default class AutoExplainLogVerbose extends PGSettingsCommand { } static args = { - database: Args.string(), - value: Args.string(), + database: Args.string({optional: true}), + value: Args.string({optional: true}), } protected settingKey: SettingKey = 'auto_explain.log_verbose' @@ -30,6 +30,7 @@ export default class AutoExplainLogVerbose extends PGSettingsCommand { return 'Verbose execution plan logging has been disabled for auto_explain.' } + protected invariant = this.booleanInvariant protected convertValue(val: unknown): boolean { return booleanConverter(val as BooleanAsString) } diff --git a/packages/cli/src/commands/pg/settings/index.ts b/packages/cli/src/commands/pg/settings/index.ts index 15fdfbbdcb..362296a6e9 100644 --- a/packages/cli/src/commands/pg/settings/index.ts +++ b/packages/cli/src/commands/pg/settings/index.ts @@ -14,7 +14,7 @@ export default class Index extends Command { } static args = { - database: Args.string(), + database: Args.string({optional: true}), } public async run(): Promise { diff --git a/packages/cli/src/commands/pg/settings/log-connections.ts b/packages/cli/src/commands/pg/settings/log-connections.ts index 639275dd4e..b6ae7b962e 100644 --- a/packages/cli/src/commands/pg/settings/log-connections.ts +++ b/packages/cli/src/commands/pg/settings/log-connections.ts @@ -16,12 +16,12 @@ export default class LogConnections extends PGSettingsCommand { } static args = { - database: Args.string(), - value: Args.string(), + database: Args.string({optional: true}), + value: Args.string({optional: true}), } protected settingKey: SettingKey = 'log_connections' - + protected invariant = this.booleanInvariant protected convertValue(val: unknown): unknown { return booleanConverter(val as BooleanAsString) } diff --git a/packages/cli/src/commands/pg/settings/log-lock-waits.ts b/packages/cli/src/commands/pg/settings/log-lock-waits.ts index 4eac063a75..777598a82e 100644 --- a/packages/cli/src/commands/pg/settings/log-lock-waits.ts +++ b/packages/cli/src/commands/pg/settings/log-lock-waits.ts @@ -12,12 +12,12 @@ export default class LogLockWaits extends PGSettingsCommand { `) static args = { - database: Args.string(), - value: Args.string(), + database: Args.string({optional: true}), + value: Args.string({optional: true}), } protected settingKey: SettingKey = 'log_lock_waits' - + protected invariant = this.booleanInvariant protected convertValue(val: unknown): boolean { return booleanConverter(val as BooleanAsString) } diff --git a/packages/cli/src/commands/pg/settings/log-min-duration-statement.ts b/packages/cli/src/commands/pg/settings/log-min-duration-statement.ts index b320fcb3c3..ceac8c991c 100644 --- a/packages/cli/src/commands/pg/settings/log-min-duration-statement.ts +++ b/packages/cli/src/commands/pg/settings/log-min-duration-statement.ts @@ -11,12 +11,12 @@ export default class LogMinDurationStatement extends PGSettingsCommand { `) static args = { - database: Args.string(), - value: Args.string(), + database: Args.string({optional: true}), + value: Args.string({optional: true}), } protected settingKey:SettingKey = 'log_min_duration_statement' - + protected invariant = this.numberInvariant protected convertValue(val: unknown): number { return val as number } diff --git a/packages/cli/src/commands/pg/settings/log-statement.ts b/packages/cli/src/commands/pg/settings/log-statement.ts index d3be9e5bef..3a69ac69f9 100644 --- a/packages/cli/src/commands/pg/settings/log-statement.ts +++ b/packages/cli/src/commands/pg/settings/log-statement.ts @@ -1,7 +1,9 @@ import {Args} from '@oclif/core' import heredoc from 'tsheredoc' import {type Setting, type SettingKey} from '../../../lib/pg/types' -import {PGSettingsCommand} from '../../../lib/pg/setter' +import {type ArgTypes, PGSettingsCommand} from '../../../lib/pg/setter' + +const values = new Set(['none', 'ddl', 'mod', 'all']) export default class LogStatement extends PGSettingsCommand { static description = heredoc(` log_statement controls which SQL statements are logged. @@ -13,12 +15,21 @@ export default class LogStatement extends PGSettingsCommand { `) static args = { - database: Args.string(), - value: Args.string({options: ['none', 'ddl', 'mod', 'all']}), + database: Args.string({optional: true}), + value: Args.string({optional: true}), } protected settingKey: SettingKey = 'log_statement' + protected invariant(args: ArgTypes): ArgTypes { + const {value, database} = args + if (values.has(database ?? '')) { + return {value: database, database: value} + } + + return args + } + protected convertValue(val: string): string { return val } diff --git a/packages/cli/src/commands/pg/settings/track-functions.ts b/packages/cli/src/commands/pg/settings/track-functions.ts index bd6560a678..0af4a2ee3f 100644 --- a/packages/cli/src/commands/pg/settings/track-functions.ts +++ b/packages/cli/src/commands/pg/settings/track-functions.ts @@ -1,8 +1,9 @@ import {Args} from '@oclif/core' import heredoc from 'tsheredoc' -import {PGSettingsCommand} from '../../../lib/pg/setter' +import {type ArgTypes, PGSettingsCommand} from '../../../lib/pg/setter' import type {Setting, SettingKey} from '../../../lib/pg/types' +const values = new Set(['none', 'pl', 'all']) // ref: https://www.postgresql.org/docs/current/runtime-config-statistics.html#GUC-TRACK-FUNCTIONS export default class TrackFunctions extends PGSettingsCommand { static description = heredoc(` @@ -13,12 +14,21 @@ export default class TrackFunctions extends PGSettingsCommand { all - All functions, including SQL and C language functions, are tracked. Simple SQL-language that are inlined are not tracked`) static args = { - database: Args.string(), - value: Args.string({options: ['none', 'pl', 'all']}), + database: Args.string({optional: true}), + value: Args.string({optional: true}), } protected settingKey: SettingKey = 'track_functions' + protected invariant(args: ArgTypes): ArgTypes { + const {value, database} = args + if (values.has(database ?? '')) { + return {value: database, database: value} + } + + return args + } + protected convertValue(val: unknown): unknown { return val } diff --git a/packages/cli/src/lib/pg/setter.ts b/packages/cli/src/lib/pg/setter.ts index 5917212e48..bc2c782488 100644 --- a/packages/cli/src/lib/pg/setter.ts +++ b/packages/cli/src/lib/pg/setter.ts @@ -5,6 +5,8 @@ import host from './host' import {essentialPlan} from './util' import {SettingKey, Setting, SettingsResponse} from './types' +export type ArgTypes = {value: string | undefined, database: string | undefined}; + export abstract class PGSettingsCommand extends Command { protected abstract settingKey: SettingKey protected abstract convertValue(val: string): unknown @@ -20,7 +22,7 @@ export abstract class PGSettingsCommand extends Command { public async run(): Promise { const {flags, args} = await this.parse() const {app} = flags - const {value, database} = args as {value: string | undefined, database: string | undefined} + const {value, database} = this.invariant(args as ArgTypes) const db = await addonResolver(this.heroku, app, database || 'DATABASE_URL') @@ -41,6 +43,28 @@ export abstract class PGSettingsCommand extends Command { ux.log(this.explain(setting)) } } + + protected abstract invariant(args: ArgTypes): ArgTypes + + protected booleanInvariant(args: ArgTypes): ArgTypes { + const {value, database} = args + try { + booleanConverter(database as BooleanAsString) + return {value: database, database: value} + } catch { + return args + } + } + + protected numberInvariant(args: ArgTypes): ArgTypes { + const {database, value} = args + + if (Number.isFinite(Number(database))) { + return {value: database, database: value} + } + + return args + } } export type BooleanAsString = 'on' | 'ON' | 'true' | 'TRUE' | 'off' | 'OFF' | 'false' | 'FALSE' diff --git a/packages/cli/test/unit/commands/pg/settings/track-functions.unit.test.ts b/packages/cli/test/unit/commands/pg/settings/track-functions.unit.test.ts index 8a8c85dbc3..cb9b973b4d 100644 --- a/packages/cli/test/unit/commands/pg/settings/track-functions.unit.test.ts +++ b/packages/cli/test/unit/commands/pg/settings/track-functions.unit.test.ts @@ -45,4 +45,18 @@ describe('pg:settings:track-functions', function () { No function calls will be tracked. `)) }) + + it('shows settings for track_functions with database and value arg reversed', async function () { + pg.patch('/postgres/v0/databases/1/config').reply(200, { + track_functions: { + value: 'test_value', + values: {test_value: 'No function calls will be tracked.'}, + }, + }) + await runCommand(Cmd, ['--app', 'myapp', 'pl', 'test-database']) + expect(stdout.output).to.equal(heredoc(` + track-functions has been set to test_value for postgres-1. + No function calls will be tracked. + `)) + }) })