mirror of
https://github.com/Kaelio/ktx.git
synced 2026-06-10 08:05:14 +02:00
fix(status): report query history readiness
This commit is contained in:
parent
bc23b1a447
commit
f78c49509f
3 changed files with 83 additions and 45 deletions
|
|
@ -266,7 +266,7 @@ describe('runKtxDoctor', () => {
|
|||
expect(testIo.stdout()).toContain('PASS Connections: 1 configured');
|
||||
});
|
||||
|
||||
it('includes Postgres historic-SQL readiness in project doctor output', async () => {
|
||||
it('includes Postgres query-history readiness in project doctor output', async () => {
|
||||
await writeFile(
|
||||
join(tempDir, 'ktx.yaml'),
|
||||
[
|
||||
|
|
@ -276,9 +276,9 @@ describe('runKtxDoctor', () => {
|
|||
' driver: postgres',
|
||||
' url: env:WAREHOUSE_DATABASE_URL',
|
||||
' readonly: true',
|
||||
' historicSql:',
|
||||
' enabled: true',
|
||||
' dialect: postgres',
|
||||
' context:',
|
||||
' queryHistory:',
|
||||
' enabled: true',
|
||||
'ingest:',
|
||||
' adapters:',
|
||||
' - live-database',
|
||||
|
|
@ -290,8 +290,8 @@ describe('runKtxDoctor', () => {
|
|||
const testIo = makeIo();
|
||||
const runHistoricSqlDoctorChecks = vi.fn(async () => [
|
||||
{
|
||||
id: 'historic-sql-postgres-warehouse',
|
||||
label: 'Postgres Historic SQL (warehouse)',
|
||||
id: 'query-history-postgres-warehouse',
|
||||
label: 'Postgres query history (warehouse)',
|
||||
status: 'pass' as const,
|
||||
detail:
|
||||
'pg_stat_statements ready (PostgreSQL 16.4); info: pg_stat_statements.max is 1000; set it to at least 5000 to reduce query-template eviction churn',
|
||||
|
|
@ -312,7 +312,7 @@ describe('runKtxDoctor', () => {
|
|||
).resolves.toBe(0);
|
||||
|
||||
expect(runHistoricSqlDoctorChecks).toHaveBeenCalledTimes(1);
|
||||
expect(testIo.stdout()).toContain('PASS Postgres Historic SQL (warehouse): pg_stat_statements ready');
|
||||
expect(testIo.stdout()).toContain('PASS Postgres query history (warehouse): pg_stat_statements ready');
|
||||
expect(testIo.stdout()).toContain('info: pg_stat_statements.max is 1000');
|
||||
expect(testIo.stdout()).not.toContain('Fix: Update the Postgres parameter group or config');
|
||||
});
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ function projectWithConnections(connections: Record<string, KtxProjectConnection
|
|||
}
|
||||
|
||||
describe('runPostgresHistoricSqlDoctorChecks', () => {
|
||||
it('passes when no Postgres historic-SQL connections are enabled', async () => {
|
||||
it('passes when no Postgres query-history connections are enabled', async () => {
|
||||
const checks = await runPostgresHistoricSqlDoctorChecks(
|
||||
projectWithConnections({
|
||||
warehouse: { driver: 'sqlite', path: './warehouse.db', readonly: true },
|
||||
|
|
@ -34,10 +34,10 @@ describe('runPostgresHistoricSqlDoctorChecks', () => {
|
|||
|
||||
expect(checks).toEqual([
|
||||
{
|
||||
id: 'historic-sql-postgres',
|
||||
label: 'Postgres Historic SQL',
|
||||
id: 'query-history-postgres',
|
||||
label: 'Postgres query history',
|
||||
status: 'pass',
|
||||
detail: 'No enabled Postgres historic-SQL connections',
|
||||
detail: 'No enabled Postgres query-history connections',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
|
@ -54,7 +54,7 @@ describe('runPostgresHistoricSqlDoctorChecks', () => {
|
|||
driver: 'postgres',
|
||||
url: 'env:WAREHOUSE_DATABASE_URL',
|
||||
readonly: true,
|
||||
historicSql: { enabled: true, dialect: 'postgres' },
|
||||
context: { queryHistory: { enabled: true } },
|
||||
},
|
||||
}),
|
||||
{ postgresHistoricSqlProbe: probe },
|
||||
|
|
@ -67,14 +67,14 @@ describe('runPostgresHistoricSqlDoctorChecks', () => {
|
|||
driver: 'postgres',
|
||||
url: 'env:WAREHOUSE_DATABASE_URL',
|
||||
readonly: true,
|
||||
historicSql: { enabled: true, dialect: 'postgres' },
|
||||
context: { queryHistory: { enabled: true } },
|
||||
},
|
||||
env: process.env,
|
||||
});
|
||||
expect(checks).toEqual([
|
||||
{
|
||||
id: 'historic-sql-postgres-warehouse',
|
||||
label: 'Postgres Historic SQL (warehouse)',
|
||||
id: 'query-history-postgres-warehouse',
|
||||
label: 'Postgres query history (warehouse)',
|
||||
status: 'pass',
|
||||
detail: 'pg_stat_statements ready (PostgreSQL 16.4)',
|
||||
},
|
||||
|
|
@ -88,7 +88,7 @@ describe('runPostgresHistoricSqlDoctorChecks', () => {
|
|||
driver: 'postgres',
|
||||
url: 'env:WAREHOUSE_DATABASE_URL',
|
||||
readonly: true,
|
||||
historicSql: { enabled: true, dialect: 'postgres' },
|
||||
context: { queryHistory: { enabled: true } },
|
||||
},
|
||||
}),
|
||||
{
|
||||
|
|
@ -104,8 +104,8 @@ describe('runPostgresHistoricSqlDoctorChecks', () => {
|
|||
|
||||
expect(checks).toEqual([
|
||||
{
|
||||
id: 'historic-sql-postgres-warehouse',
|
||||
label: 'Postgres Historic SQL (warehouse)',
|
||||
id: 'query-history-postgres-warehouse',
|
||||
label: 'Postgres query history (warehouse)',
|
||||
status: 'pass',
|
||||
detail:
|
||||
'pg_stat_statements ready (PostgreSQL 16.4); info: pg_stat_statements.max is 1000; set it to at least 5000 to reduce query-template eviction churn',
|
||||
|
|
@ -120,7 +120,7 @@ describe('runPostgresHistoricSqlDoctorChecks', () => {
|
|||
driver: 'postgres',
|
||||
url: 'env:WAREHOUSE_DATABASE_URL',
|
||||
readonly: true,
|
||||
historicSql: { enabled: true, dialect: 'postgres' },
|
||||
context: { queryHistory: { enabled: true } },
|
||||
},
|
||||
}),
|
||||
{
|
||||
|
|
@ -138,8 +138,8 @@ describe('runPostgresHistoricSqlDoctorChecks', () => {
|
|||
|
||||
expect(checks).toEqual([
|
||||
{
|
||||
id: 'historic-sql-postgres-warehouse',
|
||||
label: 'Postgres Historic SQL (warehouse)',
|
||||
id: 'query-history-postgres-warehouse',
|
||||
label: 'Postgres query history (warehouse)',
|
||||
status: 'warn',
|
||||
detail:
|
||||
'pg_stat_statements ready (PostgreSQL 16.4) with warnings: pg_stat_statements.track is none; set it to top or all in the Postgres parameter group or config; info: pg_stat_statements.max is 1000; set it to at least 5000 to reduce query-template eviction churn',
|
||||
|
|
@ -148,14 +148,42 @@ describe('runPostgresHistoricSqlDoctorChecks', () => {
|
|||
]);
|
||||
});
|
||||
|
||||
it('fails when a connection has postgres historic SQL but is not a Postgres driver', async () => {
|
||||
it('still checks legacy historicSql blocks before setup migration', async () => {
|
||||
const probe = vi.fn<PostgresHistoricSqlDoctorProbe>(async () => ({
|
||||
pgServerVersion: 'PostgreSQL 16.4',
|
||||
warnings: [],
|
||||
}));
|
||||
|
||||
const checks = await runPostgresHistoricSqlDoctorChecks(
|
||||
projectWithConnections({
|
||||
warehouse: {
|
||||
driver: 'postgres',
|
||||
url: 'env:WAREHOUSE_DATABASE_URL',
|
||||
readonly: true,
|
||||
historicSql: { enabled: true, dialect: 'postgres' },
|
||||
},
|
||||
}),
|
||||
{ postgresHistoricSqlProbe: probe },
|
||||
);
|
||||
|
||||
expect(checks).toEqual([
|
||||
{
|
||||
id: 'query-history-postgres-warehouse',
|
||||
label: 'Postgres query history (warehouse)',
|
||||
status: 'pass',
|
||||
detail: 'pg_stat_statements ready (PostgreSQL 16.4)',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it('fails when a connection has postgres query history but is not a Postgres driver', async () => {
|
||||
const checks = await runPostgresHistoricSqlDoctorChecks(
|
||||
projectWithConnections({
|
||||
warehouse: {
|
||||
driver: 'mysql',
|
||||
url: 'env:WAREHOUSE_DATABASE_URL',
|
||||
readonly: true,
|
||||
historicSql: { enabled: true, dialect: 'postgres' },
|
||||
context: { queryHistory: { enabled: true } },
|
||||
},
|
||||
}),
|
||||
{
|
||||
|
|
@ -165,11 +193,11 @@ describe('runPostgresHistoricSqlDoctorChecks', () => {
|
|||
|
||||
expect(checks).toEqual([
|
||||
{
|
||||
id: 'historic-sql-postgres-warehouse',
|
||||
label: 'Postgres Historic SQL (warehouse)',
|
||||
id: 'query-history-postgres-warehouse',
|
||||
label: 'Postgres query history (warehouse)',
|
||||
status: 'fail',
|
||||
detail: 'connections.warehouse.historicSql.dialect is postgres but driver is mysql',
|
||||
fix: 'Set connections.warehouse.driver to postgres or disable historicSql for this connection',
|
||||
detail: 'connections.warehouse.context.queryHistory is enabled but driver is mysql',
|
||||
fix: 'Set connections.warehouse.driver to postgres or disable query history for this connection',
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
|
@ -181,7 +209,7 @@ describe('runPostgresHistoricSqlDoctorChecks', () => {
|
|||
driver: 'postgres',
|
||||
url: 'env:WAREHOUSE_DATABASE_URL',
|
||||
readonly: true,
|
||||
historicSql: { enabled: true, dialect: 'postgres' },
|
||||
context: { queryHistory: { enabled: true } },
|
||||
},
|
||||
}),
|
||||
{
|
||||
|
|
@ -197,8 +225,8 @@ describe('runPostgresHistoricSqlDoctorChecks', () => {
|
|||
|
||||
expect(checks).toEqual([
|
||||
{
|
||||
id: 'historic-sql-postgres-warehouse',
|
||||
label: 'Postgres Historic SQL (warehouse)',
|
||||
id: 'query-history-postgres-warehouse',
|
||||
label: 'Postgres query history (warehouse)',
|
||||
status: 'fail',
|
||||
detail: 'pg_stat_statements extension is not installed in the connection database.',
|
||||
fix: 'Run CREATE EXTENSION pg_stat_statements; against the connection database.',
|
||||
|
|
|
|||
|
|
@ -32,16 +32,26 @@ function check(status: DoctorCheck['status'], id: string, label: string, detail:
|
|||
return fix ? { id, label, status, detail, fix } : { id, label, status, detail };
|
||||
}
|
||||
|
||||
function historicSqlRecord(connection: KtxProjectConnectionConfig): Record<string, unknown> | null {
|
||||
const historicSql = connection.historicSql;
|
||||
return historicSql && typeof historicSql === 'object' && !Array.isArray(historicSql)
|
||||
? (historicSql as Record<string, unknown>)
|
||||
: null;
|
||||
function recordValue(value: unknown): Record<string, unknown> | null {
|
||||
return value && typeof value === 'object' && !Array.isArray(value) ? (value as Record<string, unknown>) : null;
|
||||
}
|
||||
|
||||
function isEnabledPostgresHistoricSql(connection: KtxProjectConnectionConfig): boolean {
|
||||
const historicSql = historicSqlRecord(connection);
|
||||
return historicSql?.enabled === true && historicSql.dialect === 'postgres';
|
||||
function queryHistoryRecord(connection: KtxProjectConnectionConfig): Record<string, unknown> | null {
|
||||
const context = recordValue(connection.context);
|
||||
return recordValue(context?.queryHistory);
|
||||
}
|
||||
|
||||
function legacyHistoricSqlRecord(connection: KtxProjectConnectionConfig): Record<string, unknown> | null {
|
||||
return recordValue(connection.historicSql);
|
||||
}
|
||||
|
||||
function isEnabledPostgresQueryHistory(connection: KtxProjectConnectionConfig): boolean {
|
||||
const queryHistory = queryHistoryRecord(connection);
|
||||
if (queryHistory) {
|
||||
return queryHistory.enabled === true;
|
||||
}
|
||||
const legacy = legacyHistoricSqlRecord(connection);
|
||||
return legacy?.enabled === true && legacy.dialect === 'postgres';
|
||||
}
|
||||
|
||||
function isPostgresDriver(connection: KtxProjectConnectionConfig): boolean {
|
||||
|
|
@ -50,7 +60,7 @@ function isPostgresDriver(connection: KtxProjectConnectionConfig): boolean {
|
|||
}
|
||||
|
||||
function checkId(connectionId: string): string {
|
||||
return `historic-sql-postgres-${connectionId.replace(/[^a-z0-9_-]+/gi, '-')}`;
|
||||
return `query-history-postgres-${connectionId.replace(/[^a-z0-9_-]+/gi, '-')}`;
|
||||
}
|
||||
|
||||
function capabilityFailureFix(error: unknown, connectionId: string, projectDir: string): string {
|
||||
|
|
@ -61,7 +71,7 @@ function capabilityFailureFix(error: unknown, connectionId: string, projectDir:
|
|||
return String(error.remediation);
|
||||
}
|
||||
if (error instanceof Error && error.name === 'HistoricSqlVersionUnsupportedError') {
|
||||
return 'Use PostgreSQL 14 or newer, or disable historicSql for this connection';
|
||||
return 'Use PostgreSQL 14 or newer, or disable query history for this connection';
|
||||
}
|
||||
return `Fix connections.${connectionId} Postgres settings, then rerun \`ktx status --project-dir ${projectDir}\``;
|
||||
}
|
||||
|
|
@ -107,12 +117,12 @@ export async function runPostgresHistoricSqlDoctorChecks(
|
|||
deps: HistoricSqlDoctorDeps = {},
|
||||
): Promise<DoctorCheck[]> {
|
||||
const targets = Object.entries(project.config.connections)
|
||||
.filter(([, connection]) => isEnabledPostgresHistoricSql(connection))
|
||||
.filter(([, connection]) => isEnabledPostgresQueryHistory(connection))
|
||||
.sort(([left], [right]) => left.localeCompare(right));
|
||||
|
||||
if (targets.length === 0) {
|
||||
return [
|
||||
check('pass', 'historic-sql-postgres', 'Postgres Historic SQL', 'No enabled Postgres historic-SQL connections'),
|
||||
check('pass', 'query-history-postgres', 'Postgres query history', 'No enabled Postgres query-history connections'),
|
||||
];
|
||||
}
|
||||
|
||||
|
|
@ -120,15 +130,15 @@ export async function runPostgresHistoricSqlDoctorChecks(
|
|||
const env = deps.env ?? process.env;
|
||||
const checks: DoctorCheck[] = [];
|
||||
for (const [connectionId, connection] of targets) {
|
||||
const label = `Postgres Historic SQL (${connectionId})`;
|
||||
const label = `Postgres query history (${connectionId})`;
|
||||
if (!isPostgresDriver(connection)) {
|
||||
checks.push(
|
||||
check(
|
||||
'fail',
|
||||
checkId(connectionId),
|
||||
label,
|
||||
`connections.${connectionId}.historicSql.dialect is postgres but driver is ${String(connection.driver)}`,
|
||||
`Set connections.${connectionId}.driver to postgres or disable historicSql for this connection`,
|
||||
`connections.${connectionId}.context.queryHistory is enabled but driver is ${String(connection.driver)}`,
|
||||
`Set connections.${connectionId}.driver to postgres or disable query history for this connection`,
|
||||
),
|
||||
);
|
||||
continue;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue