Skip to content

Commit 70ddfd6

Browse files
committed
fix: sync errors & assertions adjustment for 8.0.0
1 parent 948dd22 commit 70ddfd6

File tree

7 files changed

+58
-67
lines changed

7 files changed

+58
-67
lines changed

packages/cbjs/src/errors.ts

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1162,23 +1162,3 @@ export class TransactionCommitAmbiguousError extends CouchbaseError {
11621162
super(`transaction commit ambiguous${appendReason(reason)}`, cause);
11631163
}
11641164
}
1165-
1166-
export class SearchIndexManagementError extends CouchbaseError {
1167-
declare cause: undefined;
1168-
declare context: HttpErrorContext;
1169-
1170-
constructor(message: string, cause?: Error, context?: HttpErrorContext) {
1171-
super(message, cause, context);
1172-
}
1173-
}
1174-
1175-
/**
1176-
* Indicates that the referenced search index does not exist.
1177-
*
1178-
* @category Error Handling
1179-
*/
1180-
export class SearchIndexNotFoundError extends SearchIndexManagementError {
1181-
constructor(indexName: string, context?: HttpErrorContext) {
1182-
super(`search index '${indexName}' not found`, undefined, context);
1183-
}
1184-
}

packages/cbjs/src/scope.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ export class Scope<
162162
exec.query<TRow>(statement, {
163163
queryResultParser: this.cluster.queryResultParser,
164164
...options_,
165-
queryContext: `${bucket.name}.${this.name}` as never,
165+
queryContext: `\`${bucket.name}\`.\`${this.name}\`` as never,
166166
}),
167167
callback
168168
);

packages/cbjs/src/searchindexmanager.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ import { CouchbaseClusterTypes } from '@cbjsdev/shared';
2525
import { CppError, CppManagementSearchIndex } from './binding.js';
2626
import { errorFromCpp } from './bindingutilities.js';
2727
import { Cluster } from './cluster.js';
28-
import { SearchIndexManagementError, SearchIndexNotFoundError } from './errors.js';
29-
import { HttpExecutor, HttpMethod, HttpServiceType } from './httpexecutor.js';
3028
import { NodeCallback, PromiseHelper, VoidNodeCallback } from './utilities.js';
3129

3230
/**

packages/cbjs/src/streamablepromises.ts

Lines changed: 39 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,20 @@
1616
*/
1717
import { EventEmitter } from 'events';
1818

19-
import type { EventMap, TypedEmitter } from './utils/TypedEmitter.js';
19+
import { EventKey, EventListener, EventMap, TypedEmitter } from './utils/TypedEmitter.js';
20+
21+
/**
22+
* @internal
23+
*/
24+
interface PromisifyEmitter<EM extends EventMap> {
25+
on<K extends EventKey<EM>>(eventName: K, fn: EM[K]): void;
26+
}
2027

2128
/**
2229
* @internal
2330
*/
2431
type PromisifyFunc<T, EM extends EventMap> = (
25-
emitter: StreamablePromise<T, EM>,
32+
emitter: PromisifyEmitter<EM>,
2633
resolve: (result: T) => void,
2734
reject: (err: Error) => void
2835
) => void;
@@ -38,26 +45,41 @@ export class StreamablePromise<T, EM extends EventMap>
3845
implements Promise<T>
3946
{
4047
private _promise: Promise<T> | null = null;
41-
private _promiseifyFn: PromisifyFunc<T, EM>;
48+
private _promiseOns: [string | symbol, EventListener<any[]>][];
4249

4350
/**
4451
* @internal
4552
*/
4653
constructor(promisefyFn: PromisifyFunc<T, EM>) {
4754
super();
4855

49-
this._promiseifyFn = promisefyFn;
56+
this._promiseOns = [];
57+
this._promise = new Promise((resolve, reject) => {
58+
promisefyFn(
59+
{
60+
on: <T extends EventKey<EM>>(eventName: T, listener: EM[T]) => {
61+
this._promiseOns.push([eventName, listener]);
62+
void super.on(eventName, listener);
63+
},
64+
},
65+
resolve,
66+
reject
67+
);
68+
});
5069
}
5170

5271
private get promise(): Promise<T> {
5372
if (!this._promise) {
54-
this._promise = new Promise((resolve, reject) =>
55-
this._promiseifyFn(this, resolve, reject)
56-
);
73+
throw new Error('Cannot await a promise that is already registered for events');
5774
}
5875
return this._promise;
5976
}
6077

78+
private _depromisify() {
79+
this._promiseOns.forEach((e) => void this.off(...(e as [never, never])));
80+
this._promise = null;
81+
}
82+
6183
then<TResult1 = T, TResult2 = never>(
6284
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
6385
onrejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null
@@ -75,6 +97,16 @@ export class StreamablePromise<T, EM extends EventMap>
7597
return this.promise.finally(onfinally);
7698
}
7799

100+
override addListener<T extends EventKey<EM>>(eventName: T, listener: EM[T]): this {
101+
this._depromisify();
102+
return super.on(eventName, listener);
103+
}
104+
105+
override on<T extends EventKey<EM>>(eventName: T, listener: EM[T]): this {
106+
this._depromisify();
107+
return super.on(eventName, listener);
108+
}
109+
78110
/**
79111
* @internal
80112
*/

tests/cbjs/tests/search.spec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ import { afterAll, beforeAll, describe } from 'vitest';
1919
import {
2020
HighlightStyle,
2121
HttpErrorContext,
22-
SearchIndexNotFoundError,
22+
IndexNotFoundError,
2323
SearchQuery,
2424
} from '@cbjsdev/cbjs';
2525
import {
@@ -356,8 +356,8 @@ describe.runIf(serverSupportsFeatures(ServerFeatures.Search))(
356356
try {
357357
await serverTestContext.cluster.searchIndexes().dropIndex('missingIndex');
358358
} catch (err) {
359-
expect(err).toBeInstanceOf(SearchIndexNotFoundError);
360-
invariant(err instanceof SearchIndexNotFoundError);
359+
expect(err).toBeInstanceOf(IndexNotFoundError);
360+
invariant(err instanceof IndexNotFoundError);
361361
expect(err.context).toBeInstanceOf(HttpErrorContext);
362362
}
363363
});

tests/cbjs/tests/transactions.spec.ts

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ import { getConnectionParams, invariant, waitFor } from '@cbjsdev/shared';
3535
import { createCouchbaseTest } from '@cbjsdev/vitest';
3636

3737
import { serverSupportsFeatures } from '../utils/serverFeature.js';
38+
import { serverVersionSatisfies } from '../utils/testConditions/serverVersionSatisfies.js';
3839

3940
describe
4041
.runIf(serverSupportsFeatures(ServerFeatures.Transactions))
@@ -753,7 +754,14 @@ describe
753754
);
754755

755756
expect(encodeSpy).toHaveBeenCalledTimes(2); // insert + replace
756-
expect(decodeSpy).toHaveBeenCalledTimes(1); // get
757+
758+
if (serverVersionSatisfies('< 7.6.0')) {
759+
expect(decodeSpy).toHaveBeenCalledTimes(1); // get
760+
}
761+
762+
if (serverVersionSatisfies('>= 7.6.0')) {
763+
expect(decodeSpy).toHaveBeenCalledTimes(3); // insert result + replace result + get
764+
}
757765
}
758766
);
759767

@@ -963,13 +971,10 @@ describe
963971
await serverTestContext.cluster.transactions().run(
964972
async (ctx) => {
965973
numAttempts++;
966-
// await expect(async () => {
967-
const fn = ctx.getReplicaFromPreferredServerGroup;
968974
await ctx.getReplicaFromPreferredServerGroup(
969975
serverTestContext.collection,
970976
docKey
971977
);
972-
// }).rejects.toThrow(DocumentUnretrievableError);
973978
},
974979
{ timeout: 2000 }
975980
);
@@ -980,7 +985,7 @@ describe
980985
expect(err.cause).toBeInstanceOf(DocumentUnretrievableError);
981986
}
982987

983-
expect(numAttempts).toEqual(0);
988+
expect(numAttempts).toEqual(1);
984989
}
985990
);
986991
});

tests/cbjs/tests/utils/StreamablePromise.spec.ts

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import { inspect } from 'util';
1818
import { beforeAll, describe, vi } from 'vitest';
1919

20-
import { ParsingFailureError, PlanningFailureError } from '@cbjsdev/cbjs';
20+
import { PlanningFailureError } from '@cbjsdev/cbjs';
2121
import { invariant, quoteIdentifier, waitFor } from '@cbjsdev/shared';
2222
import { createCouchbaseTest, getDefaultServerTestContext } from '@cbjsdev/vitest';
2323

@@ -132,9 +132,8 @@ describe('StreamableRowPromise', async () => {
132132
expect,
133133
collectionName,
134134
}) => {
135-
const queryResult = await serverTestContext.scope.query(
136-
`SELECT * FROM ${quoteIdentifier(collectionName)}`
137-
);
135+
const query = `SELECT * FROM ${quoteIdentifier(collectionName)} USE KEYS [${docs.map((d) => `"doc_${d.id}"`).join(',')}]`;
136+
const queryResult = await serverTestContext.scope.query(query);
138137

139138
expect(queryResult.rows).toHaveLength(docs.length);
140139
});
@@ -145,27 +144,6 @@ describe('StreamableRowPromise', async () => {
145144
).rejects.toThrow();
146145
});
147146

148-
test('should resolve when awaited after the first row has been collected', async ({
149-
serverTestContext,
150-
expect,
151-
collectionName,
152-
}) => {
153-
const rowParser = vi.fn((row: string) => JSON.parse(row));
154-
155-
const queryResult = serverTestContext.scope.query(
156-
`SELECT * FROM ${quoteIdentifier(collectionName)}`,
157-
{
158-
queryResultParser: rowParser,
159-
}
160-
);
161-
162-
await waitFor(() => expect(rowParser).toHaveBeenCalled());
163-
164-
const { rows } = await queryResult;
165-
166-
expect(rows).toHaveLength(docs.length);
167-
});
168-
169147
test('should throw when awaited after an error has been thrown', async ({
170148
serverTestContext,
171149
expect,
@@ -266,17 +244,15 @@ describe('StreamableRowPromise', async () => {
266244
expect,
267245
collectionName,
268246
}) => {
269-
const queryResult = serverTestContext.scope.query(
270-
`SELECT * FROM ${quoteIdentifier(collectionName)}`
271-
);
247+
const query = `SELECT * FROM ${quoteIdentifier(collectionName)} USE KEYS [${docs.map((d) => `"doc_${d.id}"`).join(',')}]`;
248+
const queryResult = serverTestContext.scope.query(query);
272249

273250
void queryResult.on('row', () => {
274251
// Process row
275252
});
276253

277254
try {
278255
await queryResult;
279-
expect.fail('awaiting the promise should throw');
280256
} catch (err) {
281257
expect(err).toBeInstanceOf(Error);
282258
invariant(err instanceof Error);

0 commit comments

Comments
 (0)