Big News: Socket raises $60M Series C at a $1B valuation to secure software supply chains for AI-driven development.Announcement
Sign In

@bonnard/sdk

Package Overview
Dependencies
Maintainers
1
Versions
12
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@bonnard/sdk - npm Package Compare versions

Comparing version
0.2.1
to
0.3.0
+1
-4
dist/client.d.ts

@@ -8,6 +8,3 @@ /**

* Execute a JSON query against the semantic layer.
*
* Supports two modes:
* - **Short names**: provide `cube` and use unqualified field names (e.g. `"revenue"`)
* - **Fully-qualified names**: omit `cube` and use dot notation (e.g. `"orders.revenue"`)
* All field names must be fully qualified (e.g. "orders.revenue").
*/

@@ -14,0 +11,0 @@ query<T = Record<string, unknown>>(options: QueryOptions): Promise<QueryResult<T>>;

+5
-53
/**
* Bonnard SDK — Client for querying semantic layer
*/
import { buildCubeQuery, simplifyResult, isCubeNativeFormat } from './query.js';
import { toCubeQuery } from './query.js';
/**

@@ -77,58 +77,11 @@ * Parse JWT expiry from the payload (base64url-decoded middle segment).

}
/**
* Build a Cube-native query from QueryOptions that already use fully-qualified names.
*/
function buildNativeQuery(options) {
const cubeQuery = {};
if (options.measures) {
cubeQuery.measures = options.measures;
}
if (options.dimensions) {
cubeQuery.dimensions = options.dimensions;
}
if (options.filters) {
cubeQuery.filters = options.filters.map(f => ({
member: f.dimension,
operator: f.operator,
values: f.values,
}));
}
if (options.timeDimension) {
cubeQuery.timeDimensions = [{
dimension: options.timeDimension.dimension,
granularity: options.timeDimension.granularity,
dateRange: options.timeDimension.dateRange,
}];
}
if (options.orderBy) {
cubeQuery.order = Object.entries(options.orderBy).map(([key, dir]) => [key, dir]);
}
if (options.limit) {
cubeQuery.limit = options.limit;
}
return cubeQuery;
}
return {
/**
* Execute a JSON query against the semantic layer.
*
* Supports two modes:
* - **Short names**: provide `cube` and use unqualified field names (e.g. `"revenue"`)
* - **Fully-qualified names**: omit `cube` and use dot notation (e.g. `"orders.revenue"`)
* All field names must be fully qualified (e.g. "orders.revenue").
*/
async query(options) {
let cubeQuery;
if (isCubeNativeFormat(options)) {
cubeQuery = buildNativeQuery(options);
}
else {
if (!options.cube) {
throw new Error('QueryOptions requires "cube" when using short field names. ' +
'Either set "cube" or use fully-qualified names (e.g. "orders.revenue").');
}
cubeQuery = buildCubeQuery(options);
}
const cubeQuery = toCubeQuery(options);
const result = await request('/api/cube/query', { query: cubeQuery });
const simplifiedData = simplifyResult(result.data);
return { data: simplifiedData, annotation: result.annotation };
return { data: result.data, annotation: result.annotation };
},

@@ -141,4 +94,3 @@ /**

const result = await request('/api/cube/query', { query: cubeQuery });
const simplifiedData = simplifyResult(result.data);
return { data: simplifiedData, annotation: result.annotation };
return { data: result.data, annotation: result.annotation };
},

@@ -145,0 +97,0 @@ /**

export { createClient } from './client.js';
export { buildCubeQuery, simplifyResult, isCubeNativeFormat } from './query.js';
export { toCubeQuery } from './query.js';
export type { BonnardConfig, QueryOptions, QueryResult, SqlResult, Filter, TimeDimension, InferQueryResult, CubeQuery, ExploreMeta, CubeMetaItem, CubeFieldMeta, CubeSegmentMeta, ExploreOptions, DashboardResult, DashboardListResult, } from './types.js';
export { createClient } from './client.js';
export { buildCubeQuery, simplifyResult, isCubeNativeFormat } from './query.js';
export { toCubeQuery } from './query.js';
/**
* Bonnard SDK — Pure query-building functions (zero IO)
* Bonnard SDK — Query format conversion (zero IO)
*/
import type { QueryOptions } from './types.js';
/**
* Detect whether a QueryOptions object uses Cube-native fully-qualified names
* (i.e. "view.field" dot notation) rather than short names that need a cube prefix.
*/
export declare function isCubeNativeFormat(options: QueryOptions): boolean;
/**
* Convert SDK QueryOptions into a Cube-native query object.
* Handles cube-name prefixing for all field references.
* All field names must be fully qualified (e.g. "orders.revenue").
*/
export declare function buildCubeQuery(options: QueryOptions): Record<string, unknown>;
/**
* Simplify Cube response keys by removing the cube prefix.
* e.g. { "orders.revenue": 100 } → { "revenue": 100 }
*/
export declare function simplifyResult<T = Record<string, unknown>>(data: Record<string, unknown>[]): T[];
export declare function toCubeQuery(options: QueryOptions): Record<string, unknown>;
/**
* Bonnard SDK — Pure query-building functions (zero IO)
* Bonnard SDK — Query format conversion (zero IO)
*/
/**
* Detect whether a QueryOptions object uses Cube-native fully-qualified names
* (i.e. "view.field" dot notation) rather than short names that need a cube prefix.
*/
export function isCubeNativeFormat(options) {
const fields = [
...(options.measures ?? []),
...(options.dimensions ?? []),
...(options.filters?.map(f => f.dimension) ?? []),
...(options.timeDimension ? [options.timeDimension.dimension] : []),
];
return fields.some(f => f.includes('.'));
}
/**
* Convert SDK QueryOptions into a Cube-native query object.
* Handles cube-name prefixing for all field references.
* All field names must be fully qualified (e.g. "orders.revenue").
*/
export function buildCubeQuery(options) {
export function toCubeQuery(options) {
const cubeQuery = {};
if (options.measures) {
cubeQuery.measures = options.measures.map(m => m.includes('.') ? m : `${options.cube}.${m}`);
cubeQuery.measures = options.measures;
}
if (options.dimensions) {
cubeQuery.dimensions = options.dimensions.map(d => d.includes('.') ? d : `${options.cube}.${d}`);
cubeQuery.dimensions = options.dimensions;
}
if (options.filters) {
cubeQuery.filters = options.filters.map(f => ({
dimension: f.dimension.includes('.') ? f.dimension : `${options.cube}.${f.dimension}`,
member: f.dimension,
operator: f.operator,

@@ -38,5 +25,3 @@ values: f.values,

cubeQuery.timeDimensions = [{
dimension: options.timeDimension.dimension.includes('.')
? options.timeDimension.dimension
: `${options.cube}.${options.timeDimension.dimension}`,
dimension: options.timeDimension.dimension,
granularity: options.timeDimension.granularity,

@@ -47,6 +32,3 @@ dateRange: options.timeDimension.dateRange,

if (options.orderBy) {
cubeQuery.order = Object.entries(options.orderBy).map(([key, dir]) => [
key.includes('.') ? key : `${options.cube}.${key}`,
dir,
]);
cubeQuery.order = Object.entries(options.orderBy).map(([key, dir]) => [key, dir]);
}

@@ -58,15 +40,1 @@ if (options.limit) {

}
/**
* Simplify Cube response keys by removing the cube prefix.
* e.g. { "orders.revenue": 100 } → { "revenue": 100 }
*/
export function simplifyResult(data) {
return data.map(row => {
const simplified = {};
for (const [key, value] of Object.entries(row)) {
const simpleName = key.includes('.') ? key.split('.').pop() : key;
simplified[simpleName] = value;
}
return simplified;
});
}

@@ -10,3 +10,2 @@ /**

export interface QueryOptions {
cube?: string;
measures?: string[];

@@ -13,0 +12,0 @@ dimensions?: string[];

{
"name": "@bonnard/sdk",
"version": "0.2.1",
"version": "0.3.0",
"description": "Bonnard SDK - query your semantic layer from any JavaScript or TypeScript app",

@@ -5,0 +5,0 @@ "type": "module",

+10
-13

@@ -23,9 +23,8 @@ # @bonnard/sdk

const { data } = await bon.query({
cube: 'orders',
measures: ['revenue', 'count'],
dimensions: ['status'],
measures: ['orders.revenue', 'orders.count'],
dimensions: ['orders.status'],
});
console.log(data);
// [{ revenue: 45000, count: 120, status: "completed" }, ...]
// [{ "orders.revenue": 45000, "orders.count": 120, "orders.status": "completed" }, ...]
```

@@ -63,6 +62,5 @@

const { data } = await bon.query({
cube: 'orders',
measures: ['revenue'],
measures: ['orders.revenue'],
timeDimension: {
dimension: 'created_at',
dimension: 'orders.created_at',
granularity: 'month',

@@ -92,14 +90,13 @@ dateRange: ['2025-01-01', '2025-12-31'],

const { data } = await bon.query({
cube: 'orders',
measures: ['revenue', 'count'],
dimensions: ['product_category'],
measures: ['orders.revenue', 'orders.count'],
dimensions: ['orders.product_category'],
filters: [
{ dimension: 'status', operator: 'equals', values: ['completed'] },
{ dimension: 'orders.status', operator: 'equals', values: ['completed'] },
],
timeDimension: {
dimension: 'created_at',
dimension: 'orders.created_at',
granularity: 'month',
dateRange: ['2025-01-01', '2025-12-31'],
},
orderBy: { revenue: 'desc' },
orderBy: { 'orders.revenue': 'desc' },
limit: 100,

@@ -106,0 +103,0 @@ });