Using Node.js with Caché - InterSystems Documentation
Using Node.js with Caché - InterSystems Documentation
Using Node.js with Caché - InterSystems Documentation
You also want an ePaper? Increase the reach of your titles
YUMPU automatically turns print PDFs into web optimized ePapers that Google loves.
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong><br />
Version 2013.1<br />
24 April 2013<br />
<strong>InterSystems</strong> Corporation 1 Memorial Drive Cambridge MA 02142 www.intersystems.com
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong><br />
<strong>Caché</strong> Version 2013.1 24 April 2013<br />
Copyright © 2013 <strong>InterSystems</strong> Corporation<br />
All rights reserved.<br />
This book was assembled and formatted in Adobe Page Description Format (PDF) using tools and information from the following sources:<br />
Oracle Corporation, RenderX, Inc., Adobe Systems, and the World Wide Web Consortium at www.w3c.org. The primary document<br />
development tools were special-purpose XML-processing applications built by <strong>InterSystems</strong> using <strong>Caché</strong> and Java.<br />
, , , ,<br />
<strong>Caché</strong> WEBLINK, and Distributed Cache Protocol are registered trademarks of <strong>InterSystems</strong> Corporation.<br />
, ,<br />
<strong>InterSystems</strong> Jalapeño Technology, Enterprise Cache Protocol, ECP, and <strong>InterSystems</strong> Zen are trademarks of <strong>InterSystems</strong> Corporation.<br />
All other brand or product names used herein are trademarks or registered trademarks of their respective companies or organizations.<br />
This document contains trade secret and confidential information which is the property of <strong>InterSystems</strong> Corporation, One Memorial Drive,<br />
Cambridge, MA 02142, or its affiliates, and is furnished for the sole purpose of the operation and maintenance of the products of <strong>InterSystems</strong><br />
Corporation. No part of this publication is to be used for any other purpose, and this publication is not to be reproduced, copied, disclosed,<br />
transmitted, stored in a retrieval system or translated into any human or computer language, in any form, by any means, in whole or in part,<br />
<strong>with</strong>out the express prior written consent of <strong>InterSystems</strong> Corporation.<br />
The copying, use and disposition of this document and the software programs described herein is prohibited except to the limited extent<br />
set forth in the standard software license agreement(s) of <strong>InterSystems</strong> Corporation covering such programs and related documentation.<br />
<strong>InterSystems</strong> Corporation makes no representations and warranties concerning such software programs other than those set forth in such<br />
standard software license agreement(s). In addition, the liability of <strong>InterSystems</strong> Corporation for any losses or damages relating to or arising<br />
out of the use of such software programs is limited in the manner set forth in such standard software license agreement(s).<br />
THE FOREGOING IS A GENERAL SUMMARY OF THE RESTRICTIONS AND LIMITATIONS IMPOSED BY INTERSYSTEMS<br />
CORPORATION ON THE USE OF, AND LIABILITY ARISING FROM, ITS COMPUTER SOFTWARE. FOR COMPLETE INFORMATION<br />
REFERENCE SHOULD BE MADE TO THE STANDARD SOFTWARE LICENSE AGREEMENT(S) OF INTERSYSTEMS CORPORATION,<br />
COPIES OF WHICH WILL BE MADE AVAILABLE UPON REQUEST.<br />
<strong>InterSystems</strong> Corporation disclaims responsibility for errors which may appear in this document, and it reserves the right, in its sole discretion<br />
and <strong>with</strong>out notice, to make substitutions and modifications in the products and practices described in this document.<br />
For Support questions about any <strong>InterSystems</strong> products, contact:<br />
<strong>InterSystems</strong> Worldwide Customer Support<br />
Tel: +1 617 621-0700<br />
Fax: +1 617 374-9391<br />
Email: support@<strong>InterSystems</strong>.com
Table of Contents<br />
About This Book .................................................................................................................................... 1<br />
1 Introduction ........................................................................................................................................ 3<br />
2 Installation ........................................................................................................................................... 5<br />
2.1 UNIX .......................................................................................................................................... 5<br />
2.2 Windows ..................................................................................................................................... 6<br />
3 Accessing <strong>Caché</strong> from <strong>Node</strong>.<strong>js</strong> ........................................................................................................... 7<br />
3.1 JSON Objects and <strong>Caché</strong> Globals .............................................................................................. 7<br />
3.2 Synchronous vs. Asynchronous cache.node Methods ................................................................ 8<br />
3.3 Overview of cache.node Methods .............................................................................................. 9<br />
3.4 Opening and Closing the <strong>Caché</strong> Database ............................................................................... 10<br />
3.5 Advanced Data Access <strong>with</strong> retrieve() and update() ................................................................ 11<br />
3.5.1 <strong>Using</strong> retrieve() .............................................................................................................. 11<br />
3.5.2 <strong>Using</strong> update() ................................................................................................................ 15<br />
3.6 Towards an Object Oriented Development Methodology ........................................................ 16<br />
4 Reference for cache.node Methods ................................................................................................. 17<br />
4.1 Example Data ........................................................................................................................... 18<br />
4.2 close() ....................................................................................................................................... 18<br />
4.3 data() ......................................................................................................................................... 18<br />
4.4 function() .................................................................................................................................. 19<br />
4.5 get() .......................................................................................................................................... 20<br />
4.6 global_directory() ..................................................................................................................... 21<br />
4.7 increment() ............................................................................................................................... 22<br />
4.8 kill() .......................................................................................................................................... 22<br />
4.9 lock() ........................................................................................................................................ 23<br />
4.10 merge() ................................................................................................................................... 23<br />
4.11 next() or order() ...................................................................................................................... 24<br />
4.12 next_node() ............................................................................................................................. 25<br />
4.13 open() ..................................................................................................................................... 27<br />
4.14 previous() ................................................................................................................................ 27<br />
4.15 previous_node() ...................................................................................................................... 28<br />
4.16 retrieve() ................................................................................................................................. 30<br />
4.17 set() ......................................................................................................................................... 32<br />
4.18 unlock() .................................................................................................................................. 32<br />
4.19 update() ................................................................................................................................... 33<br />
4.20 version() and about() .............................................................................................................. 34<br />
Appendix A: Building cache.node from Source ................................................................................ 37<br />
A.1 <strong>Using</strong> the <strong>Node</strong>.<strong>js</strong> Build Procedure ......................................................................................... 37<br />
A.1.1 Creating the Build Script (wscript) ............................................................................... 37<br />
A.1.2 Build the cache.node Module ........................................................................................ 38<br />
A.2 Building Directly from Source ................................................................................................ 38<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong><br />
iii
About This Book<br />
This book describes how to install and use the cache.node module, which provides access to <strong>Caché</strong> from a <strong>Node</strong>.<strong>js</strong> application.<br />
This book contains the following sections:<br />
• Introduction<br />
• Installation<br />
• Accessing <strong>Caché</strong> from <strong>Node</strong>.<strong>js</strong><br />
• Reference for cache.node Methods<br />
• Building cache.node from Source<br />
There is also a detailed Table of Contents.<br />
For general information, see <strong>Using</strong> <strong>InterSystems</strong> <strong>Documentation</strong>.<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 1
1<br />
Introduction<br />
This document describes cache.node, an add-on module for the <strong>Node</strong>.<strong>js</strong> environment that implements high performance<br />
access to data held in <strong>Caché</strong>.<br />
<strong>Node</strong>.<strong>js</strong> provides a means through which high performance and highly scalable network infrastructure can be easily created.<br />
It is different from conventional thread based networking software (such as web servers) because it provides a non-blocking<br />
event based architecture.<br />
Most modern web servers are implemented using a hybrid multi-process/multithreaded server architecture where a thread<br />
is dedicated to serving each request. All resources associated <strong>with</strong> that thread remain allocated until the request is satisfied<br />
and a response dispatched to the client. In the <strong>Node</strong>.<strong>js</strong> architecture, a single process is used per instance (of node) and<br />
threads are only used as a means through which operations and system calls that would otherwise block can be called<br />
asynchronously <strong>with</strong> respect to the primary thread of execution. Everything happens asynchronously, and a primary design<br />
feature is that no function should block, but rather accept a callback function that <strong>Node</strong>.<strong>js</strong> will use to notify the initiating<br />
program that the operation has completed.<br />
A consequence of the event based server architecture is that system resources (such as heap memory) are never tied-up<br />
while waiting for some other operation to complete. Because of this, network programs developed using <strong>Node</strong>.<strong>js</strong> occupy<br />
a very small footprint in terms of system resource and memory usage and a high level of scalability.<br />
The cache.node module allows <strong>Caché</strong> to be leveraged as a high performance persistence storage engine that perfectly<br />
complements the high performance <strong>Node</strong>.<strong>js</strong> environment. <strong>Caché</strong> multidimensional storage provides a very fast, flexible<br />
storage model that can be used to implement a wide variety of data structures. The <strong>Caché</strong> cache.node module allows direct<br />
access to globals, the basis of the multidimensional storage model (see <strong>Using</strong> <strong>Caché</strong> Globals for a formal description).<br />
<strong>Caché</strong> can be regarded as a NoSQL database providing B-Tree based storage but <strong>with</strong> one important difference. Whereas<br />
most B-Tree databases implement one-dimensional key/value storage, <strong>Caché</strong> provides a multi-dimensional multiple key/value<br />
storage model. This provides the basis for a highly structured NoSQL data repository. In <strong>Caché</strong> terminology, each entry is<br />
known as a "global node".<br />
Examples:<br />
One-dimensional Global Storage:<br />
MyGlobal(“key1”)=”value1”<br />
MyGlobal(“key2”)=”value2”<br />
MyGlobal(“key3”)=”value3”<br />
Multi-dimensional Global Storage:<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 3
Introduction<br />
MyGlobal(“key1”)=”value1”<br />
MyGlobal(“key1”, “key1a”)=”value1a”<br />
MyGlobal(“key1”, “key1a, “key1b”)=”value1b”<br />
MyGlobal(“key2”)=”value2”<br />
MyGlobal(“key2”, 1)=”value21”<br />
MyGlobal(“key2”, 2)=”value22”<br />
MyGlobal(“key3”)=”value3”<br />
MyGlobal(“key3”, 1, 2, 3)=”value3123”<br />
MyGlobal(“key3”, 1, 3)=”value313”<br />
4 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
2<br />
Installation<br />
This section describes the procedure for installing a pre-built cache.node module.<br />
The following components are required:<br />
• <strong>Caché</strong> installation.<br />
• <strong>Node</strong>.<strong>js</strong> version 0.4.2 (or later).<br />
<strong>Node</strong>.<strong>js</strong> is available for a number of UNIX platforms. Native support for Windows was added in version 0.6.<br />
The cache.node file is named using the <strong>Node</strong>.<strong>js</strong> .node extension for both UNIX and Windows. In the kits supplied by<br />
<strong>InterSystems</strong>, the module to be used <strong>with</strong> <strong>Node</strong>.<strong>js</strong> version 0.6 (and later) is named cache061.node. This may be renamed<br />
as the more usual cache.node name before deployment to avoid having to modify the require statement in existing<br />
<strong>Node</strong>.<strong>js</strong> software.<br />
• <strong>Node</strong>.<strong>js</strong> version 0.4.x: cache.node<br />
• <strong>Node</strong>.<strong>js</strong> version 0.6.x: cache061.node<br />
2.1 UNIX<br />
The module cache.node is actually a standard UNIX shared object (i.e. cache.so) but <strong>with</strong> an unusual <strong>Node</strong>.<strong>js</strong>-specific file<br />
extension.<br />
Copy cache.node to the following location in the node file system:<br />
.../node/lib/node/<br />
For example:<br />
/opt/local/node/lib/node/cache.node<br />
Placing the module in the recognized library path will remove the need to specify the full path in the JavaScript files. For<br />
example, in JavaScript, it will be possible to write:<br />
var globals = require(‘cache');<br />
Instead of (for example):<br />
var globals = require('/opt/local/build/default/cache');<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 5
Installation<br />
2.2 Windows<br />
The module cache.node is actually a standard Windows DLL (i.e. cache.dll) but <strong>with</strong> an unusual <strong>Node</strong>.<strong>js</strong>-specific file<br />
extension.<br />
The standard Windows installer (provided by the <strong>Node</strong>.<strong>js</strong> Group) usually places the <strong>Node</strong>.<strong>js</strong> software in the following<br />
location:<br />
C:\Program Files\node<strong>js</strong><br />
The installation mechanism usually adds this location to the Windows PATH environment variable. If this is not the case,<br />
then add it manually. Also, the NODE_PATH environment variable should be set and it, too, should be set to the <strong>Node</strong>.<strong>js</strong><br />
installation directory. For example:<br />
NODE_PATH=C:\Program Files\node<strong>js</strong><br />
Copy cache.node to the location specified in the NODE_PATH environment variable:<br />
C:\Program Files\node<strong>js</strong><br />
Placing the module in the recognized <strong>Node</strong>.<strong>js</strong> path will remove the need to specify the full path in the JavaScript files. For<br />
example, in JavaScript, it will be possible to write:<br />
var globals = require(‘cache');<br />
Instead of (for example):<br />
or:<br />
var globals = require('/node<strong>js</strong>/lib/cache');<br />
var globals = require('c:/node<strong>js</strong>/lib/cache');<br />
6 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
3<br />
Accessing <strong>Caché</strong> from <strong>Node</strong>.<strong>js</strong><br />
The cache.node module provides the basic NoSQL-style methods, and also has more advanced methods that can be used<br />
to implement a higher-level view of the <strong>Caché</strong> database which can, in turn, form the basis of an object oriented approach<br />
to development. This chapter provides an overview of the available methods and the concepts behind them.<br />
The following topics are discussed:<br />
• JSON Objects and <strong>Caché</strong> Globals — describes the basic relationship between the globals in the <strong>Caché</strong> database and<br />
JSON objects in the <strong>Node</strong>.<strong>js</strong> environment.<br />
• Synchronous vs. Asynchronous cache.node Methods — describes how to use cache.node calls both synchronously<br />
and asynchronously.<br />
• Overview of cache.node Methods — provides a quick overview of the basic NoSQL-style cache.node database methods.<br />
• Opening and Closing the <strong>Caché</strong> Database — describes how to load the cache.node module, create an instance of the<br />
cache.node object, and open or close the target <strong>Caché</strong> database.<br />
• Advanced Data Access <strong>with</strong> retrieve() and update() — describes advanced cache.node methods that perform certain<br />
operations more efficiently than the basic NoSQL-style methods.<br />
• Towards an Object Oriented Development Methodology — illustrates how the cache.node methods and JSON notation<br />
can be used for object orientated development.<br />
3.1 JSON Objects and <strong>Caché</strong> Globals<br />
In this section we will look at the basic relationship between JSON objects in the <strong>Node</strong>.<strong>js</strong> environment and globals in the<br />
<strong>Caché</strong> database.<br />
Consider the following global node:<br />
^Customer(1)="Chris Munt"<br />
Note:<br />
By convention, global names are prefixed <strong>with</strong> the ‘^’ character in <strong>Caché</strong>. However, this convention should not<br />
be followed in the corresponding JSON representation.<br />
The equivalent JSON construct will be:<br />
{global: "Customer", subscripts: [1], data: "Chris Munt"}<br />
Adding further nodes to this data construct:<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 7
Accessing <strong>Caché</strong> from <strong>Node</strong>.<strong>js</strong><br />
Globals:<br />
^Customer(1)="Chris Munt"<br />
^Customer(1, "Address", 1)="London"<br />
^Customer(1, "Address", 2)="UK"<br />
^Customer(1, "DateOfRegistration")="1 May 2010"<br />
JSON:<br />
{<br />
}<br />
{<br />
}<br />
{<br />
}<br />
{<br />
}<br />
global: "Customer",<br />
subscripts: [1],<br />
data: "Chris Munt"<br />
global: "Customer",<br />
subscripts: [1, "Address", 1],<br />
data: "London"<br />
global: "Customer",<br />
subscripts: [1, "Address", 2],<br />
data: "UK"<br />
global: "Customer",<br />
subscripts: [1, "DateOfRegistration"],<br />
data: "1 May 2010"<br />
3.2 Synchronous vs. Asynchronous cache.node Methods<br />
All methods provided by cache.node can be run either synchronously or asynchronously. While synchronous operation is<br />
conceptually easier to grasp and can be useful for debugging, the expectation in the <strong>Node</strong>.<strong>js</strong> environment is that all operations<br />
should be implemented asynchronously <strong>with</strong> a completion event raised by means of a callback function. For this reason,<br />
most of the examples given in this guide are coded to run asynchronously. To run them synchronously simply omit the<br />
callback function from the arguments list.<br />
• Synchronous operation — Method does not return until the operation is complete.<br />
• Asynchronous operation — Method returns immediately and your program is notified when the operation is complete.<br />
In order to accept notification, you must pass a callback function as an argument to the original method call. By convention,<br />
the callback will always be the last argument in the list.<br />
Consider the method to determine the version of the cache.node module in use:<br />
Synchronous operation:<br />
var result = mydata.version();<br />
Asynchronous operation:<br />
mydata.version(<br />
function(error, result) {<br />
if (error) {<br />
// error<br />
}<br />
else {<br />
// success<br />
}<br />
}<br />
);<br />
The standard convention for reporting errors in <strong>Node</strong>.<strong>js</strong> is implemented in cache.node. If an operation is successful, error<br />
will be false. If an error occurs then error will be true and the result object will contain the details according to the following<br />
JSON construct:<br />
8 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
Overview of cache.node Methods<br />
{<br />
}<br />
"ErrorMessage": [error message text],<br />
"ErrorCode": [error code],<br />
"ok": [true|false]<br />
For synchronous operation, you should check for the existence of these properties in the result object to determine whether<br />
or not an error has occurred.<br />
3.3 Overview of cache.node Methods<br />
The individual cache.node methods are described in detail in the reference section. Here is a brief summary of the available<br />
methods and their uses, <strong>with</strong> links to the reference section entries:<br />
Opening and closing the database<br />
See “Opening and Closing the <strong>Caché</strong> Database” for basic information on using these methods:<br />
• open() — opens the specified <strong>Caché</strong> database.<br />
• close() — closes a previously opened database.<br />
Operations on individual nodes<br />
• set() — sets the value of a global node.<br />
• get() — retrieves a global node.<br />
• kill() — deletes a global node.<br />
• increment() — adds 1 to the value of an integer in a global node.<br />
• merge() — copies all or part of a global to another global.<br />
Iteration over global nodes<br />
• data() — tests for the existence of a global node.<br />
• next() and previous() — gets the next or previous global node subscript on the current level.<br />
• next_node() and previous_node() — gets the next or previous global node in collation order regardless of<br />
level.<br />
• lock() and unlock() — locks global nodes for exclusive use, and unlocks nodes previously locked by your<br />
program.<br />
Advanced data access<br />
These methods perform batch read and write operations that are frequently more efficient than access <strong>with</strong> the<br />
basic NoSQL-style methods:<br />
• retrieve() — recursively retrieves all global nodes defined beneath a specified level and returns them as a<br />
single JSON object.<br />
• update() — uses information in a JSON object to write a set of globals to the database.<br />
See “Advanced Data Access <strong>with</strong> retrieve() and update()” for a detailed discussion of usage.<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 9
Accessing <strong>Caché</strong> from <strong>Node</strong>.<strong>js</strong><br />
<strong>Caché</strong>-specific methods<br />
These methods provide access to <strong>Caché</strong> information and functions:<br />
• function() — invokes a <strong>Caché</strong> function.<br />
• global_directory() — returns a list of globals held in the <strong>Caché</strong> database.<br />
• version() — returns version information about the cache.node module in use and the associated <strong>Caché</strong> database<br />
(if open).<br />
3.4 Opening and Closing the <strong>Caché</strong> Database<br />
Before any other methods can be called, the cache.node module must be loaded, an instance of the <strong>Caché</strong> object created<br />
and the target <strong>Caché</strong> database must be opened before any data can be accessed.<br />
Loading the Cache.node module<br />
If the cache.node module has been installed in the correct location for your <strong>Node</strong>.<strong>js</strong> installation, the following line will<br />
successfully load it from the default location:<br />
var globals = require('cache');<br />
If the module is installed in some other location the full path should be specified. For example:<br />
var globals = require('/opt/cm/node042/build/default/cache');<br />
Creating an instance<br />
The next task is to create an instance of the cache.node object.<br />
var mydata = new globals.Cache();<br />
Opening the Database<br />
Finally, the <strong>Caché</strong> database can be opened:<br />
where:<br />
mydata.open(parameters[, function(error, result){}]);<br />
• parameters.path — Path to the mgr directory of the target <strong>Caché</strong> installation.<br />
• parameters.username — User name for access.<br />
• parameters.password — Password for access.<br />
• parameters.namespace — Target <strong>Caché</strong> namespace.<br />
For example:<br />
mydata.open(<br />
{<br />
path:"/cache20102/mgr",<br />
username: "_SYSTEM",<br />
password: "SYS",<br />
namespace: "USER"<br />
},<br />
function(error, result){}<br />
);<br />
Closing the Database<br />
The following method will gracefully close a previously opened database.<br />
10 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
Advanced Data Access <strong>with</strong> retrieve() and update()<br />
mydata.close([function(error, result){}]);<br />
3.5 Advanced Data Access <strong>with</strong> retrieve() and update()<br />
This section describes advanced methods that perform operations that could otherwise be achieved by combining several<br />
of the basic NoSQL-style methods.<br />
The following topics are discussed:<br />
• <strong>Using</strong> retrieve() — describes retrieving groups of global nodes as a single JSON object<br />
• <strong>Using</strong> update() — describes writing a single JSON object to update groups of global nodes.<br />
The following <strong>Caché</strong> data will be used to illustrate the higher level methods.<br />
^Customer(1)="Chris Munt"<br />
^Customer(1, "Address", 1)="London"<br />
^Customer(1, "Address", 2)="UK"<br />
^Customer(1, "DateOfRegistration")="1 May 2010"<br />
^Customer(2)="Rob Tweed"<br />
^Customer(2, "Address", 1)="Reigate"<br />
^Customer(2, "Address", 2)="UK"<br />
^Customer(2, "DateOfRegistration")="7 May 2010"<br />
^Customer(3)="Jane Smith"<br />
^Customer(3, "Address", 1)="Oxford"<br />
^Customer(3, "Address", 2)="UK"<br />
^Customer(3, "DateOfRegistration")="9 June 2010"<br />
3.5.1 <strong>Using</strong> retrieve()<br />
The following topics are discussed:<br />
• Retrieve a list of global nodes (retrieve("list"))<br />
• Retrieve a list of global nodes recursively (retrieve("array"))<br />
• Retrieve a structured data object (retrieve("object"))<br />
• Controlling the amount of data returned by retrieve operations<br />
3.5.1.1 Retrieve a list of global nodes (retrieve("list"))<br />
This method will return a list of subscript values that are defined directly beneath a given level in the global.<br />
Example 1: Retrieve a list of customer numbers<br />
mydata.retrieve(<br />
{global: "Customer"},<br />
"list",<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
Three Customer records:<br />
[1, 2, 3]<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 11
Accessing <strong>Caché</strong> from <strong>Node</strong>.<strong>js</strong><br />
Example 2: Retrieve a list of address lines for a specific customer<br />
mydata.retrieve(<br />
{global: "Customer", subscripts: [1, "address"]},<br />
"list",<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
Two lines in the address for customer number 1:<br />
[1, 2]<br />
3.5.1.2 Retrieve a list of global nodes recursively (retrieve("array"))<br />
This method will return a list of subscript values together <strong>with</strong> their associated data values that are defined beneath a given<br />
level in the global. The method is recursive and will retrieve all global nodes defined beneath a chosen level.<br />
The result will be expressed as an array of global nodes: each global node expressed as a single JSON object.<br />
Example 1: Retrieve all data for a customer<br />
mydata.retrieve(<br />
{global: "Customer", subscripts: [1]},<br />
"array",<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
[<br />
]<br />
{<br />
global: "Customer",<br />
subscripts: [1],<br />
data: "Chris Munt"<br />
}<br />
{<br />
global: "Customer",<br />
subscripts: [1, "Address", 1],<br />
data: "London"<br />
}<br />
{<br />
global: "Customer",<br />
subscripts: [1, "Address", 2],<br />
data: "UK"<br />
}<br />
{<br />
global: "Customer",<br />
subscripts: [1, "DateOfRegistration],<br />
data: "1 May 2010"<br />
}<br />
3.5.1.3 Retrieve a structured data object (retrieve("object"))<br />
This method will retrieve a structured data object defined beneath a given level in a global. This method provides a structured<br />
alternative to the array of global nodes described previously.<br />
The result will be expressed as a single JSON object.<br />
Example: Retrieve all data for a customer<br />
Consider the following structured <strong>Caché</strong> global:<br />
^Customer(1, "Name")="Chris Munt"<br />
^Customer(1, "Address", 1)="London"<br />
^Customer(1, "Address", 2)="UK"<br />
^Customer(1, "DateOfRegistration")="1 May 2010"<br />
In <strong>Node</strong>.<strong>js</strong>:<br />
12 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
Advanced Data Access <strong>with</strong> retrieve() and update()<br />
mydata.retrieve(<br />
{global: "Customer", subscripts: [1]},<br />
"object",<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
{<br />
}<br />
node: {<br />
global: "Customer",<br />
subscripts: [1]<br />
}<br />
object: {<br />
Name: "Chris Munt",<br />
Address: {"1": "London", "2": "UK"},<br />
DateOfRegistration: "1 May 2010"<br />
}<br />
3.5.1.4 Controlling the amount of data returned by retrieve operations<br />
The retrieve operations are capable, depending on the underlying global structure, of returning enormous volumes of data<br />
to the <strong>Node</strong>.<strong>js</strong> environment. The following properties can be added to the requesting JSON object (i.e. the object defining<br />
the root global node) to limit the amount of data returned.<br />
• max — The maximum number of global nodes to return.<br />
• lo — The lowest global subscript to return.<br />
• hi — The highest global subscript to return.<br />
If all three properties are defined, the retrieve operation will terminate when the max number of global nodes have been<br />
returned, even if the global subscript defined in hi has not been reached.<br />
Consider the following <strong>Caché</strong> global:<br />
^Customer(1, "Address", 1)="London"<br />
^Customer(1, "Address", 2)="UK"<br />
^Customer(1, "DateOfRegistration")="1 May 2010"<br />
^Customer(1, "Name")="Chris Munt"<br />
^Customer(1, "Orders", 20100501, "Reference")="Order001"<br />
^Customer(1, "Orders", 20100503, "Reference")="Order002"<br />
^Customer(1, "Orders", 20100507, "Reference")="Order003"<br />
^Customer(1, "Orders", 20100509, "Reference")="Order004"<br />
^Customer(1, "Orders", 20100510, "Reference")="Order005"<br />
^Customer(1, "Orders", 20100520, "Reference")="Order006"<br />
^Customer(1, "Orders", 20100527, "Reference")="Order007"<br />
^Customer(1, "Orders", 20100906, "Reference")="Order008"<br />
^Customer(1, "Orders", 20110104, "Reference")="Order011"<br />
^Customer(1, "Orders", 20110203, "Reference")="Order012"<br />
^Customer(2, "Address", 1)="Reigate"<br />
^Customer(2, "Address", 2)="UK"<br />
^Customer(2, "DateOfRegistration")="7 May 2010"<br />
^Customer(2, "Name")="Rob Tweed"<br />
^Customer(2, "Orders", 20101204, "Reference")="Order009"<br />
^Customer(2, "Orders", 20101206, "Reference")="Order010"<br />
^Customer(3, "Address", 1)="Oxford"<br />
^Customer(3, "Address", 2)="UK"<br />
^Customer(3, "DateOfRegistration")="9 June 2010"<br />
^Customer(3, "Name")="Jane Smith"<br />
^Customer(4, "Name")="Jim Cooper"<br />
^Customer(5, "Name")="Eve Simpson"<br />
^Customer(6, "Name")="John Cotton"<br />
^Customer(7, "Name")="Alison Clarke"<br />
^Customer(8, "Name")="Paul Francis"<br />
^Customer(9, "Name")="Susan Reed"<br />
^Customer(10, "Name")="Mary Dodds"<br />
Note:<br />
The third subscript in the "Orders" section is the date in YYYYMMDD format.<br />
The following examples demonstrate how to use the max, lo, and hi properties:<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 13
Accessing <strong>Caché</strong> from <strong>Node</strong>.<strong>js</strong><br />
Example 1: List the registered Customer numbers between 2 and 7 (inclusive)<br />
mydata.retrieve(<br />
{global: "Customer", lo: 2, hi: 7},<br />
"list",<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
Six Customer records:<br />
[2, 3, 4, 5, 6, 7]<br />
Example 2: List the Orders placed by Customer number 1 between 7 May 2010 and 24 December 2010<br />
(inclusive)<br />
mydata.retrieve(<br />
{<br />
global: "Customer",<br />
subscripts [1, "Orders"],<br />
lo: 20100507,<br />
hi: 20101224<br />
},<br />
"list",<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
Six Customer Order records:<br />
[20100507, 20100509, 20100510, 20100520, 20100527, 20100906]<br />
Example 3: List the full details for Orders placed by Customer number 1 in September 2010<br />
mydata.retrieve(<br />
{<br />
global: "Customer",<br />
subscripts [1, "Orders"],<br />
lo: 20100901,<br />
hi: 20100930<br />
},<br />
"array",<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
One Customer Order record:<br />
[{<br />
global: "Customer",<br />
subscripts: [1, "Orders", 20100906, "Reference"],<br />
data: "Order008"<br />
}]<br />
Example 4: List first three Customers registered (by Customer number) in the database<br />
mydata.retrieve(<br />
{global: "Customer", max: 3},<br />
"list",<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
Three Customer records:<br />
[1, 2, 3]<br />
14 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
Advanced Data Access <strong>with</strong> retrieve() and update()<br />
3.5.2 <strong>Using</strong> update()<br />
The update() method allows an application to save a group of global nodes by passing information saved in a single JSON<br />
object. The nodes can represent either an array or an object:<br />
• Save a list of global nodes (update("array"))<br />
• Save a structured data object (update("object"))<br />
3.5.2.1 Save a list of global nodes (update("array"))<br />
This method performs the opposite task to that performed by the retrieve method. In other words the update method takes<br />
an array of global nodes, each expressed as a single JSON object and writes them back to the <strong>Caché</strong> database.<br />
Example 1: Create or update a record for a customer<br />
mydata.update(<br />
[<br />
{<br />
global: "Customer",<br />
subscripts: [1],<br />
data: "Chris Munt"<br />
}<br />
{<br />
global: "Customer",<br />
subscripts: [1, "Address", 1],<br />
data: "London"<br />
}<br />
{<br />
global: "Customer",<br />
subscripts: [1, "Address", 2],<br />
data: "UK"<br />
}<br />
{<br />
global: "Customer",<br />
subscripts: [1, "DateOfRegistration"],<br />
data: "1 May 2010"<br />
}<br />
],<br />
"array",<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
Operation successful if no error reported.<br />
3.5.2.2 Save a structured data object (update("object"))<br />
This method performs the opposite task to that performed by the retrieve method. In other words it writes the contents of<br />
a structured JSON object back to the <strong>Caché</strong> database.<br />
Example 1: Create or update a record for a customer<br />
mydata.update(<br />
node: {<br />
global: "Customer",<br />
subscripts: [1]<br />
},<br />
Object: {<br />
Name: "Chris Munt",<br />
DateOfRegistration: "1 May 2010",<br />
Address: {"1": "London", "2": "UK"}<br />
},<br />
"object",<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 15
Accessing <strong>Caché</strong> from <strong>Node</strong>.<strong>js</strong><br />
Operation successful if no error reported. If successful, the following set of global nodes will be created for this<br />
example:<br />
^Customer(1, "Address", 1)="London"<br />
^Customer(1, "Address", 2)="UK"<br />
^Customer(1, "DateOfRegistration")="1 May 2010"<br />
^Customer(1, "Name")="Chris Munt"<br />
3.6 Towards an Object Oriented Development<br />
Methodology<br />
The examples shown so far have illustrated the use of the <strong>Caché</strong> database as a raw NoSQL engine. The following code<br />
illustrates how the cache.node methods together <strong>with</strong> the JSON notation in JavaScript can be used to create a more Object<br />
Orientated development methodology.<br />
var globals = require('cache');<br />
var user = new globals.Cache();<br />
user.open({<br />
path:"/cache20102/mgr",<br />
username: "_SYSTEM",<br />
password: "SYS",<br />
namespace: "USER"<br />
});<br />
var customers = new Customers();<br />
var customer = customers.getCustomer(1);<br />
console.log("customer number 1 is " + customer.data);<br />
customers.setCustomer(9, "Tom Smith");<br />
user.close();<br />
function Customers() {<br />
this.global = "Customer";<br />
this.subscripts = new Array();<br />
this.getCustomer = function(id) {<br />
this.subscripts[0] = id;<br />
var person = user.get(this);<br />
return person;<br />
}<br />
this.setCustomer = function(id, name) {<br />
this.subscripts[0] = id;<br />
this.data = name;<br />
var person = user.set(this);<br />
return;<br />
}<br />
}<br />
16 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
4<br />
Reference for cache.node Methods<br />
This section provides detailed documentation for each of the functions supported by the <strong>Caché</strong> cache.node module. See<br />
the “Example Data” section for a listing of the data sets used by many of the examples in this section.<br />
The following functions are supported:<br />
• about() — see version().<br />
• close() — closes a previously opened database.<br />
• data() — tests for the existence of a global node.<br />
• function() — invokes a <strong>Caché</strong> function.<br />
• get() — retrieves a global node.<br />
• global_directory() — returns a list of globals held in the <strong>Caché</strong> database.<br />
• increment() — adds 1 to the value of an integer in a global node.<br />
• kill() — deletes a global node.<br />
• lock() — locks global nodes for exclusive use.<br />
• merge() — copies all or part of a global to another global.<br />
• next() — gets the next Global subscript on the current level.<br />
• next_node() — gets the next global node in collation order regardless of level.<br />
• open() — opens the specified <strong>Caché</strong> database.<br />
• order() — see next()<br />
• previous() — gets the previous Global subscript on the current level.<br />
• previous_node() — gets the previous global node in collation order regardless of level.<br />
• retrieve() — recursively retrieves all global nodes defined beneath a specified level.<br />
• set() — sets the value of a global node.<br />
• update() — writes the contents of a JSON object to the <strong>Caché</strong> database.<br />
• unlock() — unlocks global nodes previously locked by your program.<br />
• version() — returns basic version information about the cache.node module in use and the associated <strong>Caché</strong> database<br />
(if open).<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 17
Reference for cache.node Methods<br />
4.1 Example Data<br />
Most examples in this reference section will be based on the following simple <strong>Caché</strong> data set:<br />
^Customer(1)="Chris Munt"<br />
^Customer(1, "address")="Banstead"<br />
^Customer(2)="Rob Tweed"<br />
^Customer(3)="Jane Smith"<br />
The following <strong>Caché</strong> data will be used to illustrate the retrieve() and update() methods:<br />
^Customer(1)="Chris Munt"<br />
^Customer(1, "Address", 1)="London"<br />
^Customer(1, "Address", 2)="UK"<br />
^Customer(1, "DateOfRegistration")="1 May 2010"<br />
^Customer(2)="Rob Tweed"<br />
^Customer(2, "Address", 1)="Reigate"<br />
^Customer(2, "Address", 2)="UK"<br />
^Customer(2, "DateOfRegistration")="7 May 2010"<br />
^Customer(3)="Jane Smith"<br />
^Customer(3, "Address", 1)="Oxford"<br />
^Customer(3, "Address", 2)="UK"<br />
^Customer(3, "DateOfRegistration")="9 June 2010"<br />
4.2 close()<br />
The close() method will gracefully close a previously opened database. See “Opening and Closing the <strong>Caché</strong> Database”<br />
for a detailed description of how to open and close the database.<br />
Synchronous<br />
Asynchronous<br />
Parameters<br />
mydata.close();<br />
mydata.close(callback_function);<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example<br />
mydata.close(<br />
function(error, result) { // callback code }<br />
);<br />
4.3 data()<br />
The data() method tests for the existence of a global node.<br />
This method will return one of the following numeric values:<br />
• 0 — <strong>Node</strong> does not exist.<br />
18 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
function()<br />
• 1 — <strong>Node</strong> has data but no subnodes.<br />
• 10 — <strong>Node</strong> does not have data but has subnodes.<br />
• 11 — <strong>Node</strong> has data and has subnodes.<br />
Synchronous<br />
Asynchronous<br />
Parameters<br />
var result = mydata.data(node);<br />
mydata.data(node, callback_function);<br />
• node — the global node to be accessed.<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example<br />
mydata.data(<br />
{global: "Customer", subscripts: [1]},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
{defined: 11}<br />
4.4 function()<br />
The function() method provides a way to invoke a <strong>Caché</strong> function directly.<br />
Synchronous<br />
Asynchronous<br />
Parameters<br />
var result = mydata.function(<br />
Cache_Function_Name,<br />
Arguments ...<br />
);<br />
var result = mydata.function(<br />
{<br />
Cache_Function_Name,<br />
Arguments ...<br />
},<br />
callback_function<br />
);<br />
• Cache_Function_Name<br />
• Arguments<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 19
Reference for cache.node Methods<br />
The following examples will be based on calls to the following <strong>Caché</strong> function:<br />
Math<br />
Add(X,Y)<br />
Multiply(X,Y)<br />
; Math Functions<br />
;<br />
; Add two numbers<br />
Quit (X * Y)<br />
;<br />
; Add two numbers<br />
Quit (X * Y)<br />
;<br />
This is a simple <strong>Caché</strong> ‘routine’ file called ‘Math" containing functions to perform basic mathematical functions ("Add"<br />
and "Multiply").<br />
Example 1 (Synchronous/Non-JSON)<br />
Result:<br />
7<br />
result = mydata.function("Add^Math", 3, 4);<br />
Example 2: (Synchronous/JSON)<br />
Result:<br />
result = mydata.function({function: "Add^Math", arguments: [3, 4]});<br />
{<br />
}<br />
"function": "Add^Math",<br />
"arguments": [3, 4],<br />
"result": 7<br />
Example 3: (Asynchronous/JSON)<br />
mydata.function(<br />
{function: "Add^Math", arguments: [3, 4]},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
{<br />
}<br />
"ok": 1,<br />
"function": " Add^Math ",<br />
"arguments": [3, 4],<br />
"result": 7<br />
4.5 get()<br />
The get() method retrieves a global node.<br />
Synchronous<br />
var result = mydata.get(node);<br />
Asynchronous<br />
mydata.get(node, callback_function);<br />
20 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
global_directory()<br />
Parameters<br />
• node — the global node to be accessed.<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example 1 (Synchronous)<br />
Result:<br />
result = mydata.get({global: "Customer", subscripts: [9]});<br />
{global: "Customer", subscripts: [9], data: "", defined: 0}<br />
Example 2 (Asynchronous)<br />
mydata.get(<br />
{global: "Customer", subscripts: [1]},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
{global: "Customer", subscripts: [1], data: "Chris Munt", defined: 1}<br />
Note that the ‘defined’ property is set to 1 if the global node is actually defined and set to 0 if it is not.<br />
4.6 global_directory()<br />
The global_directory() method returns a list of globals held in the directory. The number of names returned can be controlled<br />
using the range limiting properties ‘lo’, ‘hi’ and ‘max’ (see “Controlling the amount of data returned by retrieve operations”).<br />
Synchronous<br />
Asynchronous<br />
Parameters<br />
var result = mydata.global_directory(range);<br />
mydata.global_directory (range, callback_function);<br />
• range<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example 1: Obtain a list of all globals in the directory<br />
mydata.global_directory(<br />
{},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
If successful, an array containing all global names found will be returned.<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 21
Reference for cache.node Methods<br />
Example 2: Obtain a list of all globals whose name begins <strong>with</strong> "Cust"<br />
mydata. global_directory(<br />
{lo: "Cust", hi: "Cust~"},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
If successful, an array containing all global names beginning <strong>with</strong> "Cust" will be returned.<br />
4.7 increment()<br />
The increment() method adds 1 to the value of an integer in a global node.<br />
This method provides an efficient way of uniquely assigning an (incremented) integer to a process <strong>with</strong>out using locking.<br />
When called, the integer value held in the global is incremented and the new value returned to the calling program. <strong>Caché</strong><br />
will guarantee that a unique number is assigned to multiple processes that may be accessing this function simultaneously.<br />
Synchronous<br />
Asynchronous<br />
Parameters<br />
var result = mydata.increment(node);<br />
mydata.increment (node, callback_function);<br />
• node — the global node that holds the value to be incremented.<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example<br />
mydata.increment(<br />
{global: "Counter"},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
If successful the integer value held in global "Counter" will be incremented and the new value returned as the<br />
result.<br />
4.8 kill()<br />
The kill() method deletes a global node.<br />
Synchronous<br />
var result = mydata.kill(node);<br />
Asynchronous<br />
mydata.kill(node, callback_function);<br />
22 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
lock()<br />
Parameters<br />
• node — the global node to be accessed.<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example<br />
mydata.kill(<br />
{global: "Customer", subscripts: [1]},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
Operation successful if no error reported.<br />
4.9 lock()<br />
The lock() method locks global nodes for exclusive use by your program. The method can lock either an entire Global (for<br />
example, ^Customer) or sub-sections of a Global (for example, ^Customer(1)).<br />
To prevent deadlock situations, all global nodes that your code has locked should be unlocked before your program terminates<br />
(see unlock()).<br />
Synchronous<br />
Asynchronous<br />
Parameters<br />
var result = mydata.lock(node);<br />
mydata.lock(node, callback_function);<br />
• node — the global node to be accessed.<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example<br />
mydata.lock(<br />
{global: "Customer", subscripts: [1]},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
Operation successful if no error reported.<br />
4.10 merge()<br />
The merge method copies all or part of a global to another global.<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 23
Reference for cache.node Methods<br />
Synchronous<br />
Asynchronous<br />
Parameters<br />
var result = mydata.merge(to: {destination_node},<br />
from: {source_node}};<br />
mydata.merge({to: {destination_node},<br />
from: {source_node}},<br />
callback_function);<br />
• source_node<br />
• destination_node<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example 1: Copy a whole global<br />
mydata.get(<br />
{to: {global: "CopyOfCustomer"},<br />
from: {global: "Customer"}},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
If successful, the whole of global "Customer" will be copied to "CopyOfCustomer".<br />
Example 2: Copy a section of global<br />
mydata.get(<br />
{to: {global: "Customer", subscripts: [7, "address"]},<br />
from: {global: "Customer", subscripts: [1, "address"]}},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
If successful, the subsection of global contained under "Customer(1,’address’)" will be copied to "Customer(7,’address’)".<br />
4.11 next() or order()<br />
The next() method gets the next Global subscript.<br />
Get the next value in the collating sequence for a particular level of subscript.<br />
Synchronous<br />
var result = mydata.order(node);<br />
Asynchronous<br />
mydata.order(node, callback_function);<br />
Parameters<br />
• node — the global node to be accessed.<br />
24 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
next_node()<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example 1 (Synchronous)<br />
Result:<br />
result = mydata.order({global: "Customer", subscripts: [""]},<br />
{global: "Customer", subscripts: [1], result: "1"}}<br />
Example 2 (Synchronous)<br />
Result:<br />
result = mydata.next({global: "Customer", subscripts: [3]},<br />
{global: "Customer", subscripts: [""], result: ""}}<br />
Example 3 (Asynchronous)<br />
mydata.next(<br />
{global: "Customer", subscripts: [1]},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
{global: "Customer", subscripts: [2], result: "2"}}<br />
Example 4 (Parse at the first level)<br />
key = {global: "Customer", subscripts: [""]};<br />
while ((key = user.next(key)).result != "") {<br />
console.log(JSON.stringify(key, null, '\t'))<br />
}<br />
Result:<br />
{global: "Customer", subscripts: [1], result: "1"}}<br />
{global: "Customer", subscripts: [2], result: "2"}}<br />
{global: "Customer", subscripts: [3], result: "3"}}<br />
If there is no further subscript defined in the sequence then the result property will be returned as empty string<br />
("").<br />
4.12 next_node()<br />
The next_node() method gets the next global node in the collating sequence regardless of the level of subscript.<br />
Synchronous<br />
var result = mydata.next_node(node);<br />
Asynchronous<br />
mydata.next_node(node, callback_function);<br />
Parameters<br />
• node — the global node to be accessed.<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 25
Reference for cache.node Methods<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example 1 (Synchronous)<br />
Result:<br />
result = mydata.next_node({global: "Customer"},<br />
{global: "Customer", subscripts: [1], data: "Chris Munt, defined: 1}}<br />
Example 2 (Synchronous)<br />
Result:<br />
result = mydata.next_node({global: "Customer", subscripts: [3]},<br />
{global: "Customer", defined: 0}}<br />
Example 3 (Asynchronous)<br />
mydata.next_node(<br />
{global: "Customer", subscripts: [1]},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
{<br />
}<br />
global: "Customer",<br />
subscripts: [1, "address"],<br />
data: "Banstead",<br />
defined: 1<br />
Example 4 (Parse Global)<br />
key = {global: "Customer"};<br />
while ((key = user.next_node(key)).defined) {<br />
console.log(JSON.stringify(key, null, '\t'));<br />
}<br />
Result:<br />
{<br />
}<br />
{<br />
}<br />
{<br />
}<br />
{<br />
}<br />
global: "Customer",<br />
subscripts: [1],<br />
data: "Chris Munt",<br />
defined: 1<br />
global: "Customer",<br />
subscripts: [1, "address"],<br />
data: "Banstead",<br />
defined: 1<br />
global: "Customer",<br />
subscripts: [2],<br />
data: "Rob Tweed",<br />
defined: 1<br />
global: "Customer",<br />
subscripts: [3],<br />
data: "Jane Smith",<br />
defined: 1<br />
If there is no further node defined in the sequence then the defined property will be set to zero.<br />
26 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
open()<br />
4.13 open()<br />
The open() method opens the specified <strong>Caché</strong> database. See “Opening and Closing the <strong>Caché</strong> Database” for a detailed<br />
description of how to open and close the database.<br />
Synchronous<br />
Asynchronous<br />
Parameters<br />
mydata.open(parameters);<br />
mydata.open(parameters, callback_function);<br />
• parameters — specifies the <strong>Caché</strong> database to be opened:<br />
– parameters.path — Path to the ‘mgr’ directory of the target <strong>Caché</strong> installation.<br />
– parameters.username — User name for access.<br />
– parameters.password — Password for access.<br />
– parameters.namespace — Target <strong>Caché</strong> namespace.<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example<br />
mydata.open(<br />
{<br />
path:"/cache20102/mgr",<br />
username: "_SYSTEM",<br />
password: "SYS",<br />
namespace: "USER"<br />
},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
Operation successful if no error reported.<br />
4.14 previous()<br />
The previous() method gets the previous Global subscript<br />
Get the previous value in the collating sequence for a particular level of subscript.<br />
Synchronous<br />
var result = mydata.previous(node);<br />
Asynchronous<br />
mydata.previous(node, callback_function);<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 27
Reference for cache.node Methods<br />
Parameters<br />
• node — the global node to be accessed.<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example 1 (Synchronous)<br />
Result:<br />
result = mydata.previous({global: "Customer", subscripts: [""]},<br />
{global: "Customer", subscripts: [3], result: "3"}}<br />
Example 2 (Synchronous)<br />
Result:<br />
result = mydata.previous({global: "Customer", subscripts: [2]},<br />
{global: "Customer", subscripts: ["1"], result: "1"}}<br />
Example 3 (Asynchronous)<br />
mydata.previous(<br />
{global: "Customer", subscripts: [1]},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
{global: "Customer", subscripts: [""], result: ""}}<br />
Example 4 (Parse at the first level)<br />
key = {global: "Customer", subscripts: [""]};<br />
while ((key = user.previous(key)).result != "") {<br />
console.log(JSON.stringify(key, null, '\t'))<br />
}<br />
Result:<br />
{global: "Customer", subscripts: [3], result: "3"}}<br />
{global: "Customer", subscripts: [2], result: "2"}}<br />
{global: "Customer", subscripts: [1], result: "1"}}<br />
If there is no further subscript defined in the sequence then the result property will be returned as empty string<br />
("").<br />
4.15 previous_node()<br />
The previous_node() method gets the previous global node<br />
Get the previous whole global node in the collating sequence regardless of the level of subscript.<br />
Synchronous<br />
var result = mydata.previous(node);<br />
28 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
previous_node()<br />
Asynchronous<br />
Parameters<br />
mydata.previous(node, callback_function);<br />
• node — the global node to be accessed.<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example 1 (Synchronous)<br />
result = mydata.previous_node({global: "Customer", subscripts: ["z"]},<br />
Result:<br />
{global: "Customer", subscripts: [3], data: "Jane Smith", defined: 1}}<br />
Example 2 (Synchronous)<br />
result = mydata.next_node({global: "Customer", subscripts: [2]},<br />
Result:<br />
{<br />
}<br />
global: "Customer",<br />
subscripts: [1, "address"],<br />
data: "Banstead",<br />
defined: 1<br />
Example 3 (Asynchronous)<br />
mydata.previous_node(<br />
{global: "Customer", subscripts: [1]},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
{global: "Customer", defined: 0}}<br />
Example 4 (Parse Global)<br />
key = {global: "Customer", subscripts: ["z"]};<br />
while ((key = user.previous_node(key)).defined) {<br />
console.log(JSON.stringify(key, null, '\t'));<br />
}<br />
Result:<br />
{<br />
}<br />
{<br />
}<br />
{<br />
}<br />
{<br />
global: "Customer",<br />
subscripts: [3],<br />
data: "Jane Smith",<br />
defined: 1<br />
global: "Customer",<br />
subscripts: [2],<br />
data: "Rob Tweed",<br />
defined: 1<br />
global: "Customer",<br />
subscripts: [1, "address"],<br />
data: "Banstead",<br />
defined: 1<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 29
Reference for cache.node Methods<br />
}<br />
global: "Customer",<br />
subscripts: [1],<br />
data: "Chris Munt",<br />
defined: 1<br />
If there is no further node defined in the sequence then the defined property will be set to zero.<br />
4.16 retrieve()<br />
• The retrieve(node, "list") method will return a list of subscript values that are defined directly beneath a<br />
given level in the global.<br />
• The retrieve(node, "array") method will return a list of subscript values together <strong>with</strong> their associated data<br />
values that are defined beneath a given level in the global. The method is recursive and will retrieve all global nodes<br />
defined beneath a chosen level.<br />
The result will be expressed as an array of global nodes, <strong>with</strong> each global node expressed as a single JSON object.<br />
• The retrieve(node, "object") method will retrieve a structured data object defined beneath a given level in<br />
a global. This method provides a structured alternative to an array of global nodes.<br />
The result will be expressed as a single JSON object.<br />
Synchronous<br />
Asynchronous<br />
Parameters<br />
var result = mydata.retrieve(node, type);<br />
mydata.retrieve(node, type, callback_function);<br />
• node — the global node to be accessed.<br />
• type — a literal string specifying the type of data to be accessed. Options are:<br />
– "list"<br />
– "array"<br />
– "object"<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example 1 (type = “list”): Retrieve a list of customer numbers<br />
mydata.retrieve(<br />
{global: "Customer"},<br />
"list",<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
Three Customer records:<br />
[1, 2, 3]<br />
30 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
etrieve()<br />
Example 2 (type = “list”): Retrieve a list of address lines for a specific customer<br />
mydata.retrieve(<br />
{global: "Customer", subscripts: [1, "address"]},<br />
"list",<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
Two lines in the address for customer number 1:<br />
[1, 2]<br />
Example 3 (type = “array”): Retrieve all data for a customer<br />
mydata.retrieve(<br />
{global: "Customer", subscripts: [1]},<br />
"array",<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
[<br />
]<br />
{ global: "Customer",<br />
subscripts: [1],<br />
data: "Chris Munt"<br />
}<br />
{ global: "Customer",<br />
subscripts: [1, "Address", 1],<br />
data: "London"<br />
}<br />
{ global: "Customer",<br />
subscripts: [1, "Address", 2],<br />
data: "UK"<br />
}<br />
{ global: "Customer",<br />
subscripts: [1, "DateOfRegistration],<br />
data: "1 May 2010"<br />
}<br />
Example 4 (type = “object”): Retrieve all data for a customer<br />
Consider the following structured <strong>Caché</strong> global:<br />
^Customer(1, "Name")="Chris Munt"<br />
^Customer(1, "Address", 1)="London"<br />
^Customer(1, "Address", 2)="UK"<br />
^Customer(1, "DateOfRegistration")="1 May 2010"<br />
In <strong>Node</strong>.<strong>js</strong>:<br />
mydata.retrieve(<br />
{global: "Customer", subscripts: [1]},<br />
"object",<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
{<br />
}<br />
node: {<br />
global: "Customer",<br />
subscripts: [1]<br />
}<br />
object: {<br />
Name: "Chris Munt",<br />
Address: {"1": "London", "2": "UK"},<br />
DateOfRegistration: "1 May 2010"<br />
}<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 31
Reference for cache.node Methods<br />
4.17 set()<br />
The set() method saves a global node.<br />
Synchronous<br />
Asynchronous<br />
Parameters<br />
var result = mydata.set(node);<br />
mydata.set(node, callback_function);<br />
• node — the global node to be accessed.<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example<br />
mydata.set(<br />
{global: "Customer", subscripts: [1], data: "Chris Munt"},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
Operation successful if no error reported.<br />
4.18 unlock()<br />
The unlock() method unlocks global nodes previously locked by your program (see lock()). The method can unlock either<br />
an entire Global (for example, ^Customer) or sub-sections of a Global (for example, ^Customer(1)).<br />
To release all locks held by your program, call the unlock() method <strong>with</strong> no node argument. All locks held by a <strong>Node</strong>.<strong>js</strong><br />
process will be released when the process terminates normally.<br />
Synchronous<br />
Asynchronous<br />
Parameters<br />
var result = mydata.unlock(node);<br />
var result = mydata.unlock();<br />
mydata.unlock(node, callback_function);<br />
mydata.unlock(callback_function);<br />
• node — the global node to be accessed.<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
32 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
update()<br />
Example 1: Unlock one node<br />
mydata.unlock(<br />
{global: "Customer", subscripts: [1]},<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
Operation successful if no error reported.<br />
Example 2: Unlock all locked nodes<br />
mydata.unlock(<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
Operation successful if no error reported.<br />
4.19 update()<br />
The update() method writes the contents of a JSON object to the <strong>Caché</strong> database.<br />
• The update("array") method performs the opposite task to that performed by the retrieve method. In other words<br />
the update method takes an array of global nodes, each expressed as a single JSON object and writes them back to the<br />
<strong>Caché</strong> database.<br />
• The update("object") method performs the opposite task to that performed by the retrieve method. In other words<br />
it writes the contents of a structured JSON object back to the <strong>Caché</strong> database.<br />
Synchronous<br />
Asynchronous<br />
Parameters<br />
var result = mydata.update(node, type);<br />
mydata.update(node, type, callback_function);<br />
• node — the global node to be accessed.<br />
• type — a literal string specifying the type of data to be accessed. Options are:<br />
– "array"<br />
– "object"<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
Example 1 (type = “array”): Create or update a record for a customer<br />
mydata.update(<br />
[<br />
{ global: "Customer",<br />
subscripts: [1],<br />
data: "Chris Munt"<br />
}<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 33
Reference for cache.node Methods<br />
);<br />
Result:<br />
{ global: "Customer",<br />
subscripts: [1, "Address", 1],<br />
data: "London"<br />
}<br />
{ global: "Customer",<br />
subscripts: [1, "Address", 2],<br />
data: "UK"<br />
}<br />
{ global: "Customer",<br />
subscripts: [1, "DateOfRegistration"],<br />
data: "1 May 2010"<br />
}<br />
],<br />
"array",<br />
function(error, result) { // callback code }<br />
Operation successful if no error reported.<br />
Example 2 (type = “object”): Create or update a record for a customer<br />
mydata.update(<br />
node: {<br />
global: "Customer",<br />
subscripts: [1]<br />
},<br />
Object: {<br />
Name: "Chris Munt",<br />
DateOfRegistration: "1 May 2010",<br />
Address: {"1": "London", "2": "UK"}<br />
},<br />
"object",<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
Operation successful if no error reported. If successful, the following set of global nodes will be created for this<br />
example:<br />
^Customer(1, "Address", 1)="London"<br />
^Customer(1, "Address", 2)="UK"<br />
^Customer(1, "DateOfRegistration")="1 May 2010"<br />
^Customer(1, "Name")="Chris Munt"<br />
4.20 version() and about()<br />
The version() and about() methods return basic version information about the cache.node module in use and the associated<br />
<strong>Caché</strong> database (if open).<br />
Synchronous<br />
Asynchronous<br />
Parameters<br />
var result = mydata.version();<br />
var result = mydata.about();<br />
mydata.version(callback_function);<br />
mydata.about(callback_function);<br />
• callback_function — a function of the form function(error, result){} used to return results<br />
asynchronously (see “Synchronous vs. Asynchronous cache.node Methods”).<br />
34 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
version() and about()<br />
Example<br />
mydata.version(<br />
function(error, result) { // callback code }<br />
);<br />
Result:<br />
If the <strong>Caché</strong> database is not open:<br />
<strong>Node</strong>.<strong>js</strong> Adaptor for Cache: Version: 1.0.17 (CM)<br />
If the <strong>Caché</strong> database is open:<br />
<strong>Node</strong>.<strong>js</strong> Adaptor for Cache: Version: 1.0.17 (CM); <strong>Caché</strong> Version: 2012 build 100<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 35
A<br />
Building cache.node from Source<br />
The following development tools should be installed:<br />
• C and C++ build environment.<br />
• For Ubuntu:<br />
– sudo apt-get install gcc<br />
– sudo apt-get install g++<br />
There are two methods for building the cache.node module from source:<br />
• <strong>Using</strong> the <strong>Node</strong>.<strong>js</strong> Build Procedure — using the scripts provided by the <strong>Node</strong>.<strong>js</strong> community.<br />
• Building Directly from Source — directly from the C++ source (cache.cpp).<br />
A.1 <strong>Using</strong> the <strong>Node</strong>.<strong>js</strong> Build Procedure<br />
The cache.node module is built using the script provided by node-waf script provided by the <strong>Node</strong>.<strong>js</strong> group. The node-waf<br />
scripts builds the cache.node module in accordance <strong>with</strong> instructions contained in a file called wscript.<br />
.../build/default/<br />
A.1.1 Creating the Build Script (wscript)<br />
The script provided is as follows:<br />
def set_options(opt):<br />
opt.tool_options("compiler_cxx")<br />
def configure(conf):<br />
conf.check_tool("compiler_cxx")<br />
conf.check_tool("node_addon")<br />
def build(bld):<br />
obj = bld.new_task_gen("cxx", "shlib", "node_addon")<br />
obj.cxxflags = ["-g", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE", "-Wall",<br />
"-I/cache20102/dev/cpp/include"]<br />
obj.linkflags = ["-Wl", "-lpthread", "-lrt", "-ldl", "-lc", "-lm"]<br />
obj.target = "cache"<br />
obj.source = "cache.cpp"<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 37
Building cache.node from Source<br />
Create this text file and modify it to suite your own environment. There is just one path that will require modifying for your<br />
local environment<br />
• The compiler options line (obj.cxxflags):<br />
"-I/cache20102/dev/cpp/include"<br />
This must be the directory where the <strong>Caché</strong> C header files reside (For example: callin.h)<br />
A.1.2 Build the cache.node Module<br />
In the directory containing both the wscript file created previously and the source code (cache.cpp) use the node-waf<br />
command to build the module:<br />
node-waf configure build<br />
If successful, the output will look something like the following:<br />
Setting srcdir to<br />
: /opt/cm/node042<br />
Setting blddir to<br />
: /opt/cm/node042/build<br />
Checking for program g++ or c++<br />
: /usr/bin/g++<br />
Checking for program cpp<br />
: /usr/bin/cpp<br />
Checking for program ar<br />
: /usr/bin/ar<br />
Checking for program ranlib<br />
: /usr/bin/ranlib<br />
Checking for g++<br />
: ok<br />
Checking for node path<br />
: not found<br />
Checking for node prefix<br />
: ok /opt/cm/node042<br />
'configure' finished successfully (0.974s)<br />
Waf: Entering directory `/opt/cm/node042/build'<br />
[1/2] cxx: cache.cpp -> build/default/cache_1.o<br />
[2/2] cxx_link: build/default/cache_1.o -> build/default/cache.node<br />
Waf: Leaving directory `/opt/cm/node042/build'<br />
'build' finished successfully (2.904s)<br />
root@ubuntu:/opt/cm/node042#<br />
The <strong>Caché</strong> module will be created: cache.node<br />
This module will, by default, be created in the following subdirectory:<br />
.../build/default/<br />
A.2 Building Directly from Source<br />
As an alternative to using the scripted infrastructure provided by the <strong>Node</strong>.<strong>js</strong> Group, the <strong>Caché</strong> module (cache.node) can<br />
be built directly from the C++ source code as follows:<br />
Linux:<br />
g++ -c -g -fPIC -DPIC -DEV_MULTIPLICITY=0 –DLINUX \<br />
-D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wall \<br />
-I/opt/local/node/include/node -I/cache20102/dev/cpp/include \<br />
-o cache.o cache.cpp<br />
g++ -shared -L/opt/local/node/lib -Wl -lpthread -lrt -ldl -lc -lm \<br />
-o cache.node cache.o<br />
Note the three paths that will require modifying to suit your local environment.<br />
• Path to the <strong>Node</strong>.<strong>js</strong> C/C++ header files. For example:<br />
/opt/local/node/include/node<br />
• Path to the <strong>Caché</strong> C/C++ header files. For example:<br />
/cache20102/dev/cpp/include<br />
38 <strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong>
Building Directly from Source<br />
• Path to the <strong>Node</strong>.<strong>js</strong> library files. For example:<br />
/opt/local/node/lib<br />
<strong>Using</strong> <strong>Node</strong>.<strong>js</strong> <strong>with</strong> <strong>Caché</strong> 39