Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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
52 changes: 52 additions & 0 deletions docs/pages/product/data-modeling/reference/dimensions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,58 @@ cubes:

</CodeTabs>

### `order`

The `order` parameter specifies the default sort order for a dimension. Valid
values are `asc` (ascending) and `desc` (descending). This parameter is optional.

When set, the dimension's default sort order is exposed via
[APIs and integrations][ref-apis]. Consuming applications, such as BI tools
and custom frontends, can use this metadata to apply consistent default sorting
when displaying dimension values, ensuring a uniform user experience across
different tools connected to the semantic layer.

<CodeTabs>

```javascript
cube(`orders`, {
// ...

dimensions: {
status: {
sql: `status`,
type: `string`,
order: `asc`
},

created_at: {
sql: `created_at`,
type: `time`,
order: `desc`
}
}
})
```

```yaml
cubes:
- name: orders
# ...

dimensions:
- name: status
sql: status
type: string
order: asc

- name: created_at
sql: created_at
type: time
order: desc
```

</CodeTabs>

### `primary_key`

Specify if a dimension is a primary key for a cube. The default value is
Expand Down
7 changes: 7 additions & 0 deletions packages/cubejs-api-gateway/openspec.yml
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,13 @@ components:
type: "object"
format:
$ref: "#/components/schemas/V1CubeMetaFormat"
order:
$ref: "#/components/schemas/V1CubeMetaDimensionOrder"
V1CubeMetaDimensionOrder:
type: "string"
enum:
- "asc"
- "desc"
V1CubeMetaMeasure:
type: "object"
required:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ export type DimensionDefinition = {
fieldType?: string;
multiStage?: boolean;
shiftInterval?: string;
order?: 'asc' | 'desc';
};

export type TimeShiftDefinition = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export type CubeSymbolDefinition = {
granularities?: Record<string, GranularityDefinition>;
timeShift?: TimeshiftDefinition[];
format?: string;
order?: 'asc' | 'desc';
};

export type HierarchyDefinition = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ export type DimensionConfig = {
primaryKey: boolean;
aliasMember?: string;
granularities?: GranularityDefinition[];
order?: 'asc' | 'desc';
};

export type SegmentConfig = {
Expand Down Expand Up @@ -274,6 +275,7 @@ export class CubeToMetaTransformer implements CompilerInterface {
origin: gDef.origin,
}))
: undefined,
order: extendedDimDef.order,
};
}),
segments: Object.entries(extendedCube.segments || {}).map((nameToSegment: [string, any]) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -278,6 +278,7 @@ const BaseDimensionWithoutSubQuery = {
otherwise: formatSchema
}),
meta: Joi.any(),
order: Joi.string().valid('asc', 'desc'),
values: Joi.when('type', {
is: 'switch',
then: Joi.array().items(Joi.string()),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ Object {
"key": "Meta.key for CubeA.id",
},
"name": "simple_view.id",
"order": undefined,
"primaryKey": false,
"public": true,
"shortTitle": "Title for CubeA.id",
Expand All @@ -32,6 +33,7 @@ Object {
"key": "Meta.key for CubeB.other_id",
},
"name": "simple_view.other_id",
"order": undefined,
"primaryKey": false,
"public": true,
"shortTitle": "Title for CubeB.other_id",
Expand Down Expand Up @@ -114,6 +116,7 @@ Object {
"key": "Meta.key for CubeB.other_id",
},
"name": "simple_view.CubeB_other_id",
"order": undefined,
"primaryKey": false,
"public": true,
"shortTitle": "Title for CubeB.other_id",
Expand Down Expand Up @@ -196,6 +199,7 @@ Object {
"key": "Meta.key for CubeA.id",
},
"name": "simple_view.CubeA_id",
"order": undefined,
"primaryKey": false,
"public": true,
"shortTitle": "Title for CubeA.id",
Expand All @@ -213,6 +217,7 @@ Object {
"key": "Meta.key for CubeB.id",
},
"name": "simple_view.CubeB_id",
"order": undefined,
"primaryKey": false,
"public": true,
"shortTitle": "Title for CubeB.id",
Expand All @@ -230,6 +235,7 @@ Object {
"key": "Meta.key for CubeB.other_id",
},
"name": "simple_view.CubeB_other_id",
"order": undefined,
"primaryKey": false,
"public": true,
"shortTitle": "Title for CubeB.other_id",
Expand Down Expand Up @@ -312,6 +318,7 @@ Object {
"key": "Meta.key for CubeB.other_id",
},
"name": "simple_view.CubeB_other_id",
"order": undefined,
"primaryKey": false,
"public": true,
"shortTitle": "Title for CubeB.other_id",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1675,5 +1675,68 @@ describe('Cube Validation', () => {
const validationResult = cubeValidator.validate(cube, new ConsoleErrorReporter());
expect(validationResult.error).toBeTruthy();
});

it('dimension with valid order asc - correct', async () => {
const cubeValidator = new CubeValidator(new CubeSymbols());
const cube = {
name: 'name',
sql: () => 'SELECT * FROM public.Orders',
dimensions: {
status: {
sql: () => 'status',
type: 'string',
order: 'asc'
},
},
fileName: 'fileName',
};

const validationResult = cubeValidator.validate(cube, new ConsoleErrorReporter());
expect(validationResult.error).toBeFalsy();
});

it('dimension with valid order desc - correct', async () => {
const cubeValidator = new CubeValidator(new CubeSymbols());
const cube = {
name: 'name',
sql: () => 'SELECT * FROM public.Orders',
dimensions: {
createdAt: {
sql: () => 'created_at',
type: 'time',
order: 'desc'
},
},
fileName: 'fileName',
};

const validationResult = cubeValidator.validate(cube, new ConsoleErrorReporter());
expect(validationResult.error).toBeFalsy();
});

it('dimension with invalid order value - error', async () => {
const cubeValidator = new CubeValidator(new CubeSymbols());
const cube = {
name: 'name',
sql: () => 'SELECT * FROM public.Orders',
dimensions: {
status: {
sql: () => 'status',
type: 'string',
order: 'invalid' // should only accept 'asc' or 'desc'
},
},
fileName: 'fileName',
};

const validationResult = cubeValidator.validate(cube, {
error: (message: any, _e: any) => {
console.log(message);
expect(message).toContain('order');
}
} as any);

expect(validationResult.error).toBeTruthy();
});
});
});
2 changes: 2 additions & 0 deletions rust/cubesql/cubeclient/src/models/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,9 @@ pub use self::v1_cube_meta_custom_time_format::Type as V1CubeMetaCustomTimeForma
pub mod v1_cube_meta_dimension;
pub use self::v1_cube_meta_dimension::V1CubeMetaDimension;
pub mod v1_cube_meta_dimension_granularity;
pub mod v1_cube_meta_dimension_order;
pub use self::v1_cube_meta_dimension_granularity::V1CubeMetaDimensionGranularity;
pub use self::v1_cube_meta_dimension_order::V1CubeMetaDimensionOrder;
pub mod v1_cube_meta_folder;
pub use self::v1_cube_meta_folder::V1CubeMetaFolder;
pub mod v1_cube_meta_format;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ pub struct V1CubeMetaDimension {
pub meta: Option<serde_json::Value>,
#[serde(rename = "format", skip_serializing_if = "Option::is_none")]
pub format: Option<Box<models::V1CubeMetaFormat>>,
#[serde(rename = "order", skip_serializing_if = "Option::is_none")]
pub order: Option<models::V1CubeMetaDimensionOrder>,
}

impl V1CubeMetaDimension {
Expand All @@ -46,6 +48,7 @@ impl V1CubeMetaDimension {
granularities: None,
meta: None,
format: None,
order: None,
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/*
* Cube.js
*
* Cube.js Swagger Schema
*
* The version of the OpenAPI document: 1.0.0
*
* Generated by: https://openapi-generator.tech
*/

use serde::{Deserialize, Serialize};

/// Default sort order for a dimension
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Hash, Serialize, Deserialize)]
pub enum V1CubeMetaDimensionOrder {
#[serde(rename = "asc")]
Asc,
#[serde(rename = "desc")]
Desc,
}

impl Default for V1CubeMetaDimensionOrder {
fn default() -> V1CubeMetaDimensionOrder {
Self::Asc
}
}
Loading