diff --git a/.gitignore b/.gitignore index e592b0e..837568e 100644 --- a/.gitignore +++ b/.gitignore @@ -6,4 +6,6 @@ coverage/ .env .nyc_output config/**/* -test.js \ No newline at end of file +test.js +.idea +yarn* diff --git a/README.md b/README.md index b1bbbc2..bfc6680 100644 --- a/README.md +++ b/README.md @@ -428,6 +428,21 @@ instance.create('Person', { console.log(adam.get('name')); // 'Adam' }); ``` +#### Commit et Rollback + +```javascript +try{ + instance.beginTransaction(); + await instance.create('Person', {name: 'Adam'}); + await instance.create('Person', {name: 'JuJu'}) + await instance.create('Person', {name: 'Toto'}) + await instance.commit(); +}catch (e) { + await instance.rollback(); +}finally{ + await instance.closeBeginTransaction(); +} +``` ### Merging a Node Nodes are merged based on the indexes and constraints. diff --git a/build/Collection.js b/build/Collection.js index a53b02f..43c2656 100644 --- a/build/Collection.js +++ b/build/Collection.js @@ -32,11 +32,16 @@ var Collection = /*#__PURE__*/function () { _createClass(Collection, [{ - key: Symbol.iterator, - + key: "length", + get: function get() { + return this._values.length; + } /** * Iterator */ + + }, { + key: Symbol.iterator, value: function value() { return this._values.values(); } @@ -111,11 +116,6 @@ var Collection = /*#__PURE__*/function () { return value.toJson(); })); } - }, { - key: "length", - get: function get() { - return this._values.length; - } }]); return Collection; diff --git a/build/Entity.js b/build/Entity.js index 970947b..0897ab6 100644 --- a/build/Entity.js +++ b/build/Entity.js @@ -90,13 +90,13 @@ var Entity = /*#__PURE__*/function () { _createClass(Entity, [{ key: "id", - + value: /** * Get Internal Node ID * * @return {int} */ - value: function id() { + function id() { return this._identity.toNumber(); } /** diff --git a/build/Model.js b/build/Model.js index ac0c5fe..1ef48bf 100644 --- a/build/Model.js +++ b/build/Model.js @@ -1,5 +1,7 @@ "use strict"; +function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + Object.defineProperty(exports, "__esModule", { value: true }); @@ -17,8 +19,6 @@ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } -function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } - function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } @@ -49,13 +49,13 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } -function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function () { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } -function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } diff --git a/build/ModelMap.js b/build/ModelMap.js index 8fc9915..89ca749 100644 --- a/build/ModelMap.js +++ b/build/ModelMap.js @@ -17,7 +17,7 @@ function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !( function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } -function _createForOfIteratorHelper(o) { if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (o = _unsupportedIterableToArray(o))) { var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var it, normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } +function _createForOfIteratorHelper(o, allowArrayLike) { var it; if (typeof Symbol === "undefined" || o[Symbol.iterator] == null) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e2) { throw _e2; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = o[Symbol.iterator](); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e3) { didErr = true; err = _e3; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; } function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); } diff --git a/build/Node.js b/build/Node.js index 481bea0..09b7ec5 100644 --- a/build/Node.js +++ b/build/Node.js @@ -1,5 +1,7 @@ "use strict"; +function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + Object.defineProperty(exports, "__esModule", { value: true }); @@ -21,8 +23,6 @@ var _RelationshipType = _interopRequireDefault(require("./RelationshipType")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } -function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } @@ -33,13 +33,13 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } -function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function () { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } -function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } diff --git a/build/Query/Builder.js b/build/Query/Builder.js index 31f1114..57b0bce 100644 --- a/build/Query/Builder.js +++ b/build/Query/Builder.js @@ -59,7 +59,7 @@ function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; } function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } -function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } @@ -213,7 +213,7 @@ var Builder = /*#__PURE__*/function () { key: "_addWhereParameter", value: function _addWhereParameter(key, value) { var attempt = 1; - var base = "where_".concat(key.replace(/[^a-z0-9]+/, '_')); // Try to create a unique key + var base = "where_".concat(key.replace(/[^a-z0-9]+/g, '_')); // Try to create a unique key var variable = base; @@ -757,15 +757,30 @@ var Builder = /*#__PURE__*/function () { query = _this$build.query, params = _this$build.params; + if (this._neode.isTransactionOgm) { + return this._neode.transactionOgm.txc.run(query, params); + } + + var session; + switch (query_mode) { case mode.WRITE: - return this._neode.writeCypher(query, params); - - case mode.READ: - return this._neode.readCypher(query, params); + session = this._neode.writeSession(); + return session.writeTransaction(function (tx) { + return tx.run(query, params); + }).then(function (res) { + session.close(); + return res; + }); default: - return this._neode.cypher(query, params); + session = this._neode.readSession(); + return session.readTransaction(function (tx) { + return tx.run(query, params); + }).then(function (res) { + session.close(); + return res; + }); } } }]); diff --git a/build/Relationship.js b/build/Relationship.js index def978c..a541172 100644 --- a/build/Relationship.js +++ b/build/Relationship.js @@ -1,5 +1,7 @@ "use strict"; +function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + Object.defineProperty(exports, "__esModule", { value: true }); @@ -15,8 +17,6 @@ var _RelationshipType = require("./RelationshipType"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; } -function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } - function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); } function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } @@ -39,13 +39,13 @@ function _inherits(subClass, superClass) { if (typeof superClass !== "function" function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); } -function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function () { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; } -function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); } diff --git a/build/TransactionError.js b/build/TransactionError.js index 7e11b77..6a18abd 100644 --- a/build/TransactionError.js +++ b/build/TransactionError.js @@ -1,17 +1,17 @@ "use strict"; +function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = exports.ERROR_TRANSACTION_FAILED = void 0; -function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } -function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function () { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } @@ -21,7 +21,7 @@ function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } -function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; } diff --git a/build/ValidationError.js b/build/ValidationError.js index f961c14..84f141c 100644 --- a/build/ValidationError.js +++ b/build/ValidationError.js @@ -1,17 +1,17 @@ "use strict"; +function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } + Object.defineProperty(exports, "__esModule", { value: true }); exports["default"] = exports.ERROR_VALIDATION = void 0; -function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); } - function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } } function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); } -function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function () { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } +function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; } function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); } @@ -21,7 +21,7 @@ function _wrapNativeSuper(Class) { var _cache = typeof Map === "function" ? new function _construct(Parent, args, Class) { if (_isNativeReflectConstruct()) { _construct = Reflect.construct; } else { _construct = function _construct(Parent, args, Class) { var a = [null]; a.push.apply(a, args); var Constructor = Function.bind.apply(Parent, a); var instance = new Constructor(); if (Class) _setPrototypeOf(instance, Class.prototype); return instance; }; } return _construct.apply(null, arguments); } -function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Date.prototype.toString.call(Reflect.construct(Date, [], function () {})); return true; } catch (e) { return false; } } +function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } } function _isNativeFunction(fn) { return Function.toString.call(fn).indexOf("[native code]") !== -1; } diff --git a/build/index.js b/build/index.js index a31a57d..8b13bc5 100644 --- a/build/index.js +++ b/build/index.js @@ -59,6 +59,7 @@ var Neode = /*#__PURE__*/function () { this.models = new _ModelMap["default"](this); this.schema = new _Schema["default"](this); this.factory = new _Factory["default"](this); + this._transactionOgm = undefined; this.database = database; this.setEnterprise(enterprise); } @@ -72,14 +73,14 @@ var Neode = /*#__PURE__*/function () { _createClass(Neode, [{ key: "with", - + value: /** * Define multiple models * * @param {Object} models Map of models with their schema. ie {Movie: {...}} * @return {Neode} */ - value: function _with(models) { + function _with(models) { var _this = this; Object.keys(models).forEach(function (model) { @@ -346,17 +347,104 @@ var Neode = /*#__PURE__*/function () { var database = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.database; return this.readSession(database); } + /** + * init begin Transaction + * @returns {void} + */ + + }, { + key: "beginTransaction", + value: function beginTransaction() { + if (this.isTransactionOgm) { + throw "you could not start a new transaction because you did not close the old one"; + } + + var session = this.writeSession(); + var txc = session.beginTransaction(); + this._transactionOgm = { + session: session, + txc: txc + }; + } + /** + * + * @return {boolean} + */ + + }, { + key: "isTransactionOgm", + get: function get() { + return !!this._transactionOgm; + } + /** + * get session transactions + * @returns {{Transaction|Session}} + */ + + }, { + key: "transactionOgm", + get: function get() { + if (!this._transactionOgm) { + throw "You did not initiate begin transaction"; + } + + return this._transactionOgm; + } + /** + * commit transactions + * @returns {Promise} + */ + + }, { + key: "commit", + value: function commit() { + return this.transactionOgm.txc.commit(); + } + /** + * rollback transaction + * @returns {Promise} + */ + + }, { + key: "rollback", + value: function rollback() { + return this.transactionOgm.txc.rollback(); + } + /** + * close session transactions + * @returns {Promise} + */ + + }, { + key: "closeBeginTransaction", + value: function closeBeginTransaction() { + var _this3 = this; + + return new Promise(function (resolve, reject) { + _this3.transactionOgm.session.close().then(function () { + _this3._transactionOgm = undefined; + return resolve(); + })["catch"](function () { + return reject("impossible to close session"); + }); + }); + } /** * Create an explicit Read Session * * @param {String} database - * @return {Session} + * @return {Session|Transaction} */ }, { key: "readSession", value: function readSession() { var database = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.database; + + if (this.isTransactionOgm) { + return this._transactionOgm.txc; + } + return this.driver.session({ database: database, defaultAccessMode: _neo4jDriver["default"].session.READ @@ -366,13 +454,18 @@ var Neode = /*#__PURE__*/function () { * Create an explicit Write Session * * @param {String} database - * @return {Session} + * @return {Session|Transaction} */ }, { key: "writeSession", value: function writeSession() { var database = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : this.database; + + if (this.isTransactionOgm) { + return this._transactionOgm.txc; + } + return this.driver.session({ database: database, defaultAccessMode: _neo4jDriver["default"].session.WRITE diff --git a/src/Query/Builder.js b/src/Query/Builder.js index 4a94fdc..b2eb2d6 100644 --- a/src/Query/Builder.js +++ b/src/Query/Builder.js @@ -603,30 +603,31 @@ export default class Builder { execute(query_mode = mode.WRITE) { const { query, params } = this.build(); - let session + if(this._neode.isTransactionOgm){ + return this._neode.transactionOgm.txc.run(query, params); + } + + let session; switch (query_mode) { case mode.WRITE: - session = this._neode.writeSession() - + session = this._neode.writeSession(); return session.writeTransaction(tx => tx.run(query, params)) .then(res => { - session.close() - - return res - }) + session.close(); + return res; + }); default: - session = this._neode.readSession() + session = this._neode.readSession(); return session.readTransaction(tx => tx.run(query, params)) .then(res => { - session.close() - - return res - }) + session.close(); + return res; + }); } } -} \ No newline at end of file +} diff --git a/src/index.js b/src/index.js index 2e68d54..206f62c 100644 --- a/src/index.js +++ b/src/index.js @@ -28,7 +28,7 @@ export default class Neode { this.models = new ModelMap(this); this.schema = new Schema(this); this.factory = new Factory(this); - + this._transactionOgm = undefined; this.database = database; this.setEnterprise(enterprise); @@ -329,13 +329,83 @@ export default class Neode { return this.readSession(database); } + /** + * init begin Transaction + * @returns {void} + */ + beginTransaction(){ + if(this.isTransactionOgm){ + throw "you could not start a new transaction because you did not close the old one"; + } + const session = this.writeSession(); + const txc = session.beginTransaction(); + this._transactionOgm = {session, txc}; + } + + /** + * + * @return {boolean} + */ + get isTransactionOgm(){ + return !!this._transactionOgm; + } + + + /** + * get session transactions + * @returns {{Transaction|Session}} + */ + get transactionOgm(){ + if(!this._transactionOgm){ + throw "You did not initiate begin transaction"; + } + return this._transactionOgm; + } + + /** + * commit transactions + * @returns {Promise} + */ + commit(){ + return this.transactionOgm.txc.commit(); + } + + /** + * rollback transaction + * @returns {Promise} + */ + rollback(){ + return this.transactionOgm.txc.rollback(); + } + + /** + * close session transactions + * @returns {Promise} + */ + closeBeginTransaction(){ + return new Promise(((resolve, reject) => { + this.transactionOgm.session.close() + .then(() => { + this._transactionOgm = undefined; + return resolve(); + }) + .catch(() => { + return reject("impossible to close session"); + }) + ; + })); + } + /** * Create an explicit Read Session * * @param {String} database - * @return {Session} + * @return {Session|Transaction} */ readSession(database = this.database) { + if(this.isTransactionOgm){ + return this._transactionOgm.txc; + } return this.driver.session({ database, defaultAccessMode: neo4j.session.READ, @@ -346,9 +416,12 @@ export default class Neode { * Create an explicit Write Session * * @param {String} database - * @return {Session} + * @return {Session|Transaction} */ writeSession(database = this.database) { + if(this.isTransactionOgm){ + return this._transactionOgm.txc; + } return this.driver.session({ database, defaultAccessMode: neo4j.session.WRITE, diff --git a/types/index.d.ts b/types/index.d.ts index abca0ab..745410d 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -1,641 +1,87 @@ import { QueryResult, Node as Neo4jNode, Relationship, Session, Transaction, Integer } from 'neo4j-driver'; -declare class Neode { - schema: Neode.Schema; - - /** - * Constructor - * - * @param {String} connection_string - * @param {String} username - * @param {String} password - * @param {Bool} enterprise - * @param {String} database - * @param {Object} config - * @return {Neode} - */ - constructor(connection_string: string, username: string, password: string, enterprise?: boolean, database?: string, config?: object); - - - /** - * @static - * Generate Neode instance using .env configuration - * - * @return {Neode} - */ - static fromEnv(): Neode; - - /** - * Define multiple models - * - * @param {Object} models Map of models with their schema. ie {Movie: {...}} - * @return {Neode} - */ - with(models: {[index: string]: Neode.SchemaObject}): Neode; - - /** - * Scan a directory for Models - * - * @param {String} directory Directory to scan - * @return {Neode} - */ - withDirectory(directory: string): Neode; - - /** - * Set Enterprise Mode - * - * @param {Bool} enterprise - */ - setEnterprise(enterprise: boolean): void; - - /** - * Are we running in enterprise mode? - * - * @return {Bool} - */ - enterprise(): boolean; - - /** - * Define a new Model - * - * @param {String} name - * @param {Object} schema - * @return {Model} - */ - model(name: string, schema?: Neode.SchemaObject): Neode.Model; - - /** - * Extend a model with extra configuration - * - * @param {String} name Original Model to clone - * @param {String} as New Model name - * @param {Object} using Schema changes - * @return {Model} - */ - extend(model: string, as: string, using: Neode.SchemaObject): Neode.Model; - - /** - * Create a new Node of a type - * - * @param {String} model - * @param {Object} properties - * @return {Node} - */ - create(model: string, properties: object): Promise>; - - /** - * Merge a node based on the defined indexes - * - * @param {Object} properties - * @return {Promise} - */ - merge(model: string, properties: object): Promise>; - - /** - * Merge a node based on the supplied properties - * - * @param {Object} match Specific properties to merge on - * @param {Object} set Properties to set - * @return {Promise} - */ - mergeOn(model: string, match: object, set: object): Promise>; - - /** - * Delete a Node from the graph - * - * @param {Node} node - * @return {Promise} - */ - delete(node: Neode.Node): Promise; - - /** - * Delete all node labels - * - * @param {String} label - * @return {Promise} - */ - deleteAll(model: string): Promise; - - /** - * Relate two nodes based on the type - * - * @param {Node} from Origin node - * @param {Node} to Target node - * @param {String} type Type of Relationship definition - * @param {Object} properties Properties to set against the relationships - * @param {Boolean} force_create Force the creation a new relationship? If false, the relationship will be merged - * @return {Promise} - */ - relate(from: Neode.Node, to: Neode.Node, type: string, properties: Neode.RelationshipSchema, force_create ?: boolean): Promise; - - /** - * Run an explicitly defined Read query - * - * @param {String} query - * @param {Object} params - * @return {Promise} - */ - readCypher(query: string, params: object): Promise; - - /** - * Run an explicitly defined Write query - * - * @param {String} query - * @param {Object} params - * @return {Promise} - */ - writeCypher(query: string, params: object): Promise; - - /** - * Run a Cypher query - * - * @param {String} query - * @param {Object} params - * @return {Promise} - */ - cypher(query: string, params: object, session?: Session): Promise; - - /** - * Create a new Session in the Neo4j Driver. - * - * @param {String} database - * @return {Session} - */ - session(): Session; - - /** - * Create an explicit Read Session - * - * @param {String} database - * @return {Session} - */ - readSession(database?: string): Session; - - /** - * Create an explicit Write Session - * - * @param {String} database - * @return {Session} - */ - writeSession(database?: string): Session; - - /** - * Create a new Transaction - * - * @param {String} mode - * @param {String} database - * @return {Transaction} - */ - transaction(mode?: string, database?: string): Transaction; - - /** - * Run a batch of queries within a transaction - * - * @type {Array} - * @return {Promise} - */ - batch(queries?: Array<{query: string | object, params?: object | string}>): Promise; - - /** - * Close Driver - * - * @return {void} - */ - close(): void; - - /** - * Return a new Query Builder - * - * @return {Builder} - */ - query(): Neode.Builder; - - /** - * Get a collection of nodes - * - * @param {String} label - * @param {Object} properties - * @param {String|Array|Object} order - * @param {Int} limit - * @param {Int} skip - * @return {Promise} - */ - all(label: string, properties?: object, order?: string | Array | object, limit?: number, skip?: number): Promise; - - /** - * Find a Node by it's label and primary key - * - * @param {String} label - * @param {mixed} id - * @return {Promise} - */ - find(label: string, id: string | number): Promise>; - - /** - * Find a Node by it's internal node ID - * - * @param {String} model - * @param {int} id - * @return {Promise} - */ - findById(label: string, id: number): Promise>; - - /** - * Find a Node by properties - * - * @param {String} label - * @param {mixed} key Either a string for the property name or an object of values - * @param {mixed} value Value - * @return {Promise} - */ - first(label: string, key: string | {[key: string]: any}, value: any): Promise>; - - /** - * Hydrate a set of nodes and return a NodeCollection - * - * @param {Object} res Neo4j result set - * @param {String} alias Alias of node to pluck - * @param {Definition|null} definition Force Definition - * @return {NodeCollection} - */ - hydrate(res: QueryResult, alias: string, definition?: Neode.Model): Neode.NodeCollection; - - /** - * Hydrate the first record in a result set - * - * @param {Object} res Neo4j Result - * @param {String} alias Alias of Node to pluck - * @return {Node} - */ - hydrateFirst(res: QueryResult, alias: string, definition?: Neode.Model): Neode.Node; - -} - -export = Neode; - -declare namespace Neode { - - type PropertyType = string | number | boolean; - - type TemporalPropertyTypes = 'datetime' | 'date' | 'time' | 'localdate' | 'localtime' | 'duration' - type NumberPropertyTypes = 'number' | 'int' | 'integer' | 'float' - type RelationshipPropertyTypes = 'relationship' | 'relationships' - type NodesPropertyTypes = 'node' | 'nodes' - type StringPropertyTypes = 'string' | 'uuid' - type PropertyTypes = TemporalPropertyTypes | NumberPropertyTypes - | RelationshipPropertyTypes | StringPropertyTypes | NodesPropertyTypes - | 'boolean' | 'Point'; - - type Direction = 'direction_in' | 'direction_out' | 'direction_both' | 'in' | 'out'; - - interface BaseNodeProperties { - primary?: boolean - required?: boolean - unique?: boolean - indexed?: boolean - hidden?: boolean - readonly?: boolean - default?: any - } - - interface BaseNumberNodeProperties extends BaseNodeProperties { - /** - * Minimum value of the number - */ - min: number - - /** - * Maximum value of the number - */ - max: number - - /** - * Is the number an integer - */ - integer: boolean - - /** - * Can the number handle positive value - */ - positive: boolean - - /** - * Can the number handle negative value - */ - negative: boolean - - /** - * The number has to be a multiple of - */ - multiple: number - } - - interface NumberNodeProperties extends BaseNumberNodeProperties { - type: 'number' - } - interface IntNodeProperties extends BaseNumberNodeProperties { - type: 'int' - } - interface IntegerNodeProperties extends BaseNumberNodeProperties { - type: 'integer' - } - interface FloatNodeProperties extends BaseNumberNodeProperties { - type: 'float' - - /** - * Precision, decimal count - */ - precision: number - } - - interface StringNodeProperties extends BaseNodeProperties { - type: 'string' - - regex: RegExp | { - pattern: RegExp - invert: boolean - name: string - } - - /** - * Replace parts of the string - */ - replace: { - /** - * RegExp pattern - */ - pattern: RegExp - - /** - * What should replace the pattern - */ - replace: string - } - - /** - * Should the string be in a valid email format - */ - email: boolean | { - /** - * tld Domain whitelist (e.g ['com', 'fr']) - */ - tldWhitelist: string[] - } - } - - interface BaseRelationshipNodeProperties extends BaseNodeProperties { - /** - * Neo4J Relationship name (e.g: ACTED_IN) - */ - relationship: string - - /** - * Target model name - */ - target: string - - /** - * Is the relation required to be fetch - */ - required?: boolean - - /** - * Load the relation with the parent object - */ - eager?: boolean - - /** - * Default value - */ - default?: any - - /** - * Relationship direction - */ - direction: Direction - - /** - * Behaviour when deleting the parent object - */ - cascade?: 'detach' | 'delete' - - /** - * Relationship attached properties - */ - properties?: { - [index: string]: PropertyTypes - } - } - - interface RelationshipsNodeProperties extends BaseRelationshipNodeProperties { - type: 'relationships' - } - interface RelationshipNodeProperties extends BaseRelationshipNodeProperties { - type: 'relationship' - } - - interface NodesNodeProperties extends BaseRelationshipNodeProperties { - type: 'nodes' - } - - interface NodeNodeProperties extends BaseRelationshipNodeProperties { - type: 'node' - } - - interface OtherNodeProperties extends BaseNodeProperties { - type: PropertyTypes - } - - type NodeProperty = PropertyTypes - | NumberNodeProperties | IntNodeProperties | IntegerNodeProperties | FloatNodeProperties - | RelationshipNodeProperties | RelationshipsNodeProperties - | NodeNodeProperties | NodesNodeProperties - | StringNodeProperties | OtherNodeProperties; - - export type SchemaObject = { - [index: string]: NodeProperty - }; - - export type RelationshipSchema = { - [index: string]: BaseRelationshipNodeProperties - }; - - - type Mode = 'READ' | 'WRITE'; - - class Builder { - - constructor(neode: Neode); - - /** - * Start a new Query segment and set the current statement - * - * @return {Builder} - */ - statement(prefix: string): Builder; +declare class Neode{ + schema:Neode.Schema; /** - * Start a new Where Segment - * - * @return {Builder} - */ - whereStatement(prefix: string): Builder; - - /** - * Match a Node by a definition - * - * @param {String} alias Alias in query - * @param {Model} model Model definition - * @return {Builder} Builder - */ - match(alias: string, model: Model): Builder; - - optionalMatch(alias: string, model: Model): Builder; - - /** - * Add a 'with' statement to the query - * - * @param {...String} args Variables/aliases to return - * @return {Builder} - */ - with(...args: Array): Builder; - - /** - * Create a new WhereSegment - * @param {...mixed} args - * @return {Builder} - */ - or(...args: Array): Builder; - - /** - * Add a where condition to the current statement. - * - * @param {...mixed} args Argumenta - * @return {Builder} - */ - where(...args: Array): Builder; - - /** - * Query on Internal ID - * - * @param {String} alias - * @param {Int} value - * @return {Builder} - */ - whereId(alias: string, value: number): Builder; - - /** - * Set Delete fields - * - * @param {...mixed} args - * @return {Builder} - */ - delete(...args: Array): Builder; - - /** - * Set Detach Delete fields - * - * @param {...mixed} args - * @return {Builder} - */ - detachDelete(...args: Array): Builder; - - /** - * Set Return fields - * - * @param {...mixed} args - * @return {Builder} - */ - return(...args: Array): Builder; - - /** - * Set Record Limit + * Constructor * - * @param {Int} limit - * @return {Builder} + * @param {String} connection_string + * @param {String} username + * @param {String} password + * @param {Bool} enterprise + * @param {String} database + * @param {Object} config + * @return {Neode} */ - limit(limit: number): Builder; + constructor(connection_string:string, username:string, password:string, enterprise?:boolean, database?:string, config?:object); - /** - * Set Records to Skip - * - * @param {Int} skip - * @return {Builder} - */ - skip(skip: number): Builder; /** - * Add an order by statement + * @static + * Generate Neode instance using .env configuration * - * @param {...String|object} args Order by statements - * @return {Builder} + * @return {Neode} */ - orderBy(...args: Array): Builder; + static fromEnv():Neode; /** - * Add a relationship to the query + * Define multiple models * - * @param {String|RelationshipType} relationship Relationship name or RelationshipType object - * @param {String} direction Direction of relationship DIRECTION_IN, DIRECTION_OUT - * @param {String|null} alias Relationship alias - * @param {Int|String} traversals Number of traversals (1, "1..2", "0..2", "..3") - * @return {Builder} + * @param {Object} models Map of models with their schema. ie {Movie: {...}} + * @return {Neode} */ - relationship(relationship: string | RelationshipType, direction: Neode.Direction, alias: string | null, traversals: number | string): Builder; + with(models:{[index:string]:Neode.SchemaObject}):Neode; /** - * Complete a relationship - * @param {String} alias Alias - * @param {Model} model Model definition - * @return {Builder} - */ - to(alias: string, model: Model): Builder; - - /** - * Complete the relationship statement to point to anything + * Scan a directory for Models * - * @return {Builder} + * @param {String} directory Directory to scan + * @return {Neode} */ - toAnything(): Builder; + withDirectory(directory:string):Neode; /** - * Build the Query + * Set Enterprise Mode * - * @param {...String} output References to output - * @return {Object} Object containing `query` and `params` property + * @param {Bool} enterprise */ - build(): {query: string, params: object}; + setEnterprise(enterprise:boolean):void; /** - * Execute the query + * Are we running in enterprise mode? * - * @return {Promise} + * @return {Bool} */ - execute(mode?: Mode): Promise; - } + enterprise():boolean; - class Queryable { /** - * @constructor + * Define a new Model * - * @param Neode neode + * @param {String} name + * @param {Object} schema + * @return {Model} */ - constructor(neode: Neode); + model(name:string, schema?:Neode.SchemaObject):Neode.Model; /** - * Return a new Query Builder + * Extend a model with extra configuration * - * @return {Builder} + * @param {String} name Original Model to clone + * @param {String} as New Model name + * @param {Object} using Schema changes + * @return {Model} */ - query(): Builder; + extend(model:string, as:string, using:Neode.SchemaObject):Neode.Model; /** - * Create a new node + * Create a new Node of a type * - * @param {object} properties + * @param {String} model + * @param {Object} properties * @return {Promise} */ - create(properties: T): Promise>; + create(model:string, properties:object):Promise>; /** * Merge a node based on the defined indexes @@ -643,7 +89,7 @@ declare namespace Neode { * @param {Object} properties * @return {Promise} */ - merge(properties: T): Promise>; + merge(model:string, properties:object):Promise>; /** * Merge a node based on the supplied properties @@ -652,479 +98,1070 @@ declare namespace Neode { * @param {Object} set Properties to set * @return {Promise} */ - mergeOn(match: Object, set: Object): Promise>; + mergeOn(model:string, match:object, set:object):Promise>; /** - * Delete all nodes for this model + * Delete a Node from the graph * + * @param {Node} node * @return {Promise} */ - deleteAll(): Promise; + delete(node:Neode.Node):Promise; /** - * Get a collection of nodes for this label + * Delete all node labels * - * @param {Object} properties - * @param {String|Array|Object} order - * @param {Int} limit - * @param {Int} skip + * @param {String} label * @return {Promise} */ - all(properties?: object, order?: string | Array | object, limit?: number, skip?: number): Promise; + deleteAll(model:string):Promise; /** - * Find a Node by its Primary Key + * Relate two nodes based on the type * - * @param {mixed} id + * @param {Node} from Origin node + * @param {Node} to Target node + * @param {String} type Type of Relationship definition + * @param {Object} properties Properties to set against the relationships + * @param {Boolean} force_create Force the creation a new relationship? If false, the relationship will be merged * @return {Promise} */ - find(id: string | number): Promise>; + relate(from:Neode.Node, to:Neode.Node, type:string, properties:Neode.RelationshipSchema, force_create ?:boolean):Promise; /** - * Find a Node by it's internal node ID + * Run an explicitly defined Read query * - * @param {int} id + * @param {String} query + * @param {Object} params * @return {Promise} */ - findById(id: number): Promise>; + readCypher(query:string, params:object):Promise; /** - * Find a Node by properties + * Run an explicitly defined Write query * - * @param {String} label - * @param {mixed} key Either a string for the property name or an object of values - * @param {mixed} value Value + * @param {String} query + * @param {Object} params * @return {Promise} */ - first(key: string | object, value: string | number): Promise>; + writeCypher(query:string, params:object):Promise; /** - * Get a collection of nodes within a certain distance belonging to this label + * Run a Cypher query * - * @param {Object} properties - * @param {String} location_property - * @param {Object} point - * @param {Int} distance - * @param {String|Array|Object} order - * @param {Int} limit - * @param {Int} skip + * @param {String} query + * @param {Object} params * @return {Promise} */ - withinDistance(location_property: string, point: {x: number, y: number, z?: number} | {latitude: number, longitude: number, height?: number}, distance: number, properties?: object, order?: string | Array | object, limit?: number, skip?: number): Promise; - } - - class Model extends Queryable { - constructor(neode: Neode, name: string, schema: Neode.SchemaObject); - - /** - * Get Model name - * - * @return {String} - */ - name(): string; + cypher(query:string, params:object, session?:Session):Promise; /** - * Get Schema + * Create a new Session in the Neo4j Driver. * - * @return {Object} + * @param {String} database + * @return {Session} */ - schema(): Neode.SchemaObject; + session():Session; /** - * Get a map of Properties - * - * @return {Map} + * @return {void} */ - properties(): Map; + beginTransaction():void /** - * Set Labels - * - * @param {...String} labels - * @return {Model} + * get txc + * @returns {Transaction} */ - setLabels(...labels: Array): Model; + getTxcTransaction():Transaction /** - * Get Labels - * - * @return {Array} + * get session + * @returns {Session} */ - labels(): Array; + getSessionTransaction():Session /** - * Add a property definition - * - * @param {String} key Property name - * @param {Object} schema Schema object - * @return {Model} + * @returns {Promise} */ - addProperty(key: string, schema: Neode.SchemaObject): Model; + commit():Promise /** - * Add a new relationship - * - * @param {String} name Reference of Relationship - * @param {String} type Internal Relationship type - * @param {String} relationship Internal Relationship name - * @param {String} direction Direction of Node (Use constants DIRECTION_IN, DIRECTION_OUT, DIRECTION_BOTH) - * @param {String|Model|null} target Target type definition for the - * @param {Object} schema Property Schema - * @param {Bool} eager Should this relationship be eager loaded? - * @param {Bool|String} cascade Cascade delete policy for this relationship - * @return {Relationship} + * @returns {Promise} */ - relationship(name: string, type: string, relationship: string, direction?: Neode.Direction, target?: string | Model, schema?: Neode.SchemaObject, eager?: boolean, cascade?: boolean | string): Relationship - + rollback():Promise /** - * Get all defined Relationships for this Model - * - * @return {Map} + * @return {Promise} */ - relationships(): Map; + closeBeginTransaction():Promise /** - * Get relationships defined as Eager relationships + * Create an explicit Read Session * - * @return {Array} + * @param {String} database + * @return {Session} */ - eager(): Array; + readSession(database?:string):Session; /** - * Get the name of the primary key + * Create an explicit Write Session * - * @return {String} + * @param {String} database + * @return {Session} */ - primaryKey(): string; + writeSession(database?:string):Session; /** - * Get array of hidden fields + * Create a new Transaction * - * @return {String[]} + * @param {String} mode + * @param {String} database + * @return {Transaction} */ - hidden(): Array; + transaction(mode?:string, database?:string):Transaction; /** - * Get defined merge fields + * Run a batch of queries within a transaction * - * @return {Array} - */ - mergeFields(): Array; - } - - class Schema { - - /** - * Neode will install the schema created by the constraints defined in your Node definitions. - */ - install(): void; - - /** - * Dropping the schema will remove all indexes and constraints created by Neode. - * All other indexes and constraints will be left intact. - */ - drop(): void; - } - - class RelationshipType { - - /** - * Constructor - * @param {String} type Reference of Relationship - * @param {String} relationship Internal Neo4j Relationship type (ie 'KNOWS') - * @param {String} direction Direction of Node (Use constants DIRECTION_IN, DIRECTION_OUT, DIRECTION_BOTH) - * @param {String|Model|null} target Target type definition for the - * @param {Object} schema Relationship definition schema - * @param {Bool} eager Should this relationship be eager loaded? - * @param {Bool|String} cascade Cascade delete policy for this relationship - * @return {Relationship} - */ - constructor(type: string, relationship: string, direction: Neode.Direction, target: string | Model | null, schema?: Neode.RelationshipSchema, eager?: boolean, cascade?: boolean | string); - - /** - * Type - * - * @return {String} - */ - type(): string; - - /** - * Get Internal Relationship Type - * - * @return {String} - */ - relationship(): string; - - /** - * Set Direction of relationship - * - * @return {RelationshipType} + * @type {Array} + * @return {Promise} */ - setDirection(direction: Neode.Direction): RelationshipType; + batch(queries?:Array<{query:string|object, params?:object|string}>):Promise; /** - * Get Direction of Node + * Close Driver * - * @return {String} + * @return {void} */ - direction(): Neode.Direction; + close():void; /** - * Get the target node definition + * Return a new Query Builder * - * @return {Model} + * @return {Builder} */ - target(): Model; + query():Neode.Builder; /** - * Get Schema object + * Get a collection of nodes * - * @return {Object} + * @param {String} label + * @param {Object} properties + * @param {String|Array|Object} order + * @param {Int} limit + * @param {Int} skip + * @return {Promise} */ - schema(): Neode.RelationshipSchema; + all(label:string, properties?:object, order?:string|Array|object, limit?:number, skip?:number):Promise; /** - * Should this relationship be eagerly loaded? + * Find a Node by it's label and primary key * - * @return {bool} + * @param {String} label + * @param {mixed} id + * @return {Promise} */ - eager(): boolean; + find(label:string, id:string|number):Promise>; /** - * Cascade policy for this relationship type + * Find a Node by it's internal node ID * - * @return {String} + * @param {String} model + * @param {int} id + * @return {Promise} */ - cascade(): string; - - } - - class Relationship { + findById(label:string, id:number):Promise>; /** - * Constructor + * Find a Node by properties * - * @param {Neode} neode Neode Instance - * @param {RelationshipType} type Relationship Type definition - * @param {Relationship} relationship Neo4j Relationship - * @param {Node} from Start node for the relationship - * @param {Node} to End node for the relationship - * @return {Relationship} + * @param {String} label + * @param {mixed} key Either a string for the property name or an object of values + * @param {mixed} value Value + * @return {Promise} */ - constructor(neode: Neode, type: RelationshipType, relationship: Relationship, from: Node, to: Node); + first(label:string, key:string|{[key:string]:any}, value:any):Promise>; /** - * Relationship Type definition for this node + * Hydrate a set of nodes and return a NodeCollection * - * @return {RelationshipType} + * @param {Object} res Neo4j result set + * @param {String} alias Alias of node to pluck + * @param {Definition|null} definition Force Definition + * @return {NodeCollection} */ - type(): RelationshipType; + hydrate(res:QueryResult, alias:string, definition?:Neode.Model):Neode.NodeCollection; /** - * Get Internal Relationship ID + * Hydrate the first record in a result set * - * @return {int} + * @param {Object} res Neo4j Result + * @param {String} alias Alias of Node to pluck + * @return {Node} */ - id(): number; + hydrateFirst(res:QueryResult, alias:string, definition?:Neode.Model):Neode.Node; - /** - * Return Internal Relationship ID as Neo4j Integer - * - * @return {Integer} - */ - idInt(): Integer; +} - /** - * Get Properties for this Relationship - * - * @return {Object} - */ - properties(): object; +export = Neode; - /** - * Get a property for this relationship - * - * @param {String} property Name of property - * @param {or} default Default value to supply if none exists - * @return {mixed} - */ - get(property: string, or?: T): T; +declare namespace Neode{ + + type PropertyType = string|number|boolean; + + type TemporalPropertyTypes = 'datetime'|'date'|'time'|'localdate'|'localtime'|'duration' + type NumberPropertyTypes = 'number'|'int'|'integer'|'float' + type RelationshipPropertyTypes = 'relationship'|'relationships' + type NodesPropertyTypes = 'node'|'nodes' + type StringPropertyTypes = 'string'|'uuid' + type PropertyTypes = TemporalPropertyTypes|NumberPropertyTypes + |RelationshipPropertyTypes|StringPropertyTypes|NodesPropertyTypes + |'boolean'|'Point'; + + type Direction = 'direction_in'|'direction_out'|'direction_both'|'in'|'out'; + + interface BaseNodeProperties{ + primary?:boolean + required?:boolean + unique?:boolean + indexed?:boolean + hidden?:boolean + readonly?:boolean + default?:any + } - /** - * Get originating node for this relationship - * - * @return Node - */ - startNode(): Node; + interface BaseNumberNodeProperties extends BaseNodeProperties{ + /** + * Minimum value of the number + */ + min:number + + /** + * Maximum value of the number + */ + max:number + + /** + * Is the number an integer + */ + integer:boolean + + /** + * Can the number handle positive value + */ + positive:boolean + + /** + * Can the number handle negative value + */ + negative:boolean + + /** + * The number has to be a multiple of + */ + multiple:number + } - /** - * Get destination node for this relationship - * - * @return Node - */ - endNode(): Node; + interface NumberNodeProperties extends BaseNumberNodeProperties{ + type:'number' + } - /** - * Convert Relationship to Object - * - * @return {Promise} - */ - toJson(): Promise; - } + interface IntNodeProperties extends BaseNumberNodeProperties{ + type:'int' + } - class Node { - /** - * @constructor - * - * @param {Neode} neode Neode Instance - * @param {Model} model Model definition - * @param {node} node Node Object from neo4j-driver - * @param {Map} eager Eagerly loaded values - * @return {Node} - */ - constructor(neode: Neode, model: Model, node: Neo4jNode, eager?: Map); + interface IntegerNodeProperties extends BaseNumberNodeProperties{ + type:'integer' + } - /** - * Model definition for this node - * - * @return {Model} - */ - model(): Model; + interface FloatNodeProperties extends BaseNumberNodeProperties{ + type:'float' - /** - * Get Internal Node ID - * - * @return {int} - */ - id(): number; + /** + * Precision, decimal count + */ + precision:number + } - /** - * Return Internal Node ID as Neo4j Integer - * - * @return {Integer} - */ - idInt(): Integer; + interface StringNodeProperties extends BaseNodeProperties{ + type:'string' + + regex:RegExp|{ + pattern:RegExp + invert:boolean + name:string + } + + /** + * Replace parts of the string + */ + replace:{ + /** + * RegExp pattern + */ + pattern:RegExp + + /** + * What should replace the pattern + */ + replace:string + } + + /** + * Should the string be in a valid email format + */ + email:boolean|{ + /** + * tld Domain whitelist (e.g ['com', 'fr']) + */ + tldWhitelist:string[] + } + } - /** - * Get a property for this node - * - * @param {String} property Name of property - * @param {or} default Default value to supply if none exists - * @return {mixed} - */ - get(property: string, or ?: U): U; + interface BaseRelationshipNodeProperties extends BaseNodeProperties{ + /** + * Neo4J Relationship name (e.g: ACTED_IN) + */ + relationship:string + + /** + * Target model name + */ + target:string + + /** + * Is the relation required to be fetch + */ + required?:boolean + + /** + * Load the relation with the parent object + */ + eager?:boolean + + /** + * Default value + */ + default?:any + + /** + * Relationship direction + */ + direction:Direction + + /** + * Behaviour when deleting the parent object + */ + cascade?:'detach'|'delete' + + /** + * Relationship attached properties + */ + properties?:{ + [index:string]:PropertyTypes + } + } - /** - * Get all properties for this node - * - * @return {Object} - */ - properties(): T; + interface RelationshipsNodeProperties extends BaseRelationshipNodeProperties{ + type:'relationships' + } - /** - * Update the properties of a node - * @param {Object} properties Updated properties - * @return {Promise} - */ - update(properties: T): Promise>; + interface RelationshipNodeProperties extends BaseRelationshipNodeProperties{ + type:'relationship' + } - /** - * Delete this node from the Graph - * - * @return {Promise} - */ - delete(): Promise>; + interface NodesNodeProperties extends BaseRelationshipNodeProperties{ + type:'nodes' + } - /** - * Relate this node to another based on the type - * - * @param {Node} node Node to relate to - * @param {String} type Type of Relationship definition - * @param {Object} properties Properties to set against the relationships - * @param {Boolean} force_create Force the creation a new relationship? If false, the relationship will be merged - * @return {Promise} - */ - relateTo(node: Node, type: string, properties ?: object, force_create ?: boolean): Promise; + interface NodeNodeProperties extends BaseRelationshipNodeProperties{ + type:'node' + } - /** - * When converting to string, return this model's primary key - * - * @return {String} - */ - toString(): string; + interface OtherNodeProperties extends BaseNodeProperties{ + type:PropertyTypes + } - /** - * Convert Node to Object - * - * @return {Promise} - */ - toJson(): Promise; - } + type NodeProperty = PropertyTypes + |NumberNodeProperties|IntNodeProperties|IntegerNodeProperties|FloatNodeProperties + |RelationshipNodeProperties|RelationshipsNodeProperties + |NodeNodeProperties|NodesNodeProperties + |StringNodeProperties|OtherNodeProperties; + + export type SchemaObject = { + [index:string]:NodeProperty + }; + + export type RelationshipSchema = { + [index:string]:BaseRelationshipNodeProperties + }; + + + type Mode = 'READ'|'WRITE'; + + class Builder{ + + constructor(neode:Neode); + + /** + * Start a new Query segment and set the current statement + * + * @return {Builder} + */ + statement(prefix:string):Builder; + + /** + * Start a new Where Segment + * + * @return {Builder} + */ + whereStatement(prefix:string):Builder; + + /** + * Match a Node by a definition + * + * @param {String} alias Alias in query + * @param {Model|String} model Model definition + * @return {Builder} Builder + */ + match(alias:string, model:Model|string):Builder; + + optionalMatch(alias:string, model:Model|string):Builder; + + /** + * Add a 'with' statement to the query + * + * @param {...String} args Variables/aliases to return + * @return {Builder} + */ + with(...args:Array):Builder; + + /** + * Create a new WhereSegment + * @param {...mixed} args + * @return {Builder} + */ + or(...args:Array):Builder; + + /** + * Add a where condition to the current statement. + * + * @param {...mixed} args Argumenta + * @return {Builder} + */ + where(...args:Array):Builder; + + /** + * Query on Internal ID + * + * @param {String} alias + * @param {Int} value + * @return {Builder} + */ + whereId(alias:string, value:number):Builder; + + /** + * Set Delete fields + * + * @param {...mixed} args + * @return {Builder} + */ + delete(...args:Array):Builder; + + /** + * Set Detach Delete fields + * + * @param {...mixed} args + * @return {Builder} + */ + detachDelete(...args:Array):Builder; + + /** + * Set Return fields + * + * @param {...mixed} args + * @return {Builder} + */ + return(...args:Array):Builder; + + /** + * Set Record Limit + * + * @param {Int} limit + * @return {Builder} + */ + limit(limit:number):Builder; + + /** + * Set Records to Skip + * + * @param {Int} skip + * @return {Builder} + */ + skip(skip:number):Builder; + + /** + * Add an order by statement + * + * @param {...String|object} args Order by statements + * @return {Builder} + */ + orderBy(...args:Array):Builder; + + /** + * Add a relationship to the query + * + * @param {String|RelationshipType} relationship Relationship name or RelationshipType object + * @param {String} direction Direction of relationship DIRECTION_IN, DIRECTION_OUT + * @param {String|null} alias Relationship alias + * @param {Int|String} traversals Number of traversals (1, "1..2", "0..2", "..3") + * @return {Builder} + */ + relationship(relationship:string|RelationshipType, direction:Neode.Direction, alias:string|null, traversals:number|string):Builder; + + /** + * Complete a relationship + * @param {String} alias Alias + * @param {Model|String} model Model definition + * @return {Builder} + */ + to(alias:string, model:Model|string):Builder; + + /** + * Complete the relationship statement to point to anything + * + * @return {Builder} + */ + toAnything():Builder; + + /** + * Build the Query + * + * @param {...String} output References to output + * @return {Object} Object containing `query` and `params` property + */ + build():{query:string, params:object}; + + /** + * Execute the query + * + * @return {Promise} + */ + execute(mode?:Mode):Promise; + } - class NodeCollection { + class Queryable{ + /** + * @constructor + * + * @param Neode neode + */ + constructor(neode:Neode); + + /** + * Return a new Query Builder + * + * @return {Builder} + */ + query():Builder; + + /** + * Create a new node + * + * @param {object} properties + * @return {Promise} + */ + create(properties:T):Promise>; + + /** + * Merge a node based on the defined indexes + * + * @param {Object} properties + * @return {Promise} + */ + merge(properties:T):Promise>; + + /** + * Merge a node based on the supplied properties + * + * @param {Object} match Specific properties to merge on + * @param {Object} set Properties to set + * @return {Promise} + */ + mergeOn(match:Object, set:Object):Promise>; + + /** + * Delete all nodes for this model + * + * @return {Promise} + */ + deleteAll():Promise; + + /** + * Get a collection of nodes for this label + * + * @param {Object} properties + * @param {String|Array|Object} order + * @param {Int} limit + * @param {Int} skip + * @return {Promise} + */ + all(properties?:object, order?:string|Array|object, limit?:number, skip?:number):Promise; + + /** + * Find a Node by its Primary Key + * + * @param {mixed} id + * @return {Promise} + */ + find(id:string|number):Promise>; + + /** + * Find a Node by it's internal node ID + * + * @param {int} id + * @return {Promise} + */ + findById(id:number):Promise>; + + /** + * Find a Node by properties + * + * @param {String} label + * @param {mixed} key Either a string for the property name or an object of values + * @param {mixed} value Value + * @return {Promise} + */ + first(key:string|object, value:string|number):Promise>; + + /** + * Get a collection of nodes within a certain distance belonging to this label + * + * @param {Object} properties + * @param {String} location_property + * @param {Object} point + * @param {Int} distance + * @param {String|Array|Object} order + * @param {Int} limit + * @param {Int} skip + * @return {Promise} + */ + withinDistance(location_property:string, point:{x:number, y:number, z?:number}|{latitude:number, longitude:number, height?:number}, distance:number, properties?:object, order?:string|Array|object, limit?:number, skip?:number):Promise; + } - /** - * @constructor - * @param {Neode} neode Neode Instance - * @param {Node[]} values Array of Node - * @return {Collectiob} - */ - constructor(neode: Neode, values: Array>); + class Model extends Queryable{ + constructor(neode:Neode, name:string, schema:Neode.SchemaObject); + + /** + * Get Model name + * + * @return {String} + */ + name():string; + + /** + * Get Schema + * + * @return {Object} + */ + schema():Neode.SchemaObject; + + /** + * Get a map of Properties + * + * @return {Map} + */ + properties():Map; + + /** + * Set Labels + * + * @param {...String} labels + * @return {Model} + */ + setLabels(...labels:Array):Model; + + /** + * Get Labels + * + * @return {Array} + */ + labels():Array; + + /** + * Add a property definition + * + * @param {String} key Property name + * @param {Object} schema Schema object + * @return {Model} + */ + addProperty(key:string, schema:Neode.SchemaObject):Model; + + /** + * Add a new relationship + * + * @param {String} name Reference of Relationship + * @param {String} type Internal Relationship type + * @param {String} relationship Internal Relationship name + * @param {String} direction Direction of Node (Use constants DIRECTION_IN, DIRECTION_OUT, DIRECTION_BOTH) + * @param {String|Model|null} target Target type definition for the + * @param {Object} schema Property Schema + * @param {Bool} eager Should this relationship be eager loaded? + * @param {Bool|String} cascade Cascade delete policy for this relationship + * @return {Relationship} + */ + relationship(name:string, type:string, relationship:string, direction?:Neode.Direction, target?:string|Model, schema?:Neode.SchemaObject, eager?:boolean, cascade?:boolean|string):Relationship + + + /** + * Get all defined Relationships for this Model + * + * @return {Map} + */ + relationships():Map; + + /** + * Get relationships defined as Eager relationships + * + * @return {Array} + */ + eager():Array; + + /** + * Get the name of the primary key + * + * @return {String} + */ + primaryKey():string; + + /** + * Get array of hidden fields + * + * @return {String[]} + */ + hidden():Array; + + /** + * Get defined merge fields + * + * @return {Array} + */ + mergeFields():Array; + } - /** - * Get length property - * - * @return {Int} - */ - length: number; + class Schema{ - /** - * Get a value by it's index - * - * @param {Int} index - * @return {Node} - */ - get(index: number): Node; + /** + * Neode will install the schema created by the constraints defined in your Node definitions. + * @return {Promise} + */ + install():Promise; - /** - * Get the first Node in the Collection - * - * @return {Node} - */ - first(): Node; + /** + * Dropping the schema will remove all indexes and constraints created by Neode. + * All other indexes and constraints will be left intact. + */ + drop():void; + } - /** - * Map a function to all values - * - * @param {Function} fn - * @return {mixed} - */ - map(fn: (value: Node, index: number, array: Array>) => U): Array; + class RelationshipType{ + + /** + * Constructor + * @param {String} type Reference of Relationship + * @param {String} relationship Internal Neo4j Relationship type (ie 'KNOWS') + * @param {String} direction Direction of Node (Use constants DIRECTION_IN, DIRECTION_OUT, DIRECTION_BOTH) + * @param {String|Model|null} target Target type definition for the + * @param {Object} schema Relationship definition schema + * @param {Bool} eager Should this relationship be eager loaded? + * @param {Bool|String} cascade Cascade delete policy for this relationship + * @return {Relationship} + */ + constructor(type:string, relationship:string, direction:Neode.Direction, target:string|Model|null, schema?:Neode.RelationshipSchema, eager?:boolean, cascade?:boolean|string); + + /** + * Type + * + * @return {String} + */ + type():string; + + /** + * Get Internal Relationship Type + * + * @return {String} + */ + relationship():string; + + /** + * Set Direction of relationship + * + * @return {RelationshipType} + */ + setDirection(direction:Neode.Direction):RelationshipType; + + /** + * Get Direction of Node + * + * @return {String} + */ + direction():Neode.Direction; + + /** + * Get the target node definition + * + * @return {Model} + */ + target():Model; + + /** + * Get Schema object + * + * @return {Object} + */ + schema():Neode.RelationshipSchema; + + /** + * Should this relationship be eagerly loaded? + * + * @return {bool} + */ + eager():boolean; + + /** + * Cascade policy for this relationship type + * + * @return {String} + */ + cascade():string; - /** - * Find node with function - * - * @param {Function} fn - * @return {mixed} - */ - find(fn: (value: Node, index: number, array: Array>) => U): Node; + } + class Relationship{ + + /** + * Constructor + * + * @param {Neode} neode Neode Instance + * @param {RelationshipType} type Relationship Type definition + * @param {Relationship} relationship Neo4j Relationship + * @param {Node} from Start node for the relationship + * @param {Node} to End node for the relationship + * @return {Relationship} + */ + constructor(neode:Neode, type:RelationshipType, relationship:Relationship, from:Node, to:Node); + + /** + * Relationship Type definition for this node + * + * @return {RelationshipType} + */ + type():RelationshipType; + + /** + * Get Internal Relationship ID + * + * @return {int} + */ + id():number; + + /** + * Return Internal Relationship ID as Neo4j Integer + * + * @return {Integer} + */ + idInt():Integer; + + /** + * Get Properties for this Relationship + * + * @return {Object} + */ + properties():object; + + /** + * Get a property for this relationship + * + * @param {String} property Name of property + * @param {or} default Default value to supply if none exists + * @return {mixed} + */ + get(property:string, or?:T):T; + + /** + * Get originating node for this relationship + * + * @return Node + */ + startNode():Node; + + /** + * Get destination node for this relationship + * + * @return Node + */ + endNode():Node; + + /** + * Convert Relationship to Object + * + * @return {Promise} + */ + toJson():Promise; + } - /** - * Run a function on all values - * @param {Function} fn - * @return {mixed} - */ - forEach(fn: (value: Node, index: number, array: Array>) => any): any; + class Node{ + /** + * @constructor + * + * @param {Neode} neode Neode Instance + * @param {Model} model Model definition + * @param {node} node Node Object from neo4j-driver + * @param {Map} eager Eagerly loaded values + * @return {Node} + */ + constructor(neode:Neode, model:Model, node:Neo4jNode, eager?:Map); + + /** + * Model definition for this node + * + * @return {Model} + */ + model():Model; + + /** + * Get Internal Node ID + * + * @return {int} + */ + id():number; + + /** + * Return Internal Node ID as Neo4j Integer + * + * @return {Integer} + */ + idInt():Integer; + + /** + * Get a property for this node + * + * @param {String} property Name of property + * @param {or} default Default value to supply if none exists + * @return {mixed} + */ + get(property:string, or ?:U):U; + + /** + * Get all properties for this node + * + * @return {Object} + */ + properties():T; + + /** + * Update the properties of a node + * @param {Object} properties Updated properties + * @return {Promise} + */ + update(properties:T):Promise>; + + /** + * Delete this node from the Graph + * + * @return {Promise} + */ + delete():Promise>; + + /** + * Relate this node to another based on the type + * + * @param {Node} node Node to relate to + * @param {String} type Type of Relationship definition + * @param {Object} properties Properties to set against the relationships + * @param {Boolean} force_create Force the creation a new relationship? If false, the relationship will be merged + * @return {Promise} + */ + relateTo(node:Node, type:string, properties ?:object, force_create ?:boolean):Promise; + + /** + * When converting to string, return this model's primary key + * + * @return {String} + */ + toString():string; + + /** + * Convert Node to Object + * + * @return {Promise} + */ + toJson():Promise; + } - /** - * Map the 'toJson' function on all values - * - * @return {Promise} - */ - toJson():Promise; + class NodeCollection{ + + /** + * @constructor + * @param {Neode} neode Neode Instance + * @param {Node[]} values Array of Node + * @return {Collectiob} + */ + constructor(neode:Neode, values:Array>); + + /** + * Get length property + * + * @return {Int} + */ + length:number; + + /** + * Get a value by it's index + * + * @param {Int} index + * @return {Node} + */ + get(index:number):Node; + + /** + * Get the first Node in the Collection + * + * @return {Node} + */ + first():Node; + + /** + * Map a function to all values + * + * @param {Function} fn + * @return {mixed} + */ + map(fn:(value:Node, index:number, array:Array>) => U):Array; + + /** + * Find node with function + * + * @param {Function} fn + * @return {mixed} + */ + find(fn:(value:Node, index:number, array:Array>) => U):Node; + + + /** + * Run a function on all values + * @param {Function} fn + * @return {mixed} + */ + forEach(fn:(value:Node, index:number, array:Array>) => any):any; + + /** + * Map the 'toJson' function on all values + * + * @return {Promise} + */ + toJson():Promise; - } + } }