text: "use strict";
  /**
   * Copyright (c) "Neo4j"
   * Neo4j Sweden AB [http://neo4j.com]
   *
   * This file is part of Neo4j.
   *
   * Licensed 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.
   */
  var __importDefault = (this && this.__importDefault) || function (mod) {
      return (mod && mod.__esModule) ? mod : { "default": mod };
  };
  Object.defineProperty(exports, "__esModule", { value: true });
  var result_summary_1 = __importDefault(require("./result-summary"));
  var internal_1 = require("./internal");
  var EMPTY_CONNECTION_HOLDER = internal_1.connectionHolder.EMPTY_CONNECTION_HOLDER;
  /**
   * @private
   * @param {Error} error The error
   * @returns {void}
   */
  var DEFAULT_ON_ERROR = function (error) {
      console.log('Uncaught error when processing result: ' + error);
  };
  /**
   * @private
   * @param {ResultSummary} summary
   * @returns {void}
   */
  var DEFAULT_ON_COMPLETED = function (summary) { };
  /**
   * A stream of {@link Record} representing the result of a query.
   * Can be consumed eagerly as {@link Promise} resolved with array of records and {@link ResultSummary}
   * summary, or rejected with error that contains {@link string} code and {@link string} message.
   * Alternatively can be consumed lazily using {@link Result#subscribe} function.
   * @access public
   */
  var Result = /** @class */ (function () {
      /**
       * Inject the observer to be used.
       * @constructor
       * @access private
       * @param {Promise<observer.ResultStreamObserver>} streamObserverPromise
       * @param {mixed} query - Cypher query to execute
       * @param {Object} parameters - Map with parameters to use in query
       * @param {ConnectionHolder} connectionHolder - to be notified when result is either fully consumed or error happened.
       */
      function Result(streamObserverPromise, query, parameters, connectionHolder) {
          this._stack = captureStacktrace();
          this._streamObserverPromise = streamObserverPromise;
          this._p = null;
          this._query = query;
          this._parameters = parameters || {};
          this._connectionHolder = connectionHolder || EMPTY_CONNECTION_HOLDER;
      }
      /**
       * Returns a promise for the field keys.
       *
       * *Should not be combined with {@link Result#subscribe} function.*
       *
       * @public
       * @returns {Promise<string[]>} - Field keys, in the order they will appear in records.
       }
       */
      Result.prototype.keys = function () {
          var _this = this;
          return new Promise(function (resolve, reject) {
              _this._streamObserverPromise
                  .then(function (observer) {
                  return observer.subscribe({
                      onKeys: function (keys) { return resolve(keys); },
                      onError: function (err) { return reject(err); }
                  });
              })
                  .catch(reject);
          });
      };
      /**
       * Returns a promise for the result summary.
       *
       * *Should not be combined with {@link Result#subscribe} function.*
       *
       * @public
       * @returns {Promise<ResultSummary>} - Result summary.
       *
       */
      Result.prototype.summary = function () {
          var _this = this;
          return new Promise(function (resolve, reject) {
              _this._streamObserverPromise
                  .then(function (o) {
                  o.cancel();
                  o.subscribe({
                      onCompleted: function (metadata) {
                          return _this._createSummary(metadata).then(resolve, reject);
                      },
                      onError: function (err) { return reject(err); }
                  });
              })
                  .catch(reject);
          });
      };
      /**
       * Create and return new Promise
       *
       * @private
       * @return {Promise} new Promise.
       */
      Result.prototype._getOrCreatePromise = function () {
          var _this = this;
          if (!this._p) {
              this._p = new Promise(function (resolve, reject) {
                  var records = [];
                  var observer = {
                      onNext: function (record) {
                          records.push(record);
                      },
                      onCompleted: function (summary) {
                          resolve({ records: records, summary: summary });
                      },
                      onError: function (error) {
                          reject(error);
                      }
                  };
                  _this.subscribe(observer);
              });
          }
          return this._p;
      };
      /**
       * Waits for all results and calls the passed in function with the results.
       *
       * *Should not be combined with {@link Result#subscribe} function.*
       *
       * @param {function(result: {records:Array<Record>, summary: ResultSummary})} onFulfilled - function to be called
       * when finished.
       * @param {function(error: {message:string, code:string})} onRejected - function to be called upon errors.
       * @return {Promise} promise.
       */
      Result.prototype.then = function (onFulfilled, onRejected) {
          return this._getOrCreatePromise().then(onFulfilled, onRejected);
      };
      /**
       * Catch errors when using promises.
       *
       * *Should not be combined with {@link Result#subscribe} function.*
       *
       * @param {function(error: Neo4jError)} onRejected - Function to be called upon errors.
       * @return {Promise} promise.
       */
      Result.prototype.catch = function (onRejected) {
          return this._getOrCreatePromise().catch(onRejected);
      };
      Result.prototype.finally = function (onfinally) {
          return this._getOrCreatePromise().finally(onfinally);
      };
      /**
       * Stream records to observer as they come in, this is a more efficient method
       * of handling the results, and allows you to handle arbitrarily large results.
       *
       * @param {Object} observer - Observer object
       * @param {function(keys: string[])} observer.onKeys - handle stream head, the field keys.
       * @param {function(record: Record)} observer.onNext - handle records, one by one.
       * @param {function(summary: ResultSummary)} observer.onCompleted - handle stream tail, the result summary.
       * @param {function(error: {message:string, code:string})} observer.onError - handle errors.
       * @return {void}
       */
      Result.prototype.subscribe = function (observer) {
          var _this = this;
          var onCompletedOriginal = observer.onCompleted || DEFAULT_ON_COMPLETED;
          var onCompletedWrapper = function (metadata) {
              _this._createSummary(metadata).then(function (summary) {
                  return onCompletedOriginal.call(observer, summary);
              });
          };
          observer.onCompleted = onCompletedWrapper;
          var onErrorOriginal = observer.onError || DEFAULT_ON_ERROR;
          var onErrorWrapper = function (error) {
              // notify connection holder that the used connection is not needed any more because error happened
              // and result can't bee consumed any further; call the original onError callback after that
              _this._connectionHolder.releaseConnection().then(function () {
                  replaceStacktrace(error, _this._stack);
                  onErrorOriginal.call(observer, error);
              });
          };
          observer.onError = onErrorWrapper;
          this._streamObserverPromise
              .then(function (o) {
              return o.subscribe(observer);
          })
              .catch(function (error) { return observer.onError(error); });
      };
      /**
       * Signals the stream observer that the future records should be discarded on the server.
       *
       * @protected
       * @since 4.0.0
       * @returns {void}
       */
      Result.prototype._cancel = function () {
          this._streamObserverPromise.then(function (o) { return o.cancel(); });
      };
      Result.prototype._createSummary = function (metadata) {
          var _a = internal_1.util.validateQueryAndParameters(this._query, this._parameters, {
              skipAsserts: true
          }), query = _a.validatedQuery, parameters = _a.params;
          var connectionHolder = this._connectionHolder;
          return connectionHolder
              .getConnection()
              .then(
          // onFulfilled:
          function (connection) {
              return connectionHolder
                  .releaseConnection()
                  .then(function () {
                  return connection ? connection.protocol().version : undefined;
              });
          }, 
          // onRejected:
          function (_) { return undefined; })
              .then(function (protocolVersion) {
              return new result_summary_1.default(query, parameters, metadata, protocolVersion);
          });
      };
      return Result;
  }());
  Symbol.toStringTag;
  function captureStacktrace() {
      var error = new Error('');
      if (error.stack) {
          return error.stack.replace(/^Error(\n\r)*/, ''); // we don't need the 'Error\n' part, if only it exists
      }
      return null;
  }
  /**
   * @private
   * @param {Error} error The error
   * @param {string| null} newStack The newStack
   * @returns {void}
   */
  function replaceStacktrace(error, newStack) {
      if (newStack) {
          // Error.prototype.toString() concatenates error.name and error.message nicely
          // then we add the rest of the stack trace
          error.stack = error.toString() + '\n' + newStack;
      }
  }
  exports.default = Result;
  