Skip to content

Commit 0857d18

Browse files
committed
Add support for async iteration of SODA document cursors
1 parent 9859ebc commit 0857d18

File tree

8 files changed

+240
-45
lines changed

8 files changed

+240
-45
lines changed

doc/src/api_manual/sodacursor.rst

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,14 +5,18 @@ API: SodaDocumentCursor Class
55
*****************************
66

77
A SodaDocumentCursor is used to walk through a set of SODA documents
8-
returned from a :meth:`sodaCollection.find()`
9-
:meth:`sodaOperation.getCursor()` method.
8+
returned from :meth:`sodaCollection.find()` and
9+
:meth:`sodaOperation.getCursor()` methods.
1010

1111
.. note::
1212

1313
In this release, SODA is only supported in the node-oracledb Thick mode.
1414
See :ref:`enablingthick`.
1515

16+
From node-oracledb 6.4, the SodaDocumentCursor class implements the
17+
``asyncIterator()`` symbol to support asynchronous iteration. See
18+
:ref:`accessingsodadocuments` for examples.
19+
1620
.. _sodadoccursormethods:
1721

1822
SodaDocumentCursor Methods

doc/src/release_notes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,8 @@ Thin Mode Changes
9494
Thick Mode Changes
9595
++++++++++++++++++
9696

97+
#) Added support for asynchronous iteration of SODA document cursors.
98+
9799
#) Internal code and memory optimization changes for Advanced Queuing.
98100

99101
node-oracledb `v6.3.0 <https://github.com/oracle/node-oracledb/compare/v6.2.0...v6.3.0>`__ (21 Dec 2023)

doc/src/user_guide/soda.rst

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -450,6 +450,31 @@ attribute values, or use
450450
SodaDocument returned by a :meth:`sodaCollection.find()`
451451
query.
452452

453+
From node-oracledb 6.4, you can asynchronously iterate over
454+
:ref:`SodaDocumentCursor object <sodadocumentcursorclass>`:
455+
456+
.. code-block:: javascript
457+
458+
const soda = connection.getSodaDatabase();
459+
// Create a SODA collection
460+
const collection = await soda.createCollection("mycollection");
461+
const data = [
462+
{ name: "John", age: 57 },
463+
{ name: "Sally", age: 53 }
464+
];
465+
await collection.insertMany(data);
466+
const docCursor = await collection.find().getCursor();
467+
// Use the asyncIterator for the SodaDocumentCursor object
468+
for await (const doc of docCursor) {
469+
console.log(doc.getContent());
470+
}
471+
await docCursor.close();
472+
await collection.drop();
473+
await connection.close();
474+
475+
See `soda2.js <https://github.com/oracle/node-oracledb/tree/main/examples/
476+
soda2.js>`__ for a runnable example.
477+
453478
.. _sodaqbesearches:
454479

455480
SODA Query-by-Example Searches for JSON Documents

doc/src/user_guide/sql_execution.rst

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ To fetch multiple rows at a time, use ``getRows()``:
211211
// always close the ResultSet
212212
await rs.close();
213213
214-
From node-oracledb 5.5, you can iterate over ResultSets:
214+
From node-oracledb 5.5, you can asynchronously iterate over ResultSets:
215215

216216
.. code-block:: javascript
217217
@@ -223,14 +223,20 @@ From node-oracledb 5.5, you can iterate over ResultSets:
223223
}
224224
);
225225
226+
// Fetch rows from the resultSet object using asyncIterator
226227
const rs = result.resultSet;
228+
229+
// Call the asyncIterator for the resultSet object
227230
for await (const row of rs) {
228231
console.log(row);
229232
}
230233
231234
// always close the ResultSet
232235
await rs.close();
233236
237+
See `resultset3.js <https://github.com/oracle/node-oracledb/tree/main/
238+
examples/resultset3.js>`__ for a runnable example.
239+
234240
.. _streamingresults:
235241

236242
Query Streaming

examples/soda2.js

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
/* Copyright (c) 2024, Oracle and/or its affiliates. */
2+
3+
/******************************************************************************
4+
*
5+
* This software is dual-licensed to you under the Universal Permissive License
6+
* (UPL) 1.0 as shown at https://oss.oracle.com/licenses/upl and Apache License
7+
* 2.0 as shown at http://www.apache.org/licenses/LICENSE-2.0. You may choose
8+
* either license.
9+
*
10+
* If you elect to accept the software under the Apache License, Version 2.0,
11+
* the following applies:
12+
*
13+
* Licensed under the Apache License, Version 2.0 (the "License");
14+
* you may not use this file except in compliance with the License.
15+
* You may obtain a copy of the License at
16+
*
17+
* https://www.apache.org/licenses/LICENSE-2.0
18+
*
19+
* Unless required by applicable law or agreed to in writing, software
20+
* distributed under the License is distributed on an "AS IS" BASIS,
21+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
22+
* See the License for the specific language governing permissions and
23+
* limitations under the License.
24+
*
25+
* NAME
26+
* soda2.js
27+
*
28+
* DESCRIPTION
29+
* Simple Oracle Document Access (SODA) example with SodaDocumentCursor
30+
* asyncIterators.
31+
*
32+
* Requires Oracle Database and Oracle Client 18.3, or higher.
33+
* The user must have been granted the SODA_APP and CREATE TABLE privileges.
34+
* https://node-oracledb.readthedocs.io/en/latest/user_guide/soda.html#sodaoverview
35+
*
36+
*****************************************************************************/
37+
38+
'use strict';
39+
40+
Error.stackTraceLimit = 50;
41+
42+
const oracledb = require('oracledb');
43+
const dbConfig = require('./dbconfig.js');
44+
45+
// This example requires node-oracledb Thick mode.
46+
//
47+
// Thick mode requires Oracle Client or Oracle Instant Client libraries. On
48+
// Windows and macOS Intel you can specify the directory containing the
49+
// libraries at runtime or before Node.js starts. On other platforms (where
50+
// Oracle libraries are available) the system library search path must always
51+
// include the Oracle library path before Node.js starts. If the search path
52+
// is not correct, you will get a DPI-1047 error. See the node-oracledb
53+
// installation documentation.
54+
let clientOpts = {};
55+
// On Windows and macOS Intel platforms, set the environment
56+
// variable NODE_ORACLEDB_CLIENT_LIB_DIR to the Oracle Client library path
57+
if (process.platform === 'win32' || (process.platform === 'darwin' && process.arch === 'x64')) {
58+
clientOpts = { libDir: process.env.NODE_ORACLEDB_CLIENT_LIB_DIR };
59+
}
60+
oracledb.initOracleClient(clientOpts); // enable node-oracledb Thick mode
61+
62+
// The general recommendation for simple SODA usage is to enable autocommit
63+
oracledb.autoCommit = true;
64+
65+
async function run() {
66+
let connection, collection;
67+
try {
68+
connection = await oracledb.getConnection(dbConfig);
69+
if (oracledb.oracleClientVersion < 1803000000) {
70+
throw new Error('node-oracledb SODA requires Oracle Client libraries 18.3 or greater');
71+
}
72+
73+
if (connection.oracleServerVersion < 1803000000) {
74+
throw new Error('node-oracledb SODA requires Oracle Database 18.3 or greater');
75+
}
76+
77+
const soda = connection.getSodaDatabase();
78+
collection = await soda.createCollection("Test");
79+
console.log('Created a SODA collection\n');
80+
const data = [
81+
{ name: "John", age: 57 },
82+
{ name: "Sally", age: 53 }
83+
];
84+
await collection.insertMany(data);
85+
const cursor = await collection.find().getCursor();
86+
console.log('Retrieved SODA document contents as an object using SodaDocumentCursor:');
87+
// Use the asyncIterator for the sodaDocumentCursor object
88+
for await (const doc of cursor) {
89+
console.log(doc.getContent());
90+
}
91+
await cursor.close();
92+
} catch (err) {
93+
console.error(err);
94+
} finally {
95+
if (collection) {
96+
// Drop the collection
97+
const res = await collection.drop();
98+
if (res.dropped) {
99+
console.log('\nThe collection was dropped');
100+
}
101+
}
102+
103+
if (connection) {
104+
await connection.close();
105+
}
106+
107+
}
108+
109+
}
110+
111+
run();

lib/sodaDocCursor.js

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// Copyright (c) 2018, 2023, Oracle and/or its affiliates.
1+
// Copyright (c) 2018, 2024, Oracle and/or its affiliates.
22

33
//-----------------------------------------------------------------------------
44
//
@@ -60,6 +60,19 @@ class SodaDocCursor {
6060
}
6161
}
6262

63+
[Symbol.asyncIterator]() {
64+
const cursor = this;
65+
return {
66+
async next() {
67+
const doc = await cursor.getNext();
68+
return {value: doc, done: doc === undefined};
69+
},
70+
return() {
71+
return {done: true};
72+
}
73+
};
74+
}
75+
6376
}
6477

6578
nodbUtil.wrapFns(SodaDocCursor.prototype,

test/list.txt

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4300,16 +4300,17 @@ oracledb.OUT_FORMAT_OBJECT and resultSet = true
43004300
175.3 Negative - limit().count()
43014301
175.4 keys().count()
43024302
175.5 getCursor(), basic case
4303-
175.6 skip().getCursor()
4304-
175.7 getCursor(), empty document matched
4305-
175.8 Negative - close document cursor two times
4306-
175.9 getDocuments(), basic case
4307-
175.10 getDocuments(), no documents matched
4308-
175.11 getOne(), basic case
4309-
175.12 getOne(), the filter matches multiple documents
4310-
175.13 remove(), basic case
4311-
175.14 remove(), remove zero document
4312-
175.15 remove(), remove multiple times
4303+
175.6 getCursor(), asyncIterator
4304+
175.7 skip().getCursor()
4305+
175.8 getCursor(), empty document matched
4306+
175.9 Negative - close document cursor two times
4307+
175.10 getDocuments(), basic case
4308+
175.11 getDocuments(), no documents matched
4309+
175.12 getOne(), basic case
4310+
175.13 getOne(), the filter matches multiple documents
4311+
175.14 remove(), basic case
4312+
175.15 remove(), remove zero document
4313+
175.16 remove(), remove multiple times
43134314

43144315
176. soda8.js
43154316
176.1 replaceOne(), basic case with document content

0 commit comments

Comments
 (0)