You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by av...@apache.org on 2018/09/20 10:04:26 UTC
[30/50] [abbrv] ignite git commit: IGNITE-9465: Node.js client:
improved complex object flags processing
IGNITE-9465: Node.js client: improved complex object flags processing
This closes #4713
Project: http://git-wip-us.apache.org/repos/asf/ignite/repo
Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/4b002427
Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/4b002427
Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/4b002427
Branch: refs/heads/ignite-7251
Commit: 4b002427874d1881a7ef467aaf0cce6071fc8e98
Parents: 2ab9493
Author: ekaterina-nbl <ek...@nobitlost.com>
Authored: Mon Sep 17 15:26:50 2018 +0300
Committer: Igor Sapego <is...@apache.org>
Committed: Mon Sep 17 15:26:50 2018 +0300
----------------------------------------------------------------------
modules/platforms/nodejs/README.md | 613 +------------------
modules/platforms/nodejs/examples/README.md | 128 ----
modules/platforms/nodejs/lib/BinaryObject.js | 129 ++--
.../platforms/nodejs/lib/internal/BinaryType.js | 50 +-
.../nodejs/lib/internal/BinaryTypeStorage.js | 5 +
.../nodejs/lib/internal/BinaryUtils.js | 2 +-
.../nodejs/lib/internal/MessageBuffer.js | 31 +-
modules/platforms/nodejs/spec/README.md | 42 --
.../nodejs/spec/cache/ComplexObject.spec.js | 76 +++
9 files changed, 231 insertions(+), 845 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/ignite/blob/4b002427/modules/platforms/nodejs/README.md
----------------------------------------------------------------------
diff --git a/modules/platforms/nodejs/README.md b/modules/platforms/nodejs/README.md
index 63a6725..4792caa 100644
--- a/modules/platforms/nodejs/README.md
+++ b/modules/platforms/nodejs/README.md
@@ -1,615 +1,32 @@
# NodeJS Client for Apache Ignite #
-This client allows your application to work with the [Apache Ignite platform](https://ignite.apache.org/) via the [Binary Client Protocol](https://apacheignite.readme.io/docs/binary-client-protocol).
-
-The client includes:
-- [API specification](https://rawgit.com/nobitlost/ignite/master/modules/platforms/nodejs/api_spec/index.html)
-- [implementation](./lib)
-- [examples](./examples)
-- [tests](./spec)
-- docs
- - the main readme (this file)
- - [readme for examples](./examples/README.md)
- - [readme for tests](./spec/README.md)
-
## Installation ##
[Node.js](https://nodejs.org/en/) version 8 or higher is required. Either download the Node.js [pre-built binary](https://nodejs.org/en/download/) for the target platform, or install Node.js via [package manager](https://nodejs.org/en/download/package-manager).
-Once `node` and `npm` are installed, execute the following commands:
+Once `node` and `npm` are installed, you can use one of the following installation options.
-(temporary, while the NPM module is not released on [npmjs](https://www.npmjs.com))
+### Installation via npm ###
-1. Clone or download Ignite repository https://github.com/nobitlost/ignite.git to `local_ignite_path`
-2. Go to `local_ignite_path/modules/platforms/nodejs` folder
-3. Execute `npm link` command
-4. Execute `npm link apache-ignite-client` command (needed only for examples and tests)
+Execute the following command to install the Node.js Thin Client package:
-```bash
-cd local_ignite_path/modules/platforms/nodejs
-npm link
-npm link apache-ignite-client
```
-
-## Supported Features ##
-
-The client supports all operations and types from the [Binary Client Protocol v.2.4](https://apacheignite.readme.io/v2.4/docs/binary-client-protocol) except the following not-applicable features:
-- OP_REGISTER_BINARY_TYPE_NAME and OP_GET_BINARY_TYPE_NAME operations are not supported.
-- Filter object for OP_QUERY_SCAN operation is not supported. OP_QUERY_SCAN operation itself is supported.
-- It is not possible to register a new Ignite Enum type. Reading and writing items of the existing Ignite Enum types are supported.
-
-The following additional features are supported:
-- Authentication using username/password.
-- SSL/TLS connection.
-- "Failover re-connection algorithm".
-
-## API Specification ##
-
-Full specification of the client's public API is available [here](https://rawgit.com/nobitlost/ignite/master/modules/platforms/nodejs/api_spec/index.html)
-
-It is auto-generated from the [jsdoc](http://usejsdoc.org/) comments in source files and located in the [api_spec](./api_spec) folder.
-
-Promises async/await mechanism is used by the API and the client's implementation.
-
-## Data Types ##
-
-The client supports two cases of mapping between Ignite types defined by the Binary Client Protocol and JavaScript types:
-- default mapping,
-- explicit mapping.
-
-A mapping occurs every time an application writes or reads a field to/from an Ignite cache via the client's API. A field here is any data in a cache - key or value of a cache entry or a map, element of an array or set, field of a complex object, etc.
-
-Using the client's API methods, an application can explicitly specify an Ignite type for a field. The client uses this information during the field read/write operations. It returns the corresponding JavaScript type in results of read operations. It checks the corresponding JavaScript type in inputs of write operations.
-
-If an application does not explicitly specify an Ignite type for a field, the client uses default mapping during the field read/write operations.
-
-Default mapping between Ignite and JavaScript types is described [here](https://rawgit.com/nobitlost/ignite/master/modules/platforms/nodejs/api_spec/ObjectType.html).
-
-### Complex Object Type Support ###
-
-The client provides two ways to operate with the Ignite Complex Object type - in the deserialized form and in the binary form.
-
-An application can specify an Ignite type of a field by an instance of the *ComplexObjectType* class which references an instance of a JavaScript Object. In this case, when the application reads a value of the field, the client deserializes the received Ignite Complex Object and returns it to the client as an instance of the corresponding JavaScript Object. When the application writes a value of the field, the client expects an instance of the corresponding JavaScript Object and serializes it to the Ignite Complex Object.
-
-If an application does not specify an Ignite type of a field and reads a value of the field, the client returns the received Ignite Complex Object as an instance of the *BinaryObject* class - a binary form of the Ignite Complex Object. The *BinaryObject* allows to manipulate with it's content - read and write values of the object's fields, add and remove the fields, etc. Also, an application can create an instance of the *BinaryObject* class from a JavaScript Object. An application can write the *BinaryObject* as a value of a field in a cache, if that field has no explicitly specified Ignite type.
-
-The client takes care of obtaining or registering information about Ignite Complex Object type, including schema, from/at Ignite cluster. It is done automatically by the client, when required for reading or writing of the Ignite Complex Object from/to a cache.
-
-## Usage ##
-
-The below sections exaplains the basic steps to work with Apache Ignite using NodeJS client.
-
-### Instantiate Ignite Client ###
-
-A usage of the client starts from the creation of an *IgniteClient* class instance. The constructor has one, optional, parameter - *onStateChanged* callback which will be called every time the client moves to a new connection state (see below).
-
-It is possible to create as many *IgniteClient* instances as needed. All of them will work fully independently.
-
-```javascript
-const IgniteClient = require('apache-ignite-client');
-
-const igniteClient = new IgniteClient(onStateChanged);
-
-function onStateChanged(state, reason) {
- if (state === IgniteClient.STATE.CONNECTED) {
- console.log('Client is started');
- }
- else if (state === IgniteClient.STATE.DISCONNECTED) {
- console.log('Client is stopped');
- if (reason) {
- console.log(reason);
- }
- }
-}
+npm install -g apache-ignite-client
```
-### Create Ignite Client Configuration ###
-
-The next step is to define a configuration for the client's connection - create an *IgniteClientConfiguration* class instance.
-
-A mandatory part of the configuration, which is specified in the constructor, is a list of endpoints of the Ignite nodes. At least one endpoint must be specified. A client connects to one node only - a random endpoint from the provided list. Other nodes, if provided, are used by the client for the "failover re-connection algorithm": the client tries to re-connect to the next random endpoint from the list if the current connection has lost.
-
-Optional parts of the configuration can be specified using additional set methods. They include:
-- username and password for authentication,
-- SSL/TLS connection enabling,
-- NodeJS connection options.
-
-By default, the client establishes a non-secure connection with default connection options defined by NodeJS and does not use authentication.
-
-Example: default Ignite Client Configuration
-
-```javascript
-const IgniteClient = require('apache-ignite-client');
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
-
-const igniteClientConfiguration = new IgniteClientConfiguration('127.0.0.1:10800');
-```
-
-Example: Ignite Client Configuration with username/password authentication and additional connection options
-
-```javascript
-const IgniteClient = require('apache-ignite-client');
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
-
-const igniteClientConfiguration = new IgniteClientConfiguration('127.0.0.1:10800').
- setUserName('ignite').
- setPassword('ignite').
- setConnectionOptions(false, { 'timeout' : 0 });
-```
-
-### Connect Ignite Client ###
-
-The next step is to connect the client to an Ignite node. The configuration for the client's connection, which includes endpoint(s) to connect to, is specified in the connect method.
-
-The client has three connection states - *CONNECTING*, *CONNECTED*, *DISCONNECTED*. A state is reported via *onStateChanged* callback, if that was provided in the client's constructor.
-
-Any operations with Ignite caches are possible in the *CONNECTED* state only.
-
-If the client unexpectedly lost the connection, it automatically moves to the *CONNECTING* state and tries to re-connect using the "failover re-connection algorithm". If not possible to connect to all endpoints from the provided list, the client moves to the *DISCONNECTED* state.
-
-At any moment, an application can call the disconnect method and forcibly moves the client to the *DISCONNECTED* state.
-
-When the client becomes disconnected, an application can call the connect method again - with the same or different configuration (eg. with different list of endpoints).
-
-```javascript
-const IgniteClient = require('apache-ignite-client');
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
-
-async function connectClient() {
- const igniteClient = new IgniteClient(onStateChanged);
- try {
- const igniteClientConfiguration = new IgniteClientConfiguration('127.0.0.1:10800');
- // connect to Ignite node
- await igniteClient.connect(igniteClientConfiguration);
- }
- catch (err) {
- console.log(err.message);
- }
- finally {
- igniteClient.disconnect();
- }
-}
-
-function onStateChanged(state, reason) {
- if (state === IgniteClient.STATE.CONNECTED) {
- console.log('Client is started');
- }
- else if (state === IgniteClient.STATE.DISCONNECTED) {
- console.log('Client is stopped');
- if (reason) {
- console.log(reason);
- }
- }
-}
-
-connectClient();
-```
-
-### Obtain Cache Instance ###
-
-The next step is to obtain a Cache instance - an instance of the *CacheClient* class. One Cache instance gives access to one Ignite cache.
-
-The Ignite client provides several methods to manipulate with Ignite caches and obtain a Cache instance - get a cache by it's name, create a cache with the specified name and optional cache configuration, get or create a cache, destroys a cache, etc.
-
-It is possible to obtain as many *CacheClient* instances as needed - for the same or different Ignite caches - and work with all of them "in parallel".
-
-Example: get or create cache by name and destroy the cache
-
-```javascript
-const IgniteClient = require('apache-ignite-client');
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
-
-async function getOrCreateCacheByName() {
- const igniteClient = new IgniteClient();
- try {
- await igniteClient.connect(new IgniteClientConfiguration('127.0.0.1:10800'));
- // get or create cache by name
- const cache = await igniteClient.getOrCreateCache('myCache');
-
- // perform cache key-value operations
- // ...
-
- // destroy cache
- await igniteClient.destroyCache('myCache');
- }
- catch (err) {
- console.log(err.message);
- }
- finally {
- igniteClient.disconnect();
- }
-}
-
-getOrCreateCacheByName();
-```
-
-Example: create cache by name and configuration
-
-```javascript
-const IgniteClient = require('apache-ignite-client');
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
-const CacheConfiguration = IgniteClient.CacheConfiguration;
-
-async function createCacheByConfiguration() {
- const igniteClient = new IgniteClient();
- try {
- await igniteClient.connect(new IgniteClientConfiguration('127.0.0.1:10800'));
- // create cache by name and configuration
- const cache = await igniteClient.createCache(
- 'myCache',
- new CacheConfiguration().setSqlSchema('PUBLIC'));
- }
- catch (err) {
- console.log(err.message);
- }
- finally {
- igniteClient.disconnect();
- }
-}
-
-createCacheByConfiguration();
-```
-
-Example: get existing cache by name
-
-```javascript
-const IgniteClient = require('apache-ignite-client');
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
+### Installation from Sources ###
-async function getExistingCache() {
- const igniteClient = new IgniteClient();
- try {
- await igniteClient.connect(new IgniteClientConfiguration('127.0.0.1:10800'));
- // get existing cache by name
- const cache = igniteClient.getCache('myCache');
- }
- catch (err) {
- console.log(err.message);
- }
- finally {
- igniteClient.disconnect();
- }
-}
+If you want to install the Thin Client library from Ignite sources, please follow the steps:
-getExistingCache();
-```
-
-### Configure Cache Instance ###
-
-The next step is optional.
-
-It is possible to specify concrete Ignite types for the key and/or the value of the cache. If the key and/or value is a non-primitive type (eg. a map, a collection, a complex object, etc.) it is possible to specify concrete Ignite types for fields of that objects as well.
-
-If Ignite type is not explicitly specified for some field, the client tries to make automatic default mapping between JavaScript types and Ignite object types.
-
-More details about types and mappings are clarified in the [Data Types](#data-types) section.
-
-```javascript
-const IgniteClient = require('apache-ignite-client');
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
-const ObjectType = IgniteClient.ObjectType;
-const MapObjectType = IgniteClient.MapObjectType;
-
-async function setCacheKeyValueTypes() {
- const igniteClient = new IgniteClient();
- try {
- await igniteClient.connect(new IgniteClientConfiguration('127.0.0.1:10800'));
- const cache = await igniteClient.getOrCreateCache('myCache');
- // set cache key/value types
- cache.setKeyType(ObjectType.PRIMITIVE_TYPE.INTEGER).
- setValueType(new MapObjectType(
- MapObjectType.MAP_SUBTYPE.LINKED_HASH_MAP,
- ObjectType.PRIMITIVE_TYPE.SHORT,
- ObjectType.PRIMITIVE_TYPE.BYTE_ARRAY));
- }
- catch (err) {
- console.log(err.message);
- }
- finally {
- igniteClient.disconnect();
- }
-}
-
-setCacheKeyValueTypes();
-```
-
-Now, everything is ready to manipulate with the data in the cache.
-
-### Key-Value Queries ###
-
-The *CacheClient* class provides methods to manipulate with the key and the value of the cache using Key-Value Queries operations - put, get, put all, get all, replace, clear, etc.
-
-Example: different cache Key-Value operations with primitive types
-
-```javascript
-const IgniteClient = require('apache-ignite-client');
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
-const ObjectType = IgniteClient.ObjectType;
-const CacheEntry = IgniteClient.CacheEntry;
-
-async function performCacheKeyValueOperations() {
- const igniteClient = new IgniteClient();
- try {
- await igniteClient.connect(new IgniteClientConfiguration('127.0.0.1:10800'));
- const cache = (await igniteClient.getOrCreateCache('myCache')).
- setKeyType(ObjectType.PRIMITIVE_TYPE.INTEGER);
- // put and get value
- await cache.put(1, 'abc');
- const value = await cache.get(1);
-
- // put and get multiple values using putAll()/getAll() methods
- await cache.putAll([new CacheEntry(2, 'value2'), new CacheEntry(3, 'value3')]);
- const values = await cache.getAll([1, 2, 3]);
-
- // removes all entries from the cache
- await cache.clear();
- }
- catch (err) {
- console.log(err.message);
- }
- finally {
- igniteClient.disconnect();
- }
-}
-
-performCacheKeyValueOperations();
-```
-
-Example: cache put/get Complex Objects and Binary Objects
-
-```javascript
-const IgniteClient = require('apache-ignite-client');
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
-const ObjectType = IgniteClient.ObjectType;
-const CacheEntry = IgniteClient.CacheEntry;
-const ComplexObjectType = IgniteClient.ComplexObjectType;
-
-class Person {
- constructor(id = null, name = null, salary = null) {
- this.id = id;
- this.name = name;
- this.salary = salary;
- }
-}
-
-async function putGetComplexAndBinaryObjects() {
- const igniteClient = new IgniteClient();
- try {
- await igniteClient.connect(new IgniteClientConfiguration('127.0.0.1:10800'));
- const cache = await igniteClient.getOrCreateCache('myPersonCache');
- // Complex Object type for JavaScript Person class instances
- const personComplexObjectType = new ComplexObjectType(new Person(0, '', 0)).
- setFieldType('id', ObjectType.PRIMITIVE_TYPE.INTEGER);
- // set cache key and value types
- cache.setKeyType(ObjectType.PRIMITIVE_TYPE.INTEGER).
- setValueType(personComplexObjectType);
- // put Complex Objects to the cache
- await cache.put(1, new Person(1, 'John Doe', 1000));
- await cache.put(2, new Person(2, 'Jane Roe', 2000));
- // get Complex Object, returned value is an instance of Person class
- const person = await cache.get(1);
- console.log(person);
-
- // new CacheClient instance of the same cache to operate with BinaryObjects
- const binaryCache = igniteClient.getCache('myPersonCache').
- setKeyType(ObjectType.PRIMITIVE_TYPE.INTEGER);
- // get Complex Object from the cache in a binary form, returned value is an instance of BinaryObject class
- let binaryPerson = await binaryCache.get(2);
- console.log('Binary form of Person:');
- for (let fieldName of binaryPerson.getFieldNames()) {
- let fieldValue = await binaryPerson.getField(fieldName);
- console.log(fieldName + ' : ' + fieldValue);
- }
- // modify Binary Object and put it to the cache
- binaryPerson.setField('id', 3, ObjectType.PRIMITIVE_TYPE.INTEGER).
- setField('name', 'Mary Major');
- await binaryCache.put(3, binaryPerson);
-
- // get Binary Object from the cache and convert it to JavaScript Object
- binaryPerson = await binaryCache.get(3);
- console.log(await binaryPerson.toObject(personComplexObjectType));
-
- await igniteClient.destroyCache('myPersonCache');
- }
- catch (err) {
- console.log(err.message);
- }
- finally {
- igniteClient.disconnect();
- }
-}
-
-putGetComplexAndBinaryObjects();
-```
-
-### SQL, SQL Fields and Scan Queries ###
-
-The *CacheClient* class provides the query method that accepts an instance of a concrete query definition class and returns an instance of a concrete cursor class which can be used to obtain the results of the query.
-
-Every cursor class allows
-- either to iterate over the results of the query by obtaining one element of the results after another,
-- or to get all elements of the results in a one array at once.
-
-#### SQL Query ####
-
-First, define the query by creating and configuring an instance of the *SqlQuery* class.
-
-Then, pass the *SqlQuery* instance in to the query method of the Cache instance and obtain an instance of the *Cursor* class.
-
-Finally, use the *Cursor* instance to iterate over or get all cache entries returned by the query.
-
-```javascript
-const IgniteClient = require('apache-ignite-client');
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
-const CacheConfiguration = IgniteClient.CacheConfiguration;
-const QueryEntity = IgniteClient.QueryEntity;
-const QueryField = IgniteClient.QueryField;
-const ObjectType = IgniteClient.ObjectType;
-const ComplexObjectType = IgniteClient.ComplexObjectType;
-const CacheEntry = IgniteClient.CacheEntry;
-const SqlQuery = IgniteClient.SqlQuery;
-
-async function performSqlQuery() {
- const igniteClient = new IgniteClient();
- try {
- await igniteClient.connect(new IgniteClientConfiguration('127.0.0.1:10800'));
- // cache configuration required for sql query execution
- const cacheConfiguration = new CacheConfiguration().
- setQueryEntities(
- new QueryEntity().
- setValueTypeName('Person').
- setFields([
- new QueryField('name', 'java.lang.String'),
- new QueryField('salary', 'java.lang.Double')
- ]));
- const cache = (await igniteClient.getOrCreateCache('sqlQueryPersonCache', cacheConfiguration)).
- setKeyType(ObjectType.PRIMITIVE_TYPE.INTEGER).
- setValueType(new ComplexObjectType({ 'name' : '', 'salary' : 0 }, 'Person'));
-
- // put multiple values using putAll()
- await cache.putAll([
- new CacheEntry(1, { 'name' : 'John Doe', 'salary' : 1000 }),
- new CacheEntry(2, { 'name' : 'Jane Roe', 'salary' : 2000 }),
- new CacheEntry(2, { 'name' : 'Mary Major', 'salary' : 1500 })]);
-
- // create and configure sql query
- const sqlQuery = new SqlQuery('Person', 'salary > ? and salary <= ?').
- setArgs(900, 1600);
- // obtain sql query cursor
- const cursor = await cache.query(sqlQuery);
- // getAll cache entries returned by the sql query
- for (let cacheEntry of await cursor.getAll()) {
- console.log(cacheEntry.getValue());
- }
-
- await igniteClient.destroyCache('sqlQueryPersonCache');
- }
- catch (err) {
- console.log(err.message);
- }
- finally {
- igniteClient.disconnect();
- }
-}
-
-performSqlQuery();
-```
-
-#### Scan Query ####
-
-First, define the query by creating and configuring an instance of the *ScanQuery* class.
-
-Then, pass the *ScanQuery* instance in to the query method of the Cache instance and obtain an instance of the *Cursor* class.
-
-Finally, use the *Cursor* instance to iterate over or get all cache entries returned by the query.
-
-```javascript
-const IgniteClient = require('apache-ignite-client');
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
-const ObjectType = IgniteClient.ObjectType;
-const CacheEntry = IgniteClient.CacheEntry;
-const ScanQuery = IgniteClient.ScanQuery;
-
-async function performScanQuery() {
- const igniteClient = new IgniteClient();
- try {
- await igniteClient.connect(new IgniteClientConfiguration('127.0.0.1:10800'));
- const cache = (await igniteClient.getOrCreateCache('myCache')).
- setKeyType(ObjectType.PRIMITIVE_TYPE.INTEGER);
-
- // put multiple values using putAll()
- await cache.putAll([
- new CacheEntry(1, 'value1'),
- new CacheEntry(2, 'value2'),
- new CacheEntry(3, 'value3')]);
-
- // create and configure scan query
- const scanQuery = new ScanQuery().
- setPageSize(1);
- // obtain scan query cursor
- const cursor = await cache.query(scanQuery);
- // getAll cache entries returned by the scan query
- for (let cacheEntry of await cursor.getAll()) {
- console.log(cacheEntry.getValue());
- }
-
- await igniteClient.destroyCache('myCache');
- }
- catch (err) {
- console.log(err.message);
- }
- finally {
- igniteClient.disconnect();
- }
-}
-
-performScanQuery();
-```
-
-#### SQL Fields Query ####
-
-First, define the query by creating and configuring an instance of the *SqlFieldsQuery* class.
-
-Then, pass the *SqlFieldsQuery* instance in to the query method of the Cache instance and obtain an instance of the *SqlFieldsCursor* class.
-
-Finally, use the *SqlFieldsCursor* instance to iterate over or get all elements returned by the query.
-
-```javascript
-const IgniteClient = require('apache-ignite-client');
-const IgniteClientConfiguration = IgniteClient.IgniteClientConfiguration;
-const CacheConfiguration = IgniteClient.CacheConfiguration;
-const ObjectType = IgniteClient.ObjectType;
-const CacheEntry = IgniteClient.CacheEntry;
-const SqlFieldsQuery = IgniteClient.SqlFieldsQuery;
-
-async function performSqlFieldsQuery() {
- const igniteClient = new IgniteClient();
- try {
- await igniteClient.connect(new IgniteClientConfiguration('127.0.0.1:10800'));
- const cache = await igniteClient.getOrCreateCache('myPersonCache', new CacheConfiguration().
- setSqlSchema('PUBLIC'));
-
- // create table using SqlFieldsQuery
- (await cache.query(new SqlFieldsQuery(
- 'CREATE TABLE Person (id INTEGER PRIMARY KEY, firstName VARCHAR, lastName VARCHAR, salary DOUBLE)'))).getAll();
-
- // insert data into the table
- const insertQuery = new SqlFieldsQuery('INSERT INTO Person (id, firstName, lastName, salary) values (?, ?, ?, ?)').
- setArgTypes(ObjectType.PRIMITIVE_TYPE.INTEGER);
- (await cache.query(insertQuery.setArgs(1, 'John', 'Doe', 1000))).getAll();
- (await cache.query(insertQuery.setArgs(2, 'Jane', 'Roe', 2000))).getAll();
-
- // obtain sql fields cursor
- const sqlFieldsCursor = await cache.query(
- new SqlFieldsQuery("SELECT concat(firstName, ' ', lastName), salary from Person").
- setPageSize(1));
-
- // iterate over elements returned by the query
- do {
- console.log(await sqlFieldsCursor.getValue());
- } while (sqlFieldsCursor.hasMore());
-
- // drop the table
- (await cache.query(new SqlFieldsQuery("DROP TABLE Person"))).getAll();
- }
- catch (err) {
- console.log(err.message);
- }
- finally {
- igniteClient.disconnect();
- }
-}
+1. Download Ignite sources to `local_ignite_path`
+2. Go to `local_ignite_path/modules/platforms/nodejs` folder
+3. Execute `npm link` command
+4. Execute `npm link apache-ignite-client` command (needed only for examples)
-performSqlFieldsQuery();
+```bash
+cd local_ignite_path/modules/platforms/nodejs
+npm link
+npm link apache-ignite-client #linking examples (optional)
```
-### Enable Debug ###
-
-To switch on/off the client's debug output (including errors logging), call *setDebug()* method of the *IgniteClient* instance. Debug output is disabled by default.
-
-```javascript
-const IgniteClient = require('apache-ignite-client');
-
-const igniteClient = new IgniteClient();
-igniteClient.setDebug(true);
-```
+For more information, see [Apache Ignite Node.JS Thin Client documentation](https://apacheignite.readme.io/docs/nodejs-thin-client).
http://git-wip-us.apache.org/repos/asf/ignite/blob/4b002427/modules/platforms/nodejs/examples/README.md
----------------------------------------------------------------------
diff --git a/modules/platforms/nodejs/examples/README.md b/modules/platforms/nodejs/examples/README.md
deleted file mode 100644
index 94b1433..0000000
--- a/modules/platforms/nodejs/examples/README.md
+++ /dev/null
@@ -1,128 +0,0 @@
-# Examples #
-
-NodeJS Client for Apache Ignite contains fully workable examples to demonstrate the main behavior of the client.
-
-## Description ##
-
-### Sql Example ###
-
-Source: [SqlExample.js](./SqlExample.js)
-
-This example shows primary APIs to use with Ignite as with an SQL database:
-- connects to a node
-- creates a cache, if it doesn't exist
-- creates tables (CREATE TABLE)
-- creates indices (CREATE INDEX)
-- writes data of primitive types into the tables (INSERT INTO table)
-- reads data from the tables (SELECT ...)
-- deletes tables (DROP TABLE)
-- destroys the cache
-
-### Cache Put Get Example ###
-
-Source: [CachePutGetExample.js](./CachePutGetExample.js)
-
-This example demonstrates basic Cache, Key-Value Queries and Scan Query operations:
-- connects to a node
-- creates a cache, if it doesn't exist
- - specifies key type as Integer
-- executes different cache operations with Complex Objects and Binary Objects
- - put several objects in parallel
- - putAll
- - get
- - getAll
- - ScanQuery
-- destroys the cache
-
-### Sql Query Entries Example ###
-
-Source: [SqlQueryEntriesExample.js](./SqlQueryEntriesExample.js)
-
-This example demonstrates basic Cache, Key-Value Queries and SQL Query operations:
-- connects to a node
-- creates a cache from CacheConfiguration, if it doesn't exist
-- writes data of primitive and Complex Object types into the cache using Key-Value put operation
-- reads data from the cache using SQL Query
-- destroys the cache
-
-### Auth Tls Example ###
-
-Source: [AuthTlsExample.js](./AuthTlsExample.js)
-
-This example requires [additional setup](#additional-setup-for-authtlsexample).
-
-This example demonstrates how to establish a secure connection to an Ignite node and use username/password authentication, as well as basic Key-Value Queries operations for primitive types:
-- connects to a node using TLS and providing username/password
-- creates a cache, if it doesn't exist
- - specifies key and value type of the cache
-- put data of primitive types into the cache
-- get data from the cache
-- destroys the cache
-
-
-### Failover Example ###
-
-Source: [FailoverExample.js](./FailoverExample.js)
-
-This example requires [additional setup](#additional-setup-for-failoverexample).
-
-This example demonstrates the failover behavior of the client
-- configures the client to connect to a set of nodes
-- connects to a node
-- if connection is broken, the client automatically tries to reconnect to another node
-- if no specified nodes are available, stops the client
-
-
-## Installation ##
-
-(temporary, while the NPM module is not released on [npmjs](https://www.npmjs.com))
-
-Examples are installed along with the client.
-Follow the [instructions in the main readme](../README.md#installation).
-
-## Setup and Running ##
-
-1. Run Apache Ignite server - locally or remotely.
-
-2. If needed, modify `ENDPOINT` constant in an example source file - Ignite node endpoint. The default value is `127.0.0.1:10800`.
-
-3. Run an example by calling `node <example_file_name>.js`. Eg. `node CachePutGetExample.js`
-
-## Additional Setup for AuthTlsExample ##
-
-1. Obtain certificates required for TLS:
- - either use pre-generated certificates provided in the [examples/certs](./certs) folder. Password for the files: `123456`. Note, these certificates work for an Ignite server installed locally only.
- - or obtain other existing certificates applicable for a concrete Ignite server.
- - or generate new certificates applicable for a concrete Ignite server.
-
- - The following files are needed:
- - keystore.jks, truststore.jks - for the server side
- - client.key, client.crt, ca.crt - for the client side
-
-2. Place client.key, client.crt and ca.crt files somewhere locally, eg. into the [examples/certs](./certs) folder.
-
-3. If needed, modify `TLS_KEY_FILE_NAME`, `TLS_CERT_FILE_NAME` and `TLS_CA_FILE_NAME` constants in the example source file. The default values point to the files in the [examples/certs](./certs) folder.
-
-4. Setup Apache Ignite server to accept TLS - see appropriate Ignite documentation. Provide the obtained keystore.jks and truststore.jks certificates during the setup.
-
-5. Switch on and setup authentication in Apache Ignite server - see appropriate Ignite documentation.
-
-6. If needed, modify `USER_NAME` and `PASSWORD` constants in the example source file. The default values are the default Ignite username/password.
-
-7. Executes [Setup and Running](#setup-and-running) steps.
-
-## Additional Setup for FailoverExample ##
-
-1. Run three Ignite nodes. See appropriate Ignite documentation for more details.
-
-2. If needed, modify `ENDPOINT1`, `ENDPOINT2`, `ENDPOINT2` constants in an example source file - Ignite node endpoints.
-Default values are `localhost:10800`, `localhost:10801`, `localhost:10802` respectively.
-
-2. Run an example by calling `node FailoverExample.js`.
-
-3. Shut down the node the client connected to (you can find it out from the client logs in the console).
-
-4. From the logs, you will see that the client automatically reconnects to another node which is available.
-
-5. Shut down all the nodes. You will see the client being stopped after failing to connect to each of the nodes.
-
http://git-wip-us.apache.org/repos/asf/ignite/blob/4b002427/modules/platforms/nodejs/lib/BinaryObject.js
----------------------------------------------------------------------
diff --git a/modules/platforms/nodejs/lib/BinaryObject.js b/modules/platforms/nodejs/lib/BinaryObject.js
index fb139da..9be60da 100644
--- a/modules/platforms/nodejs/lib/BinaryObject.js
+++ b/modules/platforms/nodejs/lib/BinaryObject.js
@@ -77,7 +77,9 @@ class BinaryObject {
this._typeBuilder = BinaryTypeBuilder.fromTypeName(typeName);
this._modified = false;
this._schemaOffset = null;
+ this._hasSchema = false;
this._compactFooter = false;
+ this._hasRawData = false;
}
/**
@@ -301,14 +303,22 @@ class BinaryObject {
await this._typeBuilder.finalize(communicator);
this._startPos = buffer.position;
buffer.position = this._startPos + HEADER_LENGTH;
- // write fields
- for (let field of this._fields.values()) {
- await field._writeValue(communicator, buffer, this._typeBuilder.getField(field.id).typeCode);
+ this._hasSchema = (this._fields.size > 0);
+ if (this._hasSchema) {
+ let field;
+ // write fields
+ for (field of this._fields.values()) {
+ await field._writeValue(communicator, buffer, this._typeBuilder.getField(field.id).typeCode);
+ }
+ this._schemaOffset = buffer.position - this._startPos;
+ this._offsetType = field.getOffsetType(this._startPos);
+ // write schema
+ for (let field of this._fields.values()) {
+ field._writeOffset(buffer, this._startPos, this._offsetType);
+ }
}
- this._schemaOffset = buffer.position - this._startPos;
- // write schema
- for (let field of this._fields.values()) {
- field._writeOffset(buffer, this._startPos);
+ else {
+ this._schemaOffset = 0;
}
this._length = buffer.position - this._startPos;
this._buffer = buffer;
@@ -333,7 +343,17 @@ class BinaryObject {
// version
this._buffer.writeByte(VERSION);
// flags
- this._buffer.writeShort(FLAG_USER_TYPE | FLAG_HAS_SCHEMA | FLAG_COMPACT_FOOTER);
+ let flags = FLAG_USER_TYPE;
+ if (this._hasSchema) {
+ flags = flags | FLAG_HAS_SCHEMA | FLAG_COMPACT_FOOTER;
+ }
+ if (this._offsetType === BinaryUtils.TYPE_CODE.BYTE) {
+ flags = flags | FLAG_OFFSET_ONE_BYTE;
+ }
+ else if (this._offsetType === BinaryUtils.TYPE_CODE.SHORT) {
+ flags = flags | FLAG_OFFSET_TWO_BYTES;
+ }
+ this._buffer.writeShort(flags);
// type id
this._buffer.writeInteger(this._typeBuilder.getTypeId());
// hash code
@@ -342,7 +362,7 @@ class BinaryObject {
// length
this._buffer.writeInteger(this._length);
// schema id
- this._buffer.writeInteger(this._typeBuilder.getSchemaId());
+ this._buffer.writeInteger(this._hasSchema ? this._typeBuilder.getSchemaId() : 0);
// schema offset
this._buffer.writeInteger(this._schemaOffset);
}
@@ -352,37 +372,43 @@ class BinaryObject {
*/
async _read(communicator) {
await this._readHeader(communicator);
- this._buffer.position = this._startPos + this._schemaOffset;
- const fieldOffsets = new Array();
- const fieldIds = this._typeBuilder._schema.fieldIds;
- let index = 0;
- let fieldId;
- while (this._buffer.position < this._startPos + this._length) {
- if (!this._compactFooter) {
- fieldId = this._buffer.readInteger();
- this._typeBuilder._schema.addField(fieldId);
+ if (this._hasSchema) {
+ this._buffer.position = this._startPos + this._schemaOffset;
+ const fieldOffsets = new Array();
+ const fieldIds = this._typeBuilder._schema.fieldIds;
+ let index = 0;
+ let fieldId;
+ let schemaEndOffset = this._startPos + this._length;
+ if (this._hasRawData) {
+ schemaEndOffset -= BinaryUtils.getSize(BinaryUtils.TYPE_CODE.INTEGER);
}
- else {
- if (index >= fieldIds.length) {
- throw Errors.IgniteClientError.serializationError(
- false, 'wrong number of fields in schema');
+ while (this._buffer.position < schemaEndOffset) {
+ if (!this._compactFooter) {
+ fieldId = this._buffer.readInteger();
+ this._typeBuilder._schema.addField(fieldId);
}
- fieldId = fieldIds[index];
- index++;
+ else {
+ if (index >= fieldIds.length) {
+ throw Errors.IgniteClientError.serializationError(
+ false, 'wrong number of fields in schema');
+ }
+ fieldId = fieldIds[index];
+ index++;
+ }
+ fieldOffsets.push([fieldId, this._buffer.readNumber(this._offsetType, false)]);
+ }
+ fieldOffsets.sort((val1, val2) => val1[1] - val2[1]);
+ let offset;
+ let nextOffset;
+ let field;
+ for (let i = 0; i < fieldOffsets.length; i++) {
+ fieldId = fieldOffsets[i][0];
+ offset = fieldOffsets[i][1];
+ nextOffset = i + 1 < fieldOffsets.length ? fieldOffsets[i + 1][1] : this._schemaOffset;
+ field = BinaryObjectField._fromBuffer(
+ communicator,this._buffer, this._startPos + offset, nextOffset - offset, fieldId);
+ this._fields.set(field.id, field);
}
- fieldOffsets.push([fieldId, this._buffer.readNumber(this._offsetType)]);
- }
- fieldOffsets.sort((val1, val2) => val1[1] - val2[1]);
- let offset;
- let nextOffset;
- let field;
- for (let i = 0; i < fieldOffsets.length; i++) {
- fieldId = fieldOffsets[i][0];
- offset = fieldOffsets[i][1];
- nextOffset = i + 1 < fieldOffsets.length ? fieldOffsets[i + 1][1] : this._schemaOffset;
- field = BinaryObjectField._fromBuffer(
- communicator,this._buffer, this._startPos + offset, nextOffset - offset, fieldId);
- this._fields.set(field.id, field);
}
this._buffer.position = this._startPos + this._length;
}
@@ -410,23 +436,15 @@ class BinaryObject {
const schemaId = this._buffer.readInteger();
// schema offset
this._schemaOffset = this._buffer.readInteger();
- const hasSchema = BinaryObject._isFlagSet(flags, FLAG_HAS_SCHEMA);
+ this._hasSchema = BinaryObject._isFlagSet(flags, FLAG_HAS_SCHEMA);
this._compactFooter = BinaryObject._isFlagSet(flags, FLAG_COMPACT_FOOTER);
+ this._hasRawData = BinaryObject._isFlagSet(flags, FLAG_HAS_RAW_DATA);
this._offsetType = BinaryObject._isFlagSet(flags, FLAG_OFFSET_ONE_BYTE) ?
BinaryUtils.TYPE_CODE.BYTE :
BinaryObject._isFlagSet(flags, FLAG_OFFSET_TWO_BYTES) ?
BinaryUtils.TYPE_CODE.SHORT :
BinaryUtils.TYPE_CODE.INTEGER;
-
- if (BinaryObject._isFlagSet(flags, FLAG_HAS_RAW_DATA)) {
- throw Errors.IgniteClientError.serializationError(
- false, 'complex objects with raw data are not supported');
- }
- if (this._compactFooter && !hasSchema) {
- throw Errors.IgniteClientError.serializationError(
- false, 'schema is absent for object with compact footer');
- }
- this._typeBuilder = await BinaryTypeBuilder.fromTypeId(communicator, typeId, schemaId, hasSchema);
+ this._typeBuilder = await BinaryTypeBuilder.fromTypeId(communicator, typeId, this._compactFooter ? schemaId : null);
}
}
@@ -465,6 +483,17 @@ class BinaryObjectField {
return this._value;
}
+ getOffsetType(headerStartPos) {
+ let offset = this._offset - headerStartPos;
+ if (offset < 0x100) {
+ return BinaryUtils.TYPE_CODE.BYTE;
+ }
+ else if (offset < 0x10000) {
+ return BinaryUtils.TYPE_CODE.SHORT;
+ }
+ return BinaryUtils.TYPE_CODE.INTEGER;
+ }
+
static _fromBuffer(communicator, buffer, offset, length, id) {
const result = new BinaryObjectField(null);
result._id = id;
@@ -493,8 +522,8 @@ class BinaryObjectField {
this._offset = offset;
}
- _writeOffset(buffer, headerStartPos) {
- buffer.writeInteger(this._offset - headerStartPos);
+ _writeOffset(buffer, headerStartPos, offsetType) {
+ buffer.writeNumber(this._offset - headerStartPos, offsetType, false);
}
}
http://git-wip-us.apache.org/repos/asf/ignite/blob/4b002427/modules/platforms/nodejs/lib/internal/BinaryType.js
----------------------------------------------------------------------
diff --git a/modules/platforms/nodejs/lib/internal/BinaryType.js b/modules/platforms/nodejs/lib/internal/BinaryType.js
index 98aa6a3..a111ed0 100644
--- a/modules/platforms/nodejs/lib/internal/BinaryType.js
+++ b/modules/platforms/nodejs/lib/internal/BinaryType.js
@@ -18,6 +18,7 @@
'use strict';
const Util = require('util');
+const Long = require('long');
const ComplexObjectType = require('../ObjectType').ComplexObjectType;
const BinaryTypeStorage = require('./BinaryTypeStorage');
const BinaryUtils = require('./BinaryUtils');
@@ -104,6 +105,15 @@ class BinaryType {
return result;
}
+ isValid() {
+ for (let field of this._fields.values()) {
+ if (!field.isValid()) {
+ return false;
+ }
+ }
+ return this._name !== null;
+ }
+
static _calculateId(name) {
return BinaryUtils.hashCodeLowerCase(name);
}
@@ -245,19 +255,16 @@ class BinarySchema {
}
static _updateSchemaId(schemaId, fieldId) {
- schemaId = schemaId ^ (fieldId & 0xFF);
- schemaId = schemaId * FNV1_PRIME;
- schemaId |= 0;
- schemaId = schemaId ^ ((fieldId >> 8) & 0xFF);
- schemaId = schemaId * FNV1_PRIME;
- schemaId |= 0;
- schemaId = schemaId ^ ((fieldId >> 16) & 0xFF);
- schemaId = schemaId * FNV1_PRIME;
- schemaId |= 0;
- schemaId = schemaId ^ ((fieldId >> 24) & 0xFF);
- schemaId = schemaId * FNV1_PRIME;
- schemaId |= 0;
+ schemaId = BinarySchema._updateSchemaIdPart(schemaId, fieldId & 0xFF);
+ schemaId = BinarySchema._updateSchemaIdPart(schemaId, (fieldId >> 8) & 0xFF);
+ schemaId = BinarySchema._updateSchemaIdPart(schemaId, (fieldId >> 16) & 0xFF);
+ schemaId = BinarySchema._updateSchemaIdPart(schemaId, (fieldId >> 24) & 0xFF);
+ return schemaId;
+ }
+ static _updateSchemaIdPart(schemaId, fieldIdPart) {
+ schemaId = schemaId ^ fieldIdPart;
+ schemaId = Long.fromValue(schemaId).multiply(FNV1_PRIME).getLowBits();
return schemaId;
}
@@ -304,6 +311,10 @@ class BinaryField {
return this._typeCode;
}
+ isValid() {
+ return this._name !== null;
+ }
+
static _calculateId(name) {
return BinaryUtils.hashCodeLowerCase(name);
}
@@ -335,12 +346,12 @@ class BinaryTypeBuilder {
return result;
}
- static async fromTypeId(communicator, typeId, schemaId, hasSchema) {
+ static async fromTypeId(communicator, typeId, schemaId) {
let result = new BinaryTypeBuilder();
- if (hasSchema) {
- let type = await communicator.typeStorage.getType(typeId, schemaId);
- if (type) {
- result._type = type;
+ let type = await communicator.typeStorage.getType(typeId, schemaId);
+ if (type) {
+ result._type = type;
+ if (schemaId !== null) {
result._schema = type.getSchema(schemaId);
if (!result._schema) {
throw Errors.IgniteClientError.serializationError(
@@ -348,8 +359,11 @@ class BinaryTypeBuilder {
schemaId, type.name));
}
result._fromStorage = true;
- return result;
}
+ else {
+ result._schema = new BinarySchema();
+ }
+ return result;
}
result._init(null);
result._type._id = typeId;
http://git-wip-us.apache.org/repos/asf/ignite/blob/4b002427/modules/platforms/nodejs/lib/internal/BinaryTypeStorage.js
----------------------------------------------------------------------
diff --git a/modules/platforms/nodejs/lib/internal/BinaryTypeStorage.js b/modules/platforms/nodejs/lib/internal/BinaryTypeStorage.js
index 144710a..2248eb5 100644
--- a/modules/platforms/nodejs/lib/internal/BinaryTypeStorage.js
+++ b/modules/platforms/nodejs/lib/internal/BinaryTypeStorage.js
@@ -19,6 +19,7 @@
const Errors = require('../Errors');
const BinaryUtils = require('./BinaryUtils');
+const Util = require('util');
class BinaryTypeStorage {
@@ -96,6 +97,10 @@ class BinaryTypeStorage {
}
async _putBinaryType(binaryType) {
+ if (!binaryType.isValid()) {
+ throw Errors.IgniteClientError.serializationError(
+ true, Util.format('type "%d" can not be registered', binaryType.id));
+ }
await this._communicator.send(
BinaryUtils.OPERATION.PUT_BINARY_TYPE,
async (payload) => {
http://git-wip-us.apache.org/repos/asf/ignite/blob/4b002427/modules/platforms/nodejs/lib/internal/BinaryUtils.js
----------------------------------------------------------------------
diff --git a/modules/platforms/nodejs/lib/internal/BinaryUtils.js b/modules/platforms/nodejs/lib/internal/BinaryUtils.js
index ab2d40c..2619df7 100644
--- a/modules/platforms/nodejs/lib/internal/BinaryUtils.js
+++ b/modules/platforms/nodejs/lib/internal/BinaryUtils.js
@@ -306,7 +306,7 @@ class BinaryUtils {
const BinaryObject = require('../BinaryObject');
const objectType = typeof object;
if (object === null) {
- return BinaryUtils.TYPE_CODE.NULL;
+ throw Errors.IgniteClientError.unsupportedTypeError(BinaryUtils.TYPE_CODE.NULL);
}
else if (objectType === 'number') {
return BinaryUtils.TYPE_CODE.DOUBLE;
http://git-wip-us.apache.org/repos/asf/ignite/blob/4b002427/modules/platforms/nodejs/lib/internal/MessageBuffer.js
----------------------------------------------------------------------
diff --git a/modules/platforms/nodejs/lib/internal/MessageBuffer.js b/modules/platforms/nodejs/lib/internal/MessageBuffer.js
index dc3e928..b3be7e9 100644
--- a/modules/platforms/nodejs/lib/internal/MessageBuffer.js
+++ b/modules/platforms/nodejs/lib/internal/MessageBuffer.js
@@ -105,19 +105,34 @@ class MessageBuffer {
this.writeNumber(value, BinaryUtils.TYPE_CODE.DOUBLE);
}
- writeNumber(value, type) {
+ writeNumber(value, type, signed = true) {
const size = BinaryUtils.getSize(type);
this._ensureCapacity(size);
try {
switch (type) {
case BinaryUtils.TYPE_CODE.BYTE:
- this._buffer.writeInt8(value, this._position);
+ if (signed) {
+ this._buffer.writeInt8(value, this._position);
+ }
+ else {
+ this._buffer.writeUInt8(value, this._position);
+ }
break;
case BinaryUtils.TYPE_CODE.SHORT:
- this._buffer.writeInt16LE(value, this._position);
+ if (signed) {
+ this._buffer.writeInt16LE(value, this._position);
+ }
+ else {
+ this._buffer.writeUInt16LE(value, this._position);
+ }
break;
case BinaryUtils.TYPE_CODE.INTEGER:
- this._buffer.writeInt32LE(value, this._position);
+ if (signed) {
+ this._buffer.writeInt32LE(value, this._position);
+ }
+ else {
+ this._buffer.writeUInt32LE(value, this._position);
+ }
break;
case BinaryUtils.TYPE_CODE.FLOAT:
this._buffer.writeFloatLE(value, this._position);
@@ -184,19 +199,19 @@ class MessageBuffer {
return this.readNumber(BinaryUtils.TYPE_CODE.DOUBLE);
}
- readNumber(type) {
+ readNumber(type, signed = true) {
const size = BinaryUtils.getSize(type);
this._ensureSize(size);
let value;
switch (type) {
case BinaryUtils.TYPE_CODE.BYTE:
- value = this._buffer.readInt8(this._position);
+ value = signed ? this._buffer.readInt8(this._position) : this._buffer.readUInt8(this._position);
break;
case BinaryUtils.TYPE_CODE.SHORT:
- value = this._buffer.readInt16LE(this._position);
+ value = signed ? this._buffer.readInt16LE(this._position) : this._buffer.readUInt16LE(this._position);
break;
case BinaryUtils.TYPE_CODE.INTEGER:
- value = this._buffer.readInt32LE(this._position);
+ value = signed ? this._buffer.readInt32LE(this._position) : this._buffer.readUInt32LE(this._position);
break;
case BinaryUtils.TYPE_CODE.FLOAT:
value = this._buffer.readFloatLE(this._position);
http://git-wip-us.apache.org/repos/asf/ignite/blob/4b002427/modules/platforms/nodejs/spec/README.md
----------------------------------------------------------------------
diff --git a/modules/platforms/nodejs/spec/README.md b/modules/platforms/nodejs/spec/README.md
deleted file mode 100644
index 4b947c4..0000000
--- a/modules/platforms/nodejs/spec/README.md
+++ /dev/null
@@ -1,42 +0,0 @@
-# Tests #
-
-NodeJS Client for Apache Ignite contains [Jasmine](https://www.npmjs.com/package/jasmine) tests to check the behavior of the client. the tests include:
-- functional tests which cover all API methods of the client
-- examples executors which run all examples except AuthTlsExample
-- AuthTlsExample executor
-
-## Tests Installation ##
-
-(temporary, while the NPM module is not released on [npmjs](https://www.npmjs.com))
-
-Tests are installed along with the client.
-Follow the [instructions in the main readme](../README.md#installation).
-
-## Tests Running ##
-
-1. Run Apache Ignite server locally or remotely with default configuration.
-2. Set the environment variable:
- - **APACHE_IGNITE_CLIENT_ENDPOINTS** - comma separated list of Ignite node endpoints.
- - **APACHE_IGNITE_CLIENT_DEBUG** - (optional) if *true*, tests will display additional output (default: *false*).
-3. Alternatively, instead of the environment variables setting, you can directly specify the values of the corresponding variables in [local_ignite_path/modules/platforms/nodejspec/config.js](./config.js) file.
-4. Run the tests:
-
-### Run Functional Tests ###
-
-Call `npm test` command from `local_ignite_path/modules/platforms/nodejs` folder.
-
-### Run Examples Executors ###
-
-Call `npm run test:examples` command from `local_ignite_path/modules/platforms/nodejs` folder.
-
-### Run AuthTlsExample Executor ###
-
-It requires running Apache Ignite server with non-default configuration (authentication and TLS switched on).
-
-If the server runs locally:
-- setup the server to accept TLS. During the setup use `keystore.jks` and `truststore.jks` certificates from `local_ignite_path/modules/platforms/nodejs/examples/certs/` folder. Password for the files: `123456`
-- switch on the authentication on the server. Use the default username/password.
-
-If the server runs remotely, and/or other certificates are required, and/or non-default username/password is required - see this [instruction](../examples/README.md#additional-setup-for-authtlsexample).
-
-Call `npm run test:auth_example` command from `local_ignite_path/modules/platforms/nodejs` folder.
http://git-wip-us.apache.org/repos/asf/ignite/blob/4b002427/modules/platforms/nodejs/spec/cache/ComplexObject.spec.js
----------------------------------------------------------------------
diff --git a/modules/platforms/nodejs/spec/cache/ComplexObject.spec.js b/modules/platforms/nodejs/spec/cache/ComplexObject.spec.js
index 2119ab5..9cc8115 100644
--- a/modules/platforms/nodejs/spec/cache/ComplexObject.spec.js
+++ b/modules/platforms/nodejs/spec/cache/ComplexObject.spec.js
@@ -28,6 +28,9 @@ const ComplexObjectType = IgniteClient.ComplexObjectType;
const BinaryObject = IgniteClient.BinaryObject;
const CACHE_NAME = '__test_cache';
+const ONE_BYTE_MAX_OFFSET = 0x100 - 1;
+const TWO_BYTES_MAX_OFFSET = 0x10000 - 1;
+const COMPLEX_OBJECT_HEADER_LENGTH = 24;
class Class1 {
constructor() {
@@ -323,6 +326,79 @@ describe('complex object test suite >', () => {
catch(error => done.fail(error));
});
+ it('put get complex objects with one byte offset', (done) => {
+ Promise.resolve().
+ then(async () => {
+ const key = new Date();
+ const valueType = new ComplexObjectType(new Class2(), 'Class2WithStrings');
+ const value = new Class2();
+ value.field_2_1 = 'x';
+ value.field_2_2 = 'y';
+ await putGetComplexObjects(key, value, null, valueType, value);
+ const oneByteMaxLen = getMaxFieldLength(true);
+ value.field_2_1 = 'x'.repeat(oneByteMaxLen);
+ value.field_2_2 = 'y';
+ await putGetComplexObjects(key, value, null, valueType, value);
+ }).
+ then(done).
+ catch(error => done.fail(error));
+ });
+
+ it('put get complex objects with two bytes offset', (done) => {
+ Promise.resolve().
+ then(async () => {
+ const key = new Date();
+ const valueType = new ComplexObjectType(new Class2(), 'Class2WithStrings');
+ const value = new Class2();
+ const oneByteMaxLen = getMaxFieldLength(true);
+ value.field_2_1 = 'x'.repeat(oneByteMaxLen + 1);
+ value.field_2_2 = 'y';
+ await putGetComplexObjects(key, value, null, valueType, value);
+ const twoBytesMaxLen = getMaxFieldLength(false);
+ value.field_2_1 = 'x'.repeat(twoBytesMaxLen);
+ value.field_2_2 = 'y';
+ await putGetComplexObjects(key, value, null, valueType, value);
+ }).
+ then(done).
+ catch(error => done.fail(error));
+ });
+
+ it('put get complex objects with four bytes offset', (done) => {
+ Promise.resolve().
+ then(async () => {
+ const key = new Date();
+ const valueType = new ComplexObjectType(new Class2(), 'Class2WithStrings');
+ const value = new Class2();
+ const twoBytesMaxLen = getMaxFieldLength(false);
+ value.field_2_1 = 'x'.repeat(twoBytesMaxLen + 1);
+ value.field_2_2 = 'y';
+ await putGetComplexObjects(key, value, null, valueType, value);
+ value.field_2_1 = 'x'.repeat(twoBytesMaxLen * 2);
+ value.field_2_2 = 'y';
+ await putGetComplexObjects(key, value, null, valueType, value);
+ }).
+ then(done).
+ catch(error => done.fail(error));
+ });
+
+ it('put get complex objects without schema', (done) => {
+ Promise.resolve().
+ then(async () => {
+ const key = new Date();
+ const valueType = new ComplexObjectType({});
+ const value = {};
+ await putGetComplexObjects(key, value, null, valueType, value);
+ }).
+ then(done).
+ catch(error => done.fail(error));
+ });
+
+ function getMaxFieldLength(oneByte) {
+ const maxOffset = oneByte ? ONE_BYTE_MAX_OFFSET : TWO_BYTES_MAX_OFFSET;
+ // max offset - field type code - field type (string) length - complex object header length
+ return maxOffset - 1 - 4 - COMPLEX_OBJECT_HEADER_LENGTH;
+ }
+
async function testSuiteCleanup(done) {
await TestingHelper.destroyCache(CACHE_NAME, done);
}