Skip to content

fix: AnalyticsQuerySchema cube field separation of concerns#626

Merged
hotlong merged 3 commits into
mainfrom
copilot/evaluate-functionality-compliance
Feb 11, 2026
Merged

fix: AnalyticsQuerySchema cube field separation of concerns#626
hotlong merged 3 commits into
mainfrom
copilot/evaluate-functionality-compliance

Conversation

Copilot AI commented Feb 11, 2026

Copy link
Copy Markdown
Contributor

AnalyticsQuerySchema.cube was required, causing 8 test failures. The cube targeting belongs at the API request wrapper level, not inside the query definition itself.

Changes

  • data/analytics.zod.ts: Made cube optional in AnalyticsQuerySchema — the query defines what to analyze (measures, dimensions, filters), not which cube
  • api/analytics.zod.ts: Added required cube field to AnalyticsQueryRequestSchema and added missing AnalyticsQueryRequest type export
// Before: cube required inside query (wrong layer)
AnalyticsQuerySchema.parse({ measures: ['orders.count'] }); // ❌ throws

// After: cube optional in query, required at API request level
AnalyticsQuerySchema.parse({ measures: ['orders.count'] }); // ✅
AnalyticsQueryRequestSchema.parse({
  query: { measures: ['total_revenue'] },
  cube: 'orders',  // cube lives here now
}); // ✅

All 184 test files (4860 tests) pass.


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

@vercel

vercel Bot commented Feb 11, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
objectstack-play Ready Ready Preview, Comment Feb 11, 2026 8:58pm
spec Ready Ready Preview, Comment Feb 11, 2026 8:58pm

Request Review

Copilot AI and others added 2 commits February 11, 2026 17:24
Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
… wrapper

The AnalyticsQuerySchema had cube as required, but it should be optional
at the query level since the cube context can be provided externally
(e.g., at the API request wrapper level).

- Made cube optional in AnalyticsQuerySchema (data layer)
- Added cube as required field in AnalyticsQueryRequestSchema (API layer)
- Added missing AnalyticsQueryRequest type export
- All 184 test files (4860 tests) pass

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Assess existing features against @objectstack/spec fix: AnalyticsQuerySchema cube field separation of concerns Feb 11, 2026
Copilot AI requested a review from hotlong February 11, 2026 17:31
@hotlong
hotlong marked this pull request as ready for review February 11, 2026 17:32
Copilot AI review requested due to automatic review settings February 11, 2026 17:32
@hotlong
hotlong merged commit 3c2a8fb into main Feb 11, 2026
3 of 5 checks passed

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR updates the analytics protocol schema to separate “what to query” (query definition) from “which cube to target” (API request wrapper), addressing test failures caused by cube being required in the wrong layer.

Changes:

  • Made cube optional in AnalyticsQuerySchema (data-level query definition).
  • Added required top-level cube to AnalyticsQueryRequestSchema and exported the missing AnalyticsQueryRequest type.
  • Updated pnpm-lock.yaml (includes removal/pruning of various workspace/importer and transitive dependency entries).

Reviewed changes

Copilot reviewed 2 out of 3 changed files in this pull request and generated 4 comments.

File Description
pnpm-lock.yaml Regenerated lockfile; removes/prunes workspace importer entries and older transitive toolchain versions.
packages/spec/src/data/analytics.zod.ts Makes AnalyticsQuerySchema.cube optional with updated description.
packages/spec/src/api/analytics.zod.ts Requires cube at the API request wrapper level and exports AnalyticsQueryRequest type.
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported
Comments suppressed due to low confidence (1)

pnpm-lock.yaml:335

  • This lockfile diff contains substantial unrelated churn (e.g. importer removal for example workspaces and pruning of older transitive toolchain versions). If this isn’t intentional, it will increase merge conflicts and makes the PR harder to review. Consider splitting lockfile cleanup into a separate PR/commit or describing why the lockfile regeneration is required for the analytics schema change.

Comment on lines 133 to +136
* The request format for the Analytics API.
*/
export const AnalyticsQuerySchema = z.object({
cube: z.string().describe('Target cube name'),
cube: z.string().optional().describe('Target cube name (optional when provided externally, e.g. in API request wrapper)'),

Copilot AI Feb 11, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Making AnalyticsQuerySchema.cube optional changes the exported AnalyticsQuery type to cube?: string, but downstream code treats cube as required (e.g. analytics services use it to look up the cube). Consider introducing a separate schema/type for the API-level “query definition” (no cube) and keep the service/engine AnalyticsQuery requiring cube, or update all consumers/contracts accordingly so type-checking under strict doesn’t break.

Copilot uses AI. Check for mistakes.
*/
export const AnalyticsQuerySchema = z.object({
cube: z.string().describe('Target cube name'),
cube: z.string().optional().describe('Target cube name (optional when provided externally, e.g. in API request wrapper)'),

Copilot AI Feb 11, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cube is a machine identifier and CubeSchema.name already enforces snake_case via regex. To keep validation consistent, consider applying the same regex to AnalyticsQuerySchema.cube (and other request-level cube fields) instead of accepting any string.

Suggested change
cube: z.string().optional().describe('Target cube name (optional when provided externally, e.g. in API request wrapper)'),
cube: z.string().regex(/^[a-z_][a-z0-9_]*$/).optional().describe('Target cube name (optional when provided externally, e.g. in API request wrapper)'),

Copilot uses AI. Check for mistakes.
export const AnalyticsQueryRequestSchema = z.object({
query: AnalyticsQuerySchema.describe('The analytic query definition'),
cube: z.string().describe('Target cube name'),
format: z.enum(['json', 'csv', 'xlsx']).default('json').describe('Response format'),

Copilot AI Feb 11, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

AnalyticsQueryRequestSchema now requires a top-level cube, but the nested query schema still permits query.cube. That allows conflicting values and weakens the intended separation of concerns. Consider using a query schema that omits/disallows cube (or adding a refinement that rejects requests when both cube fields are present).

Suggested change
format: z.enum(['json', 'csv', 'xlsx']).default('json').describe('Response format'),
format: z.enum(['json', 'csv', 'xlsx']).default('json').describe('Response format'),
}).superRefine((value, ctx) => {
const queryCube = (value.query as any)?.cube;
if (queryCube !== undefined) {
ctx.addIssue({
code: z.ZodIssueCode.custom,
path: ['query', 'cube'],
message: 'query.cube is not allowed when a top-level cube is provided. Remove cube from query and use the top-level cube instead.',
});
}

Copilot uses AI. Check for mistakes.
Comment on lines +33 to 34
cube: z.string().describe('Target cube name'),
format: z.enum(['json', 'csv', 'xlsx']).default('json').describe('Response format'),

Copilot AI Feb 11, 2026

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For consistency with CubeSchema.name (snake_case constraint), consider validating AnalyticsQueryRequestSchema.cube with the same regex instead of z.string() so invalid cube names are rejected at the API boundary.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants