Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/commands/metrics/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import {
printResult,
withErrorHandling,
} from '../../lib/utils/api-helper.js';
import { parseMetricId } from '../../lib/utils/validators.js';
import { parseMetricId, parseDatasourceId } from '../../lib/utils/validators.js';
import type { MetricId } from '../../lib/api/branded-types.js';
import { summarizeMetricRow } from '../../api-client/entity-summary.js';
import { createListCommand } from '../../lib/utils/list-command.js';
Expand Down Expand Up @@ -173,6 +173,11 @@ function addMetricFieldOptions(cmd: Command): Command {
)
.option('--custom-sql <sql>', 'custom SQL (required for custom_sql type)')
.option('--custom-statistics-type <type>', 'custom statistics type (continuous, binomial)')
.option(
'--datasource-id <id>',
'datasource ID the custom SQL runs against (custom_sql)',
parseDatasourceId
)
.option('--vr-lookback-interval <interval>', 'VR lookback interval (1w, 2w, 3w, 4w)')
.option('--relation-kind <kind>', 'goal relation kind (refund, replacement)')
.option('--relation-refund-operation <op>', 'refund operation (add, subtract)')
Expand Down Expand Up @@ -264,6 +269,7 @@ async function resolveMetricFieldsFromOptions(
activityInterval: options.activityInterval as string | undefined,
customSql: options.customSql as string | undefined,
customStatisticsType: options.customStatisticsType as string | undefined,
datasourceId: options.datasourceId as number | undefined,
vrLookbackInterval: options.vrLookbackInterval as string | undefined,
relationKind: options.relationKind as string | undefined,
relationRefundOperation: options.relationRefundOperation as string | undefined,
Expand Down
115 changes: 115 additions & 0 deletions src/commands/metrics/metrics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -388,6 +388,86 @@ describe('metrics command', () => {
);
});

it('should create a custom_sql metric pinned to a datasource via --datasource-id', async () => {
await metricsCommand.parseAsync([
'node',
'test',
'create',
'--name',
'BQ conversions',
'--type',
'custom_sql',
'--description',
'BigQuery conversions',
'--custom-sql',
'SELECT 1',
'--custom-statistics-type',
'binomial',
'--datasource-id',
'10',
]);

expect(mockClient.createMetric).toHaveBeenCalledWith(
expect.objectContaining({
type: 'custom_sql',
custom_sql: 'SELECT 1',
datasource_id: 10,
})
);
});

it('should use the last --datasource-id when the flag is repeated, not a radix-confused value', async () => {
await metricsCommand.parseAsync([
'node',
'test',
'create',
'--name',
'BQ conversions',
'--type',
'custom_sql',
'--description',
'BigQuery conversions',
'--custom-sql',
'SELECT 1',
'--custom-statistics-type',
'binomial',
'--datasource-id',
'16',
'--datasource-id',
'10',
]);

expect(mockClient.createMetric).toHaveBeenCalledWith(
expect.objectContaining({
datasource_id: 10,
})
);
});

it('should reject a --datasource-id with trailing non-numeric characters', async () => {
await expect(
metricsCommand.parseAsync([
'node',
'test',
'create',
'--name',
'BQ conversions',
'--type',
'custom_sql',
'--description',
'BigQuery conversions',
'--custom-sql',
'SELECT 1',
'--custom-statistics-type',
'binomial',
'--datasource-id',
'10x',
])
).rejects.toThrow();

expect(mockClient.createMetric).not.toHaveBeenCalled();
});

it('should create a goal_ratio metric with numerator and denominator types', async () => {
await metricsCommand.parseAsync([
'node',
Expand Down Expand Up @@ -807,6 +887,41 @@ describe('metrics command', () => {
expect(mockClient.activateMetric).not.toHaveBeenCalled();
});

it('should pass --datasource-id through to the version payload', async () => {
await metricsCommand.parseAsync([
'node',
'test',
'version',
'1',
'--reason',
'pin to bigquery',
'--datasource-id',
'10',
]);

expect(mockClient.createMetricVersion).toHaveBeenCalledWith(
1,
{ datasource_id: 10 },
'pin to bigquery'
);
});

it('should omit datasource_id from the version payload when --datasource-id is not passed', async () => {
await metricsCommand.parseAsync([
'node',
'test',
'version',
'1',
'--reason',
'rename',
'--name',
'x',
]);

const payload = mockClient.createMetricVersion.mock.calls[0]![1] as Record<string, unknown>;
expect(payload).not.toHaveProperty('datasource_id');
});

it('should support `new-version` alias', async () => {
await metricsCommand.parseAsync([
'node',
Expand Down
2 changes: 2 additions & 0 deletions src/core/metrics/payload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ export interface MetricFields {
activityInterval?: string | undefined;
customSql?: string | undefined;
customStatisticsType?: string | undefined;
datasourceId?: number | undefined;
vrLookbackInterval?: string | undefined;
relationKind?: string | undefined;
relationRefundOperation?: string | undefined;
Expand Down Expand Up @@ -81,6 +82,7 @@ export function buildMetricPayload(fields: MetricFields): Record<string, unknown
set('activity_interval', fields.activityInterval);
set('custom_sql', fields.customSql);
set('custom_statistics_type', fields.customStatisticsType);
set('datasource_id', fields.datasourceId);
set('vr_lookback_interval', fields.vrLookbackInterval);
set('relation_kind', fields.relationKind);
set('relation_refund_operation', fields.relationRefundOperation);
Expand Down
Loading