Skip to content
Open
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
31 changes: 22 additions & 9 deletions packages/cubejs-client-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -150,14 +150,20 @@

const MUTEX_ERROR = 'Mutex has been changed';

function mutexPromise(promise: Promise<any>) {
return promise
.then((result) => result)
.catch((error) => {
if (error !== MUTEX_ERROR) {
throw error;
}
});
class MutexCancelledError extends Error {
constructor() {
super(MUTEX_ERROR);
this.name = 'MutexCancelledError';
}
}

function mutexPromise<T>(promise: Promise<T>): Promise<T> {
return promise.catch((error) => {
if (error === MUTEX_ERROR) {
throw new MutexCancelledError();
}
throw error;
});
}

export type ResponseFormat = 'compact' | 'default' | undefined;
Expand Down Expand Up @@ -412,7 +418,14 @@
return subscribeNext();
};

const promise = requestPromise.then(requestInstance => mutexPromise(requestInstance.subscribe(loadImpl)));
const promise = requestPromise
.then(requestInstance => mutexPromise(requestInstance.subscribe(loadImpl)))
.catch((error) => {
if (error instanceof MutexCancelledError) {
return null;
Copy link

Copilot AI Dec 22, 2025

Choose a reason for hiding this comment

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

The promise chain now returns null when MutexCancelledError is caught, but the public method signatures that call loadMethod (e.g., load, sql, meta, dryRun, cubeSql) don't include null in their return types. For example, the load method signature declares Promise<ResultSet<...>> but can now return Promise<ResultSet<...> | null>. This creates a type safety issue where consumers of the API may not handle the null case properly.

Consider updating all method signatures that use loadMethod to reflect that they can return null, or document this behavior explicitly.

Suggested change
return null;
// Propagate mutex cancellation as a rejected promise instead of resolving to null,
// so that the promise's resolved type remains consistent with public method signatures.
throw error;

Copilot uses AI. Check for mistakes.
}
throw error;
});

if (callback) {
return {
Expand Down Expand Up @@ -663,7 +676,7 @@
* Get generated SQL string for the given `query`.
*/
public sql(query: DeeplyReadonly<Query | Query[]>, options?: LoadMethodOptions, callback?: LoadMethodCallback<SqlQuery>): Promise<SqlQuery> | UnsubscribeObj {
return this.loadMethod(

Check failure on line 679 in packages/cubejs-client-core/src/index.ts

View workflow job for this annotation

GitHub Actions / unit (22.x, 3.11)

Type 'Promise<unknown> | { unsubscribe: () => Promise<any>; }' is not assignable to type 'UnsubscribeObj | Promise<SqlQuery>'.

Check failure on line 679 in packages/cubejs-client-core/src/index.ts

View workflow job for this annotation

GitHub Actions / integration-cubestore (22.x)

Type 'Promise<unknown> | { unsubscribe: () => Promise<any>; }' is not assignable to type 'UnsubscribeObj | Promise<SqlQuery>'.
() => this.request('sql', {
query,
signal: options?.signal,
Expand All @@ -683,7 +696,7 @@
* Get meta description of cubes available for querying.
*/
public meta(options?: LoadMethodOptions, callback?: LoadMethodCallback<Meta>): Promise<Meta> | UnsubscribeObj {
return this.loadMethod(

Check failure on line 699 in packages/cubejs-client-core/src/index.ts

View workflow job for this annotation

GitHub Actions / unit (22.x, 3.11)

Type 'Promise<unknown> | { unsubscribe: () => Promise<any>; }' is not assignable to type 'UnsubscribeObj | Promise<Meta>'.

Check failure on line 699 in packages/cubejs-client-core/src/index.ts

View workflow job for this annotation

GitHub Actions / integration-cubestore (22.x)

Type 'Promise<unknown> | { unsubscribe: () => Promise<any>; }' is not assignable to type 'UnsubscribeObj | Promise<Meta>'.
() => this.request('meta', {
signal: options?.signal,
baseRequestId: options?.baseRequestId,
Expand All @@ -702,7 +715,7 @@
* Get query related meta without query execution
*/
public dryRun(query: DeeplyReadonly<Query | Query[]>, options?: LoadMethodOptions, callback?: LoadMethodCallback<DryRunResponse>): Promise<DryRunResponse> | UnsubscribeObj {
return this.loadMethod(

Check failure on line 718 in packages/cubejs-client-core/src/index.ts

View workflow job for this annotation

GitHub Actions / unit (22.x, 3.11)

Type 'Promise<unknown> | { unsubscribe: () => Promise<any>; }' is not assignable to type 'UnsubscribeObj | Promise<DryRunResponse>'.

Check failure on line 718 in packages/cubejs-client-core/src/index.ts

View workflow job for this annotation

GitHub Actions / integration-cubestore (22.x)

Type 'Promise<unknown> | { unsubscribe: () => Promise<any>; }' is not assignable to type 'UnsubscribeObj | Promise<DryRunResponse>'.
() => this.request('dry-run', {
query,
signal: options?.signal,
Expand All @@ -722,7 +735,7 @@
* Execute a Cube SQL query against Cube SQL interface and return the results.
*/
public cubeSql(sqlQuery: string, options?: CubeSqlOptions, callback?: LoadMethodCallback<CubeSqlResult>): Promise<CubeSqlResult> | UnsubscribeObj {
return this.loadMethod(

Check failure on line 738 in packages/cubejs-client-core/src/index.ts

View workflow job for this annotation

GitHub Actions / unit (22.x, 3.11)

Type 'Promise<unknown> | { unsubscribe: () => Promise<any>; }' is not assignable to type 'UnsubscribeObj | Promise<CubeSqlResult>'.

Check failure on line 738 in packages/cubejs-client-core/src/index.ts

View workflow job for this annotation

GitHub Actions / integration-cubestore (22.x)

Type 'Promise<unknown> | { unsubscribe: () => Promise<any>; }' is not assignable to type 'UnsubscribeObj | Promise<CubeSqlResult>'.
() => {
const request = this.request('cubesql', {
query: sqlQuery,
Expand Down
Loading