http://git-wip-us.apache.org/repos/asf/ignite/blob/c56d16fb/modules/platforms/nodejs/lib/ObjectType.js
----------------------------------------------------------------------
diff --git a/modules/platforms/nodejs/lib/ObjectType.js 
b/modules/platforms/nodejs/lib/ObjectType.js
new file mode 100644
index 0000000..f1facfd
--- /dev/null
+++ b/modules/platforms/nodejs/lib/ObjectType.js
@@ -0,0 +1,600 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+const Util = require('util');
+const Errors = require('./Errors');
+const ArgumentChecker = require('./internal/ArgumentChecker');
+
+/**
+ * Supported Ignite type codes for primitive (simple) types.
+ * @typedef ObjectType.PRIMITIVE_TYPE
+ * @enum
+ * @readonly
+ * @property BYTE 1
+ * @property SHORT 2
+ * @property INTEGER 3
+ * @property LONG 4
+ * @property FLOAT 5
+ * @property DOUBLE 6
+ * @property CHAR 7
+ * @property BOOLEAN 8
+ * @property STRING 9
+ * @property UUID 10
+ * @property DATE 11
+ * @property BYTE_ARRAY 12
+ * @property SHORT_ARRAY 13
+ * @property INTEGER_ARRAY 14
+ * @property LONG_ARRAY 15
+ * @property FLOAT_ARRAY 16
+ * @property DOUBLE_ARRAY 17
+ * @property CHAR_ARRAY 18
+ * @property BOOLEAN_ARRAY 19
+ * @property STRING_ARRAY 20
+ * @property UUID_ARRAY 21
+ * @property DATE_ARRAY 22
+ * @property ENUM 28
+ * @property ENUM_ARRAY 29
+ * @property DECIMAL 30
+ * @property DECIMAL_ARRAY 31
+ * @property TIMESTAMP 33
+ * @property TIMESTAMP_ARRAY 34
+ * @property TIME 36
+ * @property TIME_ARRAY 37
+ */
+const PRIMITIVE_TYPE = Object.freeze({
+    BYTE : 1,
+    SHORT : 2,
+    INTEGER : 3,
+    LONG : 4,
+    FLOAT : 5,
+    DOUBLE : 6,
+    CHAR : 7,
+    BOOLEAN : 8,
+    STRING : 9,
+    UUID : 10,
+    DATE : 11,
+    BYTE_ARRAY : 12,
+    SHORT_ARRAY : 13,
+    INTEGER_ARRAY : 14,
+    LONG_ARRAY : 15,
+    FLOAT_ARRAY : 16,
+    DOUBLE_ARRAY : 17,
+    CHAR_ARRAY : 18,
+    BOOLEAN_ARRAY : 19,
+    STRING_ARRAY : 20,
+    UUID_ARRAY : 21,
+    DATE_ARRAY : 22,
+    ENUM : 28,
+    ENUM_ARRAY : 29,
+    DECIMAL : 30,
+    DECIMAL_ARRAY : 31,
+    TIMESTAMP : 33,
+    TIMESTAMP_ARRAY : 34,
+    TIME : 36,
+    TIME_ARRAY : 37
+});
+
+/**
+ * Supported Ignite type codes for non-primitive (composite) types.
+ * @typedef ObjectType.COMPOSITE_TYPE
+ * @enum
+ * @readonly
+ * @property OBJECT_ARRAY 23
+ * @property COLLECTION 24
+ * @property MAP 25
+ * @property NULL 101
+ * @property COMPLEX_OBJECT 103
+ */
+const COMPOSITE_TYPE = Object.freeze({
+    OBJECT_ARRAY : 23,
+    COLLECTION : 24,
+    MAP : 25,
+    NULL : 101,
+    COMPLEX_OBJECT : 103
+});
+
+/** 
+ * Base class representing a type of Ignite object.
+ *
+ * The class has no public constructor. Only subclasses may be instantiated.
+ *
+ * There are two groups of Ignite object types:
+ *
+ * - Primitive (simple) types. To fully describe such a type it is enough to 
specify
+ * Ignite type code {@link ObjectType.PRIMITIVE_TYPE} only.
+ *
+ * - Non-primitive (composite) types. To fully describe such a type
+ * Ignite type code {@link ObjectType.COMPOSITE_TYPE} with additional 
information should be specified.
+ * Eg. a kind of map or a kind of collection.
+ *
+ * This class helps the Ignite client to make a mapping between JavaScript 
types
+ * and types used by Ignite.
+ *
+ * In many methods the Ignite client does not require to directly specify a 
type of Ignite object.
+ * In this case the Ignite client tries to make automatic mapping between 
JavaScript types
+ * and Ignite object types according to the following mapping tables:
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * DEFAULT MAPPING FROM JavaScript type TO Ignite type code.
+ *
+ * This mapping is used when an application does not explicitly specify an 
Ignite type
+ * for a field and is writing data to that field.
+ *
+ * <pre>
+ * | JavaScript type           | Ignite type code      |
+ * | ------------------------- | ----------------------|
+ * | number                    | DOUBLE                |
+ * | boolean                   | BOOLEAN               |
+ * | string                    | STRING                |
+ * | Date                      | DATE                  |
+ * | Timestamp*                | TIMESTAMP             |
+ * | EnumItem*                 | ENUM                  |
+ * | Decimal**                 | DECIMAL               |
+ * | BinaryObject*             | COMPLEX_OBJECT        |
+ * | Array of number           | DOUBLE_ARRAY          |
+ * | Array of boolean          | BOOLEAN_ARRAY         |
+ * | Array of string           | STRING_ARRAY          |
+ * | Array of Date             | DATE_ARRAY            |
+ * | Array of Timestamp*       | TIMESTAMP_ARRAY       |
+ * | Array of EnumItem*        | ENUM_ARRAY            |
+ * | Array of Decimal**        | DECIMAL_ARRAY         |
+ * | Array of BinaryObject*    | OBJECT_ARRAY          |
+ * | Array of any other Object | OBJECT_ARRAY          |
+ * | Set                       | COLLECTION (HASH_SET) |
+ * | Map                       | MAP (HASH_MAP)        |
+ * | any other Object          | COMPLEX_OBJECT        |
+ * </pre>
+ *
+ * Type of an array content is determined by the type of the first element of 
the array.
+ * Empty array has no default mapping.
+ *
+ * All other JavaScript types have no default mapping.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * DEFAULT MAPPING FROM Ignite type code TO JavaScript type.
+ *
+ * This mapping is used when an application does not explicitly specify an 
Ignite type
+ * for a field and is reading data from that field.
+ *
+ * <pre>
+ * | Ignite type code             | JavaScript type                       |
+ * | ---------------------------- | --------------------------------------|
+ * | BYTE                         | number                                |
+ * | SHORT                        | number                                |
+ * | INTEGER                      | number                                |
+ * | LONG                         | number                                |
+ * | FLOAT                        | number                                |
+ * | DOUBLE                       | number                                |
+ * | DECIMAL                      | Decimal**                             |
+ * | BOOLEAN                      | boolean                               |
+ * | STRING                       | string                                |
+ * | CHAR                         | string (one character)                |
+ * | UUID                         | Array of number (16 numbers)          |
+ * | DATE                         | Date                                  |
+ * | TIME                         | Date                                  |
+ * | TIMESTAMP                    | Timestamp*                            |
+ * | ENUM                         | EnumItem*                             |
+ * | COMPLEX_OBJECT               | BinaryObject*                         |
+ * | BYTE_ARRAY                   | Array of number                       |
+ * | SHORT_ARRAY                  | Array of number                       |
+ * | INTEGER_ARRAY                | Array of number                       |
+ * | LONG_ARRAY                   | Array of number                       |
+ * | FLOAT_ARRAY                  | Array of number                       |
+ * | DOUBLE_ARRAY                 | Array of number                       |
+ * | DECIMAL_ARRAY                | Array of Decimal**                    |
+ * | BOOLEAN_ARRAY                | Array of boolean                      |
+ * | STRING_ARRAY                 | Array of string                       |
+ * | CHAR_ARRAY                   | Array of string (one character)       |
+ * | UUID_ARRAY                   | Array of Array of number (16 numbers) |
+ * | DATE_ARRAY                   | Array of Date                         |
+ * | TIME_ARRAY                   | Array of Date                         |
+ * | TIMESTAMP_ARRAY              | Array of Timestamp*                   |
+ * | ENUM_ARRAY                   | Array of EnumItem*                    |
+ * | OBJECT_ARRAY                 | Array                                 |
+ * | COLLECTION (USER_COL)        | Array                                 |
+ * | COLLECTION (ARR_LIST)        | Array                                 |
+ * | COLLECTION (LINKED_LIST)     | Array                                 |
+ * | COLLECTION (SINGLETON_LIST)  | Array                                 |
+ * | COLLECTION (HASH_SET)        | Set                                   |
+ * | COLLECTION (LINKED_HASH_SET) | Set                                   |
+ * | COLLECTION (USER_SET)        | Set                                   |
+ * | MAP (HASH_MAP)               | Map                                   |
+ * | MAP (LINKED_HASH_MAP)        | Map                                   |
+ * | NULL                         | null                                  |
+ * </pre>
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * RETURNED JavaScript types WHEN READING DATA OF THE SPECIFIED Ignite type 
code.
+ *
+ * When an application explicitly specifies an Ignite type for a field
+ * and is reading data from that field - the following JavaScript types
+ * are returned for every concrete Ignite type code -
+ *
+ * SEE THE PREVIOUS TABLE with the following additional comments:
+ *
+ * - for COMPLEX_OBJECT the Ignite Client returns a JavaScript Object
+ * which is defined by the specified {@link ComplexObjectType}.
+ *
+ * - the returned Map for MAP is defined by the specified {@link 
MapObjectType}.
+ *
+ * - the returned Set or Array for COLLECTION is defined by the specified 
{@link CollectionObjectType}.
+ *
+ * - the returned Array for OBJECT_ARRAY is defined by the specified {@link 
ObjectArrayType}.
+ *
+ * - NULL cannot be specified as a type of a field but JavaScript null may be 
returned
+ * as a value of a field.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * ALLOWED JavaScript types WHEN WRITING DATA OF THE SPECIFIED Ignite type 
code.
+ *
+ * When an application explicitly specifies an Ignite type for a field
+ * and is writing data to that field - the following JavaScript types
+ * are allowed for every concrete Ignite type code -
+ *
+ * SEE THE PREVIOUS TABLE with the following additional comments:
+ *
+ * - for COMPLEX_OBJECT the Ignite Client allows a JavaScript Object
+ * which is defined by the specified {@link ComplexObjectType}.
+ *
+ * - the allowed Map for MAP is defined by the specified {@link MapObjectType}.
+ *
+ * - the allowed Set or Array for COLLECTION is defined by the specified 
{@link CollectionObjectType}.
+ *
+ * - the allowed Array for OBJECT_ARRAY is defined by the specified {@link 
ObjectArrayType}.
+ *
+ * - NULL cannot be specified as a type of a field but JavaScript null is 
allowed
+ * as value of a field (but not as a key/value in a cache) or as a value of 
Array/Set/Map element
+ * for all Ignite types, except BYTE, SHORT, INTEGER, LONG, FLOAT, DOUBLE, 
CHAR, BOOLEAN.
+ *
+ * - for all *_ARRAY Ignite types an empty JavaScript Array is allowed.
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * COMMENTS TO ALL TABLES
+ *
+ * JavaScript type - is a JavaScript primitive or a JavaScript Object
+ * ({@link 
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures})
+ *
+ * (*) Timestamp, EnumItem and BinaryObject - are JavaScript Objects 
introduced by the Ignite client.
+ *
+ * (**) Decimal - is an external JavaScript Object exported into the Ignite 
client
+ * ({@link https://github.com/MikeMcl/decimal.js})
+ *
+ * Ignite type code - is the type code of an Ignite primitive type ({@link 
ObjectType.PRIMITIVE_TYPE})
+ * or an Ignite composite type ({@link ObjectType.COMPOSITE_TYPE}).
+ *
+ * ----------------------------------------------------------------------------
+ *
+ * @hideconstructor
+ */
+
+class ObjectType {
+    static get PRIMITIVE_TYPE() {
+        return PRIMITIVE_TYPE;
+    }
+
+    static get COMPOSITE_TYPE() {
+        return COMPOSITE_TYPE;
+    }
+
+    /** Private methods */
+
+    constructor(typeCode) {
+        this._typeCode = typeCode;
+    }
+}
+
+/**
+ * Base class representing a non-primitive (composite) type of Ignite object.
+ *
+ * The class has no public constructor. Only subclasses may be instantiated.
+ *
+ * @hideconstructor
+ * @extends ObjectType
+ */
+class CompositeType extends ObjectType {
+}
+
+/**
+ * Supported kinds of map.
+ * @typedef MapObjectType.MAP_SUBTYPE
+ * @enum
+ * @readonly
+ * @property HASH_MAP 1
+ * @property LINKED_HASH_MAP 2
+ */
+const MAP_SUBTYPE = Object.freeze({
+    HASH_MAP : 1,
+    LINKED_HASH_MAP : 2
+});
+
+/**
+ * Class representing a map type of Ignite object.
+ *
+ * It is described by COMPOSITE_TYPE.MAP {@link ObjectType.COMPOSITE_TYPE}
+ * and one of {@link MapObjectType.MAP_SUBTYPE}.
+ *
+ * @extends CompositeType
+ */
+class MapObjectType extends CompositeType {
+    static get MAP_SUBTYPE() {
+        return MAP_SUBTYPE;
+    }
+
+    /**
+     * Public constructor.
+     *
+     * Optionally specifies a kind of map and types of keys and values in the 
map.
+     *
+     * If a kind of map is not specified, MAP_SUBTYPE.HASH_MAP is assumed.
+     *
+     * If key and/or value type is not specified then during operations the 
Ignite client
+     * will try to make automatic mapping between JavaScript types and Ignite 
object types -
+     * according to the mapping table defined in the description of the {@link 
ObjectType} class.
+     * 
+     * @param {MapObjectType.MAP_SUBTYPE} [mapSubType=MAP_SUBTYPE.HASH_MAP] - 
map subtype, one of the 
+     *   {@link MapObjectType.MAP_SUBTYPE} constants.
+     * @param {ObjectType.PRIMITIVE_TYPE | CompositeType} [keyType=null] - 
type of the keys in the map:
+     *   - either a type code of primitive (simple) type
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null (or not specified) that means the type is not specified
+     * @param {ObjectType.PRIMITIVE_TYPE | CompositeType} [valueType=null] - 
type of the values in the map:
+     *   - either a type code of primitive (simple) type
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null (or not specified) that means the type is not specified
+     *
+     * @return {MapObjectType} - new MapObjectType instance
+     *
+     * @throws {IgniteClientError} if error.
+     */
+    constructor(mapSubType = MapObjectType.MAP_SUBTYPE.HASH_MAP, keyType = 
null, valueType = null) {
+        super(COMPOSITE_TYPE.MAP);
+        const BinaryUtils = require('./internal/BinaryUtils');
+        ArgumentChecker.hasValueFrom(mapSubType, 'mapSubType', false, 
MapObjectType.MAP_SUBTYPE);
+        this._subType = mapSubType;
+        BinaryUtils.checkObjectType(keyType, 'keyType');
+        BinaryUtils.checkObjectType(valueType, 'valueType');
+        this._keyType = keyType;
+        this._valueType = valueType;
+    }
+}
+
+/**
+ * Supported kinds of collections.
+ * @typedef CollectionObjectType.COLLECTION_SUBTYPE
+ * @enum
+ * @readonly
+ * @property USER_SET -1
+ * @property USER_COL 0
+ * @property ARRAY_LIST 1
+ * @property LINKED_LIST 2
+ * @property HASH_SET 3
+ * @property LINKED_HASH_SET 4
+ * @property SINGLETON_LIST 5
+ */
+const COLLECTION_SUBTYPE = Object.freeze({
+    USER_SET : -1,
+    USER_COL : 0,
+    ARRAY_LIST : 1,
+    LINKED_LIST : 2,
+    HASH_SET : 3,
+    LINKED_HASH_SET : 4,
+    SINGLETON_LIST : 5
+});
+
+/**
+ * Class representing a collection type of Ignite object.
+ *
+ * It is described by COMPOSITE_TYPE.COLLECTION {@link 
ObjectType.COMPOSITE_TYPE}
+ * and one of {@link CollectionObjectType.COLLECTION_SUBTYPE}.
+ *
+ * @extends CompositeType
+ */
+class CollectionObjectType extends CompositeType {
+    static get COLLECTION_SUBTYPE() {
+        return COLLECTION_SUBTYPE;
+    }
+
+    /**
+     * Public constructor.
+     *
+     * Specifies a kind of collection
+     * and optionally specifies a type of elements in the collection.
+     *
+     * If the type of elements is not specified then during operations the 
Ignite client
+     * will try to make automatic mapping between JavaScript types and Ignite 
object types -
+     * according to the mapping table defined in the description of the {@link 
ObjectType} class.
+     * 
+     * @param {CollectionObjectType.COLLECTION_SUBTYPE} collectionSubType - 
collection subtype, one of the 
+     *  {@link CollectionObjectType.COLLECTION_SUBTYPE} constants.
+     * @param {ObjectType.PRIMITIVE_TYPE | CompositeType} [elementType=null] - 
type of elements in the collection:
+     *   - either a type code of primitive (simple) type
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null (or not specified) that means the type is not specified
+     *
+     * @return {CollectionObjectType} - new CollectionObjectType instance
+     *
+     * @throws {IgniteClientError} if error.
+     */
+    constructor(collectionSubType, elementType = null) {
+        super(COMPOSITE_TYPE.COLLECTION);
+        const BinaryUtils = require('./internal/BinaryUtils');
+        ArgumentChecker.hasValueFrom(
+            collectionSubType, 'collectionSubType', false, 
CollectionObjectType.COLLECTION_SUBTYPE);
+        this._subType = collectionSubType;
+        BinaryUtils.checkObjectType(elementType, 'elementType');
+        this._elementType = elementType;
+    }
+
+    /** Private methods */
+
+    /**
+     * @ignore
+     */
+    static _isSet(subType) {
+        return subType === CollectionObjectType.COLLECTION_SUBTYPE.USER_SET ||
+            subType === CollectionObjectType.COLLECTION_SUBTYPE.HASH_SET ||
+            subType === 
CollectionObjectType.COLLECTION_SUBTYPE.LINKED_HASH_SET;
+    }
+
+    /**
+     * @ignore
+     */
+    _isSet() {
+        return CollectionObjectType._isSet(this._subType);
+    }
+}
+
+/**
+ * Class representing an array type of Ignite objects.
+ *
+ * It is described by COMPOSITE_TYPE.OBJECT_ARRAY {@link 
ObjectType.COMPOSITE_TYPE}.
+ *
+ * @extends CompositeType
+ */
+class ObjectArrayType extends CompositeType {
+
+    /**
+     * Public constructor.
+     *
+     * Optionally specifies a type of elements in the array.
+     *
+     * If the type of elements is not specified then during operations the 
Ignite client
+     * will try to make automatic mapping between JavaScript types and Ignite 
object types -
+     * according to the mapping table defined in the description of the {@link 
ObjectType} class.
+     *
+     * @param {ObjectType.PRIMITIVE_TYPE | CompositeType} [elementType=null] - 
type of the array element:
+     *   - either a type code of primitive (simple) type
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null (or not specified) that means the type is not specified
+     *
+     * @return {ObjectArrayType} - new ObjectArrayType instance
+     *
+     * @throws {IgniteClientError} if error.
+     */
+    constructor(elementType = null) {
+        super(COMPOSITE_TYPE.OBJECT_ARRAY);
+        const BinaryUtils = require('./internal/BinaryUtils');
+        BinaryUtils.checkObjectType(elementType, 'elementType');
+        this._elementType = elementType;
+    }
+}
+
+/**
+ * Class representing a complex type of Ignite object.
+ *
+ * It is described by COMPOSITE_TYPE.COMPLEX_OBJECT {@link 
ObjectType.COMPOSITE_TYPE},
+ * by a name of the complex type and by a JavaScript Object which is mapped 
to/from the Ignite complex type.
+ *
+ * @extends CompositeType
+ */
+class ComplexObjectType extends CompositeType {
+
+    /**
+     * Public constructor.
+     *
+     * Specifies a JavaScript Object type which will be mapped to/from the 
complex type.
+     * This specification is done using an instance of the JavaScript Object.
+     *
+     * If an object of the complex type is going to be received (deserialized),
+     * the JavaScript Object must have a constructor without parameters or 
with optional parameters only.
+     *
+     * The JavaScript Object defines a set of fields of the complex type.
+     *
+     * By default, the fields have no types specified. It means during 
operations the Ignite client
+     * will try to make automatic mapping between JavaScript types and Ignite 
object types -
+     * according to the mapping table defined in the description of the {@link 
ObjectType} class.
+     *
+     * A type of any field may be specified later by setFieldType() method.
+     *
+     * By default, the name of the complex type is the name of the JavaScript 
Object.
+     * The name may be explicitely specified using optional typeName parameter 
in the constructor.
+     * 
+     * @param {object} jsObject - instance of JavaScript Object which will be 
mapped to/from this complex type.
+     * @param {string} [typeName] - name of the complex type.
+     *
+     * @return {ComplexObjectType} - new ComplexObjectType instance
+     *
+     * @throws {IgniteClientError} if error.
+     */
+    constructor(jsObject, typeName = null) {
+        super(COMPOSITE_TYPE.COMPLEX_OBJECT);
+        ArgumentChecker.notEmpty(jsObject, 'jsObject');
+        this._template = jsObject;
+        this._objectConstructor = jsObject && jsObject.constructor ?
+            jsObject.constructor : Object;
+        if (!typeName) {
+            typeName = this._objectConstructor.name;
+        }
+        this._typeName = typeName;
+        this._fields = new Map();
+        const BinaryUtils = require('./internal/BinaryUtils');
+        for (let fieldName of 
BinaryUtils.getJsObjectFieldNames(this._template)) {
+            this._fields.set(fieldName, null);
+        }
+    }
+
+    /**
+     * Specifies a type of the field in the complex type.
+     *
+     * If the type is not specified then during operations the Ignite client
+     * will try to make automatic mapping between JavaScript types and Ignite 
object types -
+     * according to the mapping table defined in the description of the {@link 
ObjectType} class.
+     * 
+     * @param {string} fieldName - name of the field.
+     * @param {ObjectType.PRIMITIVE_TYPE | CompositeType} fieldType - type of 
the field:
+     *   - either a type code of primitive (simple) type
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null (means the type is not specified).
+     *
+     * @return {ComplexObjectType} - the same instance of the 
ComplexObjectType.
+     *
+     * @throws {IgniteClientError} if error.
+     */
+    setFieldType(fieldName, fieldType) {
+        if (!this._fields.has(fieldName)) {
+            throw Errors.IgniteClientError.illegalArgumentError(
+                Util.format('Field "%s" is absent in the complex object type', 
fieldName));
+        }
+        const BinaryUtils = require('./internal/BinaryUtils');
+        BinaryUtils.checkObjectType(fieldType, 'fieldType');
+        this._fields.set(fieldName, fieldType);
+        return this;
+    }
+
+    /** Private methods */
+
+    /**
+     * @ignore
+     */
+    _getFieldType(fieldName) {
+        return this._fields.get(fieldName);
+    }
+}
+
+module.exports.ObjectType = ObjectType;
+module.exports.CompositeType = CompositeType;
+module.exports.MapObjectType = MapObjectType;
+module.exports.CollectionObjectType = CollectionObjectType;
+module.exports.ComplexObjectType = ComplexObjectType;
+module.exports.ObjectArrayType = ObjectArrayType;

http://git-wip-us.apache.org/repos/asf/ignite/blob/c56d16fb/modules/platforms/nodejs/lib/Query.js
----------------------------------------------------------------------
diff --git a/modules/platforms/nodejs/lib/Query.js 
b/modules/platforms/nodejs/lib/Query.js
new file mode 100644
index 0000000..5c230df
--- /dev/null
+++ b/modules/platforms/nodejs/lib/Query.js
@@ -0,0 +1,508 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+const Cursor = require('./Cursor').Cursor;
+const SqlFieldsCursor = require('./Cursor').SqlFieldsCursor;
+const ArgumentChecker = require('./internal/ArgumentChecker');
+const BinaryWriter = require('./internal/BinaryWriter');
+const BinaryUtils = require('./internal/BinaryUtils');
+
+const PAGE_SIZE_DEFAULT = 1024;
+
+/**
+ * Base class representing an Ignite SQL or Scan query.
+ *
+ * The class has no public constructor. Only subclasses may be instantiated.
+ *
+ * @hideconstructor
+ */
+class Query {
+
+    /**
+     * Set local query flag.
+     *
+     * @param {boolean} local - local query flag: true or false.
+     *
+     * @return {Query} - the same instance of the Query.
+     */
+    setLocal(local) {
+        this._local = local;
+        return this;
+    }
+
+    /**
+     * Set {@link Cursor} page size.
+     *
+     * @param {number} pageSize - cursor page size.
+     *
+     * @return {Query} - the same instance of the Query.
+     */
+    setPageSize(pageSize) {
+        this._pageSize = pageSize;
+        return this;
+    }
+
+    /** Private methods */
+
+    /**
+     * @ignore
+     */
+    constructor(operation) {
+        this._operation = operation;
+        this._local = false;
+        this._pageSize = PAGE_SIZE_DEFAULT;
+    }
+}
+
+/**
+ * Class representing an SQL query which returns the whole cache entries 
(key-value pairs).
+ * @extends Query
+ */
+class SqlQuery extends Query {
+
+    /**
+     * Public constructor.
+     *
+     * Requires name of a type (or SQL table) and SQL query string to be 
specified.
+     * Other SQL query settings have the following defaults:
+     * <pre>
+     *     SQL Query setting         :    Default value
+     *     Local query flag          :    false
+     *     Cursor page size          :    1024
+     *     Query arguments           :    not specified
+     *     Distributed joins flag    :    false
+     *     Replicated only flag      :    false
+     *     Timeout                   :    0 (disabled)
+     * </pre>
+     * Every setting may be changed using set methods.
+     *
+     * @param {string} type - name of a type or SQL table.
+     * @param {string} sql - SQL query string.
+     *
+     * @return {SqlQuery} - new SqlQuery instance.
+     */
+    constructor(type, sql) {
+        super(BinaryUtils.OPERATION.QUERY_SQL);
+        this.setType(type);
+        this.setSql(sql);
+        this._args = null;
+        this._argTypes = null;
+        this._distributedJoins = false;
+        this._replicatedOnly = false;
+        this._timeout = 0;
+    }
+
+    /**
+     * Set name of a type or SQL table.
+     *
+     * @param {string} type - name of a type or SQL table.
+     *
+     * @return {SqlQuery} - the same instance of the SqlQuery.
+     */
+    setType(type) {
+        if (this instanceof SqlFieldsQuery) {
+            ArgumentChecker.invalidArgument(type, 'type', SqlFieldsQuery);
+        }
+        else {
+            ArgumentChecker.notNull(type, 'type');
+        }
+        this._type = type;
+        return this;
+    }
+
+    /**
+     * Set SQL query string.
+     *
+     * @param {string} sql - SQL query string.
+     *
+     * @return {SqlQuery} - the same instance of the SqlQuery.
+     */
+    setSql(sql) {
+        ArgumentChecker.notNull(sql, 'sql');
+        this._sql = sql;
+        return this;
+    }
+
+    /**
+     * Set query arguments.
+     *
+     * Type of any argument may be specified using setArgTypes() method.
+     * If type of an argument is not specified then during operations the 
Ignite client
+     * will try to make automatic mapping between JavaScript types and Ignite 
object types -
+     * according to the mapping table defined in the description of the {@link 
ObjectType} class.
+     *
+     * @param {...*} args - Query arguments.
+     *
+     * @return {SqlQuery} - the same instance of the SqlQuery.
+     */
+    setArgs(...args) {
+        this._args = args;
+        return this;
+    }
+
+    /**
+     * Specifies types of query arguments.
+     *
+     * Query arguments itself are set using setArgs() method.
+     * By default, a type of every argument is not specified that means during 
operations the Ignite client
+     * will try to make automatic mapping between JavaScript types and Ignite 
object types -
+     * according to the mapping table defined in the description of the {@link 
ObjectType} class.
+     *
+     * @param {...ObjectType.PRIMITIVE_TYPE | CompositeType} argTypes - types 
of Query arguments.
+     *   The order of types must follow the order of arguments in the 
setArgs() method.
+     *   A type of every argument can be:
+     *   - either a type code of primitive (simple) type
+     *   - or an instance of class representing non-primitive (composite) type
+     *   - or null (means the type is not specified)
+     *
+     * @return {SqlQuery} - the same instance of the SqlQuery.
+     */
+    setArgTypes(...argTypes) {
+        this._argTypes = argTypes;
+        return this;
+    }
+
+    /**
+     * Set distributed joins flag.
+     *
+     * @param {boolean} distributedJoins - distributed joins flag: true or 
false.
+     *
+     * @return {SqlQuery} - the same instance of the SqlQuery.
+     */
+    setDistributedJoins(distributedJoins) {
+        this._distributedJoins = distributedJoins;
+        return this;
+    }
+
+    /**
+     * Set replicated only flag.
+     *
+     * @param {boolean} replicatedOnly - replicated only flag: true or false.
+     *
+     * @return {SqlQuery} - the same instance of the SqlQuery.
+     */
+    setReplicatedOnly(replicatedOnly) {
+        this._replicatedOnly = replicatedOnly;
+        return this;
+    }
+
+    /**
+     * Set timeout.
+     *
+     * @param {number} timeout - timeout value in milliseconds.
+     *   Must be non-negative. Zero value disables timeout.
+     *
+     * @return {SqlQuery} - the same instance of the SqlQuery.
+     */
+    setTimeout(timeout) {
+        this._timeout = timeout;
+        return this;
+    }
+
+    /** Private methods */
+
+    /**
+     * @ignore
+     */
+    async _write(buffer) {
+        await BinaryWriter.writeString(buffer, this._type);
+        await BinaryWriter.writeString(buffer, this._sql);
+        await this._writeArgs(buffer);
+        buffer.writeBoolean(this._distributedJoins);
+        buffer.writeBoolean(this._local);
+        buffer.writeBoolean(this._replicatedOnly);
+        buffer.writeInteger(this._pageSize);
+        buffer.writeLong(this._timeout);
+    }
+
+    /**
+     * @ignore
+     */
+    async _writeArgs(buffer) {
+        const argsLength = this._args ? this._args.length : 0;
+        buffer.writeInteger(argsLength);
+        if (argsLength > 0) {
+            let argType;
+            for (let i = 0; i < argsLength; i++) {
+                argType = this._argTypes && i < this._argTypes.length ? 
this._argTypes[i] : null;
+                await BinaryWriter.writeObject(buffer, this._args[i], argType);
+            }
+        }
+    }
+
+    /**
+     * @ignore
+     */
+    async _getCursor(socket, payload, keyType = null, valueType = null) {
+        const cursor = new Cursor(socket, 
BinaryUtils.OPERATION.QUERY_SQL_CURSOR_GET_PAGE, payload, keyType, valueType);
+        cursor._readId(payload);
+        return cursor;
+    }
+}
+
+/**
+ * Statement type of SQL Fields query.
+ * @typedef SqlFieldsQuery.STATEMENT_TYPE
+ * @enum
+ * @readonly
+ * @property ANY 0
+ * @property SELECT 1
+ * @property UPDATE 2
+ */
+const STATEMENT_TYPE = Object.freeze({
+    ANY : 0,
+    SELECT : 1,
+    UPDATE : 2
+});
+
+
+/**
+ * Class representing an SQL Fields query.
+ * @extends SqlQuery
+ */
+class SqlFieldsQuery extends SqlQuery {
+
+    /**
+     * Public constructor.
+     *
+     * Requires SQL query string to be specified.
+     * Other SQL Fields query settings have the following defaults:
+     * <pre>
+     *     SQL Fields Query setting  :    Default value
+     *     Local query flag          :    false
+     *     Cursor page size          :    1024
+     *     Query arguments           :    not specified
+     *     Distributed joins flag    :    false
+     *     Replicated only flag      :    false
+     *     Timeout                   :    0 (disabled)
+     *     Schema for the query      :    not specified
+     *     Max rows                  :    -1
+     *     Statement type            :    STATEMENT_TYPE.ANY
+     *     Enforce join order flag   :    false
+     *     Collocated flag           :    false
+     *     Lazy query execution flag :    false
+     *     Include field names flag  :    false
+     * </pre>
+     * Every setting may be changed using set methods.
+     *
+     * @param {string} sql - SQL query string.
+     *
+     * @return {SqlFieldsQuery} - new SqlFieldsQuery instance.
+     */
+    constructor(sql) {
+        super(null, sql);
+        this._operation = BinaryUtils.OPERATION.QUERY_SQL_FIELDS;
+        this._schema = null;
+        this._maxRows = -1;
+        this._statementType = SqlFieldsQuery.STATEMENT_TYPE.ANY;
+        this._enforceJoinOrder = false;
+        this._collocated = false;
+        this._lazy = false;
+        this._includeFieldNames = false;
+    }
+
+    static get STATEMENT_TYPE() {
+        return STATEMENT_TYPE;
+    }
+
+    /**
+     * Set schema for the query.
+     *
+     * @param {string} schema - schema for the query.
+     *
+     * @return {SqlFieldsQuery} - the same instance of the SqlFieldsQuery.
+     */
+    setSchema(schema) {
+        this._schema = schema;
+        return this;
+    }
+
+    /**
+     * Set max rows.
+     *
+     * @param {number} maxRows - max rows.
+     *
+     * @return {SqlFieldsQuery} - the same instance of the SqlFieldsQuery.
+     */
+    setMaxRows(maxRows) {
+        this._maxRows = maxRows;
+        return this;
+    }
+
+    /**
+     * Set statement type.
+     *
+     * @param {SqlFieldsQuery.STATEMENT_TYPE} type - statement type.
+     *
+     * @return {SqlFieldsQuery} - the same instance of the SqlFieldsQuery.
+     */
+    setStatementType(type) {
+        this._statementType = type;
+        return this;
+    }
+
+    /**
+     * Set enforce join order flag.
+     *
+     * @param {boolean} enforceJoinOrder - enforce join order flag: true or 
false.
+     *
+     * @return {SqlFieldsQuery} - the same instance of the SqlFieldsQuery.
+     */
+    setEnforceJoinOrder(enforceJoinOrder) {
+        this._enforceJoinOrder = enforceJoinOrder;
+        return this;
+    }
+
+    /**
+     * Set collocated flag.
+     *
+     * @param {boolean} collocated - collocated flag: true or false.
+     *
+     * @return {SqlFieldsQuery} - the same instance of the SqlFieldsQuery.
+     */
+    setCollocated(collocated) {
+        this._collocated = collocated;
+        return this;
+    }
+
+    /**
+     * Set lazy query execution flag.
+     *
+     * @param {boolean} lazy - lazy query execution flag: true or false.
+     *
+     * @return {SqlFieldsQuery} - the same instance of the SqlFieldsQuery.
+     */
+    setLazy(lazy) {
+        this._lazy = lazy;
+        return this;
+    }
+
+    /**
+     * Set include field names flag.
+     *
+     * @param {boolean} includeFieldNames - include field names flag: true or 
false.
+     *
+     * @return {SqlFieldsQuery} - the same instance of the SqlFieldsQuery.
+     */
+    setIncludeFieldNames(includeFieldNames) {
+        this._includeFieldNames = includeFieldNames;
+        return this;
+    }
+
+    /** Private methods */
+
+    /**
+     * @ignore
+     */
+    async _write(buffer) {
+        await BinaryWriter.writeString(buffer, this._schema);
+        buffer.writeInteger(this._pageSize);
+        buffer.writeInteger(this._maxRows);
+        await BinaryWriter.writeString(buffer, this._sql);
+        await this._writeArgs(buffer)
+        buffer.writeByte(this._statementType);
+        buffer.writeBoolean(this._distributedJoins);
+        buffer.writeBoolean(this._local);
+        buffer.writeBoolean(this._replicatedOnly);
+        buffer.writeBoolean(this._enforceJoinOrder);
+        buffer.writeBoolean(this._collocated);
+        buffer.writeBoolean(this._lazy);
+        buffer.writeLong(this._timeout);
+        buffer.writeBoolean(this._includeFieldNames);
+    }
+
+    /**
+     * @ignore
+     */
+    async _getCursor(socket, payload, keyType = null, valueType = null) {
+        const cursor = new SqlFieldsCursor(socket, payload);
+        await cursor._readFieldNames(payload, this._includeFieldNames);
+        return cursor;
+    }
+}
+
+/**
+ * Class representing a Scan query which returns the whole cache entries 
(key-value pairs).
+ *
+ * This version of the class does not support a possibility to specify a 
Filter object for the query.
+ * The query returns all entries from the entire cache or from the specified 
partition.
+ * @extends Query
+ */
+class ScanQuery extends Query {
+
+    /**
+     * Public constructor.
+     *
+     * Scan query settings have the following defaults:
+     * <pre>
+     *     Scan Query setting        :    Default value
+     *     Local query flag          :    false
+     *     Cursor page size          :    1024
+     *     Partition number          :    -1 (entire cache)
+     *     Filter object             :    null (not supported)
+     * </pre>
+     * Every setting (except Filter object) may be changed using set methods.
+     *
+     * @return {ScanQuery} - new ScanQuery instance.
+     */
+    constructor() {
+        super(BinaryUtils.OPERATION.QUERY_SCAN);
+        this._partitionNumber = -1;
+    }
+
+    /**
+     * Sets a partition number over which this query should iterate.
+     *
+     * If negative, the query will iterate over all partitions in the cache. 
+     *
+     * @param {number} partitionNumber - partition number over which this 
query should iterate.
+     *
+     * @return {ScanQuery} - the same instance of the ScanQuery.
+     */
+    setPartitionNumber(partitionNumber) {
+        this._partitionNumber = partitionNumber;
+        return this;
+    }
+
+    /** Private methods */
+
+    /**
+     * @ignore
+     */
+    async _write(buffer) {
+        // filter
+        await BinaryWriter.writeObject(buffer, null);
+        buffer.writeInteger(this._pageSize);
+        buffer.writeInteger(this._partitionNumber);
+        buffer.writeBoolean(this._local);
+    }
+
+    /**
+     * @ignore
+     */
+    async _getCursor(socket, payload, keyType = null, valueType = null) {
+        const cursor = new Cursor(socket, 
BinaryUtils.OPERATION.QUERY_SCAN_CURSOR_GET_PAGE, payload, keyType, valueType);
+        cursor._readId(payload);
+        return cursor;
+    }
+}
+
+module.exports.SqlQuery = SqlQuery;
+module.exports.SqlFieldsQuery = SqlFieldsQuery;
+module.exports.ScanQuery = ScanQuery;

http://git-wip-us.apache.org/repos/asf/ignite/blob/c56d16fb/modules/platforms/nodejs/lib/Timestamp.js
----------------------------------------------------------------------
diff --git a/modules/platforms/nodejs/lib/Timestamp.js 
b/modules/platforms/nodejs/lib/Timestamp.js
new file mode 100644
index 0000000..04d750c
--- /dev/null
+++ b/modules/platforms/nodejs/lib/Timestamp.js
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+const ArgumentChecker = require('./internal/ArgumentChecker');
+
+/**
+ * Class representing an Ignite timestamp type.
+ *
+ * The timestamp extends the standard JavaScript {@link Date} Object and 
consists of:
+ *   - time  - the number of milliseconds since January 1, 1970, 00:00:00 UTC,
+ *     methods of the JavaScript {@link Date} Object can be used to operate 
with the time.
+ *   - nanoseconds - fraction of the last millisecond in the range from 0 to 
999999 nanoseconds,
+ *     this class specifies additional methods to operate with the nanoseconds.
+ * @extends Date
+ */
+class Timestamp extends Date {
+
+    /**
+     * Public constructor.
+     *
+     * @param {number} time - integer value representing the number of 
milliseconds since January 1, 1970, 00:00:00 UTC.
+     * @param {number} nanos - integer value representing the nanoseconds of 
the last millisecond,
+     *                         should be in the range from 0 to 999999.
+     *
+     * @return {Timestamp} - new Timestamp instance
+     *
+     * @throws {IgniteClientError} if error.
+     */
+    constructor(time, nanos) {
+        super(time);
+        this.setNanos(nanos);
+    }
+
+    /**
+     * Returns the nanoseconds of the last millisecond from the timestamp.
+     *
+     * @return {number} - nanoseconds of the last millisecond.
+     */
+    getNanos() {
+        return this._nanos;
+    }
+
+    /**
+     * Updates the nanoseconds of the last millisecond in the timestamp.
+     *
+     * @param {number} nanos - new value for the nanoseconds of the last 
millisecond,
+     *                         should be in the range from 0 to 999999.
+     *
+     * @return {Timestamp} - the same instance of Timestamp
+     *
+     * @throws {IgniteClientError} if error.
+     */
+    setNanos(nanos) {
+        ArgumentChecker.isInteger(nanos, 'nanos');
+        this._nanos = nanos;
+        return this;
+    }
+}
+
+module.exports = Timestamp;

http://git-wip-us.apache.org/repos/asf/ignite/blob/c56d16fb/modules/platforms/nodejs/lib/internal/ArgumentChecker.js
----------------------------------------------------------------------
diff --git a/modules/platforms/nodejs/lib/internal/ArgumentChecker.js 
b/modules/platforms/nodejs/lib/internal/ArgumentChecker.js
new file mode 100644
index 0000000..9e60ad6
--- /dev/null
+++ b/modules/platforms/nodejs/lib/internal/ArgumentChecker.js
@@ -0,0 +1,83 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+const Util = require('util');
+const Errors = require('../Errors');
+
+/** Helper class for the library methods arguments check. */
+class ArgumentChecker {
+    static notEmpty(arg, argName) {
+        if (!arg || arg instanceof Array && arg.length === 0) {
+            throw 
Errors.IgniteClientError.illegalArgumentError(Util.format('"%s" argument should 
not be empty', argName));
+        }
+    }
+
+    static notNull(arg, argName) {
+        if (arg === null || arg === undefined) {
+            throw 
Errors.IgniteClientError.illegalArgumentError(Util.format('"%s" argument should 
not be null', argName));
+        }
+    }
+
+    static hasType(arg, argName, isArray, ...types) {
+        if (arg === null) {
+            return;
+        }
+        if (isArray && arg instanceof Array) {
+            for (let a of arg) {
+                ArgumentChecker.hasType(a, argName, false, ...types);
+            }
+        }
+        else {
+            for (let type of types) {
+                if (arg instanceof type) {
+                    return;
+                }
+            }
+            throw 
Errors.IgniteClientError.illegalArgumentError(Util.format('"%s" argument has 
incorrect type', argName));
+        }
+    }
+
+    static hasValueFrom(arg, argName, isArray, values) {
+        if (isArray && arg instanceof Array) {
+            for (let a of arg) {
+                ArgumentChecker.hasValueFrom(a, argName, false, values);
+            }
+        }
+        else {
+            if (!Object.values(values).includes(arg)) {
+                throw 
Errors.IgniteClientError.illegalArgumentError(Util.format('"%s" argument has 
incorrect value', argName));
+            }
+        }
+    }
+
+    static isInteger(arg, argName) {
+        if (arg === null || arg === undefined || !Number.isInteger(arg)) {
+            throw 
Errors.IgniteClientError.illegalArgumentError(Util.format('"%s" argument should 
be integer', argName));
+        }
+    }
+
+    static invalidArgument(arg, argName, type) {
+        if (arg !== null && arg !== undefined) {
+            throw Errors.IgniteClientError.illegalArgumentError(
+                Util.format('"%s" argument is invalid for %s', argName, 
type.constructor.name));
+        }
+    }
+}
+
+module.exports = ArgumentChecker;

http://git-wip-us.apache.org/repos/asf/ignite/blob/c56d16fb/modules/platforms/nodejs/lib/internal/BinaryReader.js
----------------------------------------------------------------------
diff --git a/modules/platforms/nodejs/lib/internal/BinaryReader.js 
b/modules/platforms/nodejs/lib/internal/BinaryReader.js
new file mode 100644
index 0000000..8c25c39
--- /dev/null
+++ b/modules/platforms/nodejs/lib/internal/BinaryReader.js
@@ -0,0 +1,197 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+const Decimal = require('decimal.js');
+const BinaryObject = require('../BinaryObject');
+const CollectionObjectType = require('../ObjectType').CollectionObjectType;
+const Errors = require('../Errors');
+const Timestamp = require('../Timestamp');
+const EnumItem = require('../EnumItem');
+const BinaryUtils = require('./BinaryUtils');
+
+class BinaryReader {
+
+    static async readObject(buffer, expectedType = null) {
+        const typeCode = buffer.readByte();
+        BinaryUtils.checkTypesComatibility(expectedType, typeCode);
+        return await BinaryReader._readTypedObject(buffer, typeCode, 
expectedType);
+    }
+
+    static async readStringArray(buffer) {
+        return await BinaryReader._readTypedObject(buffer, 
BinaryUtils.TYPE_CODE.STRING_ARRAY);
+    }
+
+    static async _readTypedObject(buffer, objectTypeCode, expectedType = null) 
{
+        switch (objectTypeCode) {
+            case BinaryUtils.TYPE_CODE.BYTE:
+            case BinaryUtils.TYPE_CODE.SHORT:
+            case BinaryUtils.TYPE_CODE.INTEGER:
+            case BinaryUtils.TYPE_CODE.FLOAT:
+            case BinaryUtils.TYPE_CODE.DOUBLE:
+                return buffer.readNumber(objectTypeCode);
+            case BinaryUtils.TYPE_CODE.LONG:
+                return buffer.readLong().toNumber();
+            case BinaryUtils.TYPE_CODE.CHAR:
+                return buffer.readChar();
+            case BinaryUtils.TYPE_CODE.BOOLEAN:
+                return buffer.readBoolean();
+            case BinaryUtils.TYPE_CODE.STRING:
+                return buffer.readString();
+            case BinaryUtils.TYPE_CODE.UUID:
+                return BinaryReader._readUUID(buffer);
+            case BinaryUtils.TYPE_CODE.DATE:
+                return buffer.readDate();
+            case BinaryUtils.TYPE_CODE.ENUM:
+            case BinaryUtils.TYPE_CODE.BINARY_ENUM:
+                return await BinaryReader._readEnum(buffer);
+            case BinaryUtils.TYPE_CODE.DECIMAL:
+                return BinaryReader._readDecimal(buffer);
+            case BinaryUtils.TYPE_CODE.TIMESTAMP:
+                return BinaryReader._readTimestamp(buffer);
+            case BinaryUtils.TYPE_CODE.TIME:
+                return buffer.readDate();
+            case BinaryUtils.TYPE_CODE.BYTE_ARRAY:
+            case BinaryUtils.TYPE_CODE.SHORT_ARRAY:
+            case BinaryUtils.TYPE_CODE.INTEGER_ARRAY:
+            case BinaryUtils.TYPE_CODE.LONG_ARRAY:
+            case BinaryUtils.TYPE_CODE.FLOAT_ARRAY:
+            case BinaryUtils.TYPE_CODE.DOUBLE_ARRAY:
+            case BinaryUtils.TYPE_CODE.CHAR_ARRAY:
+            case BinaryUtils.TYPE_CODE.BOOLEAN_ARRAY:
+            case BinaryUtils.TYPE_CODE.STRING_ARRAY:
+            case BinaryUtils.TYPE_CODE.UUID_ARRAY:
+            case BinaryUtils.TYPE_CODE.DATE_ARRAY:
+            case BinaryUtils.TYPE_CODE.OBJECT_ARRAY:
+            case BinaryUtils.TYPE_CODE.ENUM_ARRAY:
+            case BinaryUtils.TYPE_CODE.DECIMAL_ARRAY:
+            case BinaryUtils.TYPE_CODE.TIMESTAMP_ARRAY:
+            case BinaryUtils.TYPE_CODE.TIME_ARRAY:
+                return await BinaryReader._readArray(buffer, objectTypeCode, 
expectedType);
+            case BinaryUtils.TYPE_CODE.COLLECTION:
+                return await BinaryReader._readCollection(buffer, 
expectedType);
+            case BinaryUtils.TYPE_CODE.MAP:
+                return await BinaryReader._readMap(buffer, expectedType);
+            case BinaryUtils.TYPE_CODE.BINARY_OBJECT:
+                return await BinaryReader._readBinaryObject(buffer, 
expectedType);
+            case BinaryUtils.TYPE_CODE.NULL:
+                return null;
+            case BinaryUtils.TYPE_CODE.COMPLEX_OBJECT:
+                return await BinaryReader._readComplexObject(buffer, 
expectedType);
+            default:
+                throw 
Errors.IgniteClientError.unsupportedTypeError(objectTypeCode);
+        }
+    }
+
+    static _readUUID(buffer) {
+        return 
[...buffer.readBuffer(BinaryUtils.getSize(BinaryUtils.TYPE_CODE.UUID))];
+    }
+
+    static async _readEnum(buffer) {
+        const enumItem = new EnumItem(0);
+        await enumItem._read(buffer);
+        return enumItem;
+    }
+
+    static _readDecimal(buffer) {
+        const scale = buffer.readInteger();
+        const dataLength = buffer.readInteger();
+        const data = buffer.readBuffer(dataLength);
+        const isNegative = (data[0] & 0x80) !== 0;
+        if (isNegative) {
+            data[0] &= 0x7F;
+        }
+        let result = new Decimal('0x' + data.toString('hex'));
+        if (isNegative) {
+            result = result.negated();
+        }
+        return result.mul(Decimal.pow(10, -scale));
+    }
+
+    static _readTimestamp(buffer) {
+        return new Timestamp(buffer.readLong().toNumber(), 
buffer.readInteger());
+    }
+
+    static async _readArray(buffer, arrayTypeCode, arrayType) {
+        if (arrayTypeCode === BinaryUtils.TYPE_CODE.OBJECT_ARRAY) {
+            buffer.readInteger();
+        }
+        const length = buffer.readInteger();
+        const elementType = BinaryUtils.getArrayElementType(arrayType ? 
arrayType : arrayTypeCode);
+        const keepElementType = elementType === null ? true : 
BinaryUtils.keepArrayElementType(arrayTypeCode);
+        const result = new Array(length);
+        for (let i = 0; i < length; i++) {
+            result[i] = keepElementType ?
+                await BinaryReader.readObject(buffer, elementType) :
+                await BinaryReader._readTypedObject(buffer, elementType);
+        }
+        return result;
+    }
+
+    static async _readMap(buffer, expectedMapType) {
+        const result = new Map();
+        const size = buffer.readInteger();
+        const subType = buffer.readByte();
+        let key, value;
+        for (let i = 0; i < size; i++) {
+            key = await BinaryReader.readObject(buffer, expectedMapType ? 
expectedMapType._keyType : null);
+            value = await BinaryReader.readObject(buffer, expectedMapType ? 
expectedMapType._valueType : null);
+            result.set(key, value);
+        }
+        return result;
+    }
+
+    static async _readCollection(buffer, expectedColType) {
+        const size = buffer.readInteger();
+        const subType = buffer.readByte();
+        const isSet = CollectionObjectType._isSet(subType);
+        const result = isSet ? new Set() : new Array(size);
+        let element;
+        for (let i = 0; i < size; i++) {
+            element = await BinaryReader.readObject(buffer, expectedColType ? 
expectedColType._elementType : null);
+            if (isSet) {
+                result.add(element);
+            }
+            else {
+                result[i] = element;
+            }
+        }
+        return result;
+    }
+
+    static async _readBinaryObject(buffer, expectedType) {
+        const size = buffer.readInteger();
+        const startPos = buffer.position;
+        buffer.position = startPos + size;
+        const offset = buffer.readInteger();
+        const endPos = buffer.position;
+        buffer.position = startPos + offset;
+        const result = await BinaryReader.readObject(buffer, expectedType);
+        buffer.position = endPos;
+        return result;
+    }
+
+    static async _readComplexObject(buffer, expectedType) {
+        buffer.position = buffer.position - 1;
+        const binaryObject = await BinaryObject._fromBuffer(buffer);
+        return expectedType ?
+            await binaryObject.toObject(expectedType) : binaryObject;
+    }
+}
+
+module.exports = BinaryReader;

http://git-wip-us.apache.org/repos/asf/ignite/blob/c56d16fb/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
new file mode 100644
index 0000000..b9e239d
--- /dev/null
+++ b/modules/platforms/nodejs/lib/internal/BinaryType.js
@@ -0,0 +1,472 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+const Util = require('util');
+const ComplexObjectType = require('../ObjectType').ComplexObjectType;
+const BinaryTypeStorage = require('./BinaryTypeStorage');
+const BinaryUtils = require('./BinaryUtils');
+const BinaryWriter = require('./BinaryWriter');
+const Errors = require('../Errors');
+
+class BinaryType {
+    constructor(name) {
+        this._name = name;
+        this._id = BinaryType._calculateId(name);
+        this._fields = new Map();
+        this._schemas = new Map();
+        this._isEnum = false;
+        this._enumValues = null;
+    }
+
+    get id() {
+        return this._id;
+    }
+
+    get name() {
+        return this._name;
+    }
+
+    get fields() {
+        return [...this._fields.values()];
+    }
+
+    getField(fieldId) {
+        return this._fields.get(fieldId);
+    }
+
+    hasField(fieldId) {
+        return this._fields.has(fieldId);
+    }
+
+    removeField(fieldId) {
+        return this._fields.delete(fieldId);
+    }
+
+    setField(field) {
+        this._fields.set(field.id, field);
+    }
+
+    hasSchema(schemaId) {
+        return this._schemas.has(schemaId);
+    }
+
+    addSchema(schema) {
+        if (!this.hasSchema(schema.id)) {
+            this._schemas.set(schema.id, schema);
+        }
+    }
+
+    getSchema(schemaId) {
+        return this._schemas.get(schemaId);
+    }
+
+    merge(binaryType, binarySchema) {
+        let fieldId;
+        for (let field of binaryType.fields) {
+            fieldId = field.id;
+            if (this.hasField(fieldId)) {
+                if (this.getField(fieldId).typeCode !== field.typeCode) {
+                    throw Errors.IgniteClientError.serializationError(
+                        true, Util.format('type conflict for field "%s" of 
complex object type "%s"'),
+                        field.name, this._name);
+                }
+            }
+            else {
+                this.setField(field);
+            }
+        }
+        this.addSchema(binarySchema);
+    }
+
+    clone() {
+        const result = new BinaryType();
+        result._name = this._name;
+        result._id = this._id;
+        result._fields = new Map(this._fields.entries());
+        result._schemas = new Map(this._schemas.entries());
+        result._isEnum = this._isEnum;
+        return result;
+    }
+
+    static _calculateId(name) {
+        return BinaryUtils.hashCodeLowerCase(name);
+    }
+
+    async _write(buffer) {
+        // type id
+        buffer.writeInteger(this._id);
+        // type name
+        await BinaryWriter.writeString(buffer, this._name);
+        // affinity key field name
+        await BinaryWriter.writeString(buffer, null);
+        // fields count
+        buffer.writeInteger(this._fields.size);
+        // fields
+        for (let field of this._fields.values()) {
+            await field._write(buffer);
+        }
+        await this._writeEnum(buffer);
+        // schemas count
+        buffer.writeInteger(this._schemas.size);
+        for (let schema of this._schemas.values()) {
+            await schema._write(buffer);
+        }
+    }
+
+    async _writeEnum(buffer) {
+        buffer.writeBoolean(this._isEnum);
+        if (this._isEnum) {
+            const length = this._enumValues ? this._enumValues.length : 0;
+            buffer.writeInteger(length);
+            if (length > 0) {
+                for (let [key, value] of this._enumValues) {
+                    await BinaryWriter.writeString(buffer, key);
+                    buffer.writeInteger(value);
+                }
+            }
+        }
+    }
+
+    async _read(buffer) {
+        // type id
+        this._id = buffer.readInteger();
+        // type name
+        const BinaryReader = require('./BinaryReader');
+        this._name = await BinaryReader.readObject(buffer);
+        // affinity key field name
+        await BinaryReader.readObject(buffer);
+        // fields count
+        const fieldsCount = buffer.readInteger();
+        // fields
+        let field;
+        for (let i = 0; i < fieldsCount; i++) {
+            field = new BinaryField(null, null);
+            await field._read(buffer);
+            this.setField(field);
+        }
+        await this._readEnum(buffer);
+        // schemas count
+        const schemasCount = buffer.readInteger();
+        // schemas
+        let schema;
+        for (let i = 0; i < schemasCount; i++) {
+            schema = new BinarySchema();
+            await schema._read(buffer);
+            this.addSchema(schema);
+        }
+    }
+
+    async _readEnum(buffer) {
+        const BinaryReader = require('./BinaryReader');
+        this._isEnum = buffer.readBoolean();
+        if (this._isEnum) {
+            const valuesCount = buffer.readInteger();
+            this._enumValues = new Array(valuesCount);
+            for (let i = 0; i < valuesCount; i++) {
+                this._enumValues[i] = [await BinaryReader.readObject(buffer), 
buffer.readInteger()];
+            }
+        }
+    }
+}
+
+/** FNV1 hash offset basis. */
+const FNV1_OFFSET_BASIS = 0x811C9DC5;
+/** FNV1 hash prime. */
+const FNV1_PRIME = 0x01000193;
+
+class BinarySchema {
+    constructor() {
+        this._id = BinarySchema._schemaInitialId();
+        this._fieldIds = new Set();
+        this._isValid = true;
+    }
+
+    get id() {
+        return this._id;
+    }
+
+    get fieldIds() {
+        return [...this._fieldIds];
+    }
+
+    finalize() {
+        if (!this._isValid) {
+            this._id = BinarySchema._schemaInitialId();
+            for (let fieldId of this._fieldIds) {
+                this._id = BinarySchema._updateSchemaId(this._id, fieldId);
+            }
+            this._isValid = true;
+        }
+    }
+
+    clone() {
+        const result = new BinarySchema();
+        result._id = this._id;
+        result._fieldIds = new Set(this._fieldIds);
+        result._isValid = this._isValid;
+        return result;
+    }
+
+    addField(fieldId) {
+        if (!this.hasField(fieldId)) {
+            this._fieldIds.add(fieldId);
+            if (this._isValid) {
+                this._id = BinarySchema._updateSchemaId(this._id, fieldId);
+            }
+        }
+    }
+
+    removeField(fieldId) {
+        if (this._fieldIds.delete(fieldId)) {
+            this._isValid = false;
+        }
+    }
+
+    hasField(fieldId) {
+        return this._fieldIds.has(fieldId);
+    }
+
+    static _schemaInitialId() {
+        return FNV1_OFFSET_BASIS | 0;
+    }
+
+    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;
+
+        return schemaId;
+    }
+
+    async _write(buffer) {
+        this.finalize();
+        // schema id
+        buffer.writeInteger(this._id);
+        // fields count
+        buffer.writeInteger(this._fieldIds.size);
+        // field ids
+        for (let fieldId of this._fieldIds) {
+            buffer.writeInteger(fieldId);
+        }
+    }
+
+    async _read(buffer) {
+        // schema id
+        this._id = buffer.readInteger();
+        // fields count
+        const fieldsCount = buffer.readInteger();
+        // field ids
+        for (let i = 0; i < fieldsCount; i++) {
+            this._fieldIds.add(buffer.readInteger());
+        }
+    }
+}
+
+class BinaryField {
+    constructor(name, typeCode) {
+        this._name = name;
+        this._id = BinaryField._calculateId(name);
+        this._typeCode = typeCode;
+    }
+
+    get id() {
+        return this._id;
+    }
+
+    get name() {
+        return this._name;
+    }
+
+    get typeCode() {
+        return this._typeCode;
+    }
+
+    static _calculateId(name) {
+        return BinaryUtils.hashCodeLowerCase(name);
+    }
+
+    async _write(buffer) {
+        // field name
+        await BinaryWriter.writeString(buffer, this._name);
+        // type code
+        buffer.writeInteger(this._typeCode);
+        // field id
+        buffer.writeInteger(this._id);
+    }
+
+    async _read(buffer) {
+        const BinaryReader = require('./BinaryReader');
+        // field name
+        this._name = await BinaryReader.readObject(buffer);
+        // type code
+        this._typeCode = buffer.readInteger();
+        // field id
+        this._id = buffer.readInteger();
+    }
+}
+
+class BinaryTypeBuilder {
+
+    static fromTypeName(typeName) {
+        let result = new BinaryTypeBuilder();
+        result._init(typeName);
+        return result;
+    }
+
+    static async fromTypeId(typeId, schemaId, hasSchema) {
+        let result = new BinaryTypeBuilder();
+        if (hasSchema) {
+            let type = await BinaryTypeStorage.getEntity().getType(typeId, 
schemaId);
+            if (type) {
+                result._type = type;
+                result._schema = type.getSchema(schemaId);
+                if (!result._schema) {
+                    throw Errors.IgniteClientError.serializationError(
+                        false, Util.format('schema id "%d" specified for 
complex object of type "%s" not found',
+                            schemaId, type.name));
+                }
+                result._fromStorage = true;
+                return result;
+            }
+        }
+        result._init(null);
+        result._type._id = typeId;
+        return result;
+    }
+
+    static fromObject(jsObject, complexObjectType = null) {
+        if (complexObjectType) {
+            return BinaryTypeBuilder.fromComplexObjectType(complexObjectType, 
jsObject);
+        }
+        else {
+            const result = new BinaryTypeBuilder();
+            result._fromComplexObjectType(new ComplexObjectType(jsObject), 
jsObject);
+            return result;
+        }
+    }
+
+    static fromComplexObjectType(complexObjectType, jsObject) {
+        let result = new BinaryTypeBuilder();
+        const typeInfo = 
BinaryTypeStorage.getEntity().getByComplexObjectType(complexObjectType);
+        if (typeInfo) {
+            result._type = typeInfo[0];
+            result._schema = typeInfo[1];
+            result._fromStorage = true;
+        }
+        else {
+            result._fromComplexObjectType(complexObjectType, jsObject);
+            
BinaryTypeStorage.getEntity().setByComplexObjectType(complexObjectType, 
result._type, result._schema);
+        }
+        return result;        
+    }
+
+    getTypeId() {
+        return this._type.id;
+    }
+
+    getTypeName() {
+        return this._type.name;
+    }
+
+    getSchemaId() {
+        return this._schema.id;
+    }
+
+    getFields() {
+        return this._type.fields;
+    }
+
+    getField(fieldId) {
+        return this._type._fields.get(fieldId);
+    }
+
+    setField(fieldName, fieldTypeCode = null) {
+        const fieldId = BinaryField._calculateId(fieldName);
+        if (!this._type.hasField(fieldId) || !this._schema.hasField(fieldId) ||
+            this._type.getField(fieldId).typeCode !== fieldTypeCode) {
+            this._beforeModify();
+            this._type.setField(new BinaryField(fieldName, fieldTypeCode));
+            this._schema.addField(fieldId);
+        }
+    }
+
+    removeField(fieldName) {
+        const fieldId = BinaryField._calculateId(fieldName);
+        if (this._type.hasField(fieldId)) {
+            this._beforeModify();
+            this._type.removeField(fieldId);
+            this._schema.removeField(fieldId);
+        }
+    }
+
+    async finalize() {
+        this._schema.finalize();
+        await BinaryTypeStorage.getEntity().addType(this._type, this._schema);
+    }
+
+    constructor() {
+        this._type = null;
+        this._schema = null;
+        this._fromStorage = false;
+    }
+
+    _fromComplexObjectType(complexObjectType, jsObject) {
+        this._init(complexObjectType._typeName);
+        if (complexObjectType._template) {
+            this._setFields(complexObjectType, complexObjectType._template, 
jsObject);
+        }
+    }
+
+    _init(typeName) {
+        this._type = new BinaryType(typeName);
+        this._schema = new BinarySchema();
+    }
+
+    _beforeModify() {
+        if (this._fromStorage) {
+            this._type = this._type.clone();
+            this._schema = this._schema.clone();
+            this._fromStorage = false;
+        }
+    }
+
+    _setFields(complexObjectType, objectTemplate, jsObject) {
+        let fieldType;
+        for (let fieldName of 
BinaryUtils.getJsObjectFieldNames(objectTemplate)) {
+            fieldType = complexObjectType._getFieldType(fieldName);
+            if (!fieldType && jsObject[fieldName]) {
+                fieldType = BinaryUtils.calcObjectType(jsObject[fieldName]);
+            }
+            this.setField(fieldName, BinaryUtils.getTypeCode(fieldType));
+        }
+    }
+}
+
+module.exports = BinaryType;
+module.exports.BinaryField = BinaryField;
+module.exports.BinaryTypeBuilder = BinaryTypeBuilder;

http://git-wip-us.apache.org/repos/asf/ignite/blob/c56d16fb/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
new file mode 100644
index 0000000..d79156b
--- /dev/null
+++ b/modules/platforms/nodejs/lib/internal/BinaryTypeStorage.js
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+'use strict';
+
+const Errors = require('../Errors');
+const BinaryUtils = require('./BinaryUtils');
+
+class BinaryTypeStorage {
+
+    static getEntity() {
+        if (!BinaryTypeStorage._entity) {
+            throw Errors.IgniteClientError.internalError();
+        }
+        return BinaryTypeStorage._entity;
+    }
+
+    static createEntity(socket) {
+        BinaryTypeStorage._entity = new BinaryTypeStorage(socket);
+    }
+
+    async addType(binaryType, binarySchema) {
+        const typeId = binaryType.id;
+        const schemaId = binarySchema.id;
+        let storageType = this._types.get(typeId);
+        if (!storageType || !storageType.hasSchema(schemaId)) {
+            binaryType.addSchema(binarySchema);
+            if (!storageType) {
+                this._types.set(typeId, binaryType);
+                storageType = binaryType;
+            }
+            else {
+                storageType.merge(binaryType, binarySchema);
+            }
+            await this._putBinaryType(binaryType);
+        }
+    }
+
+    async getType(typeId, schemaId = null) {
+        let storageType = this._types.get(typeId);
+        if (!storageType || schemaId && !storageType.hasSchema(schemaId)) {
+            storageType = await this._getBinaryType(typeId);
+            if (storageType) {
+                this._types.set(storageType.id, storageType);
+            }
+        }
+        return storageType;
+    }
+
+    getByComplexObjectType(complexObjectType) {
+        return this._complexObjectTypes.get(complexObjectType);
+    }
+
+    setByComplexObjectType(complexObjectType, type, schema) {
+        if (!this._complexObjectTypes.has(complexObjectType)) {
+            this._complexObjectTypes.set(complexObjectType, [type, schema]);
+        }
+    }
+
+    /** Private methods */
+
+    constructor(socket) {
+        this._socket = socket;
+        this._types = new Map();
+        this._complexObjectTypes = new Map();
+    }
+
+    async _getBinaryType(typeId) {
+        const BinaryType = require('./BinaryType');
+        let binaryType = new BinaryType(null);
+        binaryType._id = typeId;
+        await this._socket.send(
+            BinaryUtils.OPERATION.GET_BINARY_TYPE,
+            async (payload) => {
+                payload.writeInteger(typeId);
+            },
+            async (payload) => {
+                const exist = payload.readBoolean();
+                if (exist) {
+                    await binaryType._read(payload);
+                }
+                else {
+                    binaryType = null;
+                }
+            });
+        return binaryType;
+    }
+
+    async _putBinaryType(binaryType) {
+        await this._socket.send(
+            BinaryUtils.OPERATION.PUT_BINARY_TYPE,
+            async (payload) => {
+                await binaryType._write(payload);
+            });
+    }
+}
+
+module.exports = BinaryTypeStorage;

Reply via email to