Using Node.js with Caché - InterSystems

6 downloads 79 Views 155KB Size Report
Using Node.js with Caché. Version 2012.2. 31 August 2012. InterSystems Corporation 1 Memorial Drive Cambridge MA 02142 www.intersystems.com ...
Using Node.js with Caché Version 2012.2 31 August 2012

InterSystems Corporation 1 Memorial Drive Cambridge MA 02142 www.intersystems.com

Using Node.js with Caché Caché Version 2012.2 31 August 2012 Copyright © 2012 InterSystems Corporation All rights reserved. This book was assembled and formatted in Adobe Page Description Format (PDF) using tools and information from the following sources: Sun Microsystems, RenderX, Inc., Adobe Systems, and the World Wide Web Consortium at www.w3c.org.The primary document development tools were special-purpose XML-processing applications built by InterSystems using Caché and Java.

,

,

Caché WEBLINK, Distributed Cache Protocol, M/SQL, M/NET, and M/PACT are registered trademarks of InterSystems Corporation.

,

,

,

,

InterSystems Jalapeño Technology, Enterprise Cache Protocol, ECP, and InterSystems Zen are trademarks of InterSystems Corporation. All other brand or product names used herein are trademarks or registered trademarks of their respective companies or organizations. This document contains trade secret and confidential information which is the property of InterSystems Corporation, One Memorial Drive, Cambridge, MA 02142, or its affiliates, and is furnished for the sole purpose of the operation and maintenance of the products of InterSystems Corporation. No part of this publication is to be used for any other purpose, and this publication is not to be reproduced, copied, disclosed, 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, without the express prior written consent of InterSystems Corporation. The copying, use and disposition of this document and the software programs described herein is prohibited except to the limited extent set forth in the standard software license agreement(s) of InterSystems Corporation covering such programs and related documentation. InterSystems Corporation makes no representations and warranties concerning such software programs other than those set forth in such standard software license agreement(s). In addition, the liability of InterSystems Corporation for any losses or damages relating to or arising out of the use of such software programs is limited in the manner set forth in such standard software license agreement(s). THE FOREGOING IS A GENERAL SUMMARY OF THE RESTRICTIONS AND LIMITATIONS IMPOSED BY INTERSYSTEMS CORPORATION ON THE USE OF, AND LIABILITY ARISING FROM, ITS COMPUTER SOFTWARE. FOR COMPLETE INFORMATION REFERENCE SHOULD BE MADE TO THE STANDARD SOFTWARE LICENSE AGREEMENT(S) OF INTERSYSTEMS CORPORATION, COPIES OF WHICH WILL BE MADE AVAILABLE UPON REQUEST. InterSystems Corporation disclaims responsibility for errors which may appear in this document, and it reserves the right, in its sole discretion and without notice, to make substitutions and modifications in the products and practices described in this document. For Support questions about any InterSystems products, contact: InterSystems Worldwide Customer Support Tel: +1 617 621-0700 Fax: +1 617 374-9391 Email: [email protected]

Table of Contents About This Book .................................................................................................................................... 1 1 Introduction ........................................................................................................................................ 3 2 Installation ........................................................................................................................................... 5 2.1 UNIX .......................................................................................................................................... 5 2.2 Windows ..................................................................................................................................... 6 3 Accessing Caché from Node.js ........................................................................................................... 7 3.1 JSON Objects and Caché Globals .............................................................................................. 7 3.2 Synchronous vs. Asynchronous cache.node Methods ................................................................ 8 3.3 Overview of cache.node Methods .............................................................................................. 9 3.4 Opening and Closing the Caché Database ............................................................................... 10 3.5 Advanced Data Access with retrieve() and update() ................................................................ 11 3.5.1 Using retrieve() .............................................................................................................. 11 3.5.2 Using update() ................................................................................................................ 15 3.6 Towards an Object Oriented Development Methodology ........................................................ 16 4 Reference for cache.node Methods ................................................................................................. 17 4.1 Example Data ........................................................................................................................... 18 4.2 close() ....................................................................................................................................... 18 4.3 data() ......................................................................................................................................... 18 4.4 function() .................................................................................................................................. 19 4.5 get() .......................................................................................................................................... 20 4.6 global_directory() ..................................................................................................................... 21 4.7 increment() ............................................................................................................................... 22 4.8 kill() .......................................................................................................................................... 22 4.9 lock() ........................................................................................................................................ 23 4.10 merge() ................................................................................................................................... 23 4.11 next() or order() ...................................................................................................................... 24 4.12 next_node() ............................................................................................................................. 25 4.13 open() ..................................................................................................................................... 27 4.14 previous() ................................................................................................................................ 27 4.15 previous_node() ...................................................................................................................... 28 4.16 retrieve() ................................................................................................................................. 30 4.17 set() ......................................................................................................................................... 32 4.18 unlock() .................................................................................................................................. 32 4.19 update() ................................................................................................................................... 33 4.20 version() and about() .............................................................................................................. 34 Appendix A:Building cache.node from Source ................................................................................. 37 A.1 Using the Node.js Build Procedure ......................................................................................... 37 A.1.1 Creating the Build Script (wscript) ............................................................................... 37 A.1.2 Build the cache.node Module ........................................................................................ 38 A.2 Building Directly from Source ................................................................................................ 38

Using Node.js with Caché                                                                                                                                                      iii

About This Book This book describes how to install and use the cache.node module, which provides access to Caché from a Node.js application. This book contains the following sections: •

Introduction



Installation



Accessing Caché from Node.js



Reference for cache.node Methods



Building cache.node from Source

There is also a detailed Table of Contents. For general information, see Using InterSystems Documentation.

Using Node.js with Caché                                                                                                                                                       1

1 Introduction This document describes cache.node, an add-on module for the Node.js environment that implements high performance access to data held in Caché. Node.js provides a means through which high performance and highly scalable network infrastructure can be easily created. It is different from conventional thread based networking software (such as web servers) because it provides a non-blocking event based architecture. Most modern web servers are implemented using a hybrid multi-process/multithreaded server architecture where a thread is dedicated to serving each request. All resources associated with that thread remain allocated until the request is satisfied and a response dispatched to the client. In the Node.js architecture, a single process is used per instance (of node) and threads are only used as a means through which operations and system calls that would otherwise block can be called asynchronously with respect to the primary thread of execution. Everything happens asynchronously, and a primary design feature is that no function should block, but rather accept a callback function that Node.js will use to notify the initiating program that the operation has completed. A consequence of the event based server architecture is that system resources (such as heap memory) are never tied-up while waiting for some other operation to complete. Because of this, network programs developed using Node.js occupy a very small footprint in terms of system resource and memory usage and a high level of scalability. The cache.node module allows Caché to be leveraged as a high performance persistence storage engine that perfectly complements the high performance Node.js environment. Caché multidimensional storage provides a very fast, flexible storage model that can be used to implement a wide variety of data structures. The Caché cache.node module allows direct access to globals, the basis of the multidimensional storage model (see Using Caché Globals for a formal description). Caché can be regarded as a NoSQL database providing B-Tree based storage but with one important difference. Whereas most B-Tree databases implement one-dimensional key/value storage, Caché provides a multi-dimensional multiple key/value storage model. This provides the basis for a highly structured NoSQL data repository. In Caché terminology, each entry is known as a "global node". Examples: One-dimensional Global Storage: MyGlobal(“key1”)=”value1” MyGlobal(“key2”)=”value2” MyGlobal(“key3”)=”value3”

Multi-dimensional Global Storage:

Using Node.js with Caché                                                                                                                                                       3

Introduction MyGlobal(“key1”)=”value1” MyGlobal(“key1”, “key1a”)=”value1a” MyGlobal(“key1”, “key1a, “key1b”)=”value1b” MyGlobal(“key2”)=”value2” MyGlobal(“key2”, 1)=”value21” MyGlobal(“key2”, 2)=”value22” MyGlobal(“key3”)=”value3” MyGlobal(“key3”, 1, 2, 3)=”value3123” MyGlobal(“key3”, 1, 3)=”value313”

4                                                                                                                                                       Using Node.js with Caché

2 Installation This section describes the procedure for installing a pre-built cache.node module. The following components are required: •

Caché installation.



Node.js version 0.4.2 (or later).

Node.js is available for a number of UNIX platforms. Native support for Windows was added in version 0.6. The cache.node file is named using the Node.js .node extension for both UNIX and Windows. In the kits supplied by InterSystems, the module to be used with Node.js version 0.6 (and later) is named cache061.node. This may be renamed as the more usual cache.node name before deployment to avoid having to modify the require statement in existing Node.js software. •

Node.js version 0.4.x: cache.node



Node.js version 0.6.x: cache061.node

2.1 UNIX The module cache.node is actually a standard UNIX shared object (i.e. cache.so) but with an unusual Node.js-specific file extension. Copy cache.node to the following location in the node file system: .../node/lib/node/

For example: /opt/local/node/lib/node/cache.node

Placing the module in the recognized library path will remove the need to specify the full path in the JavaScript files. For example, in JavaScript, it will be possible to write: var globals = require(‘cache');

Instead of (for example): var globals = require('/opt/local/build/default/cache');

Using Node.js with Caché                                                                                                                                                       5

Installation

2.2 Windows The module cache.node is actually a standard Windows DLL (i.e. cache.dll) but with an unusual Node.js-specific file extension. The standard Windows installer (provided by the Node.js Group) usually places the Node.js software in the following location: C:\Program Files\nodejs

The installation mechanism usually adds this location to the Windows PATH environment variable. If this is not the case, then add it manually. Also, the NODE_PATH environment variable should be set and it, too, should be set to the Node.js installation directory. For example: NODE_PATH=C:\Program Files\nodejs

Copy cache.node to the location specified in the NODE_PATH environment variable: C:\Program Files\nodejs

Placing the module in the recognized Node.js path will remove the need to specify the full path in the JavaScript files. For example, in JavaScript, it will be possible to write: var globals = require(‘cache');

Instead of (for example): var globals = require('/nodejs/lib/cache');

or: var globals = require('c:/nodejs/lib/cache');

6                                                                                                                                                       Using Node.js with Caché

3 Accessing Caché from Node.js The cache.node module provides the basic NoSQL-style methods, and also has more advanced methods that can be used to implement a higher-level view of the Caché database which can, in turn, form the basis of an object oriented approach to development. This chapter provides an overview of the available methods and the concepts behind them. The following topics are discussed: •

JSON Objects and Caché Globals — describes the basic relationship between the globals in the Caché database and JSON objects in the Node.js environment.



Synchronous vs. Asynchronous cache.node Methods — describes how to use cache.node calls both synchronously and asynchronously.



Overview of cache.node Methods — provides a quick overview of the basic NoSQL-style cache.node database methods.



Opening and Closing the Caché Database — describes how to load the cache.node module, create an instance of the cache.node object, and open or close the target Caché database.



Advanced Data Access with retrieve() and update() — describes advanced cache.node methods that perform certain operations more efficiently than the basic NoSQL-style methods.



Towards an Object Oriented Development Methodology — illustrates how the cache.node methods and JSON notation can be used for object orientated development.

3.1 JSON Objects and Caché Globals In this section we will look at the basic relationship between JSON objects in the Node.js environment and globals in the Caché database. Consider the following global node: ^Customer(1)="Chris Munt"

Note:

By convention, global names are prefixed with the ‘^’ character in Caché. However, this convention should not be followed in the corresponding JSON representation.

The equivalent JSON construct will be: {global: "Customer", subscripts: [1], data: "Chris Munt"}

Adding further nodes to this data construct:

Using Node.js with Caché                                                                                                                                                       7

Accessing Caché from Node.js

Globals: ^Customer(1)="Chris Munt" ^Customer(1, "Address", 1)="London" ^Customer(1, "Address", 2)="UK" ^Customer(1, "DateOfRegistration")="1 May 2010"

JSON: { global: "Customer", subscripts: [1], data: "Chris Munt" } { global: "Customer", subscripts: [1, "Address", 1], data: "London" } { global: "Customer", subscripts: [1, "Address", 2], data: "UK" } { global: "Customer", subscripts: [1, "DateOfRegistration"], data: "1 May 2010" }

3.2 Synchronous vs. Asynchronous cache.node Methods All methods provided by cache.node can be run either synchronously or asynchronously. While synchronous operation is conceptually easier to grasp and can be useful for debugging, the expectation in the Node.js environment is that all operations should be implemented asynchronously with a completion event raised by means of a callback function. For this reason, most of the examples given in this guide are coded to run asynchronously. To run them synchronously simply omit the callback function from the arguments list. •

Synchronous operation — Method does not return until the operation is complete.



Asynchronous operation — Method returns immediately and your program is notified when the operation is complete. In order to accept notification, you must pass a callback function as an argument to the original method call. By convention, the callback will always be the last argument in the list.

Consider the method to determine the version of the cache.node module in use: Synchronous operation: var result = mydata.version();

Asynchronous operation: mydata.version( function(error, result) { if (error) { // error } else { // success } } );

The standard convention for reporting errors in Node.js is implemented in cache.node. If an operation is successful, error will be false. If an error occurs then error will be true and the result object will contain the details according to the following JSON construct:

8                                                                                                                                                       Using Node.js with Caché

Overview of cache.node Methods { "ErrorMessage": [error message text], "ErrorCode": [error code], "ok": [true|false] }

For synchronous operation, you should check for the existence of these properties in the result object to determine whether or not an error has occurred.

3.3 Overview of cache.node Methods The individual cache.node methods are described in detail in the reference section. Here is a brief summary of the available methods and their uses, with links to the reference section entries: Opening and closing the database See “Opening and Closing the Caché Database ” for basic information on using these methods: •

open() — opens the specified Caché database.



close() — closes a previously opened database.

Operations on individual nodes •

set() — sets the value of a global node.



get() — retrieves a global node.



kill() — deletes a global node.



increment() — adds 1 to the value of an integer in a global node.



merge() — copies all or part of a global to another global.

Iteration over global nodes •

data() — tests for the existence of a global node.



next() and previous() — gets the next or previous global node subscript on the current level.



next_node() and previous_node() — gets the next or previous global node in collation order regardless of level.



lock() and unlock() — locks global nodes for exclusive use, and unlocks nodes previously locked by your program.

Advanced data access These methods perform batch read and write operations that are frequently more efficient than access with the basic NoSQL-style methods: •

retrieve() — recursively retrieves all global nodes defined beneath a specified level and returns them as a single JSON object.



update() — uses information in a JSON object to write a set of globals to the database.

See “Advanced Data Access with retrieve() and update() ” for a detailed discussion of usage.

Using Node.js with Caché                                                                                                                                                       9

Accessing Caché from Node.js

Caché-specific methods These methods provide access to Caché information and functions: •

function() — invokes a Caché function.



global_directory() — returns a list of globals held in the Caché database.



version() — returns version information about the cache.node module in use and the associated Caché database (if open).

3.4 Opening and Closing the Caché Database Before any other methods can be called, the cache.node module must be loaded, an instance of the Caché object created and the target Caché database must be opened before any data can be accessed.

Loading the Cache.node module If the cache.node module has been installed in the correct location for your Node.js installation, the following line will successfully load it from the default location: var globals = require('cache');

If the module is installed in some other location the full path should be specified. For example: var globals = require('/opt/cm/node042/build/default/cache');

Creating an instance The next task is to create an instance of the cache.node object. var mydata = new globals.Cache();

Opening the Database Finally, the Caché database can be opened: mydata.open(parameters[, function(error, result){}]);

where: •

parameters.path — Path to the mgr directory of the target Caché installation.



parameters.username — User name for access.



parameters.password — Password for access.



parameters.namespace — Target Caché namespace.

For example: mydata.open( { path:"/cache20102/mgr", username: "_SYSTEM", password: "SYS", namespace: "USER" }, function(error, result){} );

Closing the Database The following method will gracefully close a previously opened database.

10                                                                                                                                                     Using Node.js with Caché

Advanced Data Access with retrieve() and update() mydata.close([function(error, result){}]);

3.5 Advanced Data Access with retrieve() and update() This section describes advanced methods that perform operations that could otherwise be achieved by combining several of the basic NoSQL-style methods. The following topics are discussed: •

Using retrieve() — describes retrieving groups of global nodes as a single JSON object



Using update() — describes writing a single JSON object to update groups of global nodes.

The following Caché data will be used to illustrate the higher level methods. ^Customer(1)="Chris Munt" ^Customer(1, "Address", 1)="London" ^Customer(1, "Address", 2)="UK" ^Customer(1, "DateOfRegistration")="1 May 2010" ^Customer(2)="Rob Tweed" ^Customer(2, "Address", 1)="Reigate" ^Customer(2, "Address", 2)="UK" ^Customer(2, "DateOfRegistration")="7 May 2010" ^Customer(3)="Jane Smith" ^Customer(3, "Address", 1)="Oxford" ^Customer(3, "Address", 2)="UK" ^Customer(3, "DateOfRegistration")="9 June 2010"

3.5.1 Using retrieve() The following topics are discussed: •

Retrieve a list of global nodes (retrieve("list"))



Retrieve a list of global nodes recursively (retrieve("array"))



Retrieve a structured data object (retrieve("object"))



Controlling the amount of data returned by retrieve operations

3.5.1.1 Retrieve a list of global nodes (retrieve("list")) This method will return a list of subscript values that are defined directly beneath a given level in the global. Example 1: Retrieve a list of customer numbers mydata.retrieve( {global: "Customer"}, "list", function(error, result) { // callback code } );

Result: Three Customer records: [1, 2, 3]

Using Node.js with Caché                                                                                                                                                     11

Accessing Caché from Node.js

Example 2: Retrieve a list of address lines for a specific customer mydata.retrieve( {global: "Customer", subscripts: [1, "address"]}, "list", function(error, result) { // callback code } );

Result: Two lines in the address for customer number 1: [1, 2]

3.5.1.2 Retrieve a list of global nodes recursively (retrieve("array")) This method will return a list of subscript values together with their associated data values that are defined beneath a given level in the global. The method is recursive and will retrieve all global nodes defined beneath a chosen level. The result will be expressed as an array of global nodes: each global node expressed as a single JSON object. Example 1: Retrieve all data for a customer mydata.retrieve( {global: "Customer", subscripts: [1]}, "array", function(error, result) { // callback code } );

Result: [ { global: "Customer", subscripts: [1], data: "Chris Munt" } { global: "Customer", subscripts: [1, "Address", 1], data: "London" } { global: "Customer", subscripts: [1, "Address", 2], data: "UK" } { global: "Customer", subscripts: [1, "DateOfRegistration], data: "1 May 2010" } ]

3.5.1.3 Retrieve a structured data object (retrieve("object")) This method will retrieve a structured data object defined beneath a given level in a global. This method provides a structured alternative to the array of global nodes described previously. The result will be expressed as a single JSON object. Example: Retrieve all data for a customer Consider the following structured Caché global: ^Customer(1, ^Customer(1, ^Customer(1, ^Customer(1,

"Name")="Chris Munt" "Address", 1)="London" "Address", 2)="UK" "DateOfRegistration")="1 May 2010"

In Node.js:

12                                                                                                                                                     Using Node.js with Caché

Advanced Data Access with retrieve() and update() mydata.retrieve( {global: "Customer", subscripts: [1]}, "object", function(error, result) { // callback code } );

Result: { node: { global: "Customer", subscripts: [1] } object: { Name: "Chris Munt", Address: {"1": "London", "2": "UK"}, DateOfRegistration: "1 May 2010" } }

3.5.1.4 Controlling the amount of data returned by retrieve operations The retrieve operations are capable, depending on the underlying global structure, of returning enormous volumes of data to the Node.js environment. The following properties can be added to the requesting JSON object (i.e. the object defining the root global node) to limit the amount of data returned. •

max — The maximum number of global nodes to return.



lo — The lowest global subscript to return.



hi — The highest global subscript to return.

If all three properties are defined, the retrieve operation will terminate when the max number of global nodes have been returned, even if the global subscript defined in hi has not been reached. Consider the following Caché global: ^Customer(1, "Address", 1)="London" ^Customer(1, "Address", 2)="UK" ^Customer(1, "DateOfRegistration")="1 May 2010" ^Customer(1, "Name")="Chris Munt" ^Customer(1, "Orders", 20100501, "Reference")="Order001" ^Customer(1, "Orders", 20100503, "Reference")="Order002" ^Customer(1, "Orders", 20100507, "Reference")="Order003" ^Customer(1, "Orders", 20100509, "Reference")="Order004" ^Customer(1, "Orders", 20100510, "Reference")="Order005" ^Customer(1, "Orders", 20100520, "Reference")="Order006" ^Customer(1, "Orders", 20100527, "Reference")="Order007" ^Customer(1, "Orders", 20100906, "Reference")="Order008" ^Customer(1, "Orders", 20110104, "Reference")="Order011" ^Customer(1, "Orders", 20110203, "Reference")="Order012" ^Customer(2, "Address", 1)="Reigate" ^Customer(2, "Address", 2)="UK" ^Customer(2, "DateOfRegistration")="7 May 2010" ^Customer(2, "Name")="Rob Tweed" ^Customer(2, "Orders", 20101204, "Reference")="Order009" ^Customer(2, "Orders", 20101206, "Reference")="Order010" ^Customer(3, "Address", 1)="Oxford" ^Customer(3, "Address", 2)="UK" ^Customer(3, "DateOfRegistration")="9 June 2010" ^Customer(3, "Name")="Jane Smith" ^Customer(4, "Name")="Jim Cooper" ^Customer(5, "Name")="Eve Simpson" ^Customer(6, "Name")="John Cotton" ^Customer(7, "Name")="Alison Clarke" ^Customer(8, "Name")="Paul Francis" ^Customer(9, "Name")="Susan Reed" ^Customer(10, "Name")="Mary Dodds"

Note:

The third subscript in the "Orders" section is the date in YYYYMMDD format.

The following examples demonstrate how to use the max, lo, and hi properties:

Using Node.js with Caché                                                                                                                                                     13

Accessing Caché from Node.js

Example 1: List the registered Customer numbers between 2 and 7 (inclusive) mydata.retrieve( {global: "Customer", lo: 2, hi: 7}, "list", function(error, result) { // callback code } );

Result: Six Customer records: [2, 3, 4, 5, 6, 7]

Example 2: List the Orders placed by Customer number 1 between 7 May 2010 and 24 December 2010 (inclusive) mydata.retrieve( { global: "Customer", subscripts [1, "Orders"], lo: 20100507, hi: 20101224 }, "list", function(error, result) { // callback code } );

Result: Six Customer Order records: [20100507, 20100509, 20100510, 20100520, 20100527, 20100906]

Example 3: List the full details for Orders placed by Customer number 1 in September 2010 mydata.retrieve( { global: "Customer", subscripts [1, "Orders"], lo: 20100901, hi: 20100930 }, "array", function(error, result) { // callback code } );

Result: One Customer Order record: [{ global: "Customer", subscripts: [1, "Orders", 20100906, "Reference"], data: "Order008" }]

Example 4: List first three Customers registered (by Customer number) in the database mydata.retrieve( {global: "Customer", max: 3}, "list", function(error, result) { // callback code } );

Result: Three Customer records: [1, 2, 3]

14                                                                                                                                                     Using Node.js with Caché

Advanced Data Access with retrieve() and update()

3.5.2 Using update() The update() method allows an application to save a group of global nodes by passing information saved in a single JSON object. The nodes can represent either an array or an object: •

Save a list of global nodes (update("array"))



Save a structured data object (update("object"))

3.5.2.1 Save a list of global nodes (update("array")) This method performs the opposite task to that performed by the retrieve method. In other words the update method takes an array of global nodes, each expressed as a single JSON object and writes them back to the Caché database. Example 1: Create or update a record for a customer mydata.update( [ { global: "Customer", subscripts: [1], data: "Chris Munt" } { global: "Customer", subscripts: [1, "Address", 1], data: "London" } { global: "Customer", subscripts: [1, "Address", 2], data: "UK" } { global: "Customer", subscripts: [1, "DateOfRegistration"], data: "1 May 2010" } ], "array", function(error, result) { // callback code } );

Result: Operation successful if no error reported.

3.5.2.2 Save a structured data object (update("object")) This method performs the opposite task to that performed by the retrieve method. In other words it writes the contents of a structured JSON object back to the Caché database. Example 1: Create or update a record for a customer mydata.update( node: { global: "Customer", subscripts: [1] }, Object: { Name: "Chris Munt", DateOfRegistration: "1 May 2010", Address: {"1": "London", "2": "UK"} }, "object", function(error, result) { // callback code } );

Result:

Using Node.js with Caché                                                                                                                                                     15

Accessing Caché from Node.js

Operation successful if no error reported. If successful, the following set of global nodes will be created for this example: ^Customer(1, ^Customer(1, ^Customer(1, ^Customer(1,

"Address", 1)="London" "Address", 2)="UK" "DateOfRegistration")="1 May 2010" "Name")="Chris Munt"

3.6 Towards an Object Oriented Development Methodology The examples shown so far have illustrated the use of the Caché database as a raw NoSQL engine. The following code illustrates how the cache.node methods together with the JSON notation in JavaScript can be used to create a more Object Orientated development methodology. var globals = require('cache'); var user = new globals.Cache(); user.open({ path:"/cache20102/mgr", username: "_SYSTEM", password: "SYS", namespace: "USER" }); var customers = new Customers(); var customer = customers.getCustomer(1); console.log("customer number 1 is " + customer.data); customers.setCustomer(9, "Tom Smith"); user.close(); function Customers() { this.global = "Customer"; this.subscripts = new Array(); this.getCustomer = function(id) { this.subscripts[0] = id; var person = user.get(this); return person; } this.setCustomer = function(id, name) { this.subscripts[0] = id; this.data = name; var person = user.set(this); return; } }

16                                                                                                                                                     Using Node.js with Caché

4 Reference for cache.node Methods This section provides detailed documentation for each of the functions supported by the Caché cache.node module. See the “Example Data” section for a listing of the data sets used by many of the examples in this section. The following functions are supported: •

about() — see version().



close() — closes a previously opened database.



data() — tests for the existence of a global node.



function() — invokes a Caché function.



get() — retrieves a global node.



global_directory() — returns a list of globals held in the Caché database.



increment() — adds 1 to the value of an integer in a global node.



kill() — deletes a global node.



lock() — locks global nodes for exclusive use.



merge() — copies all or part of a global to another global.



next() — gets the next Global subscript on the current level.



next_node() — gets the next global node in collation order regardless of level.



open() — opens the specified Caché database.



order() — see next()



previous() — gets the previous Global subscript on the current level.



previous_node() — gets the previous global node in collation order regardless of level.



retrieve() — recursively retrieves all global nodes defined beneath a specified level.



set() — sets the value of a global node.



update() — writes the contents of a JSON object to the Caché database.



unlock() — unlocks global nodes previously locked by your program.



version() — returns basic version information about the cache.node module in use and the associated Caché database (if open).

Using Node.js with Caché                                                                                                                                                     17

Reference for cache.node Methods

4.1 Example Data Most examples in this reference section will be based on the following simple Caché data set: ^Customer(1)="Chris Munt" ^Customer(1, "address")="Banstead" ^Customer(2)="Rob Tweed" ^Customer(3)="Jane Smith"

The following Caché data will be used to illustrate the retrieve() and update() methods: ^Customer(1)="Chris Munt" ^Customer(1, "Address", 1)="London" ^Customer(1, "Address", 2)="UK" ^Customer(1, "DateOfRegistration")="1 May 2010" ^Customer(2)="Rob Tweed" ^Customer(2, "Address", 1)="Reigate" ^Customer(2, "Address", 2)="UK" ^Customer(2, "DateOfRegistration")="7 May 2010" ^Customer(3)="Jane Smith" ^Customer(3, "Address", 1)="Oxford" ^Customer(3, "Address", 2)="UK" ^Customer(3, "DateOfRegistration")="9 June 2010"

4.2 close() The close() method will gracefully close a previously opened database. See “Opening and Closing the Caché Database” for a detailed description of how to open and close the database. Synchronous mydata.close();

Asynchronous mydata.close(callback_function);

Parameters •

callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example mydata.close( function(error, result) { // callback code } );

4.3 data() The data() method tests for the existence of a global node. This method will return one of the following numeric values: •

0 — Node does not exist.

18                                                                                                                                                     Using Node.js with Caché

function()



1 — Node has data but no subnodes.



10 — Node does not have data but has subnodes.



11 — Node has data and has subnodes.

Synchronous var result = mydata.data(node);

Asynchronous mydata.data(node, callback_function);

Parameters •

node — the global node to be accessed.



callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example mydata.data( {global: "Customer", subscripts: [1]}, function(error, result) { // callback code } );

Result: {defined: 11}

4.4 function() The function() method provides a way to invoke a Caché function directly. Synchronous var result = mydata.function( Cache_Function_Name, Arguments ... );

Asynchronous var result = mydata.function( { Cache_Function_Name, Arguments ... }, callback_function );

Parameters •

Cache_Function_Name



Arguments



callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”).

Using Node.js with Caché                                                                                                                                                     19

Reference for cache.node Methods

The following examples will be based on calls to the following Caché function: Math Add(X,Y) Multiply(X,Y)

; Math Functions ; ; Add two numbers Quit (X * Y) ; ; Add two numbers Quit (X * Y) ;

This is a simple Caché ‘routine’ file called ‘Math" containing functions to perform basic mathematical functions ("Add" and "Multiply"). Example 1 (Synchronous/Non-JSON) result = mydata.function("Add^Math", 3, 4);

Result: 7 Example 2: (Synchronous/JSON) result = mydata.function({function: "Add^Math", arguments: [3, 4]});

Result: { "function": "Add^Math", "arguments": [3, 4], "result": 7 }

Example 3: (Asynchronous/JSON) mydata.function( {function: "Add^Math", arguments: [3, 4]}, function(error, result) { // callback code } );

Result: { "ok": 1, "function": " Add^Math ", "arguments": [3, 4], "result": 7 }

4.5 get() The get() method retrieves a global node. Synchronous var result = mydata.get(node);

Asynchronous mydata.get(node, callback_function);

20                                                                                                                                                     Using Node.js with Caché

global_directory()

Parameters •

node — the global node to be accessed.



callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example 1 (Synchronous) result = mydata.get({global: "Customer", subscripts: [9]});

Result: {global: "Customer", subscripts: [9], data: "", defined: 0}

Example 2 (Asynchronous) mydata.get( {global: "Customer", subscripts: [1]}, function(error, result) { // callback code } );

Result: {global: "Customer", subscripts: [1], data: "Chris Munt", defined: 1}

Note that the ‘defined’ property is set to 1 if the global node is actually defined and set to 0 if it is not.

4.6 global_directory() The global_directory() method returns a list of globals held in the directory. The number of names returned can be controlled using the range limiting properties ‘lo’, ‘hi’ and ‘max’ (see “Controlling the amount of data returned by retrieve operations”). Synchronous var result = mydata.global_directory(range);

Asynchronous mydata.global_directory (range, callback_function);

Parameters •

range



callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example 1: Obtain a list of all globals in the directory mydata.global_directory( {}, function(error, result) { // callback code } );

Result: If successful, an array containing all global names found will be returned.

Using Node.js with Caché                                                                                                                                                     21

Reference for cache.node Methods

Example 2: Obtain a list of all globals whose name begins with "Cust" mydata. global_directory( {lo: "Cust", hi: "Cust~"}, function(error, result) { // callback code } );

Result: If successful, an array containing all global names beginning with "Cust" will be returned.

4.7 increment() The increment() method adds 1 to the value of an integer in a global node. This method provides an efficient way of uniquely assigning an (incremented) integer to a process without using locking. When called, the integer value held in the global is incremented and the new value returned to the calling program. Caché will guarantee that a unique number is assigned to multiple processes that may be accessing this function simultaneously. Synchronous var result = mydata.increment(node);

Asynchronous mydata.increment (node, callback_function);

Parameters •

node — the global node that holds the value to be incremented.



callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example mydata.increment( {global: "Counter"}, function(error, result) { // callback code } );

Result: If successful the integer value held in global "Counter" will be incremented and the new value returned as the result.

4.8 kill() The kill() method deletes a global node. Synchronous var result = mydata.kill(node);

Asynchronous mydata.kill(node, callback_function);

22                                                                                                                                                     Using Node.js with Caché

lock()

Parameters •

node — the global node to be accessed.



callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example mydata.kill( {global: "Customer", subscripts: [1]}, function(error, result) { // callback code } );

Result: Operation successful if no error reported.

4.9 lock() The lock() method locks global nodes for exclusive use by your program. The method can lock either an entire Global (for example, ^Customer) or sub-sections of a Global (for example, ^Customer(1)). To prevent deadlock situations, all global nodes that your code has locked should be unlocked before your program terminates (see unlock()). Synchronous var result = mydata.lock(node);

Asynchronous mydata.lock(node, callback_function);

Parameters •

node — the global node to be accessed.



callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example mydata.lock( {global: "Customer", subscripts: [1]}, function(error, result) { // callback code } );

Result: Operation successful if no error reported.

4.10 merge() The merge method copies all or part of a global to another global.

Using Node.js with Caché                                                                                                                                                     23

Reference for cache.node Methods

Synchronous var result = mydata.merge(to: {destination_node}, from: {source_node}};

Asynchronous mydata.merge({to: {destination_node}, from: {source_node}}, callback_function);

Parameters •

source_node



destination_node



callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example 1: Copy a whole global mydata.get( {to: {global: "CopyOfCustomer"}, from: {global: "Customer"}}, function(error, result) { // callback code } );

Result: If successful, the whole of global "Customer" will be copied to "CopyOfCustomer". Example 2: Copy a section of global mydata.get( {to: {global: "Customer", subscripts: [7, "address"]}, from: {global: "Customer", subscripts: [1, "address"]}}, function(error, result) { // callback code } );

Result: If successful, the subsection of global contained under "Customer(1,’address’)" will be copied to "Customer(7,’address’)".

4.11 next() or order() The next() method gets the next Global subscript. Get the next value in the collating sequence for a particular level of subscript. Synchronous var result = mydata.order(node);

Asynchronous mydata.order(node, callback_function);

Parameters •

node — the global node to be accessed.

24                                                                                                                                                     Using Node.js with Caché

next_node()



callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example 1 (Synchronous) result = mydata.order({global: "Customer", subscripts: [""]},

Result: {global: "Customer", subscripts: [1], result: "1"}}

Example 2 (Synchronous) result = mydata.next({global: "Customer", subscripts: [3]},

Result: {global: "Customer", subscripts: [""], result: ""}}

Example 3 (Asynchronous) mydata.next( {global: "Customer", subscripts: [1]}, function(error, result) { // callback code } );

Result: {global: "Customer", subscripts: [2], result: "2"}}

Example 4 (Parse at the first level) key = {global: "Customer", subscripts: [""]}; while ((key = user.next(key)).result != "") { console.log(JSON.stringify(key, null, '\t')) }

Result: {global: "Customer", subscripts: [1], result: "1"}} {global: "Customer", subscripts: [2], result: "2"}} {global: "Customer", subscripts: [3], result: "3"}}

If there is no further subscript defined in the sequence then the result property will be returned as empty string ("").

4.12 next_node() The next_node() method gets the next global node in the collating sequence regardless of the level of subscript. Synchronous var result = mydata.next_node(node);

Asynchronous mydata.next_node(node, callback_function);

Parameters •

node — the global node to be accessed.

Using Node.js with Caché                                                                                                                                                     25

Reference for cache.node Methods



callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example 1 (Synchronous) result = mydata.next_node({global: "Customer"},

Result: {global: "Customer", subscripts: [1], data: "Chris Munt, defined: 1}}

Example 2 (Synchronous) result = mydata.next_node({global: "Customer", subscripts: [3]},

Result: {global: "Customer", defined: 0}}

Example 3 (Asynchronous) mydata.next_node( {global: "Customer", subscripts: [1]}, function(error, result) { // callback code } );

Result: { global: "Customer", subscripts: [1, "address"], data: "Banstead", defined: 1 }

Example 4 (Parse Global) key = {global: "Customer"}; while ((key = user.next_node(key)).defined) { console.log(JSON.stringify(key, null, '\t')); }

Result: { global: "Customer", subscripts: [1], data: "Chris Munt", defined: 1 } { global: "Customer", subscripts: [1, "address"], data: "Banstead", defined: 1 } { global: "Customer", subscripts: [2], data: "Rob Tweed", defined: 1 } { global: "Customer", subscripts: [3], data: "Jane Smith", defined: 1 }

If there is no further node defined in the sequence then the defined property will be set to zero.

26                                                                                                                                                     Using Node.js with Caché

open()

4.13 open() The open() method opens the specified Caché database. See “ Opening and Closing the Caché Database ” for a detailed description of how to open and close the database. Synchronous mydata.open(parameters);

Asynchronous mydata.open(parameters, callback_function);

Parameters •



parameters — specifies the Caché database to be opened:



parameters.path — Path to the ‘mgr’ directory of the target Caché installation.



parameters.username — User name for access.



parameters.password — Password for access.



parameters.namespace — Target Caché namespace.

callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example mydata.open( { path:"/cache20102/mgr", username: "_SYSTEM", password: "SYS", namespace: "USER" }, function(error, result) { // callback code } );

Result: Operation successful if no error reported.

4.14 previous() The previous() method gets the previous Global subscript Get the previous value in the collating sequence for a particular level of subscript. Synchronous var result = mydata.previous(node);

Asynchronous mydata.previous(node, callback_function);

Using Node.js with Caché                                                                                                                                                     27

Reference for cache.node Methods

Parameters •

node — the global node to be accessed.



callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example 1 (Synchronous) result = mydata.previous({global: "Customer", subscripts: [""]},

Result: {global: "Customer", subscripts: [3], result: "3"}}

Example 2 (Synchronous) result = mydata.previous({global: "Customer", subscripts: [2]},

Result: {global: "Customer", subscripts: ["1"], result: "1"}}

Example 3 (Asynchronous) mydata.previous( {global: "Customer", subscripts: [1]}, function(error, result) { // callback code } );

Result: {global: "Customer", subscripts: [""], result: ""}}

Example 4 (Parse at the first level) key = {global: "Customer", subscripts: [""]}; while ((key = user.previous(key)).result != "") { console.log(JSON.stringify(key, null, '\t')) }

Result: {global: "Customer", subscripts: [3], result: "3"}} {global: "Customer", subscripts: [2], result: "2"}} {global: "Customer", subscripts: [1], result: "1"}}

If there is no further subscript defined in the sequence then the result property will be returned as empty string ("").

4.15 previous_node() The previous_node() method gets the previous global node Get the previous whole global node in the collating sequence regardless of the level of subscript. Synchronous var result = mydata.previous(node);

28                                                                                                                                                     Using Node.js with Caché

previous_node()

Asynchronous mydata.previous(node, callback_function);

Parameters •

node — the global node to be accessed.



callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example 1 (Synchronous) result = mydata.previous_node({global: "Customer", subscripts: ["z"]},

Result: {global: "Customer", subscripts: [3], data: "Jane Smith", defined: 1}}

Example 2 (Synchronous) result = mydata.next_node({global: "Customer", subscripts: [2]},

Result: { global: "Customer", subscripts: [1, "address"], data: "Banstead", defined: 1 }

Example 3 (Asynchronous) mydata.previous_node( {global: "Customer", subscripts: [1]}, function(error, result) { // callback code } );

Result: {global: "Customer", defined: 0}}

Example 4 (Parse Global) key = {global: "Customer", subscripts: ["z"]}; while ((key = user.previous_node(key)).defined) { console.log(JSON.stringify(key, null, '\t')); }

Result: { global: "Customer", subscripts: [3], data: "Jane Smith", defined: 1 } { global: "Customer", subscripts: [2], data: "Rob Tweed", defined: 1 } { global: "Customer", subscripts: [1, "address"], data: "Banstead", defined: 1 } {

Using Node.js with Caché                                                                                                                                                     29

Reference for cache.node Methods global: "Customer", subscripts: [1], data: "Chris Munt", defined: 1 }

If there is no further node defined in the sequence then the defined property will be set to zero.

4.16 retrieve() •

The retrieve(node, "list") method will return a list of subscript values that are defined directly beneath a given level in the global.



The retrieve(node, "array") method will return a list of subscript values together with their associated data values that are defined beneath a given level in the global. The method is recursive and will retrieve all global nodes defined beneath a chosen level. The result will be expressed as an array of global nodes, with each global node expressed as a single JSON object.



The retrieve(node, "object") method will retrieve a structured data object defined beneath a given level in a global. This method provides a structured alternative to an array of global nodes. The result will be expressed as a single JSON object.

Synchronous var result = mydata.retrieve(node, type);

Asynchronous mydata.retrieve(node, type, callback_function);

Parameters •

node — the global node to be accessed.



type — a literal string specifying the type of data to be accessed. Options are:





"list"



"array"



"object"

callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example 1 (type = “list”): Retrieve a list of customer numbers mydata.retrieve( {global: "Customer"}, "list", function(error, result) { // callback code } );

Result: Three Customer records: [1, 2, 3]

30                                                                                                                                                     Using Node.js with Caché

retrieve()

Example 2 (type = “list”): Retrieve a list of address lines for a specific customer mydata.retrieve( {global: "Customer", subscripts: [1, "address"]}, "list", function(error, result) { // callback code } );

Result: Two lines in the address for customer number 1: [1, 2]

Example 3 (type = “array”): Retrieve all data for a customer mydata.retrieve( {global: "Customer", subscripts: [1]}, "array", function(error, result) { // callback code } );

Result: [ { } { } { } {

global: "Customer", subscripts: [1], data: "Chris Munt" global: "Customer", subscripts: [1, "Address", 1], data: "London" global: "Customer", subscripts: [1, "Address", 2], data: "UK" global: "Customer", subscripts: [1, "DateOfRegistration], data: "1 May 2010"

} ]

Example 4 (type = “object”): Retrieve all data for a customer Consider the following structured Caché global: ^Customer(1, ^Customer(1, ^Customer(1, ^Customer(1,

"Name")="Chris Munt" "Address", 1)="London" "Address", 2)="UK" "DateOfRegistration")="1 May 2010"

In Node.js: mydata.retrieve( {global: "Customer", subscripts: [1]}, "object", function(error, result) { // callback code } );

Result: { node: { global: "Customer", subscripts: [1] } object: { Name: "Chris Munt", Address: {"1": "London", "2": "UK"}, DateOfRegistration: "1 May 2010" } }

Using Node.js with Caché                                                                                                                                                     31

Reference for cache.node Methods

4.17 set() The set() method saves a global node. Synchronous var result = mydata.set(node);

Asynchronous mydata.set(node, callback_function);

Parameters •

node — the global node to be accessed.



callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example mydata.set( {global: "Customer", subscripts: [1], data: "Chris Munt"}, function(error, result) { // callback code } );

Result: Operation successful if no error reported.

4.18 unlock() The unlock() method unlocks global nodes previously locked by your program (see lock()). The method can unlock either an entire Global (for example, ^Customer) or sub-sections of a Global (for example, ^Customer(1)). To release all locks held by your program, call the unlock() method with no node argument. All locks held by a Node.js process will be released when the process terminates normally. Synchronous var result = mydata.unlock(node); var result = mydata.unlock();

Asynchronous mydata.unlock(node, callback_function); mydata.unlock(callback_function);

Parameters •

node — the global node to be accessed.



callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”).

32                                                                                                                                                     Using Node.js with Caché

update()

Example 1: Unlock one node mydata.unlock( {global: "Customer", subscripts: [1]}, function(error, result) { // callback code } );

Result: Operation successful if no error reported. Example 2: Unlock all locked nodes mydata.unlock( function(error, result) { // callback code } );

Result: Operation successful if no error reported.

4.19 update() The update() method writes the contents of a JSON object to the Caché database. •

The update("array") method performs the opposite task to that performed by the retrieve method. In other words the update method takes an array of global nodes, each expressed as a single JSON object and writes them back to the Caché database.



The update("object") method performs the opposite task to that performed by the retrieve method. In other words it writes the contents of a structured JSON object back to the Caché database.

Synchronous var result = mydata.update(node, type);

Asynchronous mydata.update(node, type, callback_function);

Parameters •

node — the global node to be accessed.



type — a literal string specifying the type of data to be accessed. Options are:





"array"



"object"

callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”). Example 1 (type = “array”): Create or update a record for a customer mydata.update( [ { global: "Customer", subscripts: [1], data: "Chris Munt" }

Using Node.js with Caché                                                                                                                                                     33

Reference for cache.node Methods { } { } {

global: "Customer", subscripts: [1, "Address", 1], data: "London" global: "Customer", subscripts: [1, "Address", 2], data: "UK" global: "Customer", subscripts: [1, "DateOfRegistration"], data: "1 May 2010"

} ], "array", function(error, result) { // callback code } );

Result: Operation successful if no error reported. Example 2 (type = “object”): Create or update a record for a customer mydata.update( node: { global: "Customer", subscripts: [1] }, Object: { Name: "Chris Munt", DateOfRegistration: "1 May 2010", Address: {"1": "London", "2": "UK"} }, "object", function(error, result) { // callback code } );

Result: Operation successful if no error reported. If successful, the following set of global nodes will be created for this example: ^Customer(1, ^Customer(1, ^Customer(1, ^Customer(1,

"Address", 1)="London" "Address", 2)="UK" "DateOfRegistration")="1 May 2010" "Name")="Chris Munt"

4.20 version() and about() The version() and about() methods return basic version information about the cache.node module in use and the associated Caché database (if open). Synchronous var result = mydata.version(); var result = mydata.about();

Asynchronous mydata.version(callback_function); mydata.about(callback_function);

Parameters •

callback_function — a function of the form function(error, result){} used to return results

asynchronously (see “Synchronous vs. Asynchronous cache.node Methods ”).

34                                                                                                                                                     Using Node.js with Caché

version() and about()

Example mydata.version( function(error, result) { // callback code } );

Result: If the Caché database is not open: Node.js Adaptor for Cache: Version: 1.0.17 (CM)

If the Caché database is open: Node.js Adaptor for Cache: Version: 1.0.17 (CM); Caché Version: 2012 build 100

Using Node.js with Caché                                                                                                                                                     35

A Building cache.node from Source The following development tools should be installed: •

C and C++ build environment.



For Ubuntu: –

sudo apt-get install gcc



sudo apt-get install g++

There are two methods for building the cache.node module from source: •

Using the Node.js Build Procedure — using the scripts provided by the Node.js community.



Building Directly from Source — directly from the C++ source (cache.cpp).

A.1 Using the Node.js Build Procedure The cache.node module is built using the script provided by node-waf script provided by the Node.js group. The node-waf scripts builds the cache.node module in accordance with instructions contained in a file called wscript. .../build/default/

A.1.1 Creating the Build Script (wscript) The script provided is as follows: def set_options(opt): opt.tool_options("compiler_cxx") def configure(conf): conf.check_tool("compiler_cxx") conf.check_tool("node_addon") def build(bld): obj = bld.new_task_gen("cxx", "shlib", "node_addon") obj.cxxflags = ["-g", "-D_FILE_OFFSET_BITS=64", "-D_LARGEFILE_SOURCE", "-Wall", "-I/cache20102/dev/cpp/include"] obj.linkflags = ["-Wl", "-lpthread", "-lrt", "-ldl", "-lc", "-lm"] obj.target = "cache" obj.source = "cache.cpp"

Using Node.js with Caché                                                                                                                                                     37

Building cache.node from Source

Create this text file and modify it to suite your own environment. There is just one path that will require modifying for your local environment •

The compiler options line (obj.cxxflags): "-I/cache20102/dev/cpp/include"

This must be the directory where the Caché C header files reside (For example: callin.h)

A.1.2 Build the cache.node Module In the directory containing both the wscript file created previously and the source code (cache.cpp) use the node-waf command to build the module: node-waf configure build

If successful, the output will look something like the following: Setting srcdir to : /opt/cm/node042 Setting blddir to : /opt/cm/node042/build Checking for program g++ or c++ : /usr/bin/g++ Checking for program cpp : /usr/bin/cpp Checking for program ar : /usr/bin/ar Checking for program ranlib : /usr/bin/ranlib Checking for g++ : ok Checking for node path : not found Checking for node prefix : ok /opt/cm/node042 'configure' finished successfully (0.974s) Waf: Entering directory `/opt/cm/node042/build' [1/2] cxx: cache.cpp -> build/default/cache_1.o [2/2] cxx_link: build/default/cache_1.o -> build/default/cache.node Waf: Leaving directory `/opt/cm/node042/build' 'build' finished successfully (2.904s) root@ubuntu:/opt/cm/node042#

The Caché module will be created: cache.node This module will, by default, be created in the following subdirectory: .../build/default/

A.2 Building Directly from Source As an alternative to using the scripted infrastructure provided by the Node.js Group, the Caché module (cache.node) can be built directly from the C++ source code as follows: Linux: g++ -c -g -fPIC -DPIC -DEV_MULTIPLICITY=0 –DLINUX \ -D_FILE_OFFSET_BITS=64 -D_LARGEFILE_SOURCE -Wall \ -I/opt/local/node/include/node -I/cache20102/dev/cpp/include \ -o cache.o cache.cpp g++ -shared -L/opt/local/node/lib -Wl -lpthread -lrt -ldl -lc -lm \ -o cache.node cache.o

Note the three paths that will require modifying to suit your local environment. •

Path to the Node.js C/C++ header files. For example: /opt/local/node/include/node



Path to the Caché C/C++ header files. For example: /cache20102/dev/cpp/include

38                                                                                                                                                     Using Node.js with Caché

Building Directly from Source



Path to the Node.js library files. For example: /opt/local/node/lib

Using Node.js with Caché                                                                                                                                                     39