Merge 1.9.0-dev JavaScript changes adding Promises etc
This commit is contained in:
parent
4b52b86532
commit
16be352385
30
CHANGELOG.md
30
CHANGELOG.md
|
@ -1,6 +1,34 @@
|
|||
# Change Log
|
||||
|
||||
## node-oracledb v1.9.0 (DD Mon YYYY)
|
||||
## node-oracledb v1.9.0 Development (19 Apr 2016)
|
||||
|
||||
** Note this is a development release: features are subject to change.**
|
||||
|
||||
- Added Promise support. All asynchronous functions can now return
|
||||
promises. By default the standard Promise library is used for Node
|
||||
0.12, 4 and 5. This can be overridden.
|
||||
|
||||
- Added a `toQueryStream()` method for ResultSets, letting REF CURSORS
|
||||
be transformed into Readable Streams.
|
||||
|
||||
- Added an experimental query Stream `_close()` method. It allows query
|
||||
streams to be closed without needing to fetch all the data. It is
|
||||
not for production use.
|
||||
|
||||
- Added aliases `pool.close()` and `connection.close()` for
|
||||
`pool.terminate()` and `connection.release()` respectively.
|
||||
|
||||
- Some method parameter validation checks, such as the number or types
|
||||
of parameters, will now throw errors synchronously instead of
|
||||
returning errors via the callback.
|
||||
|
||||
- Removed an extra call to `getRows()` made by `queryStream()` at
|
||||
end-of-fetch.
|
||||
|
||||
- Some random crashes caused by connections being garbage collected
|
||||
while still in use should no longer occur.
|
||||
|
||||
- Regularized NJS error message capitalization.
|
||||
|
||||
## node-oracledb v1.8.0 (24 Mar 2016)
|
||||
|
||||
|
|
19
README.md
19
README.md
|
@ -5,7 +5,7 @@
|
|||
The node-oracledb add-on for Node.js powers high performance Oracle
|
||||
Database applications.
|
||||
|
||||
Use node-oracledb to connect Node.js 0.10, 0.12, 4 LTS and 5 to
|
||||
Use node-oracledb to connect Node.js 0.10, 0.12, 4 and 5 to
|
||||
Oracle Database.
|
||||
|
||||
The add-on is stable, well documented, and has a comprehensive test suite.
|
||||
|
@ -15,11 +15,12 @@ The node-oracledb project is open source and maintained by Oracle Corp. The hom
|
|||
|
||||
### Node-oracledb supports:
|
||||
|
||||
- [Promises](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#promiseoverview), Callbacks and Streams
|
||||
- [SQL and PL/SQL execution](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#sqlexecution)
|
||||
- Fetching of query results by [callbacks](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#resultsethandling) or [streams](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#streamingresults)
|
||||
- [REF CURSORs](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#refcursors)
|
||||
- [Large Objects: CLOBs and BLOBs](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#lobhandling)
|
||||
- [Query results as JavaScript objects or array ](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#queryoutputformats)
|
||||
- Oracle Database 12.1 [JSON datatype](http://docs.oracle.com/database/121/ADXDB/json.htm#ADXDB6246)
|
||||
- [Query results as JavaScript objects or arrays](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#queryoutputformats)
|
||||
- [Smart mapping between JavaScript and Oracle types with manual override available](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#typemap)
|
||||
- [Data binding using JavaScript objects or arrays](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#bind)
|
||||
- [Transaction Management](https://github.com/oracle/node-oracledb/blob/master/doc/api.md#transactionmgt)
|
||||
|
@ -35,6 +36,10 @@ The node-oracledb project is open source and maintained by Oracle Corp. The hom
|
|||
- [Runtime Load Balancing (RLB)](http://docs.oracle.com/database/121/ADFNS/adfns_perf_scale.htm#ADFNS515)
|
||||
- [Transparent Application Failover (TAF)](http://docs.oracle.com/database/121/ADFNS/adfns_avail.htm#ADFNS534)
|
||||
|
||||
Various Oracle Database and Oracle Client versions, can be used.
|
||||
Oracle's cross-version compatibility allows one node-oracledb
|
||||
installation to connect to different database versions.
|
||||
|
||||
We are actively working on supporting the best Oracle Database
|
||||
features, and on functionality requests from
|
||||
[users involved in the project](https://github.com/oracle/node-oracledb/issues).
|
||||
|
@ -56,7 +61,7 @@ See [INSTALL](https://github.com/oracle/node-oracledb/tree/master/INSTALL.md) fo
|
|||
|
||||
There are examples in the [examples](https://github.com/oracle/node-oracledb/tree/master/examples) directory.
|
||||
|
||||
### A simple query example:
|
||||
### A simple query example with callbacks:
|
||||
|
||||
```javascript
|
||||
var oracledb = require('oracledb');
|
||||
|
@ -90,6 +95,8 @@ With Oracle's sample HR schema, the output is:
|
|||
[ [ 60, 'IT' ], [ 90, 'Executive' ], [ 100, 'Finance' ] ]
|
||||
```
|
||||
|
||||
Node Promises can also be used.
|
||||
|
||||
## <a name="doc"></a> Documentation
|
||||
|
||||
See [Documentation for the Oracle Database Node.js Add-on](https://github.com/oracle/node-oracledb/tree/master/doc/api.md).
|
||||
|
@ -98,9 +105,9 @@ See [Documentation for the Oracle Database Node.js Add-on](https://github.com/or
|
|||
|
||||
See [CHANGELOG](https://github.com/oracle/node-oracledb/tree/master/CHANGELOG.md)
|
||||
|
||||
## <a name="testing"></a> Testsuite
|
||||
## <a name="testing"></a> Test Suite
|
||||
|
||||
To run the included testsuite see [test/README](https://github.com/oracle/node-oracledb/tree/master/test/README.md).
|
||||
To run the included test suite see [test/README](https://github.com/oracle/node-oracledb/tree/master/test/README.md).
|
||||
|
||||
## <a name="contrib"></a> Contributing
|
||||
|
||||
|
|
712
doc/api.md
712
doc/api.md
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,59 @@
|
|||
/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* NAME
|
||||
* promises.js
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Executes a basic query using promises instead of the callback pattern.
|
||||
*
|
||||
* Scripts to create the HR schema can be found at:
|
||||
* https://github.com/oracle/db-sample-schemas
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
var oracledb = require('oracledb');
|
||||
var dbConfig = require('./dbconfig.js');
|
||||
|
||||
oracledb.getConnection(
|
||||
{
|
||||
user : dbConfig.user,
|
||||
password : dbConfig.password,
|
||||
connectString : dbConfig.connectString
|
||||
})
|
||||
.then(function(connection) {
|
||||
return connection.execute(
|
||||
"SELECT department_id, department_name " +
|
||||
"FROM departments " +
|
||||
"WHERE department_id = :did",
|
||||
[180]
|
||||
)
|
||||
.then(function(result) {
|
||||
console.log(result.metaData);
|
||||
console.log(result.rows);
|
||||
|
||||
return connection.release();
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.log(err.message);
|
||||
|
||||
return connection.release();
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.error(err.message);
|
||||
});
|
|
@ -19,7 +19,9 @@
|
|||
* refcursor.js
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Shows using a Result Set to fetch rows from a REF CURSOR
|
||||
* Shows using a ResultSet to fetch rows from a REF CURSOR using getRows().
|
||||
* Streaming is also possible (this is not shown).
|
||||
*
|
||||
* Uses Oracle's sample HR schema.
|
||||
* Use demo.sql to create the required procedure or do:
|
||||
*
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* NAME
|
||||
* refcursortoquerystream.js
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Converts a refcursor (returned from execute) to a query stream for an
|
||||
* alternative means of processing instead of using resultSet.getRows().
|
||||
*
|
||||
* Scripts to create the HR schema can be found at:
|
||||
* https://github.com/oracle/db-sample-schemas
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
var oracledb = require('oracledb');
|
||||
var dbConfig = require('./dbconfig.js');
|
||||
|
||||
oracledb.getConnection(
|
||||
{
|
||||
user : dbConfig.user,
|
||||
password : dbConfig.password,
|
||||
connectString : dbConfig.connectString
|
||||
},
|
||||
function(err, connection) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
connection.execute(
|
||||
"BEGIN"
|
||||
+ " OPEN :cursor FOR SELECT department_id, department_name FROM departments;"
|
||||
+ "END;",
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir : oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
var cursor;
|
||||
var queryStream;
|
||||
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
doRelease(connection);
|
||||
return;
|
||||
}
|
||||
|
||||
cursor = result.outBinds.cursor;
|
||||
queryStream = cursor.toQueryStream();
|
||||
|
||||
queryStream.on('data', function (row) {
|
||||
console.log(row);
|
||||
});
|
||||
|
||||
queryStream.on('error', function (err) {
|
||||
console.error(err.message);
|
||||
doRelease(connection);
|
||||
});
|
||||
|
||||
queryStream.on('end', function () {
|
||||
doRelease(connection);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function doRelease(connection) {
|
||||
connection.release(
|
||||
function(err) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
|
@ -0,0 +1,83 @@
|
|||
/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* NAME
|
||||
* resultsettoquerystream.js
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Converts a ResultSet returned from execute() into a Readable Stream.
|
||||
* This is an alternative instead of using resultset.getRows().
|
||||
* Note: using connnection.queryStream() is recommended for top level
|
||||
* queries because it avoids having to duplicate error handling in the
|
||||
* callback and event.
|
||||
*
|
||||
* Scripts to create the HR schema can be found at:
|
||||
* https://github.com/oracle/db-sample-schemas
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
var oracledb = require('oracledb');
|
||||
var dbConfig = require('./dbconfig.js');
|
||||
|
||||
oracledb.getConnection(
|
||||
dbConfig,
|
||||
function(err, connection)
|
||||
{
|
||||
if (err) { console.error(err.message); return; }
|
||||
var sql = "SELECT employee_id, last_name FROM employees WHERE ROWNUM < 25 ORDER BY employee_id";
|
||||
connection.execute(
|
||||
sql,
|
||||
[],
|
||||
{
|
||||
resultSet: true,
|
||||
prefetchRows: 25
|
||||
},
|
||||
function(err, result)
|
||||
{
|
||||
if (err)
|
||||
{
|
||||
console.error(err.message);
|
||||
doRelease(connection);
|
||||
return;
|
||||
}
|
||||
var queryStream = result.resultSet.toQueryStream();
|
||||
|
||||
queryStream.on('data', function(row) {
|
||||
console.log(row);
|
||||
});
|
||||
|
||||
queryStream.on('error', function(err) {
|
||||
console.error(err.message);
|
||||
doRelease(connection);
|
||||
});
|
||||
|
||||
queryStream.on('end', function() {
|
||||
doRelease(connection);
|
||||
});
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
function doRelease(connection)
|
||||
{
|
||||
connection.release(
|
||||
function(err)
|
||||
{
|
||||
if (err) { console.error(err.message); }
|
||||
});
|
||||
}
|
|
@ -32,107 +32,108 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
var http = require('http');
|
||||
var http = require('http');
|
||||
var oracledb = require('oracledb');
|
||||
var dbConfig = require('./dbconfig.js');
|
||||
|
||||
var portid = 7000; // HTTP listening port number
|
||||
var httpPort = 7000;
|
||||
|
||||
// Main entry point. Creates a connection pool, on callback creates an
|
||||
// HTTP server and executes a query based on the URL parameter given.
|
||||
// HTTP server that executes a query based on the URL parameter given.
|
||||
// The pool values shown are the default values.
|
||||
oracledb.createPool (
|
||||
{
|
||||
user : dbConfig.user,
|
||||
password : dbConfig.password,
|
||||
connectString : dbConfig.connectString,
|
||||
poolMax : 4, // maximum size of the pool
|
||||
poolMin : 0, // let the pool shrink completely
|
||||
poolIncrement : 1, // only grow the pool by one connection at a time
|
||||
poolTimeout : 0 // never terminate idle connections
|
||||
},
|
||||
function(err, pool)
|
||||
{
|
||||
function init() {
|
||||
oracledb.createPool(
|
||||
{
|
||||
user: dbConfig.user,
|
||||
password: dbConfig.password,
|
||||
connectString: dbConfig.connectString,
|
||||
poolMax: 4, // maximum size of the pool
|
||||
poolMin: 0, // let the pool shrink completely
|
||||
poolIncrement: 1, // only grow the pool by one connection at a time
|
||||
poolTimeout: 0 // never terminate idle connections
|
||||
},
|
||||
function(err, pool) {
|
||||
if (err) {
|
||||
console.error("createPool() error: " + err.message);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create HTTP server and listen on port - httpPort
|
||||
http
|
||||
.createServer(function(request, response) {
|
||||
handleRequest(request, response, pool);
|
||||
})
|
||||
.listen(httpPort, "localhost");
|
||||
|
||||
console.log("Server running at http://localhost:" + httpPort);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
function handleRequest(request, response, pool) {
|
||||
var urlparts = request.url.split("/");
|
||||
var deptid = urlparts[1];
|
||||
|
||||
htmlHeader(
|
||||
response,
|
||||
"Oracle Database Driver for Node.js",
|
||||
"Example using node-oracledb driver"
|
||||
);
|
||||
|
||||
if (deptid != parseInt(deptid)) {
|
||||
handleError(
|
||||
response,
|
||||
'URL path "' + deptid + '" is not an integer. Try http://localhost:' + httpPort + '/30',
|
||||
null
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Checkout a connection from the pool
|
||||
pool.getConnection(function(err, connection) {
|
||||
if (err) {
|
||||
console.error("createPool() callback: " + err.message);
|
||||
handleError(response, "getConnection() error", err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Create HTTP server and listen on port - portid
|
||||
var hs = http.createServer (
|
||||
function(request, response) // Callback gets HTTP request & response object
|
||||
{
|
||||
var urlparts = request.url.split("/");
|
||||
var deptid = urlparts[1];
|
||||
// console.log("Connections open: " + pool.connectionsOpen);
|
||||
// console.log("Connections in use: " + pool.connectionsInUse);
|
||||
|
||||
htmlHeader(response,
|
||||
"Oracle Database Driver for Node.js" ,
|
||||
"Example using node-oracledb driver");
|
||||
|
||||
if (deptid != parseInt(deptid)) {
|
||||
handleError(response, 'URL path "' + deptid +
|
||||
'" is not an integer. Try http://localhost:' + portid + '/30', null);
|
||||
connection.execute(
|
||||
"SELECT employee_id, first_name, last_name " +
|
||||
"FROM employees " +
|
||||
"WHERE department_id = :id",
|
||||
[deptid], // bind variable value
|
||||
function(err, result) {
|
||||
if (err) {
|
||||
connection.release(function(err) {
|
||||
if (err) {
|
||||
// Just logging because handleError call below will have already
|
||||
// ended the response.
|
||||
console.error("execute() error release() error", err);
|
||||
}
|
||||
});
|
||||
handleError(response, "execute() error", err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Checkout a connection from the pool
|
||||
pool.getConnection (
|
||||
function(err, connection)
|
||||
{
|
||||
if (err) {
|
||||
handleError(response, "getConnection() failed ", err);
|
||||
return;
|
||||
}
|
||||
displayResults(response, result, deptid);
|
||||
|
||||
// console.log("Connections open: " + pool.connectionsOpen);
|
||||
// console.log("Connections in use: " + pool.connectionsInUse);
|
||||
|
||||
connection.execute(
|
||||
"SELECT employee_id, first_name, last_name " +
|
||||
"FROM employees " +
|
||||
"WHERE department_id = :id",
|
||||
[deptid], // bind variable value
|
||||
function(err, result)
|
||||
{
|
||||
if (err) {
|
||||
connection.release(
|
||||
function(err)
|
||||
{
|
||||
if (err) {
|
||||
handleError(response, "execute() error release() callback", err);
|
||||
return;
|
||||
}
|
||||
});
|
||||
handleError(response, "execute() callback", err);
|
||||
return;
|
||||
}
|
||||
|
||||
displayResults(response, result, deptid);
|
||||
|
||||
/* Release the connection back to the connection pool */
|
||||
connection.release(
|
||||
function(err)
|
||||
{
|
||||
if (err) {
|
||||
handleError(response, "normal release() callback", err);
|
||||
} else {
|
||||
htmlFooter(response);
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
hs.listen(portid, "localhost");
|
||||
|
||||
console.log("Server running at http://localhost:" + portid);
|
||||
/* Release the connection back to the connection pool */
|
||||
connection.release(function(err) {
|
||||
if (err) {
|
||||
handleError(response, "normal release() error", err);
|
||||
} else {
|
||||
htmlFooter(response);
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
// Report an error
|
||||
function handleError(response, text, err)
|
||||
{
|
||||
function handleError(response, text, err) {
|
||||
if (err) {
|
||||
text += err.message;
|
||||
}
|
||||
|
@ -141,10 +142,8 @@ function handleError(response, text, err)
|
|||
htmlFooter(response);
|
||||
}
|
||||
|
||||
|
||||
// Display query results
|
||||
function displayResults(response, result, deptid)
|
||||
{
|
||||
function displayResults(response, result, deptid) {
|
||||
response.write("<h2>" + "Employees in Department " + deptid + "</h2>");
|
||||
response.write("<table>");
|
||||
|
||||
|
@ -166,40 +165,38 @@ function displayResults(response, result, deptid)
|
|||
response.write("</table>");
|
||||
}
|
||||
|
||||
|
||||
// Prepare HTML header
|
||||
function htmlHeader(response, title, caption)
|
||||
{
|
||||
response.writeHead (200, {"Content-Type" : "text/html" });
|
||||
response.write ("<!DOCTYPE html>");
|
||||
response.write ("<html>");
|
||||
response.write ("<head>");
|
||||
response.write ("<style>" +
|
||||
"body {background:#FFFFFF;color:#000000;font-family:Arial,sans-serif;margin:40px;padding:10px;font-size:12px;text-align:center;}" +
|
||||
"h1 {margin:0px;margin-bottom:12px;background:#FF0000;text-align:center;color:#FFFFFF;font-size:28px;}" +
|
||||
"table {border-collapse: collapse; margin-left:auto; margin-right:auto;}" +
|
||||
"td {padding:8px;border-style:solid}" +
|
||||
"</style>\n");
|
||||
response.write ("<title>" + caption + "</title>");
|
||||
response.write ("</head>");
|
||||
response.write ("<body>");
|
||||
response.write ("<h1>" + title + "</h1>");
|
||||
function htmlHeader(response, title, caption) {
|
||||
response.writeHead(200, {"Content-Type": "text/html"});
|
||||
response.write("<!DOCTYPE html>");
|
||||
response.write("<html>");
|
||||
response.write("<head>");
|
||||
response.write("<style>" +
|
||||
"body {background:#FFFFFF;color:#000000;font-family:Arial,sans-serif;margin:40px;padding:10px;font-size:12px;text-align:center;}" +
|
||||
"h1 {margin:0px;margin-bottom:12px;background:#FF0000;text-align:center;color:#FFFFFF;font-size:28px;}" +
|
||||
"table {border-collapse: collapse; margin-left:auto; margin-right:auto;}" +
|
||||
"td {padding:8px;border-style:solid}" +
|
||||
"</style>\n");
|
||||
response.write("<title>" + caption + "</title>");
|
||||
response.write("</head>");
|
||||
response.write("<body>");
|
||||
response.write("<h1>" + title + "</h1>");
|
||||
}
|
||||
|
||||
|
||||
// Prepare HTML footer
|
||||
function htmlFooter(response)
|
||||
{
|
||||
function htmlFooter(response) {
|
||||
response.write("</body>\n</html>");
|
||||
response.end();
|
||||
}
|
||||
|
||||
process
|
||||
.on('SIGTERM', function() {
|
||||
console.log("\nTerminating");
|
||||
process.exit(0);
|
||||
})
|
||||
.on('SIGINT', function() {
|
||||
console.log("\nTerminating");
|
||||
process.exit(0);
|
||||
});
|
||||
.on('SIGTERM', function() {
|
||||
console.log("\nTerminating");
|
||||
process.exit(0);
|
||||
})
|
||||
.on('SIGINT', function() {
|
||||
console.log("\nTerminating");
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
init();
|
||||
|
|
|
@ -0,0 +1,195 @@
|
|||
/* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* NAME
|
||||
* webapppromises.js
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Shows a web based query using connections from connection pool. This is
|
||||
* similar to webapp.js but uses promises.
|
||||
*
|
||||
* This displays a table of employees in the specified department.
|
||||
*
|
||||
* The script creates an HTTP server listening on port 7000 and
|
||||
* accepts a URL parameter for the department ID, for example:
|
||||
* http://localhost:7000/90
|
||||
*
|
||||
* Uses Oracle's sample HR schema. Scripts to create the HR schema
|
||||
* can be found at: https://github.com/oracle/db-sample-schemas
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
var http = require('http');
|
||||
var oracledb = require('oracledb');
|
||||
var dbConfig = require('./dbconfig.js');
|
||||
var httpPort = 7000;
|
||||
|
||||
// Main entry point. Creates a connection pool, on callback creates an
|
||||
// HTTP server that executes a query based on the URL parameter given.
|
||||
// The pool values shown are the default values.
|
||||
function init() {
|
||||
oracledb.createPool({
|
||||
user: dbConfig.user,
|
||||
password: dbConfig.password,
|
||||
connectString: dbConfig.connectString,
|
||||
poolMax: 4, // maximum size of the pool
|
||||
poolMin: 0, // let the pool shrink completely
|
||||
poolIncrement: 1, // only grow the pool by one connection at a time
|
||||
poolTimeout: 0 // never terminate idle connections
|
||||
})
|
||||
.then(function(pool) {
|
||||
// Create HTTP server and listen on port - httpPort
|
||||
http
|
||||
.createServer(function(request, response) {
|
||||
handleRequest(request, response, pool);
|
||||
})
|
||||
.listen(httpPort, "localhost");
|
||||
|
||||
console.log("Server running at http://localhost:" + httpPort);
|
||||
})
|
||||
.catch(function(err) {
|
||||
console.error("createPool() error: " + err.message);
|
||||
});
|
||||
}
|
||||
|
||||
function handleRequest(request, response, pool) {
|
||||
var urlparts = request.url.split("/");
|
||||
var deptid = urlparts[1];
|
||||
|
||||
htmlHeader(
|
||||
response,
|
||||
"Oracle Database Driver for Node.js",
|
||||
"Example using node-oracledb driver"
|
||||
);
|
||||
|
||||
if (deptid != parseInt(deptid)) {
|
||||
handleError(
|
||||
response,
|
||||
'URL path "' + deptid + '" is not an integer. Try http://localhost:' + httpPort + '/30',
|
||||
null
|
||||
);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Checkout a connection from the pool
|
||||
pool.getConnection()
|
||||
.then(function(connection) {
|
||||
// console.log("Connections open: " + pool.connectionsOpen);
|
||||
// console.log("Connections in use: " + pool.connectionsInUse);
|
||||
|
||||
connection.execute(
|
||||
"SELECT employee_id, first_name, last_name " +
|
||||
"FROM employees " +
|
||||
"WHERE department_id = :id",
|
||||
[deptid] // bind variable value
|
||||
)
|
||||
.then(function(result) {
|
||||
displayResults(response, result, deptid);
|
||||
|
||||
/* Release the connection back to the connection pool */
|
||||
connection.release()
|
||||
.then(function() {
|
||||
htmlFooter(response);
|
||||
})
|
||||
.catch(function(err) {
|
||||
handleError(response, "normal release() error", err);
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
connection.release()
|
||||
.catch(function(err) {
|
||||
// Just logging because handleError call below will have already
|
||||
// ended the response.
|
||||
console.error("execute() error release() error", err);
|
||||
});
|
||||
handleError(response, "execute() error", err);
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
handleError(response, "getConnection() error", err);
|
||||
});
|
||||
}
|
||||
|
||||
// Report an error
|
||||
function handleError(response, text, err) {
|
||||
if (err) {
|
||||
text += err.message;
|
||||
}
|
||||
console.error(text);
|
||||
response.write("<p>Error: " + text + "</p>");
|
||||
htmlFooter(response);
|
||||
}
|
||||
|
||||
// Display query results
|
||||
function displayResults(response, result, deptid) {
|
||||
response.write("<h2>" + "Employees in Department " + deptid + "</h2>");
|
||||
response.write("<table>");
|
||||
|
||||
// Column Title
|
||||
response.write("<tr>");
|
||||
for (var col = 0; col < result.metaData.length; col++) {
|
||||
response.write("<td>" + result.metaData[col].name + "</td>");
|
||||
}
|
||||
response.write("</tr>");
|
||||
|
||||
// Rows
|
||||
for (var row = 0; row < result.rows.length; row++) {
|
||||
response.write("<tr>");
|
||||
for (col = 0; col < result.rows[row].length; col++) {
|
||||
response.write("<td>" + result.rows[row][col] + "</td>");
|
||||
}
|
||||
response.write("</tr>");
|
||||
}
|
||||
response.write("</table>");
|
||||
}
|
||||
|
||||
// Prepare HTML header
|
||||
function htmlHeader(response, title, caption) {
|
||||
response.writeHead(200, {"Content-Type": "text/html"});
|
||||
response.write("<!DOCTYPE html>");
|
||||
response.write("<html>");
|
||||
response.write("<head>");
|
||||
response.write("<style>" +
|
||||
"body {background:#FFFFFF;color:#000000;font-family:Arial,sans-serif;margin:40px;padding:10px;font-size:12px;text-align:center;}" +
|
||||
"h1 {margin:0px;margin-bottom:12px;background:#FF0000;text-align:center;color:#FFFFFF;font-size:28px;}" +
|
||||
"table {border-collapse: collapse; margin-left:auto; margin-right:auto;}" +
|
||||
"td {padding:8px;border-style:solid}" +
|
||||
"</style>\n");
|
||||
response.write("<title>" + caption + "</title>");
|
||||
response.write("</head>");
|
||||
response.write("<body>");
|
||||
response.write("<h1>" + title + "</h1>");
|
||||
}
|
||||
|
||||
// Prepare HTML footer
|
||||
function htmlFooter(response) {
|
||||
response.write("</body>\n</html>");
|
||||
response.end();
|
||||
}
|
||||
|
||||
process
|
||||
.on('SIGTERM', function() {
|
||||
console.log("\nTerminating");
|
||||
process.exit(0);
|
||||
})
|
||||
.on('SIGINT', function() {
|
||||
console.log("\nTerminating");
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
init();
|
|
@ -17,16 +17,49 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
var resultset = require('./resultset.js');
|
||||
var Stream = require('./resultset-read-stream');
|
||||
var QueryStream = require('./querystream.js');
|
||||
var nodbUtil = require('./util.js');
|
||||
var executePromisified;
|
||||
var commitPromisified;
|
||||
var rollbackPromisified;
|
||||
var releasePromisified;
|
||||
var breakPromisified;
|
||||
|
||||
// The queryStream function is similar to execute except that it immediately
|
||||
// returns a readable stream.
|
||||
// returns a QueryStream.
|
||||
function queryStream(sql, binding, options) {
|
||||
var self = this;
|
||||
var stream;
|
||||
|
||||
stream = new Stream(self, sql, binding, options);
|
||||
nodbUtil.assert(arguments.length > 0 && arguments.length < 4, 'NJS-009');
|
||||
nodbUtil.assert(typeof sql === 'string', 'NJS-006', 1);
|
||||
|
||||
if (binding) {
|
||||
nodbUtil.assert(nodbUtil.isObjectOrArray(binding), 'NJS-006', 2);
|
||||
}
|
||||
|
||||
if (options) {
|
||||
nodbUtil.assert(nodbUtil.isObject(options), 'NJS-006', 3);
|
||||
}
|
||||
|
||||
binding = binding || [];
|
||||
options = options || {};
|
||||
|
||||
options.resultSet = true;
|
||||
|
||||
stream = new QueryStream(null, self._oracledb);
|
||||
|
||||
self._execute(sql, binding, options, function(err, result) {
|
||||
if (err) {
|
||||
stream._open(err, null);
|
||||
} else {
|
||||
resultset.extend(result.resultSet, self._oracledb);
|
||||
stream._open(null, result.resultSet);
|
||||
}
|
||||
});
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
@ -39,24 +72,45 @@ function execute(a1, a2, a3, a4) {
|
|||
var executeCb;
|
||||
var custExecuteCb;
|
||||
|
||||
// Added this check so that node doesn't hang if no arguments are passed.
|
||||
if (arguments.length < 2 || arguments.length > 4) {
|
||||
if (arguments.length && typeof arguments[arguments.length - 1] === 'function') {
|
||||
arguments[arguments.length - 1](new Error('NJS-009: invalid number of parameters'));
|
||||
return;
|
||||
} else {
|
||||
throw new Error('NJS-009: invalid number of parameters');
|
||||
}
|
||||
nodbUtil.assert(arguments.length > 1 && arguments.length < 5, 'NJS-009');
|
||||
nodbUtil.assert(typeof a1 === 'string', 'NJS-006', 1);
|
||||
|
||||
switch (arguments.length) {
|
||||
case 2:
|
||||
nodbUtil.assert(typeof a2 === 'function', 'NJS-006', 2);
|
||||
break;
|
||||
case 3:
|
||||
nodbUtil.assert(nodbUtil.isObjectOrArray(a2), 'NJS-006', 2);
|
||||
nodbUtil.assert(typeof a3 === 'function', 'NJS-006', 3);
|
||||
break;
|
||||
case 4:
|
||||
nodbUtil.assert(nodbUtil.isObjectOrArray(a2), 'NJS-006', 2);
|
||||
nodbUtil.assert(nodbUtil.isObject(a3), 'NJS-006', 3);
|
||||
nodbUtil.assert(typeof a4 === 'function', 'NJS-006', 4);
|
||||
break;
|
||||
}
|
||||
|
||||
custExecuteCb = function(err, result) {
|
||||
var outBindsKeys;
|
||||
var outBindsIdx;
|
||||
|
||||
if (err) {
|
||||
executeCb(err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Need to extend resultsets which may come from either the query results
|
||||
// or outBinds.
|
||||
if (result.resultSet) {
|
||||
resultset.extend(result.resultSet);
|
||||
resultset.extend(result.resultSet, self._oracledb);
|
||||
} else if (result.outBinds) {
|
||||
outBindsKeys = Object.keys(result.outBinds);
|
||||
|
||||
for (outBindsIdx = 0; outBindsIdx < outBindsKeys.length; outBindsIdx += 1) {
|
||||
if (result.outBinds[outBindsKeys[outBindsIdx]] instanceof self._oracledb.ResultSet) {
|
||||
resultset.extend(result.outBinds[outBindsKeys[outBindsIdx]], self._oracledb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
executeCb(null, result);
|
||||
|
@ -78,20 +132,32 @@ function execute(a1, a2, a3, a4) {
|
|||
}
|
||||
}
|
||||
|
||||
executePromisified = nodbUtil.promisify(execute);
|
||||
|
||||
// This commit function is just a place holder to allow for easier extension later.
|
||||
function commit() {
|
||||
function commit(commitCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof commitCb === 'function', 'NJS-006', 1);
|
||||
|
||||
self._commit.apply(self, arguments);
|
||||
}
|
||||
|
||||
commitPromisified = nodbUtil.promisify(commit);
|
||||
|
||||
// This rollback function is just a place holder to allow for easier extension later.
|
||||
function rollback() {
|
||||
function rollback(rollbackCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof rollbackCb === 'function', 'NJS-006', 1);
|
||||
|
||||
self._rollback.apply(self, arguments);
|
||||
}
|
||||
|
||||
rollbackPromisified = nodbUtil.promisify(rollback);
|
||||
|
||||
// This release function is used to override the release method of the Connection
|
||||
// class, which is defined in the C layer. Currently the main difference is that
|
||||
// connections obtained from a pool need to invoke the pool's _onConnectionRelease
|
||||
|
@ -99,26 +165,38 @@ function rollback() {
|
|||
function release(releaseCb) {
|
||||
var self = this;
|
||||
|
||||
// _pool will only exist on connections obtained from a pool.
|
||||
if (self._pool && self._pool.queueRequests !== false) {
|
||||
self._release(function(err) {
|
||||
releaseCb(err);
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof releaseCb === 'function', 'NJS-006', 1);
|
||||
|
||||
self._release(function(err) {
|
||||
releaseCb(err);
|
||||
|
||||
// pool will only exist for connections obtained from a pool.
|
||||
if (self._pool && self._pool.queueRequests !== false) {
|
||||
self._pool._onConnectionRelease();
|
||||
});
|
||||
} else {
|
||||
self._release(releaseCb);
|
||||
}
|
||||
}
|
||||
|
||||
// Need to maintain a reference to the connection instance to ensure that the
|
||||
// garbage collector doesn't destroy it too soon.
|
||||
self = undefined;
|
||||
});
|
||||
}
|
||||
|
||||
releasePromisified = nodbUtil.promisify(release);
|
||||
|
||||
// This release function is just a place holder to allow for easier extension later.
|
||||
// It's attached to the module as break is a reserved word.
|
||||
module.break = function() {
|
||||
module.break = function(breakCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof breakCb === 'function', 'NJS-006', 1);
|
||||
|
||||
self._break.apply(self, arguments);
|
||||
};
|
||||
|
||||
breakPromisified = nodbUtil.promisify(module.break);
|
||||
|
||||
// The extend method is used to extend the Connection instance from the C layer with
|
||||
// custom properties and method overrides. References to the original methods are
|
||||
// maintained so they can be invoked by the overriding method at the right time.
|
||||
|
@ -143,7 +221,7 @@ function extend(conn, oracledb, pool) {
|
|||
writable: true
|
||||
},
|
||||
execute: {
|
||||
value: execute,
|
||||
value: executePromisified,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -151,7 +229,7 @@ function extend(conn, oracledb, pool) {
|
|||
value: conn.commit
|
||||
},
|
||||
commit: {
|
||||
value: commit,
|
||||
value: commitPromisified,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -159,7 +237,7 @@ function extend(conn, oracledb, pool) {
|
|||
value: conn.rollback
|
||||
},
|
||||
rollback: {
|
||||
value: rollback,
|
||||
value: rollbackPromisified,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -167,7 +245,12 @@ function extend(conn, oracledb, pool) {
|
|||
value: conn.release
|
||||
},
|
||||
release: {
|
||||
value: release,
|
||||
value: releasePromisified,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
close: { // alias for release
|
||||
value: releasePromisified,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -175,7 +258,7 @@ function extend(conn, oracledb, pool) {
|
|||
value: conn.break
|
||||
},
|
||||
break: {
|
||||
value: module.break,
|
||||
value: breakPromisified,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
}
|
||||
|
|
|
@ -17,6 +17,8 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
var Duplex = require('stream').Duplex;
|
||||
var util = require('util');
|
||||
|
||||
|
|
|
@ -17,11 +17,16 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
var oracledbCLib;
|
||||
var oracledbInst;
|
||||
var Lob = require('./lob.js').Lob;
|
||||
var pool = require('./pool.js');
|
||||
var connection = require('./connection.js');
|
||||
var nodbUtil = require('./util.js');
|
||||
var createPoolPromisified;
|
||||
var getConnectionPromisified;
|
||||
|
||||
try {
|
||||
oracledbCLib = require('../build/Release/oracledb');
|
||||
|
@ -43,6 +48,10 @@ oracledbCLib.Oracledb.prototype.newLob = function(iLob) {
|
|||
function createPool(poolAttrs, createPoolCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 2, 'NJS-009');
|
||||
nodbUtil.assert(nodbUtil.isObject(poolAttrs), 'NJS-006', 1);
|
||||
nodbUtil.assert(typeof createPoolCb === 'function', 'NJS-006', 2);
|
||||
|
||||
self._createPool(poolAttrs, function(err, poolInst) {
|
||||
if (err) {
|
||||
createPoolCb(err);
|
||||
|
@ -51,16 +60,22 @@ function createPool(poolAttrs, createPoolCb) {
|
|||
|
||||
pool.extend(poolInst, poolAttrs, self);
|
||||
|
||||
createPoolCb(undefined, poolInst);
|
||||
createPoolCb(null, poolInst);
|
||||
});
|
||||
}
|
||||
|
||||
createPoolPromisified = nodbUtil.promisify(createPool);
|
||||
|
||||
// This getConnection function is used the override the getConnection method of the
|
||||
// Oracledb class, which is defined in the C layer. The override allows us to do
|
||||
// things like extend out the connection instance prior to passing it to the caller.
|
||||
function getConnection(connAttrs, createConnectionCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 2, 'NJS-009');
|
||||
nodbUtil.assert(nodbUtil.isObject(connAttrs), 'NJS-006', 1);
|
||||
nodbUtil.assert(typeof createConnectionCb === 'function', 'NJS-006', 2);
|
||||
|
||||
self._getConnection(connAttrs, function(err, connInst) {
|
||||
if (err) {
|
||||
createConnectionCb(err);
|
||||
|
@ -69,10 +84,12 @@ function getConnection(connAttrs, createConnectionCb) {
|
|||
|
||||
connection.extend(connInst, self);
|
||||
|
||||
createConnectionCb(undefined, connInst);
|
||||
createConnectionCb(null, connInst);
|
||||
});
|
||||
}
|
||||
|
||||
getConnectionPromisified = nodbUtil.promisify(getConnection);
|
||||
|
||||
// The extend method is used to extend the Oracledb instance from the C layer with
|
||||
// custom properties and method overrides. References to the original methods are
|
||||
// maintained so they can be invoked by the overriding method at the right time.
|
||||
|
@ -83,6 +100,9 @@ function extend(oracledb) {
|
|||
Object.defineProperties(
|
||||
oracledb,
|
||||
{
|
||||
_oracledb: { // Known to be used in util.js' promisify function.
|
||||
value: oracledb
|
||||
},
|
||||
DEFAULT: {
|
||||
value: 0,
|
||||
enumerable: true
|
||||
|
@ -135,6 +155,11 @@ function extend(oracledb) {
|
|||
value: 4002,
|
||||
enumerable: true
|
||||
},
|
||||
Promise: {
|
||||
value: global.Promise,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
Oracledb: {
|
||||
value: oracledbCLib.Oracledb,
|
||||
enumerable: true
|
||||
|
@ -169,7 +194,7 @@ function extend(oracledb) {
|
|||
value: oracledb.createPool
|
||||
},
|
||||
createPool: {
|
||||
value: createPool,
|
||||
value: createPoolPromisified,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -177,7 +202,7 @@ function extend(oracledb) {
|
|||
value: oracledb.getConnection
|
||||
},
|
||||
getConnection: {
|
||||
value: getConnection,
|
||||
value: getConnectionPromisified,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
}
|
||||
|
@ -185,7 +210,7 @@ function extend(oracledb) {
|
|||
);
|
||||
}
|
||||
|
||||
oracledbInst = new oracledbCLib.Oracledb;
|
||||
oracledbInst = new oracledbCLib.Oracledb();
|
||||
|
||||
extend(oracledbInst);
|
||||
|
||||
|
|
73
lib/pool.js
73
lib/pool.js
|
@ -17,7 +17,12 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
var connection = require('./connection.js');
|
||||
var nodbUtil = require('./util.js');
|
||||
var getConnectionPromisified;
|
||||
var terminatePromisified;
|
||||
|
||||
// completeConnectionRequest does the actual work of getting a connection from a
|
||||
// pool when queuing is enabled. It's abstracted out so it can be called from
|
||||
|
@ -50,7 +55,7 @@ function completeConnectionRequest(getConnectionCb) {
|
|||
|
||||
connection.extend(connInst, self._oracledb, self);
|
||||
|
||||
getConnectionCb(undefined, connInst);
|
||||
getConnectionCb(null, connInst);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -119,7 +124,7 @@ function onRequestTimeout(timerIdx) {
|
|||
self._connRequestQueue.splice(requestIndex, 1);
|
||||
self._connRequestTimersMap[timerIdx] = null;
|
||||
|
||||
payloadToDequeue.getConnectionCb(new Error('NJS-040: connection request timeout'));
|
||||
payloadToDequeue.getConnectionCb(new Error(nodbUtil.getErrorMessage('NJS-040')));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -134,6 +139,9 @@ function getConnection(getConnectionCb) {
|
|||
var timeoutHandle;
|
||||
var timerIdx;
|
||||
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof getConnectionCb === 'function', 'NJS-006', 1);
|
||||
|
||||
// Added this check because if the pool isn't valid and we reference self.poolMax
|
||||
// (which is a C layer getter) an error will be thrown.
|
||||
if (!self._isValid) {
|
||||
|
@ -150,21 +158,21 @@ function getConnection(getConnectionCb) {
|
|||
}
|
||||
|
||||
if (self.queueRequests === false) { // queueing is disabled for pool
|
||||
if (self._enableStats) {
|
||||
self._getConnection(function(err, connInst) {
|
||||
if (err) {
|
||||
self._getConnection(function(err, connInst) {
|
||||
if (err) {
|
||||
if (self._enableStats) {
|
||||
self._totalFailedRequests += 1;
|
||||
|
||||
getConnectionCb(err);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
getConnectionCb(null, connInst);
|
||||
});
|
||||
} else {
|
||||
self._getConnection(getConnectionCb);
|
||||
}
|
||||
getConnectionCb(err);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
connection.extend(connInst, self._oracledb, self);
|
||||
|
||||
getConnectionCb(null, connInst);
|
||||
});
|
||||
} else if (self._connectionsOut < self.poolMax) { // queueing enabled, but not needed
|
||||
completeConnectionRequest.call(self, getConnectionCb);
|
||||
} else { // need to queue the request
|
||||
|
@ -200,10 +208,14 @@ function getConnection(getConnectionCb) {
|
|||
}
|
||||
}
|
||||
|
||||
getConnectionPromisified = nodbUtil.promisify(getConnection);
|
||||
|
||||
function terminate(terminateCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof terminateCb === 'function', 'NJS-006', 1);
|
||||
|
||||
self._terminate(function(err) {
|
||||
if (!err) {
|
||||
self._isValid = false;
|
||||
|
@ -213,6 +225,8 @@ function terminate(terminateCb) {
|
|||
});
|
||||
}
|
||||
|
||||
terminatePromisified = nodbUtil.promisify(terminate);
|
||||
|
||||
// logStats is used to add a hidden method (_logStats) to each pool instance. This
|
||||
// provides an easy way to log out the statistics related information that's collected
|
||||
// when _enableStats is set to true when creating a pool. This functionality may
|
||||
|
@ -290,13 +304,23 @@ function extend(pool, poolAttrs, oracledb) {
|
|||
_oracledb: { // storing a reference to the base instance to avoid circular references with require
|
||||
value: oracledb
|
||||
},
|
||||
queueRequests: {
|
||||
value: queueRequests, // true will queue requests when conn pool is maxed out
|
||||
enumerable: true
|
||||
queueRequests: { // true will queue requests when conn pool is maxed out
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return queueRequests;
|
||||
},
|
||||
set: function() {
|
||||
throw new Error(nodbUtil.getErrorMessage('NJS-014', 'queueRequests'));
|
||||
}
|
||||
},
|
||||
queueTimeout: {
|
||||
value: queueTimeout, // milliseconds a connection request can spend in queue before being failed
|
||||
enumerable: true
|
||||
queueTimeout: { // milliseconds a connection request can spend in queue before being failed
|
||||
enumerable: true,
|
||||
get: function() {
|
||||
return queueTimeout;
|
||||
},
|
||||
set: function() {
|
||||
throw new Error(nodbUtil.getErrorMessage('NJS-014', 'queueTimeout'));
|
||||
}
|
||||
},
|
||||
_isValid: { // used to ensure operations are not done after terminate
|
||||
value: true,
|
||||
|
@ -373,7 +397,7 @@ function extend(pool, poolAttrs, oracledb) {
|
|||
value: pool.getConnection
|
||||
},
|
||||
getConnection: {
|
||||
value: getConnection,
|
||||
value: getConnectionPromisified,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -381,7 +405,12 @@ function extend(pool, poolAttrs, oracledb) {
|
|||
value: pool.terminate
|
||||
},
|
||||
terminate: {
|
||||
value: terminate,
|
||||
value: terminatePromisified,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
close: { // alias for terminate
|
||||
value: terminatePromisified,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
}
|
||||
|
|
|
@ -0,0 +1,230 @@
|
|||
/* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
var util = require('util');
|
||||
var Readable = require('stream').Readable;
|
||||
|
||||
// This class was originally based on https://github.com/sagiegurari/simple-oracledb/blob/master/lib/resultset-read-stream.js
|
||||
function QueryStream(resultSet, oracledb) {
|
||||
var self = this;
|
||||
|
||||
Object.defineProperties(
|
||||
self,
|
||||
{
|
||||
_oracledb: { // storing a reference to the base instance to avoid circular references with require
|
||||
value: oracledb
|
||||
},
|
||||
_resultSet: {
|
||||
value: resultSet,
|
||||
writable: true
|
||||
},
|
||||
_fetchedRows: { // a local cache of rows fetched from a call to resultSet.getRows
|
||||
value: [],
|
||||
writable: true
|
||||
},
|
||||
_fetchedAllRows: { // used to avoid an unnecessary call to resultSet.getRows
|
||||
value: false,
|
||||
writable: true
|
||||
},
|
||||
_fetching: { // used to serialize method calls on the resultset
|
||||
value: false,
|
||||
writable: true
|
||||
},
|
||||
_closed: { // used to track that the stream is closed
|
||||
value: false,
|
||||
writable: true
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
Readable.call(self, {
|
||||
objectMode: true
|
||||
});
|
||||
|
||||
if (self._resultSet) { // If true, no need to invoke _open, we are ready to go.
|
||||
self.emit('metadata', self._resultSet.metaData);
|
||||
|
||||
self.emit('open');
|
||||
}
|
||||
}
|
||||
|
||||
util.inherits(QueryStream, Readable);
|
||||
|
||||
// The _open method is only meant to be called when a QueryStream is created
|
||||
// but not passed in the resultSet during initialization. In those cases the
|
||||
// QueryStream object will have been returned immediately and the _open method
|
||||
// will be called later to pass the resultset (or error getting the resultset)
|
||||
// along.
|
||||
QueryStream.prototype._open = function(err, rs) {
|
||||
var self = this;
|
||||
|
||||
if (err) {
|
||||
self.emit('error', err);
|
||||
return;
|
||||
}
|
||||
|
||||
self._resultSet = rs;
|
||||
|
||||
self.emit('metadata', self._resultSet.metaData);
|
||||
|
||||
// Trigger the event listener that may have been added in _read now that the
|
||||
// resultset is ready.
|
||||
self.emit('open');
|
||||
};
|
||||
|
||||
// The stream _read implementation which fetches the next row from the resultset.
|
||||
QueryStream.prototype._read = function () {
|
||||
var self = this;
|
||||
var fetchCount;
|
||||
|
||||
if (!self._resultSet) {
|
||||
// Still waiting on the resultset, add an event listener to retry when ready
|
||||
return self.once('open', function() {
|
||||
self._read();
|
||||
});
|
||||
}
|
||||
|
||||
if (self._closed) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (self._fetchedRows.length) {
|
||||
// We have rows already fetched that need to be pushed
|
||||
self.push(self._fetchedRows.shift());
|
||||
} else if (self._fetchedAllRows) {
|
||||
// Calling the C layer close directly to avoid assertions on the public method
|
||||
self._resultSet._close(function(err) {
|
||||
if (err) {
|
||||
self.emit('error', err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Signal the end of the stream
|
||||
self.push(null);
|
||||
});
|
||||
} else {
|
||||
// Using _fetching to indicate that the resultset is working to avoid potential
|
||||
// errors related to close w/conncurrent operations on resultsets
|
||||
self._fetching = true;
|
||||
|
||||
fetchCount = self._oracledb.maxRows || 100;
|
||||
|
||||
// Calling the C layer getRows directly to avoid assertions on the public method
|
||||
self._resultSet._getRows(fetchCount, function(err, rows) {
|
||||
if (err) {
|
||||
// We'll return the error from getRows, but first try to close the resultSet.
|
||||
self._resultSet.close(function() {});
|
||||
|
||||
self.emit('error', err);
|
||||
return;
|
||||
}
|
||||
|
||||
self._fetching = false;
|
||||
|
||||
// Close may have been called while the resultset was fetching.
|
||||
if (self._closed) {
|
||||
// Trigger the event listener that may have been added in close now that
|
||||
// the resultset has finished working.
|
||||
self.emit('_doneFetching');
|
||||
return;
|
||||
}
|
||||
|
||||
self._fetchedRows = rows;
|
||||
|
||||
if (self._fetchedRows.length < fetchCount) {
|
||||
self._fetchedAllRows = true;
|
||||
}
|
||||
|
||||
if (self._fetchedRows.length) {
|
||||
self.push(self._fetchedRows.shift());
|
||||
} else { // No more rows to fetch
|
||||
// Calling the C layer close directly to avoid assertions on the public method
|
||||
self._resultSet._close(function(err) {
|
||||
if (err) {
|
||||
self.emit('error', err);
|
||||
return;
|
||||
}
|
||||
|
||||
// Signal the end of the stream
|
||||
self.push(null);
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// The close method is not a standard method on stream instances in Node.js but
|
||||
// it was added to provide developers with a means of stopping the flow of data
|
||||
// and closing the stream without having to allow the entire resultset to finish
|
||||
// streaming.
|
||||
function close(callback) {
|
||||
var self = this;
|
||||
|
||||
// Setting _closed early to prevent _read invocations from being processed and
|
||||
// to allow _doneFetching to be emitted if needed.
|
||||
self._closed = true;
|
||||
|
||||
if (!self.isPaused()) {
|
||||
self.pause();
|
||||
}
|
||||
|
||||
// We can't close the resultset if it's currently fetching. Add a listener
|
||||
// to call close when the resulset is done fetching.
|
||||
if (self._fetching) {
|
||||
self.once('_doneFetching', function() {
|
||||
self._close(callback);
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
self.once('close', callback);
|
||||
}
|
||||
|
||||
// It's possible for close to be called very early, even before the resultset
|
||||
// has been set via _open (if needed).
|
||||
if (!self._resultSet) {
|
||||
self.emit('close');
|
||||
} else {
|
||||
// Calling the C layer close directly to avoid assertions on the public method
|
||||
self._resultSet._close(function(err) {
|
||||
if (err) {
|
||||
self.emit('error', err);
|
||||
return;
|
||||
}
|
||||
|
||||
self.emit('close');
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Exposing close as a private method for now.
|
||||
Object.defineProperty(
|
||||
QueryStream.prototype,
|
||||
'_close',
|
||||
{
|
||||
value: close,
|
||||
writable: true
|
||||
}
|
||||
);
|
||||
|
||||
module.exports = QueryStream;
|
|
@ -1,121 +0,0 @@
|
|||
/* Copyright (c) 2015, 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
var util = require('util');
|
||||
var stream = require('stream');
|
||||
var Readable = stream.Readable;
|
||||
var resultset = require('./resultset.js');
|
||||
|
||||
// A node.js read stream for resultsets (based on https://github.com/sagiegurari/simple-oracledb/blob/master/lib/resultset-read-stream.js).
|
||||
function ResultSetReadStream(conn, sql, binding, options) {
|
||||
var self = this;
|
||||
|
||||
binding = binding || [];
|
||||
options = options || {};
|
||||
|
||||
options.resultSet = true;
|
||||
|
||||
self.streamNumRows = conn._oracledb.maxRows || 100;
|
||||
|
||||
Readable.call(self, {
|
||||
objectMode: true
|
||||
});
|
||||
|
||||
Object.defineProperty(self, 'nextRow', {
|
||||
// Sets the nextRow value.
|
||||
set: function (nextRow) {
|
||||
self.next = nextRow;
|
||||
|
||||
if (self.inRead) {
|
||||
self._read();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
conn._execute(sql, binding, options, function(err, result) {
|
||||
self._onExecuteDone(err, result);
|
||||
});
|
||||
}
|
||||
|
||||
util.inherits(ResultSetReadStream, Readable);
|
||||
|
||||
// The stream _read implementation which fetches the next row from the resultset.
|
||||
ResultSetReadStream.prototype._read = function () {
|
||||
var self = this;
|
||||
|
||||
self.inRead = false;
|
||||
|
||||
if (self.next) {
|
||||
self.next(function onNextRowRead(error, data) {
|
||||
if (error) {
|
||||
self.emit('error', error);
|
||||
} else if (data) {
|
||||
self.push(data);
|
||||
} else {
|
||||
self.push(null);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
self.inRead = true;
|
||||
}
|
||||
};
|
||||
|
||||
ResultSetReadStream.prototype._onExecuteDone = function(err, result) {
|
||||
var self = this;
|
||||
|
||||
if (err) {
|
||||
self.nextRow = function emitError(streamCallback) {
|
||||
streamCallback(err);
|
||||
};
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
resultset.extend(result.resultSet);
|
||||
|
||||
self.emit('metadata', result.resultSet.metaData);
|
||||
|
||||
var close = function (streamCallback, causeError) {
|
||||
result.resultSet.close(function onClose(closeError) {
|
||||
streamCallback(causeError || closeError);
|
||||
});
|
||||
};
|
||||
|
||||
var readRows;
|
||||
|
||||
self.nextRow = function fetchNextRow(streamCallback) {
|
||||
if (readRows && readRows.length) {
|
||||
streamCallback(null, readRows.shift());
|
||||
} else {
|
||||
result.resultSet.getRows(self.streamNumRows, function onRow(rowError, rows) {
|
||||
if (rowError) {
|
||||
close(streamCallback, rowError);
|
||||
} else if ((!rows) || (!rows.length)) {
|
||||
close(streamCallback);
|
||||
} else {
|
||||
readRows = rows;
|
||||
|
||||
streamCallback(null, readRows.shift());
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = ResultSetReadStream;
|
106
lib/resultset.js
106
lib/resultset.js
|
@ -17,41 +17,126 @@
|
|||
*
|
||||
*****************************************************************************/
|
||||
|
||||
'use strict';
|
||||
|
||||
var QueryStream = require('./querystream.js');
|
||||
var nodbUtil = require('./util.js');
|
||||
var closePromisified;
|
||||
var getRowPromisified;
|
||||
var getRowsPromisified;
|
||||
|
||||
// This close function is just a place holder to allow for easier extension later.
|
||||
function close() {
|
||||
function close(closeCb) {
|
||||
var self = this;
|
||||
|
||||
self._close.apply(self, arguments);
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof closeCb === 'function', 'NJS-006', 1);
|
||||
|
||||
if (self._convertedToStream) {
|
||||
closeCb(new Error(nodbUtil.getErrorMessage('NJS-042')));
|
||||
return;
|
||||
}
|
||||
|
||||
self._processingStarted = true;
|
||||
|
||||
self._close(function(err) {
|
||||
// Need to maintain a reference to the resultset instance to ensure that the
|
||||
// garbage collector doesn't destroy it too soon.
|
||||
self = undefined;
|
||||
|
||||
closeCb(err);
|
||||
});
|
||||
}
|
||||
|
||||
closePromisified = nodbUtil.promisify(close);
|
||||
|
||||
// This getRow function is just a place holder to allow for easier extension later.
|
||||
function getRow() {
|
||||
function getRow(getRowCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 1, 'NJS-009');
|
||||
nodbUtil.assert(typeof getRowCb === 'function', 'NJS-006', 1);
|
||||
|
||||
if (self._convertedToStream) {
|
||||
getRowCb(new Error(nodbUtil.getErrorMessage('NJS-042')));
|
||||
return;
|
||||
}
|
||||
|
||||
self._processingStarted = true;
|
||||
|
||||
self._getRow.apply(self, arguments);
|
||||
}
|
||||
|
||||
getRowPromisified = nodbUtil.promisify(getRow);
|
||||
|
||||
// This getRows function is just a place holder to allow for easier extension later.
|
||||
function getRows() {
|
||||
function getRows(numRows, getRowsCb) {
|
||||
var self = this;
|
||||
|
||||
nodbUtil.assert(arguments.length === 2, 'NJS-009');
|
||||
nodbUtil.assert(typeof numRows === 'number', 'NJS-006', 1);
|
||||
nodbUtil.assert(typeof getRowsCb === 'function', 'NJS-006', 2);
|
||||
|
||||
if (self._convertedToStream) {
|
||||
getRowsCb(new Error(nodbUtil.getErrorMessage('NJS-042')));
|
||||
return;
|
||||
}
|
||||
|
||||
self._processingStarted = true;
|
||||
|
||||
self._getRows.apply(self, arguments);
|
||||
}
|
||||
|
||||
getRowsPromisified = nodbUtil.promisify(getRows);
|
||||
|
||||
function toQueryStream() {
|
||||
var self = this;
|
||||
var stream;
|
||||
|
||||
nodbUtil.assert(arguments.length === 0, 'NJS-009');
|
||||
|
||||
if (self._processingStarted) {
|
||||
throw new Error(nodbUtil.getErrorMessage('NJS-041'));
|
||||
return;
|
||||
}
|
||||
|
||||
if (self._convertedToStream) {
|
||||
throw new Error(nodbUtil.getErrorMessage('NJS-043'));
|
||||
return;
|
||||
}
|
||||
|
||||
self._convertedToStream = true;
|
||||
|
||||
stream = new QueryStream(self, self._oracledb);
|
||||
|
||||
return stream;
|
||||
}
|
||||
|
||||
// The extend method is used to extend the ResultSet instance from the C layer with
|
||||
// custom properties and method overrides. References to the original methods are
|
||||
// maintained so they can be invoked by the overriding method at the right time.
|
||||
function extend(resultSet) {
|
||||
function extend(resultSet, oracledb) {
|
||||
// Using Object.defineProperties to add properties to the ResultSet instance with
|
||||
// special properties, such as enumerable but not writable.
|
||||
Object.defineProperties(
|
||||
resultSet,
|
||||
{
|
||||
_oracledb: { // storing a reference to the base instance to avoid circular references with require
|
||||
value: oracledb
|
||||
},
|
||||
_processingStarted: { // used to prevent conversion to stream after invoking methods
|
||||
value: false,
|
||||
writable: true
|
||||
},
|
||||
_convertedToStream: { // used to prevent invoking methods after conversion to stream
|
||||
value: false,
|
||||
writable: true
|
||||
},
|
||||
_close: {
|
||||
value: resultSet.close
|
||||
},
|
||||
close: {
|
||||
value: close,
|
||||
value: closePromisified,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -59,7 +144,7 @@ function extend(resultSet) {
|
|||
value: resultSet.getRow
|
||||
},
|
||||
getRow: {
|
||||
value: getRow,
|
||||
value: getRowPromisified,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
|
@ -67,7 +152,12 @@ function extend(resultSet) {
|
|||
value: resultSet.getRows
|
||||
},
|
||||
getRows: {
|
||||
value: getRows,
|
||||
value: getRowsPromisified,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
},
|
||||
toQueryStream: {
|
||||
value: toQueryStream,
|
||||
enumerable: true,
|
||||
writable: true
|
||||
}
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
var util = require('util');
|
||||
|
||||
// errorMessages is a temporary duplication of error messages defined in the C
|
||||
// layer that will be removed once a function to fetch from the C layer is added.
|
||||
var errorMessages = {
|
||||
'NJS-005': 'NJS-005: invalid value for parameter %d',
|
||||
'NJS-006': 'NJS-006: invalid type for parameter %d',
|
||||
'NJS-009': 'NJS-009: invalid number of parameters',
|
||||
'NJS-014': 'NJS-014: %s is a read-only property',
|
||||
'NJS-037': 'NJS-037: incompatible type of value provided',
|
||||
'NJS-040': 'NJS-040: connection request timeout',
|
||||
'NJS-041': 'NJS-041: cannot convert ResultSet to QueryStream after invoking methods',
|
||||
'NJS-042': 'NJS-042: cannot invoke ResultSet methods after converting to QueryStream',
|
||||
'NJS-043': "NJS-043: ResultSet already converted to QueryStream"
|
||||
};
|
||||
|
||||
// getErrorMessage is used to get and format error messages to make throwing errors
|
||||
// a little more convenient.
|
||||
function getErrorMessage(errorCode, messageArg1) {
|
||||
if (messageArg1) {
|
||||
return util.format(errorMessages[errorCode], messageArg1);
|
||||
} else {
|
||||
return util.format(errorMessages[errorCode]);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.getErrorMessage = getErrorMessage;
|
||||
|
||||
// assert it typically used in the beginning of public functions to assert preconditions
|
||||
// for the function to execute. Most commonly it's used to validate arguments lenght
|
||||
// and types and throw an error if they don't match what is expected.
|
||||
function assert(condition, errorCode, messageArg1) {
|
||||
if (!condition) {
|
||||
throw new Error(getErrorMessage(errorCode, messageArg1));
|
||||
}
|
||||
}
|
||||
|
||||
module.exports.assert = assert;
|
||||
|
||||
// The promisify function is used to wrap async methods to add optional promise
|
||||
// support. If the last parameter passed to a method is a function, then it is
|
||||
// assumed that the callback pattern is being used and the method is invoked as
|
||||
// usual. Otherwise a promise is returned and later resolved or rejected based on
|
||||
// the return of the method.
|
||||
function promisify(func) {
|
||||
return function() {
|
||||
var self = this;
|
||||
var args;
|
||||
|
||||
// This/self could refer to the base class instance, pool, connection, etc. All
|
||||
// class instances have a private reference to the base class for convenience.
|
||||
if (!self._oracledb.Promise || typeof arguments[arguments.length - 1] === 'function') {
|
||||
return func.apply(self, arguments);
|
||||
} else {
|
||||
// Converting to an array so we can extend it later with a custom callback
|
||||
args = Array.prototype.slice.call(arguments);
|
||||
|
||||
return new self._oracledb.Promise(function(resolve, reject) {
|
||||
var errorCode;
|
||||
|
||||
try {
|
||||
args[args.length] = function(err, result) {
|
||||
if (err) {
|
||||
reject(err);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
};
|
||||
|
||||
func.apply(self, args);
|
||||
} catch (err) {
|
||||
errorCode = err.message.substr(0, 7);
|
||||
|
||||
// Check for invalid number or type of parameter(s) as they should be
|
||||
// eagerly thrown.
|
||||
if (errorCode === 'NJS-009' || errorCode === 'NJS-006') {
|
||||
// Throwing the error outside of the promise wrapper so that its not
|
||||
// swallowed up as a rejection.
|
||||
process.nextTick(function() {
|
||||
throw err;
|
||||
});
|
||||
} else {
|
||||
reject(err);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
module.exports.promisify = promisify;
|
||||
|
||||
function isObject(value) {
|
||||
return value !== null && typeof value === 'object';
|
||||
}
|
||||
|
||||
module.exports.isObject = isObject;
|
||||
|
||||
function isObjectOrArray(value) {
|
||||
return (value !== null && typeof value === 'object') || Array.isArray(value);
|
||||
}
|
||||
|
||||
module.exports.isObjectOrArray = isObjectOrArray;
|
10
package.json
10
package.json
|
@ -33,19 +33,19 @@
|
|||
"url": "git://github.com/oracle/node-oracledb.git"
|
||||
},
|
||||
"dependencies": {
|
||||
"nan": "~2.2.0"
|
||||
"nan": "~2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"mocha": "~2.2.5",
|
||||
"should": "~6.0.1",
|
||||
"async": "~0.9.0"
|
||||
"mocha": "^2.4.5",
|
||||
"should": "^8.3.1",
|
||||
"async": "^1.5.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "mocha -R spec --timeout 10000 test/*.js",
|
||||
"testWindows": "mocha -R spec --timeout 0 test\\*.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.28 <6"
|
||||
"node": ">=0.10.28 <7"
|
||||
},
|
||||
"maintainers": [
|
||||
{
|
||||
|
|
|
@ -2599,7 +2599,7 @@ void Connection::Async_AfterExecute(uv_work_t *req)
|
|||
Nan::New<v8::String>("outBinds").ToLocalChecked(),
|
||||
outBindValue,
|
||||
v8::ReadOnly);
|
||||
|
||||
|
||||
Nan::Set(result, Nan::New<v8::String>("rowsAffected").ToLocalChecked(), Nan::Undefined());
|
||||
|
||||
Nan::Set(result, Nan::New<v8::String>("rows").ToLocalChecked(), Nan::Undefined());
|
||||
|
|
|
@ -1038,7 +1038,7 @@ NAN_METHOD(ILob::Write)
|
|||
/* If iLob is invalid from JS, then throw an exception */
|
||||
NJS_CHECK_OBJECT_VALID2 ( iLob, info );
|
||||
|
||||
LobBaton *lobBaton = new LobBaton ( iLob->njsconn_->LOBCount (),
|
||||
LobBaton *lobBaton = new LobBaton ( iLob->njsconn_->LOBCount (),
|
||||
buffer_obj, callback );
|
||||
|
||||
NJS_CHECK_NUMBER_OF_ARGS (lobBaton->error, info, 2, 2, exitWrite);
|
||||
|
|
|
@ -53,19 +53,19 @@ static const char *errMsg[] =
|
|||
"NJS-014: %s is a read-only property", // errReadOnly
|
||||
"NJS-015: type was not specified for conversion", // errNoTypeForConversion
|
||||
"NJS-016: buffer is too small for OUT binds", // errInsufficientBufferForBinds
|
||||
"NJS-017: concurrent operations on resultSet are not allowed", // errBusyResultSet
|
||||
"NJS-018: invalid result set", // errInvalidResultSet
|
||||
"NJS-019: resultSet cannot be returned for non-query statements", // errInvalidNonQueryExecution
|
||||
"NJS-017: concurrent operations on ResultSet are not allowed", // errBusyResultSet
|
||||
"NJS-018: invalid ResultSet", // errInvalidResultSet
|
||||
"NJS-019: ResultSet cannot be returned for non-query statements", // errInvalidNonQueryExecution
|
||||
"NJS-020: empty array was specified to fetch values as string", // errEmptyArrayForFetchAs
|
||||
"NJS-021: invalid type for conversion specified", // errInvalidTypeForConversion
|
||||
"NJS-022: invalid LOB", // errInvalidLob
|
||||
"NJS-022: invalid Lob", // errInvalidLob
|
||||
"NJS-023: concurrent operations on LOB are not allowed", // errBusyLob
|
||||
"NJS-024: memory allocation failed", // errInsufficientMemory
|
||||
"NJS-025: overflow when calculating results area size", // errResultsTooLarge
|
||||
"NJS-026: maxRows must be greater than zero", // errInvalidmaxRows
|
||||
"NJS-027: unexpected SQL parsing error", // errSQLSyntaxError
|
||||
"NJS-028: raw database type is not supported with DML Returning statements", // errBufferReturningInvalid
|
||||
"NJS-029: Invalid object from javascript", // errInvalidJSObject
|
||||
"NJS-029: invalid object from JavaScript", // errInvalidJSObject
|
||||
"NJS-030: connection cannot be released because Lob operations are in progress", // errBusyConnLOB
|
||||
"NJS-031: connection cannot be released because ResultSet operations are in progress", // errBusyConnRS
|
||||
"NJS-032: connection cannot be released because a database call is in progress", // errBusyConnDB
|
||||
|
@ -77,10 +77,9 @@ static const char *errMsg[] =
|
|||
"NJS-038: maxArraySize value should be greater than 0", // errInvalidValueArrayBind
|
||||
"NJS-039: empty array is not allowed for IN bind", // errEmptyArray
|
||||
"NJS-040: connection request timeout", // errConnRequestTimeout
|
||||
"NJS-041: error used in JS layer 41",
|
||||
"NJS-042: error used in JS Layer 42",
|
||||
"NJS-043: error used in JS Layer 43",
|
||||
|
||||
"NJS-041: cannot convert ResultSet to QueryStream after invoking methods", // errCannotConvertRsToStream
|
||||
"NJS-042: cannot invoke ResultSet methods after converting to QueryStream", // errCannotInvokeRsMethods
|
||||
"NJS-043: ResultSet already converted to QueryStream", // errResultSetAlreadyConverted
|
||||
};
|
||||
|
||||
string NJSMessages::getErrorMsg ( NJSErrorType err, ... )
|
||||
|
|
|
@ -76,9 +76,9 @@ typedef enum
|
|||
errInvalidValueArrayBind,
|
||||
errEmptyArray,
|
||||
errConnRequestTimeout,
|
||||
errUsedInJS41,
|
||||
errUsedInJS42,
|
||||
errUsedInJS43,
|
||||
errCannotConvertRsToStream,
|
||||
errCannotInvokeRsMethods,
|
||||
errResultSetAlreadyConverted,
|
||||
|
||||
// New ones should be added here
|
||||
|
||||
|
|
|
@ -718,7 +718,6 @@ describe('1. connection.js', function(){
|
|||
|
||||
describe('1.6 Testing parameter assertions', function() {
|
||||
var conn1;
|
||||
var sql = 'select 1 from dual';
|
||||
|
||||
beforeEach('get connection ready', function(done) {
|
||||
oracledb.getConnection(credential, function(err, conn) {
|
||||
|
@ -735,37 +734,173 @@ describe('1. connection.js', function(){
|
|||
});
|
||||
});
|
||||
|
||||
it('1.6.1 too few params without a callback should throw error', function(done) {
|
||||
it('1.6.1 too few params should throw an error', function(done) {
|
||||
// This test returns a promise because the last parameter to execute is not
|
||||
// a function. Normally, errors thrown in a promise would be directed to
|
||||
// to a catch handler. In the case of an "accidental promise" the error
|
||||
// could go undetected. Because of this, the promisify function in util.js
|
||||
// uses process.nextTick to throw invalid number or type of params (NJS-009
|
||||
// and NJS-006). This test has been updated to account for this behavior.
|
||||
var promiseSupportEnabled = oracledb.Promise !== undefined;
|
||||
var listeners = process.listeners('uncaughtException');
|
||||
|
||||
if (promiseSupportEnabled) {
|
||||
process.removeAllListeners('uncaughtException');
|
||||
|
||||
process.once('uncaughtException', function(err) {
|
||||
listeners.forEach(function(listener) {
|
||||
process.on('uncaughtException', listener);
|
||||
});
|
||||
|
||||
should.exist(err);
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
// Using try catch for instances where promises are not supported or have
|
||||
// been disabled by setting oracledb.Promise to something falsey.
|
||||
try {
|
||||
conn1.execute(sql);
|
||||
conn1.execute();
|
||||
} catch (err) {
|
||||
if (promiseSupportEnabled) {
|
||||
listeners.forEach(function(listener) {
|
||||
process.on('uncaughtException', listener);
|
||||
});
|
||||
}
|
||||
|
||||
should.exist(err);
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('1.6.2 too few params with a callback should pass error in callback', function(done) {
|
||||
conn1.execute(function(err, result) {
|
||||
should.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
it('1.6.2 too many params should throw error', function(done) {
|
||||
// This test returns a promise because the last parameter to execute is not
|
||||
// a function. Normally, errors thrown in a promise would be directed to
|
||||
// to a catch handler. In the case of an "accidental promise" the error
|
||||
// could go undetected. Because of this, the promisify function in util.js
|
||||
// uses process.nextTick to throw invalid number or type of params (NJS-009
|
||||
// and NJS-006). This test has been updated to account for this behavior.
|
||||
var promiseSupportEnabled = oracledb.Promise !== undefined;
|
||||
var listeners = process.listeners('uncaughtException');
|
||||
|
||||
it('1.6.3 too many params without a callback should throw error', function(done) {
|
||||
if (promiseSupportEnabled) {
|
||||
process.removeAllListeners('uncaughtException');
|
||||
|
||||
process.once('uncaughtException', function(err) {
|
||||
listeners.forEach(function(listener) {
|
||||
process.on('uncaughtException', listener);
|
||||
});
|
||||
|
||||
should.exist(err);
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
// Using try catch for instances where promises are not supported or have
|
||||
// been disabled by setting oracledb.Promise to something falsey.
|
||||
try {
|
||||
conn1.execute(1, 2, 3, 4, 5);
|
||||
} catch (err) {
|
||||
if (promiseSupportEnabled) {
|
||||
listeners.forEach(function(listener) {
|
||||
process.on('uncaughtException', listener);
|
||||
});
|
||||
}
|
||||
should.exist(err);
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('1.6.3 wrong type for param 1 should throw an error', function(done) {
|
||||
// Don't need to listen for unhandledRejection because a promise will not
|
||||
// be returned as the last param is a function.
|
||||
try {
|
||||
conn1.execute(1, function() {});
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('1.6.4 too many params with a callback should pass error in callback', function(done) {
|
||||
conn1.execute(1, 2, 3, 4, function(err, result) {
|
||||
it('1.6.4 wrong type for param 2 should throw an error', function(done) {
|
||||
// This test returns a promise because the last parameter to execute is not
|
||||
// a function. Normally, errors thrown in a promise would be directed to
|
||||
// to a catch handler. In the case of an "accidental promise" the error
|
||||
// could go undetected. Because of this, the promisify function in util.js
|
||||
// uses process.nextTick to throw invalid number or type of params (NJS-009
|
||||
// and NJS-006). This test has been updated to account for this behavior.
|
||||
var promiseSupportEnabled = oracledb.Promise !== undefined;
|
||||
var listeners = process.listeners('uncaughtException');
|
||||
|
||||
if (promiseSupportEnabled) {
|
||||
process.removeAllListeners('uncaughtException');
|
||||
|
||||
process.once('uncaughtException', function(err) {
|
||||
listeners.forEach(function(listener) {
|
||||
process.on('uncaughtException', listener);
|
||||
});
|
||||
|
||||
should.exist(err);
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
|
||||
// Using try catch for instances where promises are not supported or have
|
||||
// been disabled by setting oracledb.Promise to something falsey.
|
||||
try {
|
||||
conn1.execute('select 1 from dual', 1);
|
||||
} catch (err) {
|
||||
if (promiseSupportEnabled) {
|
||||
listeners.forEach(function(listener) {
|
||||
process.on('uncaughtException', listener);
|
||||
});
|
||||
}
|
||||
|
||||
should.exist(err);
|
||||
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('1.6.5 wrong type for param 3 should throw an error', function(done) {
|
||||
// Don't need to listen for unhandledRejection because a promise will not
|
||||
// be returned as the last param is a function.
|
||||
try {
|
||||
conn1.execute('select 1 from dual', 1, function() {});
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
done();
|
||||
}
|
||||
});
|
||||
|
||||
it('1.6.6 wrong type for param 4 should throw an error', function(done) {
|
||||
// Don't need to listen for unhandledRejection because a promise will not
|
||||
// be returned as the last param is a function.
|
||||
try {
|
||||
conn1.execute('select 1 from dual', {}, 1, function() {});
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
done();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
describe('1.7 Close method', function() {
|
||||
it('1.7.1 close can be used as an alternative to release', function(done) {
|
||||
oracledb.getConnection(credential, function(err, conn) {
|
||||
should.not.exist(err);
|
||||
|
||||
conn.close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
});
|
||||
|
||||
})
|
||||
});
|
||||
|
|
|
@ -18,6 +18,15 @@
|
|||
1.5 Testing commit() & rollback() functions
|
||||
1.5.1 commit() function works well
|
||||
1.5.2 rollback() function works well
|
||||
1.6 Testing parameter assertions
|
||||
1.6.1 too few params should throw an error
|
||||
1.6.2 too many params should throw error
|
||||
1.6.3 wrong type for param 1 should throw an error
|
||||
1.6.4 wrong type for param 2 should throw an error
|
||||
1.6.5 wrong type for param 3 should throw an error
|
||||
1.6.6 wrong type for param 4 should throw an error
|
||||
1.7 Close method
|
||||
1.7.1 close can be used as an alternative to release
|
||||
|
||||
2. pool.js
|
||||
2.1 default values
|
||||
|
@ -57,6 +66,8 @@
|
|||
2.8.4 does not generate NJS-040 if request is queued for less time than queueTimeout
|
||||
2.9 connection request queue (_enableStats & _logStats functionality)_logStats must be called prior to terminating pool.
|
||||
2.9.1 works after the pool as been terminated
|
||||
2.10 Close method
|
||||
2.10.1 close can be used as an alternative to release
|
||||
|
||||
|
||||
3. examples.js
|
||||
|
@ -226,7 +237,7 @@
|
|||
12.7.2 maxRows option is ignored with REF Cursor
|
||||
|
||||
13. stream.js
|
||||
13.1 Testing ResultSet stream
|
||||
13.1 Testing QueryStream
|
||||
13.1.1 stream results for oracle connection
|
||||
13.1.2 stream results for oracle connection (outFormat: oracledb.OBJECT)
|
||||
13.1.3 errors in query
|
||||
|
@ -238,6 +249,13 @@
|
|||
13.1.9 Read CLOBs after stream close
|
||||
13.1.10 meta data
|
||||
13.1.11 stream stress test
|
||||
13.2 Testing QueryStream._close
|
||||
13.2.1 should be able to stop the stream early with _close
|
||||
13.2.2 should be able to stop the stream before any data
|
||||
13.2.3 should invoke an optional callback passed to _close
|
||||
13.3 Testing QueryStream\'s maxRows control
|
||||
13.3.1 should use oracledb.maxRows for fetching
|
||||
13.3.2 should default to 100 if oracledb.maxRows is falsey
|
||||
|
||||
14. stream2.js
|
||||
14.1 Bind by position and return an array
|
||||
|
@ -248,7 +266,32 @@
|
|||
14.6 maxRows option is ignored as expect
|
||||
14.7 Negative - queryStream() has no parameters
|
||||
14.8 Negative - give invalid SQL as first parameter
|
||||
14.9 Negatvie - give non-query SQL
|
||||
14.9 Negative - give non-query SQL
|
||||
|
||||
15. resultsetToQueryStream.js
|
||||
15.1 Testing ResultSet.toQueryStream
|
||||
15.1.1 should allow resultsets to be converted to streams
|
||||
15.2 Testing ResultSet/QueryStream conversion errors
|
||||
15.2.1 should prevent conversion to stream after getRow is invoked
|
||||
15.2.2 should prevent conversion to stream after getRows is invoked
|
||||
15.2.3 should prevent conversion to stream after close is invoked
|
||||
15.2.4 should prevent invoking getRow after conversion to stream
|
||||
15.2.5 should prevent invoking getRows after conversion to stream
|
||||
15.2.6 should prevent invoking close after conversion to stream
|
||||
15.2.7 should prevent calling toQueryStream more than once
|
||||
|
||||
16. promises.js
|
||||
16.1 returns a promise from oracledb.getConnection
|
||||
16.2 returns a promise from oracledb.createPool
|
||||
16.3 returns a promise from pool.terminate
|
||||
16.4 returns a promise from pool.getConnection
|
||||
16.5 returns a promise from connection.release
|
||||
16.6 returns a promise from connection.execute
|
||||
16.7 returns a promise from connection.commit
|
||||
16.8 returns a promise form connection.rollback
|
||||
16.9 returns a promise from resultSet.close
|
||||
16.10 returns a promise from resultSet.getRow
|
||||
16.11 returns a promise from resultSet.getRows
|
||||
|
||||
21. datatypeAssist.js
|
||||
|
||||
|
|
34
test/pool.js
34
test/pool.js
|
@ -640,12 +640,14 @@ describe('2. pool.js', function(){
|
|||
);
|
||||
});
|
||||
|
||||
it('2.7.1 throws error if called after pool is terminated and a callback is not provided', function(done) {
|
||||
// Skipping this test because assertions were added to the JS layer for all
|
||||
// public methods. This now throws NJS-009: invalid number of parameters.
|
||||
it.skip('2.7.1 throws error if called after pool is terminated and a callback is not provided', function(done) {
|
||||
pool1.terminate(function(err) {
|
||||
should.not.exist(err);
|
||||
|
||||
try {
|
||||
pool1.getConnection(1);
|
||||
pool1.getConnection();
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
(err.message).should.startWith('NJS-002: invalid pool');
|
||||
|
@ -953,4 +955,30 @@ describe('2. pool.js', function(){
|
|||
);
|
||||
});
|
||||
});
|
||||
})
|
||||
|
||||
describe('2.10 Close method', function(){
|
||||
it('2.10.1 close can be used as an alternative to release', function(done) {
|
||||
oracledb.createPool(
|
||||
{
|
||||
externalAuth : credential.externalAuth,
|
||||
user : credential.user,
|
||||
password : credential.password,
|
||||
connectString : credential.connectString,
|
||||
poolMin : 0,
|
||||
poolMax : 1,
|
||||
poolIncrement : 1,
|
||||
poolTimeout : 1
|
||||
},
|
||||
function(err, pool){
|
||||
should.not.exist(err);
|
||||
|
||||
pool.close(function(err) {
|
||||
should.not.exist(err);
|
||||
|
||||
done();
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,339 @@
|
|||
/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* The node-oracledb test suite uses 'mocha', 'should' and 'async'.
|
||||
* See LICENSE.md for relevant licenses.
|
||||
*
|
||||
* NAME
|
||||
* 16. promises.js
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Promise tests.
|
||||
*
|
||||
* NUMBERING RULE
|
||||
* Test numbers follow this numbering rule:
|
||||
* 1 - 20 are reserved for basic functional tests
|
||||
* 21 - 50 are reserved for data type supporting tests
|
||||
* 51 onwards are for other tests
|
||||
*
|
||||
*****************************************************************************/
|
||||
'use strict';
|
||||
|
||||
var oracledb = require('oracledb');
|
||||
var should = require('should');
|
||||
var async = require('async');
|
||||
var dbConfig = require('./dbconfig.js');
|
||||
|
||||
// Need to skip these tests if Promises are not supported
|
||||
var it = (oracledb.Promise) ? global.it : global.it.skip;
|
||||
|
||||
describe('16. promises.js', function(){
|
||||
|
||||
it('16.1 returns a promise from oracledb.getConnection', function(done) {
|
||||
var promise = oracledb.getConnection(dbConfig);
|
||||
|
||||
promise.should.be.an.instanceof(oracledb.Promise);
|
||||
|
||||
promise
|
||||
.then(function(conn) {
|
||||
conn.should.be.ok;
|
||||
conn.release(function(err) {
|
||||
if (err)
|
||||
return done(err);
|
||||
else
|
||||
return done();
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.2 returns a promise from oracledb.createPool', function(done) {
|
||||
var promise = oracledb.createPool(dbConfig);
|
||||
|
||||
promise.should.be.an.instanceof(oracledb.Promise);
|
||||
|
||||
promise
|
||||
.then(function(pool) {
|
||||
pool.should.be.ok;
|
||||
pool.terminate(function(err) {
|
||||
if (err)
|
||||
return done(err);
|
||||
else
|
||||
return done();
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.3 returns a promise from pool.terminate', function(done) {
|
||||
oracledb.createPool(dbConfig)
|
||||
.then(function(pool) {
|
||||
pool.should.be.ok;
|
||||
var promise = pool.terminate();
|
||||
promise.should.be.an.instanceof(oracledb.Promise);
|
||||
return promise;
|
||||
})
|
||||
.then(function() {
|
||||
return done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.4 returns a promise from pool.getConnection', function(done) {
|
||||
oracledb.createPool(dbConfig)
|
||||
.then(function(pool) {
|
||||
pool.should.be.ok;
|
||||
var getConnPromise = pool.getConnection();
|
||||
getConnPromise.should.be.an.instanceof(oracledb.Promise);
|
||||
getConnPromise
|
||||
.then(function(conn) {
|
||||
conn.release(function(err) {
|
||||
if (err) {
|
||||
return done(err);
|
||||
}
|
||||
|
||||
pool.terminate()
|
||||
.then(function() {
|
||||
return done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.5 returns a promise from connection.release', function(done) {
|
||||
oracledb.getConnection(dbConfig)
|
||||
.then(function(conn) {
|
||||
conn.should.be.ok;
|
||||
var promise = conn.release();
|
||||
promise.should.be.an.instanceof(oracledb.Promise);
|
||||
return promise;
|
||||
})
|
||||
.then(function() {
|
||||
return done();
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.6 returns a promise from connection.execute', function(done) {
|
||||
oracledb.getConnection(dbConfig)
|
||||
.then(function(conn) {
|
||||
conn.should.be.ok;
|
||||
var executePromise = conn.execute('select 1 from dual');
|
||||
executePromise.should.be.an.instanceof(oracledb.Promise);
|
||||
return executePromise
|
||||
.then(function(result) {
|
||||
result.rows[0][0].should.eql(1);
|
||||
|
||||
return conn.release()
|
||||
.then(done);
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.7 returns a promise from connection.commit', function(done) {
|
||||
oracledb.getConnection(dbConfig)
|
||||
.then(function(conn) {
|
||||
var commitPromise;
|
||||
conn.should.be.ok;
|
||||
commitPromise = conn.commit();
|
||||
commitPromise.should.be.an.instanceof(oracledb.Promise);
|
||||
|
||||
return commitPromise
|
||||
.then(function() {
|
||||
return conn.release()
|
||||
.then(done);
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.8 returns a promise form connection.rollback', function(done) {
|
||||
oracledb.getConnection(dbConfig)
|
||||
.then(function(conn) {
|
||||
var rollbackPromise;
|
||||
conn.should.be.ok;
|
||||
rollbackPromise = conn.rollback();
|
||||
rollbackPromise.should.be.an.instanceof(oracledb.Promise);
|
||||
|
||||
return rollbackPromise
|
||||
.then(function() {
|
||||
return conn.release()
|
||||
.then(done);
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.9 returns a promise from resultSet.close', function(done) {
|
||||
oracledb.getConnection(dbConfig)
|
||||
.then(function(conn) {
|
||||
conn.should.be.ok;
|
||||
|
||||
return conn.execute('select 1 from dual', [], {resultSet: true})
|
||||
.then(function(result) {
|
||||
var closePromise;
|
||||
closePromise = result.resultSet.close();
|
||||
closePromise.should.be.an.instanceof(oracledb.Promise);
|
||||
|
||||
return closePromise
|
||||
.then(function() {
|
||||
return conn.release()
|
||||
.then(done);
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
})
|
||||
|
||||
it('16.10 returns a promise from resultSet.getRow', function(done) {
|
||||
|
||||
function finishProcessing(conn, resultSet) {
|
||||
return resultSet.close()
|
||||
.then(function() {
|
||||
conn.release();
|
||||
})
|
||||
}
|
||||
|
||||
function processResultSet(conn, resultSet) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
function processRow() {
|
||||
var getRowPromise;
|
||||
|
||||
getRowPromise = resultSet.getRow();
|
||||
getRowPromise.should.be.an.instanceof(oracledb.Promise);
|
||||
|
||||
getRowPromise
|
||||
.then(function(row) {
|
||||
if (!row) {
|
||||
finishProcessing(conn, resultSet)
|
||||
.then(function() {
|
||||
resolve();
|
||||
});
|
||||
} else {
|
||||
row[0].should.eql(1);
|
||||
|
||||
processRow();
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
processRow();
|
||||
});
|
||||
}
|
||||
|
||||
oracledb.getConnection(dbConfig)
|
||||
.then(function(conn) {
|
||||
conn.should.be.ok;
|
||||
|
||||
return conn.execute('select 1 from dual', [], {resultSet: true})
|
||||
.then(function(result) {
|
||||
return processResultSet(conn, result.resultSet)
|
||||
.then(function() {
|
||||
done();
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
|
||||
}) // 16.10
|
||||
|
||||
it('16.11 returns a promise from resultSet.getRows', function(done) {
|
||||
function finishProcessing(conn, resultSet) {
|
||||
return resultSet.close()
|
||||
.then(function() {
|
||||
conn.release();
|
||||
});
|
||||
}
|
||||
|
||||
function processResultSet(conn, resultSet) {
|
||||
return new Promise(function(resolve, reject) {
|
||||
function processRows() {
|
||||
var getRowsPromise;
|
||||
|
||||
getRowsPromise = resultSet.getRows(2);
|
||||
getRowsPromise.should.be.an.instanceof(oracledb.Promise);
|
||||
|
||||
getRowsPromise
|
||||
.then(function(rows) {
|
||||
if (rows.length === 0) {
|
||||
finishProcessing(conn, resultSet)
|
||||
.then(function() {
|
||||
resolve();
|
||||
});
|
||||
} else {
|
||||
rows[0][0].should.eql(1);
|
||||
rows[1][0].should.eql(2);
|
||||
|
||||
processRows();
|
||||
}
|
||||
})
|
||||
.catch(function(err) {
|
||||
reject(err);
|
||||
});
|
||||
}
|
||||
|
||||
processRows();
|
||||
});
|
||||
}
|
||||
|
||||
oracledb.getConnection(dbConfig)
|
||||
.then(function(conn) {
|
||||
conn.should.be.ok;
|
||||
|
||||
return conn.execute('select 1 from dual union select 2 from dual', [], {resultSet: true})
|
||||
.then(function(result) {
|
||||
return processResultSet(conn, result.resultSet)
|
||||
.then(function() {
|
||||
return done();
|
||||
});
|
||||
});
|
||||
})
|
||||
.catch(function(err) {
|
||||
return done(err);
|
||||
});
|
||||
}) // 16.11
|
||||
|
||||
})
|
|
@ -630,15 +630,16 @@ describe('12. resultSet1.js', function() {
|
|||
);
|
||||
|
||||
function fetchRowFromRS(rs) {
|
||||
rs.getRows(function(err, rows) {
|
||||
try {
|
||||
rs.getRows(function() {});
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
err.message.should.eql('NJS-009: invalid number of parameters');
|
||||
should.not.exist(rows);
|
||||
rs.close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -685,7 +686,7 @@ describe('12. resultSet1.js', function() {
|
|||
function fetchRowFromRS(rs, numRows) {
|
||||
rs.getRows(numRows, function(err, rows) {
|
||||
should.exist(err);
|
||||
err.message.should.startWith('NJS-006: invalid type for parameter 1');
|
||||
err.message.should.eql('NJS-006: invalid type for parameter 1');
|
||||
rs.close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
|
@ -709,14 +710,16 @@ describe('12. resultSet1.js', function() {
|
|||
);
|
||||
|
||||
function fetchRowFromRS(rs, numRows) {
|
||||
rs.getRows(numRows, function(err, rows) {
|
||||
try {
|
||||
rs.getRows(numRows, function() {});
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
err.message.should.startWith('NJS-006: invalid type for parameter 1');
|
||||
rs.close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -870,15 +873,16 @@ describe('12. resultSet1.js', function() {
|
|||
);
|
||||
|
||||
function fetchRowFromRS(rs, numRows) {
|
||||
rs.getRow(numRows, function(err, row) {
|
||||
try {
|
||||
rs.getRow(numRows, function() {});
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
err.message.should.eql('NJS-009: invalid number of parameters');
|
||||
should.not.exist(row);
|
||||
rs.close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -943,7 +947,7 @@ describe('12. resultSet1.js', function() {
|
|||
accessCount.should.be.exactly(10);
|
||||
rs.close(function(err) {
|
||||
should.exist(err);
|
||||
err.message.should.eql("NJS-018: invalid result set");
|
||||
err.message.should.startWith('NJS-018:');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
@ -979,7 +983,7 @@ describe('12. resultSet1.js', function() {
|
|||
should.not.exist(err);
|
||||
rs.getRows(numRows, function(err, rows) {
|
||||
should.exist(err);
|
||||
err.message.should.eql("NJS-018: invalid result set");
|
||||
err.message.should.startWith('NJS-018:');
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
|
|
@ -0,0 +1,377 @@
|
|||
/* Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved. */
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* You may not use the identified files except in compliance with the Apache
|
||||
* License, Version 2.0 (the "License.")
|
||||
*
|
||||
* You may obtain a copy of the License at
|
||||
* http://www.apache.org/licenses/LICENSE-2.0.
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
*
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* The node-oracledb test suite uses 'mocha', 'should' and 'async'.
|
||||
* See LICENSE.md for relevant licenses.
|
||||
*
|
||||
* NAME
|
||||
* 15. resultsetToStream.js
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Testing driver query results via stream feature.
|
||||
*
|
||||
* NUMBERING RULE
|
||||
* Test numbers follow this numbering rule:
|
||||
* 1 - 20 are reserved for basic functional tests
|
||||
* 21 - 50 are reserved for data type supporting tests
|
||||
* 51 onwards are for other tests
|
||||
*
|
||||
*****************************************************************************/
|
||||
'use strict';
|
||||
|
||||
var oracledb = require('oracledb');
|
||||
var should = require('should');
|
||||
var async = require('async');
|
||||
var dbConfig = require('./dbconfig.js');
|
||||
|
||||
describe('15. resultsetToStream.js', function () {
|
||||
|
||||
if (dbConfig.externalAuth) {
|
||||
var credential = {externalAuth: true, connectString: dbConfig.connectString};
|
||||
} else {
|
||||
var credential = dbConfig;
|
||||
}
|
||||
|
||||
var connection = null;
|
||||
var rowsAmount = 217;
|
||||
before(function(done) {
|
||||
async.series([
|
||||
function getConn(cb) {
|
||||
oracledb.getConnection(credential, function(err, conn) {
|
||||
should.not.exist(err);
|
||||
connection = conn;
|
||||
cb();
|
||||
});
|
||||
},
|
||||
function createTab(cb) {
|
||||
var proc = "BEGIN \n" +
|
||||
" DECLARE \n" +
|
||||
" e_table_exists EXCEPTION; \n" +
|
||||
" PRAGMA EXCEPTION_INIT(e_table_exists, -00942);\n " +
|
||||
" BEGIN \n" +
|
||||
" EXECUTE IMMEDIATE ('DROP TABLE nodb_employees'); \n" +
|
||||
" EXCEPTION \n" +
|
||||
" WHEN e_table_exists \n" +
|
||||
" THEN NULL; \n" +
|
||||
" END; \n" +
|
||||
" EXECUTE IMMEDIATE (' \n" +
|
||||
" CREATE TABLE nodb_employees ( \n" +
|
||||
" employees_id NUMBER, \n" +
|
||||
" employees_name VARCHAR2(20), \n" +
|
||||
" employees_history CLOB \n" +
|
||||
" ) \n" +
|
||||
" '); \n" +
|
||||
"END; ";
|
||||
|
||||
connection.execute(
|
||||
proc,
|
||||
function(err) {
|
||||
should.not.exist(err);
|
||||
cb();
|
||||
}
|
||||
);
|
||||
},
|
||||
function insertRows(cb) {
|
||||
var proc = "DECLARE \n" +
|
||||
" x NUMBER := 0; \n" +
|
||||
" n VARCHAR2(20); \n" +
|
||||
" clobData CLOB; \n" +
|
||||
"BEGIN \n" +
|
||||
" FOR i IN 1..217 LOOP \n" +
|
||||
" x := x + 1; \n" +
|
||||
" n := 'staff ' || x; \n" +
|
||||
" INSERT INTO nodb_employees VALUES (x, n, EMPTY_CLOB()) RETURNING employees_history INTO clobData; \n" +
|
||||
" DBMS_LOB.WRITE(clobData, 20, 1, '12345678901234567890'); \n" +
|
||||
" END LOOP; \n" +
|
||||
"end; ";
|
||||
|
||||
connection.execute(
|
||||
proc,
|
||||
function(err) {
|
||||
should.not.exist(err);
|
||||
cb();
|
||||
}
|
||||
);
|
||||
}
|
||||
], done);
|
||||
}) // before
|
||||
|
||||
after(function(done) {
|
||||
async.series([
|
||||
function(callback) {
|
||||
connection.execute(
|
||||
"DROP TABLE nodb_employees",
|
||||
function(err) {
|
||||
should.not.exist(err);
|
||||
callback();
|
||||
}
|
||||
);
|
||||
},
|
||||
function(callback) {
|
||||
connection.release(function(err) {
|
||||
should.not.exist(err);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
], done);
|
||||
}) // after
|
||||
|
||||
describe('15.1 Testing ResultSet.toQueryStream', function () {
|
||||
it('15.1.1 should allow resultsets to be converted to streams', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var stream = result.outBinds.cursor.toQueryStream();
|
||||
|
||||
stream.on('error', function (error) {
|
||||
console.log(error);
|
||||
should.fail(error, null, 'Error event should not be triggered');
|
||||
});
|
||||
|
||||
var counter = 0;
|
||||
stream.on('data', function (data) {
|
||||
should.exist(data);
|
||||
counter++;
|
||||
});
|
||||
|
||||
stream.on('end', function () {
|
||||
should.equal(counter, rowsAmount);
|
||||
|
||||
setTimeout(done, 500);
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('15.2 Testing ResultSet/QueryStream conversion errors', function () {
|
||||
it('15.2.1 should prevent conversion to stream after getRow is invoked', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir: oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var cursor = result.outBinds.cursor;
|
||||
|
||||
cursor.getRow(function(err, row) {
|
||||
should.not.exist(err);
|
||||
|
||||
cursor.close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
var stream = cursor.toQueryStream();
|
||||
} catch (err) {
|
||||
(err.message).should.startWith('NJS-041:');
|
||||
// NJS-041: cannot convert to stream after invoking methods
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('15.2.2 should prevent conversion to stream after getRows is invoked', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir : oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var cursor = result.outBinds.cursor;
|
||||
|
||||
cursor.getRows(5, function(err, rows) {
|
||||
should.not.exist(err);
|
||||
|
||||
cursor.close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
|
||||
try {
|
||||
var stream = cursor.toQueryStream();
|
||||
} catch (err) {
|
||||
(err.message).should.startWith('NJS-041:');
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('15.2.3 should prevent conversion to stream after close is invoked', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir : oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var cursor = result.outBinds.cursor;
|
||||
|
||||
cursor.close(function(err) {
|
||||
should.not.exist(err);
|
||||
|
||||
done();
|
||||
});
|
||||
|
||||
try {
|
||||
var stream = cursor.toQueryStream();
|
||||
} catch (err) {
|
||||
(err.message).should.startWith('NJS-041:');
|
||||
}
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('15.2.4 should prevent invoking getRow after conversion to stream', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir : oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var cursor = result.outBinds.cursor;
|
||||
var stream = cursor.toQueryStream();
|
||||
|
||||
cursor.getRow(function(err, row) {
|
||||
(err.message).should.startWith('NJS-042:');
|
||||
// NJS-042: cannot invoke methods after converting to stream
|
||||
|
||||
// Closing cursor via stream._close because the cursor.close method
|
||||
// is not invokable after conversion to stream.
|
||||
stream._close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('15.2.5 should prevent invoking getRows after conversion to stream', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir : oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var cursor = result.outBinds.cursor;
|
||||
var stream = cursor.toQueryStream();
|
||||
|
||||
cursor.getRows(5, function(err, rows) {
|
||||
(err.message).should.startWith('NJS-042:');
|
||||
|
||||
// Closing cursor via stream._close because the cursor.close method
|
||||
// is not invokable after conversion to stream.
|
||||
stream._close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('15.2.6 should prevent invoking close after conversion to stream', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir : oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var cursor = result.outBinds.cursor;
|
||||
var stream = cursor.toQueryStream();
|
||||
|
||||
cursor.close(function(err) {
|
||||
(err.message).should.startWith('NJS-042:');
|
||||
|
||||
// Closing cursor via stream._close because the cursor.close method
|
||||
// is not invokable after conversion to stream.
|
||||
stream._close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
|
||||
it('15.2.7 should prevent calling toQueryStream more than once', function (done) {
|
||||
connection.execute(
|
||||
'begin \n' +
|
||||
' open :cursor for select employees_name from nodb_employees; \n' +
|
||||
'end;',
|
||||
{
|
||||
cursor: { type: oracledb.CURSOR, dir : oracledb.BIND_OUT }
|
||||
},
|
||||
function(err, result) {
|
||||
should.not.exist(err);
|
||||
|
||||
var cursor = result.outBinds.cursor;
|
||||
|
||||
// First conversion to stream
|
||||
var stream = cursor.toQueryStream();
|
||||
|
||||
try {
|
||||
// Second conversion to stream
|
||||
stream = cursor.toQueryStream();
|
||||
} catch (err) {
|
||||
(err.message).should.startWith('NJS-043:');
|
||||
|
||||
stream._close(function(err) {
|
||||
should.not.exist(err);
|
||||
done();
|
||||
});
|
||||
}
|
||||
}
|
||||
);
|
||||
}); // 15.2.7
|
||||
|
||||
}); // 15.2
|
||||
});
|
298
test/stream1.js
298
test/stream1.js
|
@ -39,7 +39,6 @@ var async = require('async');
|
|||
var dbConfig = require('./dbconfig.js');
|
||||
|
||||
describe('13. stream1.js', function () {
|
||||
var connection = false;
|
||||
|
||||
if (dbConfig.externalAuth) {
|
||||
var credential = {externalAuth: true, connectString: dbConfig.connectString};
|
||||
|
@ -47,85 +46,91 @@ describe('13. stream1.js', function () {
|
|||
var credential = dbConfig;
|
||||
}
|
||||
|
||||
var createTable =
|
||||
"BEGIN \
|
||||
DECLARE \
|
||||
e_table_exists EXCEPTION; \
|
||||
PRAGMA EXCEPTION_INIT(e_table_exists, -00942); \
|
||||
BEGIN \
|
||||
EXECUTE IMMEDIATE ('DROP TABLE nodb_employees'); \
|
||||
EXCEPTION \
|
||||
WHEN e_table_exists \
|
||||
THEN NULL; \
|
||||
END; \
|
||||
EXECUTE IMMEDIATE (' \
|
||||
CREATE TABLE nodb_employees ( \
|
||||
employees_id NUMBER, \
|
||||
employees_name VARCHAR2(20), \
|
||||
employees_history CLOB \
|
||||
) \
|
||||
'); \
|
||||
END; ";
|
||||
|
||||
var insertRows =
|
||||
"DECLARE \
|
||||
x NUMBER := 0; \
|
||||
n VARCHAR2(20); \
|
||||
clobData CLOB;\
|
||||
BEGIN \
|
||||
FOR i IN 1..217 LOOP \
|
||||
x := x + 1; \
|
||||
n := 'staff ' || x; \
|
||||
INSERT INTO nodb_employees VALUES (x, n, EMPTY_CLOB()) RETURNING employees_history INTO clobData; \
|
||||
\
|
||||
DBMS_LOB.WRITE(clobData, 20, 1, '12345678901234567890');\
|
||||
END LOOP; \
|
||||
END; ";
|
||||
var connection = null;
|
||||
var rowsAmount = 217;
|
||||
|
||||
before(function (done) {
|
||||
oracledb.getConnection(credential, function (err, conn) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
connection = conn;
|
||||
connection.execute(createTable, function (err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
connection.execute(insertRows, function (err) {
|
||||
if (err) {
|
||||
console.error(err);
|
||||
return;
|
||||
}
|
||||
done();
|
||||
before(function(done) {
|
||||
async.series([
|
||||
function getConn(cb) {
|
||||
oracledb.getConnection(credential, function(err, conn) {
|
||||
should.not.exist(err);
|
||||
connection = conn;
|
||||
cb();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
},
|
||||
function createTab(cb) {
|
||||
var proc = "BEGIN \n" +
|
||||
" DECLARE \n" +
|
||||
" e_table_exists EXCEPTION; \n" +
|
||||
" PRAGMA EXCEPTION_INIT(e_table_exists, -00942);\n " +
|
||||
" BEGIN \n" +
|
||||
" EXECUTE IMMEDIATE ('DROP TABLE nodb_employees'); \n" +
|
||||
" EXCEPTION \n" +
|
||||
" WHEN e_table_exists \n" +
|
||||
" THEN NULL; \n" +
|
||||
" END; \n" +
|
||||
" EXECUTE IMMEDIATE (' \n" +
|
||||
" CREATE TABLE nodb_employees ( \n" +
|
||||
" employees_id NUMBER, \n" +
|
||||
" employees_name VARCHAR2(20), \n" +
|
||||
" employees_history CLOB \n" +
|
||||
" ) \n" +
|
||||
" '); \n" +
|
||||
"END; ";
|
||||
|
||||
after(function (done) {
|
||||
connection.execute(
|
||||
'DROP TABLE nodb_employees',
|
||||
function (err) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return;
|
||||
}
|
||||
connection.release(function (err) {
|
||||
if (err) {
|
||||
console.error(err.message);
|
||||
return;
|
||||
connection.execute(
|
||||
proc,
|
||||
function(err) {
|
||||
should.not.exist(err);
|
||||
cb();
|
||||
}
|
||||
done();
|
||||
});
|
||||
}
|
||||
);
|
||||
});
|
||||
);
|
||||
},
|
||||
function insertRows(cb) {
|
||||
var proc = "DECLARE \n" +
|
||||
" x NUMBER := 0; \n" +
|
||||
" n VARCHAR2(20); \n" +
|
||||
" clobData CLOB; \n" +
|
||||
"BEGIN \n" +
|
||||
" FOR i IN 1..217 LOOP \n" +
|
||||
" x := x + 1; \n" +
|
||||
" n := 'staff ' || x; \n" +
|
||||
" INSERT INTO nodb_employees VALUES (x, n, EMPTY_CLOB()) RETURNING employees_history INTO clobData; \n" +
|
||||
" DBMS_LOB.WRITE(clobData, 20, 1, '12345678901234567890'); \n" +
|
||||
" END LOOP; \n" +
|
||||
"end; ";
|
||||
|
||||
describe('13.1 Testing ResultSet stream', function () {
|
||||
connection.execute(
|
||||
proc,
|
||||
function(err) {
|
||||
should.not.exist(err);
|
||||
cb();
|
||||
}
|
||||
);
|
||||
}
|
||||
], done);
|
||||
}) // before
|
||||
|
||||
after(function(done) {
|
||||
async.series([
|
||||
function(callback) {
|
||||
connection.execute(
|
||||
"DROP TABLE nodb_employees",
|
||||
function(err) {
|
||||
should.not.exist(err);
|
||||
callback();
|
||||
}
|
||||
);
|
||||
},
|
||||
function(callback) {
|
||||
connection.release(function(err) {
|
||||
should.not.exist(err);
|
||||
callback();
|
||||
});
|
||||
},
|
||||
], done);
|
||||
}) // after
|
||||
|
||||
describe('13.1 Testing QueryStream', function () {
|
||||
it('13.1.1 stream results for oracle connection', function (done) {
|
||||
connection.should.be.ok;
|
||||
|
||||
|
@ -357,6 +362,7 @@ describe('13. stream1.js', function () {
|
|||
var counter = 0;
|
||||
var clobs = [];
|
||||
var clobsRead = 0;
|
||||
|
||||
stream.on('data', function (data) {
|
||||
var rowIndex = counter;
|
||||
|
||||
|
@ -487,4 +493,146 @@ describe('13. stream1.js', function () {
|
|||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('13.2 Testing QueryStream._close', function () {
|
||||
it('13.2.1 should be able to stop the stream early with _close', function (done) {
|
||||
connection.should.be.ok;
|
||||
|
||||
var stream = connection.queryStream('SELECT employees_name FROM nodb_employees');
|
||||
|
||||
stream.on('data', function () {
|
||||
stream.pause();
|
||||
stream._close();
|
||||
});
|
||||
|
||||
stream.on('close', function() {
|
||||
done();
|
||||
});
|
||||
|
||||
stream.on('end', function () {
|
||||
done(new Error('Reached the end of the stream'));
|
||||
});
|
||||
|
||||
stream.on('error', function (err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('13.2.2 should be able to stop the stream before any data', function (done) {
|
||||
connection.should.be.ok;
|
||||
|
||||
var stream = connection.queryStream('SELECT employees_name FROM nodb_employees');
|
||||
|
||||
stream.on('close', function() {
|
||||
done();
|
||||
});
|
||||
|
||||
// Close is synchronous so it needs to be called after the close listener is added.
|
||||
stream._close();
|
||||
|
||||
stream.on('data', function () {
|
||||
done(new Error('Received data'));
|
||||
});
|
||||
|
||||
stream.on('end', function () {
|
||||
done(new Error('Reached the end of the stream'));
|
||||
});
|
||||
|
||||
stream.on('error', function (err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('13.2.3 should invoke an optional callback passed to _close', function (done) {
|
||||
connection.should.be.ok;
|
||||
|
||||
var stream = connection.queryStream('SELECT employees_name FROM nodb_employees');
|
||||
|
||||
stream._close(function() {
|
||||
done();
|
||||
});
|
||||
|
||||
stream.on('data', function () {
|
||||
done(new Error('Received data'));
|
||||
});
|
||||
|
||||
stream.on('end', function () {
|
||||
done(new Error('Reached the end of the stream'));
|
||||
});
|
||||
|
||||
stream.on('error', function (err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('13.3 Testing QueryStream\'s maxRows control', function () {
|
||||
it('13.3.1 should use oracledb.maxRows for fetching', function (done) {
|
||||
var defaultMaxRows;
|
||||
var testMaxRows = 9;
|
||||
|
||||
connection.should.be.ok;
|
||||
|
||||
defaultMaxRows = oracledb.maxRows;
|
||||
|
||||
oracledb.maxRows = testMaxRows;
|
||||
|
||||
var stream = connection.queryStream('SELECT employees_name FROM nodb_employees');
|
||||
|
||||
stream.on('data', function () {
|
||||
stream.pause();
|
||||
|
||||
// Using the internal/private caches to validate
|
||||
should.equal(stream._fetchedRows.length, testMaxRows - (1 + stream._readableState.buffer.length));
|
||||
stream._close();
|
||||
});
|
||||
|
||||
stream.on('close', function() {
|
||||
oracledb.maxRows = defaultMaxRows;
|
||||
done();
|
||||
});
|
||||
|
||||
stream.on('end', function () {
|
||||
done(new Error('Reached the end of the stream'));
|
||||
});
|
||||
|
||||
stream.on('error', function (err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
|
||||
it('13.3.2 should default to 100 if oracledb.maxRows is falsey', function (done) {
|
||||
var defaultMaxRows;
|
||||
var testMaxRows = 0;
|
||||
|
||||
connection.should.be.ok;
|
||||
|
||||
defaultMaxRows = oracledb.maxRows;
|
||||
|
||||
oracledb.maxRows = testMaxRows;
|
||||
|
||||
var stream = connection.queryStream('SELECT employees_name FROM nodb_employees');
|
||||
|
||||
stream.on('data', function () {
|
||||
stream.pause();
|
||||
|
||||
// Using the internal/private caches to validate
|
||||
should.equal(stream._fetchedRows.length, (99 - stream._readableState.buffer.length));
|
||||
stream._close();
|
||||
});
|
||||
|
||||
stream.on('close', function() {
|
||||
oracledb.maxRows = defaultMaxRows;
|
||||
done();
|
||||
});
|
||||
|
||||
stream.on('end', function () {
|
||||
done(new Error('Reached the end of the stream'));
|
||||
});
|
||||
|
||||
stream.on('error', function (err) {
|
||||
done(err);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
@ -242,20 +242,15 @@ describe('14. stream2.js', function() {
|
|||
}) // 14.6
|
||||
|
||||
it('14.7 Negative - queryStream() has no parameters', function(done) {
|
||||
var stream;
|
||||
|
||||
var stream = connection.queryStream();
|
||||
|
||||
stream.on('error', function(error) {
|
||||
should.exist(error);
|
||||
// console.log(error);
|
||||
// NJS-006: invalid type for parameter 1
|
||||
setTimeout(done, 500);
|
||||
});
|
||||
|
||||
stream.on('data', function(data) {
|
||||
should.not.exist(data);
|
||||
});
|
||||
|
||||
try {
|
||||
stream = connection.queryStream();
|
||||
} catch (err) {
|
||||
should.exist(err);
|
||||
err.message.should.eql('NJS-009: invalid number of parameters');
|
||||
done();
|
||||
}
|
||||
})
|
||||
|
||||
it('14.8 Negative - give invalid SQL as first parameter', function(done) {
|
||||
|
|
Loading…
Reference in New Issue