mirror of https://github.com/buster-so/buster.git
Add metric data retrieval endpoint and update schemas
- Introduced a new endpoint to retrieve metric data with pagination at /metric_files/:id/data. - Added MetricDataParamsSchema and MetricDataQuerySchema for request validation. - Updated GetMetricDataRequestSchema to include an optional limit parameter for pagination.
This commit is contained in:
parent
cf8610eda4
commit
3c8f1f4615
|
@ -0,0 +1,78 @@
|
|||
import { type AssetPermissionCheck, checkPermission } from '@buster/access-controls';
|
||||
import type { User } from '@buster/database';
|
||||
import { getUserOrganizationId } from '@buster/database';
|
||||
import type { MetricDataResponse } from '@buster/server-shared/metrics';
|
||||
import { HTTPException } from 'hono/http-exception';
|
||||
|
||||
/**
|
||||
* Handler for retrieving metric data
|
||||
*
|
||||
* This handler:
|
||||
* 1. Validates user has access to the organization
|
||||
* 2. Checks user has permission to view the metric file
|
||||
* 3. Retrieves the metric definition
|
||||
* 4. Parses the metric content to extract SQL
|
||||
* 5. Executes the query against the data source
|
||||
* 6. Returns the data with metadata and pagination info
|
||||
*
|
||||
* @param metricId - The ID of the metric to retrieve data for
|
||||
* @param limit - Maximum number of rows to return (default 5000, max 5000)
|
||||
* @param user - The authenticated user
|
||||
* @returns The metric data with metadata
|
||||
*/
|
||||
export async function getMetricDataHandler(
|
||||
metricId: string,
|
||||
limit: number = 5000,
|
||||
user: User
|
||||
): Promise<MetricDataResponse> {
|
||||
// Get user's organization
|
||||
const userOrg = await getUserOrganizationId(user.id);
|
||||
|
||||
if (!userOrg) {
|
||||
throw new HTTPException(403, {
|
||||
message: 'You must be part of an organization to access metric data',
|
||||
});
|
||||
}
|
||||
|
||||
const { organizationId } = userOrg;
|
||||
|
||||
// Check if user has permission to view this metric file
|
||||
const permissionCheck: AssetPermissionCheck = {
|
||||
userId: user.id,
|
||||
assetId: metricId,
|
||||
assetType: 'metric_file',
|
||||
requiredRole: 'can_view',
|
||||
organizationId,
|
||||
};
|
||||
|
||||
const permissionResult = await checkPermission(permissionCheck);
|
||||
|
||||
if (!permissionResult.hasAccess) {
|
||||
throw new HTTPException(403, {
|
||||
message: 'You do not have permission to view this metric',
|
||||
});
|
||||
}
|
||||
|
||||
// Ensure limit is within bounds
|
||||
const queryLimit = Math.min(Math.max(limit, 1), 5000);
|
||||
|
||||
// TODO: Implement the following steps in subsequent tickets:
|
||||
// 1. Retrieve metric definition from database
|
||||
// 2. Parse metric content (YAML/JSON) to extract SQL query
|
||||
// 3. Get data source connection details
|
||||
// 4. Execute query using appropriate data source adapter
|
||||
// 5. Process results and build metadata
|
||||
// 6. Check if there are more records beyond the limit
|
||||
|
||||
// Placeholder response for now
|
||||
return {
|
||||
data: [],
|
||||
data_metadata: {
|
||||
column_count: 0,
|
||||
column_metadata: [],
|
||||
row_count: 0,
|
||||
},
|
||||
metricId,
|
||||
has_more_records: false,
|
||||
};
|
||||
}
|
|
@ -1,15 +1,36 @@
|
|||
import { MetricDownloadParamsSchema } from '@buster/server-shared/metrics';
|
||||
import {
|
||||
MetricDataParamsSchema,
|
||||
MetricDataQuerySchema,
|
||||
MetricDownloadParamsSchema,
|
||||
} from '@buster/server-shared/metrics';
|
||||
import { zValidator } from '@hono/zod-validator';
|
||||
import { Hono } from 'hono';
|
||||
import { HTTPException } from 'hono/http-exception';
|
||||
import { requireAuth } from '../../../middleware/auth';
|
||||
import '../../../types/hono.types';
|
||||
import { downloadMetricFileHandler } from './download-metric-file';
|
||||
import { getMetricDataHandler } from './get-metric-data';
|
||||
|
||||
const app = new Hono()
|
||||
// Apply authentication middleware to all routes
|
||||
.use('*', requireAuth)
|
||||
|
||||
// GET /metric_files/:id/data - Get metric data with pagination
|
||||
.get(
|
||||
'/:id/data',
|
||||
zValidator('param', MetricDataParamsSchema),
|
||||
zValidator('query', MetricDataQuerySchema),
|
||||
async (c) => {
|
||||
const { id } = c.req.valid('param');
|
||||
const { limit } = c.req.valid('query');
|
||||
const user = c.get('busterUser');
|
||||
|
||||
const response = await getMetricDataHandler(id, limit, user);
|
||||
|
||||
return c.json(response);
|
||||
}
|
||||
)
|
||||
|
||||
// GET /metric_files/:id/download - Download metric file data as CSV
|
||||
.get('/:id/download', zValidator('param', MetricDownloadParamsSchema), async (c) => {
|
||||
const { id } = c.req.valid('param');
|
||||
|
|
|
@ -8,7 +8,9 @@ export const GetMetricRequestSchema = z.object({
|
|||
version_number: z.number().optional(), //api will default to latest if not provided
|
||||
});
|
||||
|
||||
export const GetMetricDataRequestSchema = GetMetricRequestSchema;
|
||||
export const GetMetricDataRequestSchema = GetMetricRequestSchema.extend({
|
||||
limit: z.number().min(1).max(5000).default(5000).optional(),
|
||||
});
|
||||
|
||||
export const GetMetricListRequestSchema = z.object({
|
||||
/** The token representing the current page number for pagination */
|
||||
|
|
|
@ -39,3 +39,21 @@ export type ShareMetricResponse = z.infer<typeof ShareMetricResponseSchema>;
|
|||
export type ShareDeleteResponse = z.infer<typeof ShareDeleteResponseSchema>;
|
||||
export type ShareUpdateResponse = z.infer<typeof ShareUpdateResponseSchema>;
|
||||
export type MetricDataResponse = z.infer<typeof MetricDataResponseSchema>;
|
||||
|
||||
/**
|
||||
* Path parameters for metric data endpoint
|
||||
*/
|
||||
export const MetricDataParamsSchema = z.object({
|
||||
id: z.string().uuid('Metric ID must be a valid UUID'),
|
||||
});
|
||||
|
||||
export type MetricDataParams = z.infer<typeof MetricDataParamsSchema>;
|
||||
|
||||
/**
|
||||
* Query parameters for metric data endpoint
|
||||
*/
|
||||
export const MetricDataQuerySchema = z.object({
|
||||
limit: z.coerce.number().min(1).max(5000).default(5000).optional(),
|
||||
});
|
||||
|
||||
export type MetricDataQuery = z.infer<typeof MetricDataQuerySchema>;
|
||||
|
|
Loading…
Reference in New Issue