From d00e226731694a7bd34000b55a412218ecf7b6ee Mon Sep 17 00:00:00 2001 From: Eric Black Date: Fri, 5 Apr 2024 14:17:54 -0700 Subject: [PATCH 1/2] Convert log min duration statement to oclif --- .../pg/settings/log-min-duration-statement.ts | 34 ++++++++++++ packages/cli/src/lib/pg/setter.ts | 2 + .../log-min-duration-statement.unit.test.ts | 53 +++++++++++++++++++ .../settings/log_min_duration_statement.js | 28 ---------- packages/pg-v5/index.js | 1 - .../commands/settings/settings.unit.test.js | 24 +++++++++ 6 files changed, 113 insertions(+), 29 deletions(-) create mode 100644 packages/cli/src/commands/pg/settings/log-min-duration-statement.ts create mode 100644 packages/cli/test/unit/commands/pg/settings/log-min-duration-statement.unit.test.ts delete mode 100644 packages/pg-v5/commands/settings/log_min_duration_statement.js 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 new file mode 100644 index 0000000000..3cbb4fcf94 --- /dev/null +++ b/packages/cli/src/commands/pg/settings/log-min-duration-statement.ts @@ -0,0 +1,34 @@ +import {Args} from '@oclif/core' +import heredoc from 'tsheredoc' +import {PGSettingsCommand, type Setting, type SettingKey} from '../../../lib/pg/setter' + +export default class LogMinDurationStatement extends PGSettingsCommand { + static description = heredoc(` + The duration of each completed statement will be logged if the statement completes after the time specified by VALUE. + VALUE needs to specified as a whole number, in milliseconds. + Setting log_min_duration_statement to zero prints all statement durations and -1 will disable logging statement durations. + `) + + static args = { + database: Args.string(), + value: Args.integer(), + } + + protected settingKey:SettingKey = 'log_min_duration_statement' + + protected convertValue(val: number): number { + return val + } + + protected explain(setting: Setting) { + if (setting.value === -1) { + return 'The duration of each completed statement will not be logged.' + } + + if (setting.value === 0) { + return 'The duration of each completed statement will be logged.' + } + + return `The duration of each completed statement will be logged if the statement ran for at least ${setting.value} milliseconds.` + } +} diff --git a/packages/cli/src/lib/pg/setter.ts b/packages/cli/src/lib/pg/setter.ts index ecfd57a001..5917212e48 100644 --- a/packages/cli/src/lib/pg/setter.ts +++ b/packages/cli/src/lib/pg/setter.ts @@ -10,6 +10,8 @@ export abstract class PGSettingsCommand extends Command { protected abstract convertValue(val: string): unknown protected abstract explain(setting: Setting): string + static topic = 'pg' + static flags = { app: flags.app({required: true}), remote: flags.remote(), diff --git a/packages/cli/test/unit/commands/pg/settings/log-min-duration-statement.unit.test.ts b/packages/cli/test/unit/commands/pg/settings/log-min-duration-statement.unit.test.ts new file mode 100644 index 0000000000..adb1d25f93 --- /dev/null +++ b/packages/cli/test/unit/commands/pg/settings/log-min-duration-statement.unit.test.ts @@ -0,0 +1,53 @@ +import {expect} from '@oclif/test' +import * as nock from 'nock' +import {stdout} from 'stdout-stderr' +import heredoc from 'tsheredoc' +import runCommand from '../../../../helpers/runCommand' +import Cmd from '../../../../../src/commands/pg/settings/log-min-duration-statement' +import * as fixtures from '../../../../fixtures/addons/fixtures' + +describe('pg:settings:log-min-duration-statement', () => { + const addon = fixtures.addons['dwh-db'] + + beforeEach(() => { + nock('https://api.heroku.com') + .post('/actions/addons/resolve', { + app: 'myapp', + addon: 'test-database', + }).reply(200, [addon]) + }) + + afterEach(() => { + nock.cleanAll() + }) + + it('shows settings for auto_explain with value', async () => { + nock('https://api.data.heroku.com') + .get(`/postgres/v0/databases/${addon.id}/config`).reply(200, {log_min_duration_statement: {value: 'test_value'}}) + await runCommand(Cmd, ['--app', 'myapp', 'test-database']) + expect(stdout.output).to.equal(heredoc(` + log-min-duration-statement is set to test_value for ${addon.name}. + The duration of each completed statement will be logged if the statement ran for at least test_value milliseconds. + `)) + }) + + it('shows settings for auto_explain with no value', async () => { + nock('https://api.data.heroku.com') + .get(`/postgres/v0/databases/${addon.id}/config`).reply(200, {log_min_duration_statement: {value: -1}}) + await runCommand(Cmd, ['--app', 'myapp', 'test-database']) + expect(stdout.output).to.equal(heredoc(` + log-min-duration-statement is set to -1 for ${addon.name}. + The duration of each completed statement will not be logged. + `)) + }) + + it('shows settings for auto_explain with no value', async () => { + nock('https://api.data.heroku.com') + .get(`/postgres/v0/databases/${addon.id}/config`).reply(200, {log_min_duration_statement: {value: 0}}) + await runCommand(Cmd, ['--app', 'myapp', 'test-database']) + expect(stdout.output).to.equal(heredoc(` + log-min-duration-statement is set to 0 for ${addon.name}. + The duration of each completed statement will be logged. + `)) + }) +}) diff --git a/packages/pg-v5/commands/settings/log_min_duration_statement.js b/packages/pg-v5/commands/settings/log_min_duration_statement.js deleted file mode 100644 index 6836677603..0000000000 --- a/packages/pg-v5/commands/settings/log_min_duration_statement.js +++ /dev/null @@ -1,28 +0,0 @@ -'use strict' - -const cli = require('heroku-cli-util') -const settings = require('../../lib/setter') - -function explain(setting) { - if (setting.value === -1) { - return 'The duration of each completed statement will not be logged.' - } - - if (setting.value === 0) { - return 'The duration of each completed statement will be logged.' - } - - return `The duration of each completed statement will be logged if the statement ran for at least ${setting.value} milliseconds.` -} - -module.exports = { - topic: 'pg', - command: 'settings:log-min-duration-statement', - description: `The duration of each completed statement will be logged if the statement completes after the time specified by VALUE. -VALUE needs to specified as a whole number, in milliseconds.`, - help: 'Setting log_min_duration_statement to zero prints all statement durations and -1 will disable logging statement durations.', - needsApp: true, - needsAuth: true, - args: [{name: 'value', optional: true}, {name: 'database', optional: true}], - run: cli.command({preauth: true}, settings.generate('log_min_duration_statement', settings.numeric, explain)), -} diff --git a/packages/pg-v5/index.js b/packages/pg-v5/index.js index 4127404ed7..629f4903eb 100644 --- a/packages/pg-v5/index.js +++ b/packages/pg-v5/index.js @@ -29,7 +29,6 @@ exports.commands = flatten([ require('./commands/settings/auto_explain_log_nested_statements'), require('./commands/settings/auto_explain_log_triggers'), require('./commands/settings/log_lock_waits'), - require('./commands/settings/log_min_duration_statement'), require('./commands/settings/log_statement'), require('./commands/settings/track_functions'), require('./commands/unfollow'), diff --git a/packages/pg-v5/test/unit/commands/settings/settings.unit.test.js b/packages/pg-v5/test/unit/commands/settings/settings.unit.test.js index e59d89b469..d2a2d82aa0 100644 --- a/packages/pg-v5/test/unit/commands/settings/settings.unit.test.js +++ b/packages/pg-v5/test/unit/commands/settings/settings.unit.test.js @@ -96,6 +96,30 @@ describe('pg:settings', () => { .then(() => expect(cli.stdout).to.equal(`${settingsResultName} is set to ${settingResult.value} for postgres-1.\n${settingResult.values[settingResult.value]}\n`)) }) + it('shows settings for auto_explain_log_analyze with value', () => { + setupSettingsMockData('auto_explain.log_analyze') + cmd = proxyquire('../../../../commands/settings/auto_explain_log_analyze', { + settings: proxyquire.noCallThru().load('../../../../lib/setter', { + './fetcher': fetcher, + }), + }) + pg.get('/postgres/v0/databases/1/config').reply(200, settingsResult) + return cmd.run({args: {database: 'test-database', value: ''}, flags: {}}) + .then(() => expect(cli.stdout).to.equal('auto-explain.log-analyze is set to test_value for postgres-1.\nEXPLAIN ANALYZE execution plans will be logged.\n')) + }) + + it('shows settings for auto_explain_log_analyze with no value', () => { + setupSettingsMockData('auto_explain.log_analyze', '') + cmd = proxyquire('../../../../commands/settings/auto_explain_log_analyze', { + settings: proxyquire.noCallThru().load('../../../../lib/setter', { + './fetcher': fetcher, + }), + }) + pg.get('/postgres/v0/databases/1/config').reply(200, settingsResult) + return cmd.run({args: {database: 'test-database', value: ''}, flags: {}}) + .then(() => expect(cli.stdout).to.equal('auto-explain.log-analyze is set to for postgres-1.\nEXPLAIN ANALYZE execution plans will not be logged.\n')) + }) + it('shows settings for log_min_duration_statement with value', () => { setupSettingsMockData('log_min_duration_statement') cmd = proxyquire('../../../../commands/settings/log_min_duration_statement', { From e9a21055ba28a1cec15a9ab11ead57aed31fa8db Mon Sep 17 00:00:00 2001 From: Justin Wilaby Date: Mon, 8 Apr 2024 15:41:18 -0700 Subject: [PATCH 2/2] Update import paths for types --- .../pg/settings/log-min-duration-statement.ts | 9 +-- .../commands/settings/settings.unit.test.js | 60 ------------------- 2 files changed, 5 insertions(+), 64 deletions(-) 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 3cbb4fcf94..89bb3e1a2f 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 @@ -1,6 +1,7 @@ import {Args} from '@oclif/core' import heredoc from 'tsheredoc' -import {PGSettingsCommand, type Setting, type SettingKey} from '../../../lib/pg/setter' +import {PGSettingsCommand} from '../../../lib/pg/setter' +import type {Setting, SettingKey} from '../../../lib/pg/types' export default class LogMinDurationStatement extends PGSettingsCommand { static description = heredoc(` @@ -16,11 +17,11 @@ export default class LogMinDurationStatement extends PGSettingsCommand { protected settingKey:SettingKey = 'log_min_duration_statement' - protected convertValue(val: number): number { - return val + protected convertValue(val: unknown): number { + return val as number } - protected explain(setting: Setting) { + protected explain(setting: Setting) { if (setting.value === -1) { return 'The duration of each completed statement will not be logged.' } diff --git a/packages/pg-v5/test/unit/commands/settings/settings.unit.test.js b/packages/pg-v5/test/unit/commands/settings/settings.unit.test.js index d2a2d82aa0..66af46ae42 100644 --- a/packages/pg-v5/test/unit/commands/settings/settings.unit.test.js +++ b/packages/pg-v5/test/unit/commands/settings/settings.unit.test.js @@ -96,66 +96,6 @@ describe('pg:settings', () => { .then(() => expect(cli.stdout).to.equal(`${settingsResultName} is set to ${settingResult.value} for postgres-1.\n${settingResult.values[settingResult.value]}\n`)) }) - it('shows settings for auto_explain_log_analyze with value', () => { - setupSettingsMockData('auto_explain.log_analyze') - cmd = proxyquire('../../../../commands/settings/auto_explain_log_analyze', { - settings: proxyquire.noCallThru().load('../../../../lib/setter', { - './fetcher': fetcher, - }), - }) - pg.get('/postgres/v0/databases/1/config').reply(200, settingsResult) - return cmd.run({args: {database: 'test-database', value: ''}, flags: {}}) - .then(() => expect(cli.stdout).to.equal('auto-explain.log-analyze is set to test_value for postgres-1.\nEXPLAIN ANALYZE execution plans will be logged.\n')) - }) - - it('shows settings for auto_explain_log_analyze with no value', () => { - setupSettingsMockData('auto_explain.log_analyze', '') - cmd = proxyquire('../../../../commands/settings/auto_explain_log_analyze', { - settings: proxyquire.noCallThru().load('../../../../lib/setter', { - './fetcher': fetcher, - }), - }) - pg.get('/postgres/v0/databases/1/config').reply(200, settingsResult) - return cmd.run({args: {database: 'test-database', value: ''}, flags: {}}) - .then(() => expect(cli.stdout).to.equal('auto-explain.log-analyze is set to for postgres-1.\nEXPLAIN ANALYZE execution plans will not be logged.\n')) - }) - - it('shows settings for log_min_duration_statement with value', () => { - setupSettingsMockData('log_min_duration_statement') - cmd = proxyquire('../../../../commands/settings/log_min_duration_statement', { - settings: proxyquire.noCallThru().load('../../../../lib/setter', { - './fetcher': fetcher, - }), - }) - pg.get('/postgres/v0/databases/1/config').reply(200, settingsResult) - return cmd.run({args: {database: 'test-database', value: ''}, flags: {}}) - .then(() => expect(cli.stdout).to.equal('log-min-duration-statement is set to test_value for postgres-1.\nThe duration of each completed statement will be logged if the statement ran for at least test_value milliseconds.\n')) - }) - - it('shows settings for log_min_duration_statement with no value', () => { - setupSettingsMockData('log_min_duration_statement', -1) - cmd = proxyquire('../../../../commands/settings/log_min_duration_statement', { - settings: proxyquire.noCallThru().load('../../../../lib/setter', { - './fetcher': fetcher, - }), - }) - pg.get('/postgres/v0/databases/1/config').reply(200, settingsResult) - return cmd.run({args: {database: 'test-database', value: ''}, flags: {}}) - .then(() => expect(cli.stdout).to.equal('log-min-duration-statement is set to -1 for postgres-1.\nThe duration of each completed statement will not be logged.\n')) - }) - - it('shows settings for log_min_duration_statement with value set to 0', () => { - setupSettingsMockData('log_min_duration_statement', 0) - cmd = proxyquire('../../../../commands/settings/log_min_duration_statement', { - settings: proxyquire.noCallThru().load('../../../../lib/setter', { - './fetcher': fetcher, - }), - }) - pg.get('/postgres/v0/databases/1/config').reply(200, settingsResult) - return cmd.run({args: {database: 'test-database', value: ''}, flags: {}}) - .then(() => expect(cli.stdout).to.equal('log-min-duration-statement is set to 0 for postgres-1.\nThe duration of each completed statement will be logged.\n')) - }) - it('shows settings for auto_explain_log_nested_statements with value', () => { setupSettingsMockData('auto_explain.log_nested_statements') cmd = proxyquire('../../../../commands/settings/auto_explain_log_nested_statements', {