25.01.2015 Views

Using Node.js with Caché - InterSystems Documentation

Using Node.js with Caché - InterSystems Documentation

Using Node.js with Caché - InterSystems Documentation

SHOW MORE
SHOW LESS

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

Hooray! Your file is uploaded and ready to be published.

Saved successfully!

Ooh no, something went wrong!