Skip to content

Commit 51c0a64

Browse files
authored
Add cursor.kill (#629)
* Add cursor.kill * Add test case * fix query -> cursor * typo
1 parent f06d1fa commit 51c0a64

File tree

4 files changed

+96
-32
lines changed

4 files changed

+96
-32
lines changed

CHANGELOG.md

+10
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,16 @@ All notable changes to this project will be documented in this file.
55
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
66
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
77

8+
## Unreleased
9+
10+
## Added
11+
12+
- Added `cursor.kill` method
13+
14+
Cursors that have not yet been fully depleted can now be killed using the
15+
`cursor.kill` method. Note that this method has no effect if the cursor
16+
is already depleted.
17+
818
## [6.11.1] - 2019-08-30
919

1020
### Fixed

docs/Drivers/JS/Reference/Cursor.md

+48-30
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ _Cursor_ instances are incrementally depleted as they are read from.
77

88
```js
99
const db = new Database();
10-
const cursor = await db.query('FOR x IN 1..5 RETURN x');
10+
const cursor = await db.query(aql`FOR x IN 1..5 RETURN x`);
1111
// query result list: [1, 2, 3, 4, 5]
1212
const value = await cursor.next();
1313
assert.equal(value, 1);
@@ -31,8 +31,8 @@ remaining result list.
3131
**Examples**
3232

3333
```js
34-
const cursor = await db.query('FOR x IN 1..5 RETURN x');
35-
const result = await cursor.all()
34+
const cursor = await db.query(aql`FOR x IN 1..5 RETURN x`);
35+
const result = await cursor.all();
3636
// result is an array containing the entire query result
3737
assert.deepEqual(result, [1, 2, 3, 4, 5]);
3838
assert.equal(cursor.hasNext(), false);
@@ -86,22 +86,22 @@ Equivalent to _Array.prototype.forEach_ (except async).
8686

8787
**Arguments**
8888

89-
* **fn**: `Function`
89+
- **fn**: `Function`
9090

9191
A function that will be invoked for each value in the cursor's remaining
9292
result list until it explicitly returns `false` or the cursor is exhausted.
9393

9494
The function receives the following arguments:
9595

96-
* **value**: `any`
96+
- **value**: `any`
9797

9898
The value in the cursor's remaining result list.
9999

100-
* **index**: `number`
100+
- **index**: `number`
101101

102102
The index of the value in the cursor's remaining result list.
103103

104-
* **cursor**: `Cursor`
104+
- **cursor**: `Cursor`
105105

106106
The cursor itself.
107107

@@ -115,11 +115,11 @@ function doStuff(value) {
115115
return VALUE;
116116
}
117117

118-
const cursor = await db.query('FOR x IN ["a", "b", "c"] RETURN x')
118+
const cursor = await db.query(aql`FOR x IN ["a", "b", "c"] RETURN x`);
119119
const last = await cursor.each(doStuff);
120-
assert.deepEqual(results, ['A', 'B', 'C']);
120+
assert.deepEqual(results, ["A", "B", "C"]);
121121
assert.equal(cursor.hasNext(), false);
122-
assert.equal(last, 'C');
122+
assert.equal(last, "C");
123123
```
124124

125125
## cursor.every
@@ -137,30 +137,30 @@ Equivalent to _Array.prototype.every_ (except async).
137137

138138
**Arguments**
139139

140-
* **fn**: `Function`
140+
- **fn**: `Function`
141141

142142
A function that will be invoked for each value in the cursor's remaining
143143
result list until it returns a value that evaluates to `false` or the cursor
144144
is exhausted.
145145

146146
The function receives the following arguments:
147147

148-
* **value**: `any`
148+
- **value**: `any`
149149

150150
The value in the cursor's remaining result list.
151151

152-
* **index**: `number`
152+
- **index**: `number`
153153

154154
The index of the value in the cursor's remaining result list.
155155

156-
* **cursor**: `Cursor`
156+
- **cursor**: `Cursor`
157157

158158
The cursor itself.
159159

160160
```js
161161
const even = value => value % 2 === 0;
162162

163-
const cursor = await db.query('FOR x IN 2..5 RETURN x');
163+
const cursor = await db.query(aql`FOR x IN 2..5 RETURN x`);
164164
const result = await cursor.every(even);
165165
assert.equal(result, false); // 3 is not even
166166
assert.equal(cursor.hasNext(), true);
@@ -187,7 +187,7 @@ Equivalent to _Array.prototype.some_ (except async).
187187
```js
188188
const even = value => value % 2 === 0;
189189

190-
const cursor = await db.query('FOR x IN 1..5 RETURN x');
190+
const cursor = await db.query(aql`FOR x IN 1..5 RETURN x`);
191191
const result = await cursor.some(even);
192192
assert.equal(result, true); // 2 is even
193193
assert.equal(cursor.hasNext(), true);
@@ -198,7 +198,7 @@ assert.equal(value, 3); // next value after 2
198198

199199
## cursor.map
200200

201-
`cursor.map(fn): Array<any>`
201+
`async cursor.map(fn): Array<any>`
202202

203203
Advances the cursor by applying the function _fn_ to each value in the cursor's
204204
remaining result list until the cursor is exhausted.
@@ -212,30 +212,30 @@ to do this for very large query result sets.
212212

213213
**Arguments**
214214

215-
* **fn**: `Function`
215+
- **fn**: `Function`
216216

217217
A function that will be invoked for each value in the cursor's remaining
218218
result list until the cursor is exhausted.
219219

220220
The function receives the following arguments:
221221

222-
* **value**: `any`
222+
- **value**: `any`
223223

224224
The value in the cursor's remaining result list.
225225

226-
* **index**: `number`
226+
- **index**: `number`
227227

228228
The index of the value in the cursor's remaining result list.
229229

230-
* **cursor**: `Cursor`
230+
- **cursor**: `Cursor`
231231

232232
The cursor itself.
233233

234234
**Examples**
235235

236236
```js
237237
const square = value => value * value;
238-
const cursor = await db.query('FOR x IN 1..5 RETURN x');
238+
const cursor = await db.query(aql`FOR x IN 1..5 RETURN x`);
239239
const result = await cursor.map(square);
240240
assert.equal(result.length, 5);
241241
assert.deepEqual(result, [1, 4, 9, 16, 25]);
@@ -244,7 +244,7 @@ assert.equal(cursor.hasNext(), false);
244244

245245
## cursor.reduce
246246

247-
`cursor.reduce(fn, [accu]): any`
247+
`async cursor.reduce(fn, [accu]): any`
248248

249249
Exhausts the cursor by reducing the values in the cursor's remaining result list
250250
with the given function _fn_. If _accu_ is not provided, the first value in the
@@ -255,28 +255,28 @@ Equivalent to _Array.prototype.reduce_ (except async).
255255

256256
**Arguments**
257257

258-
* **fn**: `Function`
258+
- **fn**: `Function`
259259

260260
A function that will be invoked for each value in the cursor's remaining
261261
result list until the cursor is exhausted.
262262

263263
The function receives the following arguments:
264264

265-
* **accu**: `any`
265+
- **accu**: `any`
266266

267267
The return value of the previous call to _fn_. If this is the first call,
268268
_accu_ will be set to the _accu_ value passed to _reduce_ or the first value
269269
in the cursor's remaining result list.
270270

271-
* **value**: `any`
271+
- **value**: `any`
272272

273273
The value in the cursor's remaining result list.
274274

275-
* **index**: `number`
275+
- **index**: `number`
276276

277277
The index of the value in the cursor's remaining result list.
278278

279-
* **cursor**: `Cursor`
279+
- **cursor**: `Cursor`
280280

281281
The cursor itself.
282282

@@ -286,8 +286,8 @@ Equivalent to _Array.prototype.reduce_ (except async).
286286
const add = (a, b) => a + b;
287287
const baseline = 1000;
288288

289-
const cursor = await db.query('FOR x IN 1..5 RETURN x');
290-
const result = await cursor.reduce(add, baseline)
289+
const cursor = await db.query(aql`FOR x IN 1..5 RETURN x`);
290+
const result = await cursor.reduce(add, baseline);
291291
assert.equal(result, baseline + 1 + 2 + 3 + 4 + 5);
292292
assert.equal(cursor.hasNext(), false);
293293

@@ -297,3 +297,21 @@ const result = await cursor.reduce(add);
297297
assert.equal(result, 1 + 2 + 3 + 4 + 5);
298298
assert.equal(cursor.hasNext(), false);
299299
```
300+
301+
## cursor.kill
302+
303+
`async cursor.kill(): void`
304+
305+
Kills the cursor and frees up associated database resources.
306+
307+
This method has no effect if all result batches have already been fetched.
308+
309+
**Examples**
310+
311+
```js
312+
const cursor = await db.query(aql`FOR x IN 1..5 RETURN x`);
313+
await cursor.kill(); // has no effect
314+
315+
const cursor2 = await db.query(aql`FOR x IN 1..5 RETURN x`, { batchSize: 2 });
316+
await cursor2.kill(); // this kills the cursor
317+
```

src/cursor.ts

+16-2
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ export class ArrayCursor {
77
private _connection: Connection;
88
private _result: any;
99
private _hasMore: boolean;
10-
private _id: string;
10+
private _id: string | undefined;
1111
private _host?: number;
1212
private _allowDirtyRead?: boolean;
1313

@@ -20,8 +20,8 @@ export class ArrayCursor {
2020
this.extra = body.extra;
2121
this._connection = connection;
2222
this._result = body.result;
23-
this._hasMore = Boolean(body.hasMore);
2423
this._id = body.id;
24+
this._hasMore = Boolean(body.id && body.hasMore);
2525
this._host = host;
2626
this.count = body.count;
2727
this._allowDirtyRead = allowDirtyRead;
@@ -152,4 +152,18 @@ export class ArrayCursor {
152152
}
153153
return accu;
154154
}
155+
156+
async kill(): Promise<void> {
157+
if (!this._hasMore) return undefined;
158+
return this._connection.request(
159+
{
160+
method: "DELETE",
161+
path: `/_api/cursor/${this._id}`
162+
},
163+
() => {
164+
this._hasMore = false;
165+
return undefined;
166+
}
167+
);
168+
}
155169
}

src/test/08-cursors.ts

+22
Original file line numberDiff line numberDiff line change
@@ -193,4 +193,26 @@ describe("Cursor API", () => {
193193
expect(result).to.eql(aqlResult.reduce((a, b) => a + b));
194194
});
195195
});
196+
describe("cursor.kill", () => {
197+
it("kills the cursor", async () => {
198+
const cursor = await db.query(aql`FOR i IN 1..5 RETURN i`, {
199+
batchSize: 2
200+
});
201+
const { _connection: connection, _host: host, _id: id } = cursor as any;
202+
expect(cursor).to.have.property("_hasMore", true);
203+
await cursor.kill();
204+
expect(cursor).to.have.property("_hasMore", false);
205+
try {
206+
await connection.request({
207+
method: "PUT",
208+
path: `/_api/cursor/${id}`,
209+
host: host
210+
});
211+
} catch (e) {
212+
expect(e).to.have.property("errorNum", 1600);
213+
return;
214+
}
215+
expect.fail("should not be able to fetch additional result set");
216+
});
217+
});
196218
});

0 commit comments

Comments
 (0)