jsforce
Version:
Salesforce API Library for JavaScript
1,276 lines (1,265 loc) • 150 kB
JavaScript
import _Reflect$construct from "@babel/runtime-corejs3/core-js-stable/reflect/construct";
import _Object$getOwnPropertySymbols from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols";
import _filterInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/filter";
import _Object$getOwnPropertyDescriptor from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor";
import _forEachInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/for-each";
import _Object$getOwnPropertyDescriptors from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors";
import _Object$defineProperties from "@babel/runtime-corejs3/core-js-stable/object/define-properties";
import _Object$defineProperty from "@babel/runtime-corejs3/core-js-stable/object/define-property";
import _sliceInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/slice";
import _Array$from from "@babel/runtime-corejs3/core-js-stable/array/from";
import _Symbol from "@babel/runtime-corejs3/core-js-stable/symbol";
import _getIteratorMethod from "@babel/runtime-corejs3/core-js/get-iterator-method";
import _slicedToArray from "@babel/runtime-corejs3/helpers/slicedToArray";
import _objectWithoutProperties from "@babel/runtime-corejs3/helpers/objectWithoutProperties";
import _asyncToGenerator from "@babel/runtime-corejs3/helpers/asyncToGenerator";
import _defineProperty from "@babel/runtime-corejs3/helpers/defineProperty";
import _typeof from "@babel/runtime-corejs3/helpers/typeof";
import _createClass from "@babel/runtime-corejs3/helpers/createClass";
import _classCallCheck from "@babel/runtime-corejs3/helpers/classCallCheck";
import _possibleConstructorReturn from "@babel/runtime-corejs3/helpers/possibleConstructorReturn";
import _getPrototypeOf from "@babel/runtime-corejs3/helpers/getPrototypeOf";
import _inherits from "@babel/runtime-corejs3/helpers/inherits";
import _wrapNativeSuper from "@babel/runtime-corejs3/helpers/wrapNativeSuper";
var _excluded = ["pollInterval", "pollTimeout", "input"],
_excluded2 = ["Id", "type", "attributes"];
function _createForOfIteratorHelper(r, e) { var t = "undefined" != typeof _Symbol && _getIteratorMethod(r) || r["@@iterator"]; if (!t) { if (_Array$isArray(r) || (t = _unsupportedIterableToArray(r)) || e && r && "number" == typeof r.length) { t && (r = t); var _n = 0, F = function F() {}; return { s: F, n: function n() { return _n >= r.length ? { done: !0 } : { done: !1, value: r[_n++] }; }, e: function e(r) { throw r; }, 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 o, a = !0, u = !1; return { s: function s() { t = t.call(r); }, n: function n() { var r = t.next(); return a = r.done, r; }, e: function e(r) { u = !0, o = r; }, f: function f() { try { a || null == t.return || t.return(); } finally { if (u) throw o; } } }; }
function _unsupportedIterableToArray(r, a) { if (r) { var _context29; if ("string" == typeof r) return _arrayLikeToArray(r, a); var t = _sliceInstanceProperty(_context29 = {}.toString.call(r)).call(_context29, 8, -1); return "Object" === t && r.constructor && (t = r.constructor.name), "Map" === t || "Set" === t ? _Array$from(r) : "Arguments" === t || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(t) ? _arrayLikeToArray(r, a) : void 0; } }
function _arrayLikeToArray(r, a) { (null == a || a > r.length) && (a = r.length); for (var e = 0, n = Array(a); e < a; e++) n[e] = r[e]; return n; }
function ownKeys(e, r) { var t = _Object$keys2(e); if (_Object$getOwnPropertySymbols) { var o = _Object$getOwnPropertySymbols(e); r && (o = _filterInstanceProperty(o).call(o, function (r) { return _Object$getOwnPropertyDescriptor(e, r).enumerable; })), t.push.apply(t, o); } return t; }
function _objectSpread(e) { for (var r = 1; r < arguments.length; r++) { var _context27, _context28; var t = null != arguments[r] ? arguments[r] : {}; r % 2 ? _forEachInstanceProperty(_context27 = ownKeys(Object(t), !0)).call(_context27, function (r) { _defineProperty(e, r, t[r]); }) : _Object$getOwnPropertyDescriptors ? _Object$defineProperties(e, _Object$getOwnPropertyDescriptors(t)) : _forEachInstanceProperty(_context28 = ownKeys(Object(t))).call(_context28, function (r) { _Object$defineProperty(e, r, _Object$getOwnPropertyDescriptor(t, r)); }); } return e; }
import _regeneratorRuntime from "@babel/runtime-corejs3/regenerator";
import _Array$isArray from "@babel/runtime-corejs3/core-js-stable/array/is-array";
import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes";
import _JSON$stringify from "@babel/runtime-corejs3/core-js-stable/json/stringify";
import _Date$now from "@babel/runtime-corejs3/core-js-stable/date/now";
import _concatInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/concat";
import _URL from "@babel/runtime-corejs3/core-js-stable/url";
import _Promise from "@babel/runtime-corejs3/core-js-stable/promise";
import _Object$keys2 from "@babel/runtime-corejs3/core-js-stable/object/keys";
import _setTimeout from "@babel/runtime-corejs3/core-js-stable/set-timeout";
import "core-js/modules/es.error.cause.js";
import "core-js/modules/es.array.iterator.js";
import "core-js/modules/es.array.push.js";
import "core-js/modules/es.function.name.js";
import "core-js/modules/es.map.js";
import "core-js/modules/es.object.keys.js";
import "core-js/modules/es.object.to-string.js";
import "core-js/modules/es.regexp.exec.js";
import "core-js/modules/es.regexp.test.js";
import "core-js/modules/es.regexp.to-string.js";
import "core-js/modules/es.set.js";
import "core-js/modules/web.dom-exception.constructor.js";
import "core-js/modules/web.dom-exception.stack.js";
import "core-js/modules/web.dom-exception.to-string-tag.js";
import "core-js/modules/web.structured-clone.js";
function _callSuper(t, o, e) { return o = _getPrototypeOf(o), _possibleConstructorReturn(t, _isNativeReflectConstruct() ? _Reflect$construct(o, e || [], _getPrototypeOf(t).constructor) : o.apply(t, e)); }
function _isNativeReflectConstruct() { try { var t = !Boolean.prototype.valueOf.call(_Reflect$construct(Boolean, [], function () {})); } catch (t) {} return (_isNativeReflectConstruct = function _isNativeReflectConstruct() { return !!t; })(); }
import { EventEmitter } from 'events';
import { Writable } from 'stream';
import { Serializable, Parsable } from '../record-stream';
import HttpApi from '../http-api';
import { registerModule } from '../jsforce';
import { getLogger } from '../util/logger';
import { concatStreamsAsDuplex } from '../util/stream';
import is from '@sindresorhus/is';
var JobPollingTimeoutError = /*#__PURE__*/function (_Error) {
/**
*
*/
function JobPollingTimeoutError(message, jobId) {
var _this;
_classCallCheck(this, JobPollingTimeoutError);
_this = _callSuper(this, JobPollingTimeoutError, [message]);
_this.name = 'JobPollingTimeout';
_this.jobId = jobId;
return _this;
}
_inherits(JobPollingTimeoutError, _Error);
return _createClass(JobPollingTimeoutError);
}(/*#__PURE__*/_wrapNativeSuper(Error));
var BulkApiV2 = /*#__PURE__*/function (_HttpApi) {
function BulkApiV2() {
_classCallCheck(this, BulkApiV2);
return _callSuper(this, BulkApiV2, arguments);
}
_inherits(BulkApiV2, _HttpApi);
return _createClass(BulkApiV2, [{
key: "hasErrorInResponseBody",
value: function hasErrorInResponseBody(body) {
return _Array$isArray(body) && _typeof(body[0]) === 'object' && 'errorCode' in body[0];
}
}, {
key: "isSessionExpired",
value: function isSessionExpired(response) {
var _context;
return response.statusCode === 401 && _includesInstanceProperty(_context = response.body).call(_context, 'INVALID_SESSION_ID');
}
}, {
key: "parseError",
value: function parseError(body) {
return {
errorCode: body[0].errorCode,
message: body[0].message
};
}
}]);
}(HttpApi);
export var BulkV2 = /*#__PURE__*/function () {
function BulkV2(connection) {
_classCallCheck(this, BulkV2);
/**
* Polling interval in milliseconds
*
* Default: 1000 (1 second)
*/
_defineProperty(this, "pollInterval", 1000);
/**
* Polling timeout in milliseconds
*
* Default: 30000 (30 seconds)
*/
_defineProperty(this, "pollTimeout", 30000);
this.connection = connection;
this.logger = this.connection._logLevel ? getLogger('bulk2').createInstance(this.connection._logLevel) : getLogger('bulk2');
}
/**
* Create an instance of an ingest job object.
*
* @params {NewIngestJobOptions} options object
* @returns {IngestJobV2} An ingest job instance
* @example
* // Upsert records to the Account object.
*
* const job = connection.bulk2.createJob({
* operation: 'insert'
* object: 'Account',
* });
*
* // create the job in the org
* await job.open()
*
* // upload data
* await job.uploadData(csvFile)
*
* // finished uploading data, mark it as ready for processing
* await job.close()
*/
return _createClass(BulkV2, [{
key: "createJob",
value: function createJob(options) {
return new IngestJobV2(this.connection, {
bodyParams: options,
pollingOptions: this
});
}
/**
* Get an ingest or query job instance specified by a given job ID
*
* @param options Options object with a job ID
* @returns IngestJobV2 An ingest job
*/
}, {
key: "job",
value: function job() {
var type = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'ingest';
var options = arguments.length > 1 ? arguments[1] : undefined;
if (type === 'ingest') {
return new IngestJobV2(this.connection, {
id: options.id,
pollingOptions: this
});
} else {
return new QueryJobV2(this.connection, {
id: options.id,
pollingOptions: this
});
}
}
/**
* Create, upload, and start bulkload job
*/
}, {
key: "loadAndWaitForResults",
value: (function () {
var _loadAndWaitForResults = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee(options) {
var pollInterval, pollTimeout, input, createJobOpts, job, err;
return _regeneratorRuntime.wrap(function _callee$(_context2) {
while (1) switch (_context2.prev = _context2.next) {
case 0:
if (!options.pollTimeout) options.pollTimeout = this.pollTimeout;
if (!options.pollInterval) options.pollInterval = this.pollInterval;
pollInterval = options.pollInterval, pollTimeout = options.pollTimeout, input = options.input, createJobOpts = _objectWithoutProperties(options, _excluded);
job = this.createJob(createJobOpts);
_context2.prev = 4;
_context2.next = 7;
return job.open();
case 7:
_context2.next = 9;
return job.uploadData(input);
case 9:
_context2.next = 11;
return job.close();
case 11:
_context2.next = 13;
return job.poll(pollInterval, pollTimeout);
case 13:
_context2.next = 15;
return job.getAllResults();
case 15:
return _context2.abrupt("return", _context2.sent);
case 18:
_context2.prev = 18;
_context2.t0 = _context2["catch"](4);
err = _context2.t0;
this.logger.error("bulk load failed due to: ".concat(err.message));
if (err.name !== 'JobPollingTimeoutError') {
// fires off one last attempt to clean up and ignores the result | error
job.delete().catch(function (ignored) {
return ignored;
});
}
throw err;
case 24:
case "end":
return _context2.stop();
}
}, _callee, this, [[4, 18]]);
}));
function loadAndWaitForResults(_x) {
return _loadAndWaitForResults.apply(this, arguments);
}
return loadAndWaitForResults;
}()
/**
* Execute bulk query and get a record stream.
*
* Default timeout: 10000ms
*
* @param soql SOQL query
* @param options
*
* @returns {RecordStream} - Record stream, convertible to a CSV data stream
*/
)
}, {
key: "query",
value: (function () {
var _query = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee2(soql, options) {
var queryJob, recordStream, dataStream, queryRecordsStream, err;
return _regeneratorRuntime.wrap(function _callee2$(_context3) {
while (1) switch (_context3.prev = _context3.next) {
case 0:
queryJob = new QueryJobV2(this.connection, {
bodyParams: {
query: soql,
operation: options !== null && options !== void 0 && options.scanAll ? 'queryAll' : 'query',
columnDelimiter: options === null || options === void 0 ? void 0 : options.columnDelimiter,
lineEnding: options === null || options === void 0 ? void 0 : options.lineEnding
},
pollingOptions: this
});
recordStream = new Parsable();
dataStream = recordStream.stream('csv');
_context3.prev = 3;
_context3.next = 6;
return queryJob.open();
case 6:
_context3.next = 8;
return queryJob.poll(options === null || options === void 0 ? void 0 : options.pollInterval, options === null || options === void 0 ? void 0 : options.pollTimeout);
case 8:
_context3.next = 10;
return queryJob.result().then(function (s) {
return s.stream();
});
case 10:
queryRecordsStream = _context3.sent;
queryRecordsStream.pipe(dataStream);
_context3.next = 20;
break;
case 14:
_context3.prev = 14;
_context3.t0 = _context3["catch"](3);
err = _context3.t0;
this.logger.error("bulk query failed due to: ".concat(err.message));
if (err.name !== 'JobPollingTimeoutError') {
// fires off one last attempt to clean up and ignores the result | error
queryJob.delete().catch(function (ignored) {
return ignored;
});
}
throw err;
case 20:
return _context3.abrupt("return", recordStream);
case 21:
case "end":
return _context3.stop();
}
}, _callee2, this, [[3, 14]]);
}));
function query(_x2, _x3) {
return _query.apply(this, arguments);
}
return query;
}())
}]);
}();
export var QueryJobV2 = /*#__PURE__*/function (_EventEmitter) {
function QueryJobV2(conn, options) {
var _this2;
_classCallCheck(this, QueryJobV2);
_this2 = _callSuper(this, QueryJobV2);
_this2.connection = conn;
_this2.logger = _this2.connection._logLevel ? getLogger('bulk2:QueryJobV2').createInstance(_this2.connection._logLevel) : getLogger('bulk2:QueryJobV2');
if ('id' in options) {
_this2._id = options.id;
} else {
_this2.bodyParams = options.bodyParams;
}
_this2.pollingOptions = options.pollingOptions;
// default error handler to keep the latest error
_this2.on('error', function (error) {
return _this2.error = error;
});
return _this2;
}
/**
* Get the query job ID.
*
* @returns {string} query job Id.
*/
_inherits(QueryJobV2, _EventEmitter);
return _createClass(QueryJobV2, [{
key: "id",
get: function get() {
return this.jobInfo ? this.jobInfo.id : this._id;
}
/**
* Get the query job info.
*
* @returns {Promise<QueryJobInfoV2>} query job information.
*/
}, {
key: "getInfo",
value: function getInfo() {
if (this.jobInfo) {
return this.jobInfo;
}
throw new Error('No internal job info. Make sure to call `await job.check`.');
}
/**
* Creates a query job
*
* @returns {Promise<QueryJobInfoV2>} job information.
*/
}, {
key: "open",
value: (function () {
var _open = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
return _regeneratorRuntime.wrap(function _callee3$(_context4) {
while (1) switch (_context4.prev = _context4.next) {
case 0:
if (this.bodyParams) {
_context4.next = 2;
break;
}
throw new Error('Missing required body params to open a new query job.');
case 2:
_context4.prev = 2;
_context4.next = 5;
return this.createQueryRequest({
method: 'POST',
body: _JSON$stringify(this.bodyParams),
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
responseType: 'application/json'
});
case 5:
this.jobInfo = _context4.sent;
this.logger.debug("Successfully created job ".concat(this.id));
this.emit('open', this.jobInfo);
_context4.next = 14;
break;
case 10:
_context4.prev = 10;
_context4.t0 = _context4["catch"](2);
this.emit('error', _context4.t0);
throw _context4.t0;
case 14:
return _context4.abrupt("return", this.jobInfo);
case 15:
case "end":
return _context4.stop();
}
}, _callee3, this, [[2, 10]]);
}));
function open() {
return _open.apply(this, arguments);
}
return open;
}()
/**
* Abort the job
*
* The 'aborted' event is emitted when the job successfully aborts.
* @returns {Promise<QueryJobInfoV2>} job information.
*/
)
}, {
key: "abort",
value: (function () {
var _abort = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee4() {
var state;
return _regeneratorRuntime.wrap(function _callee4$(_context5) {
while (1) switch (_context5.prev = _context5.next) {
case 0:
_context5.prev = 0;
state = 'Aborted';
_context5.next = 4;
return this.createQueryRequest({
method: 'PATCH',
path: "/".concat(this.id),
body: _JSON$stringify({
state: state
}),
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
responseType: 'application/json'
});
case 4:
this.jobInfo = _context5.sent;
this.logger.debug("Successfully aborted job ".concat(this.id));
return _context5.abrupt("return", this.jobInfo);
case 9:
_context5.prev = 9;
_context5.t0 = _context5["catch"](0);
this.emit('error', _context5.t0);
throw _context5.t0;
case 13:
case "end":
return _context5.stop();
}
}, _callee4, this, [[0, 9]]);
}));
function abort() {
return _abort.apply(this, arguments);
}
return abort;
}()
/**
* Poll for the state of the processing for the job.
*
* @param interval Polling interval in milliseconds
* @param timeout Polling timeout in milliseconds
* @returns {Promise<Record[]>} A promise that resolves when the job finished being processed.
*/
)
}, {
key: "poll",
value: (function () {
var _poll = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee5() {
var _context6, _context7;
var interval,
timeout,
jobId,
startTime,
endTime,
res,
timeoutError,
_args5 = arguments;
return _regeneratorRuntime.wrap(function _callee5$(_context8) {
while (1) switch (_context8.prev = _context8.next) {
case 0:
interval = _args5.length > 0 && _args5[0] !== undefined ? _args5[0] : this.pollingOptions.pollInterval;
timeout = _args5.length > 1 && _args5[1] !== undefined ? _args5[1] : this.pollingOptions.pollTimeout;
jobId = this.id;
startTime = _Date$now();
endTime = startTime + timeout;
this.logger.debug('Start polling for job status');
this.logger.debug(_concatInstanceProperty(_context6 = "Polling options: timeout:".concat(timeout, "ms | interval: ")).call(_context6, interval, "ms."));
if (!(timeout === 0)) {
_context8.next = 9;
break;
}
throw new JobPollingTimeoutError("Skipping polling because of timeout = 0ms. Job Id = ".concat(jobId), jobId);
case 9:
if (!(endTime > _Date$now())) {
_context8.next = 35;
break;
}
_context8.prev = 10;
_context8.next = 13;
return this.check();
case 13:
res = _context8.sent;
_context8.t0 = res.state;
_context8.next = _context8.t0 === 'Aborted' ? 17 : _context8.t0 === 'UploadComplete' ? 18 : _context8.t0 === 'InProgress' ? 18 : _context8.t0 === 'Failed' ? 22 : _context8.t0 === 'JobComplete' ? 24 : 27;
break;
case 17:
throw new Error('Job has been aborted');
case 18:
this.emit('inProgress', res);
_context8.next = 21;
return delay(interval);
case 21:
return _context8.abrupt("break", 27);
case 22:
// unlike ingest jobs, the API doesn't return an error msg:
// https://developer.salesforce.com/docs/atlas.en-us.api_asynch.meta/api_asynch/query_get_one_job.htm
this.logger.debug(res);
throw new Error('Query job failed to complete');
case 24:
this.logger.debug("Job ".concat(this.id, " was successfully processed."));
this.emit('jobComplete', res);
return _context8.abrupt("return");
case 27:
_context8.next = 33;
break;
case 29:
_context8.prev = 29;
_context8.t1 = _context8["catch"](10);
this.emit('error', _context8.t1);
throw _context8.t1;
case 33:
_context8.next = 9;
break;
case 35:
timeoutError = new JobPollingTimeoutError(_concatInstanceProperty(_context7 = "Polling timed out after ".concat(timeout, "ms. Job Id = ")).call(_context7, jobId), jobId);
this.emit('error', timeoutError);
throw timeoutError;
case 38:
case "end":
return _context8.stop();
}
}, _callee5, this, [[10, 29]]);
}));
function poll() {
return _poll.apply(this, arguments);
}
return poll;
}()
/**
* Check the latest job status
*
* @returns {Promise<QueryJobInfoV2>} job information.
*/
)
}, {
key: "check",
value: (function () {
var _check = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee6() {
var jobInfo;
return _regeneratorRuntime.wrap(function _callee6$(_context9) {
while (1) switch (_context9.prev = _context9.next) {
case 0:
_context9.prev = 0;
_context9.next = 3;
return this.createQueryRequest({
method: 'GET',
path: "/".concat(this.id),
responseType: 'application/json'
});
case 3:
jobInfo = _context9.sent;
this.jobInfo = jobInfo;
return _context9.abrupt("return", jobInfo);
case 8:
_context9.prev = 8;
_context9.t0 = _context9["catch"](0);
this.emit('error', _context9.t0);
throw _context9.t0;
case 12:
case "end":
return _context9.stop();
}
}, _callee6, this, [[0, 8]]);
}));
function check() {
return _check.apply(this, arguments);
}
return check;
}()
/**
* Get the results for a query job as a record stream
*
* This method assumes the job finished being processed
* @returns {RecordStream} - Record stream, convertible to a CSV data stream
*/
)
}, {
key: "result",
value: (function () {
var _result = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee7() {
var resultStream, resultDataStream, resultsPath, _context10, resPromise;
return _regeneratorRuntime.wrap(function _callee7$(_context11) {
while (1) switch (_context11.prev = _context11.next) {
case 0:
resultStream = new Parsable();
resultDataStream = resultStream.stream('csv');
resultsPath = "/".concat(this.id, "/results");
case 3:
if (!(this.locator !== 'null')) {
_context11.next = 10;
break;
}
resPromise = this.createQueryRequest({
method: 'GET',
path: this.locator
// resultsPath starts with '/'
? _concatInstanceProperty(_context10 = "".concat(resultsPath, "?locator=")).call(_context10, this.locator) : resultsPath,
headers: {
Accept: 'text/csv'
}
});
resPromise.stream().pipe(resultDataStream);
_context11.next = 8;
return resPromise;
case 8:
_context11.next = 3;
break;
case 10:
return _context11.abrupt("return", resultStream);
case 11:
case "end":
return _context11.stop();
}
}, _callee7, this);
}));
function result() {
return _result.apply(this, arguments);
}
return result;
}()
/**
* Deletes a query job.
*/
)
}, {
key: "delete",
value: (function () {
var _delete2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee8() {
return _regeneratorRuntime.wrap(function _callee8$(_context12) {
while (1) switch (_context12.prev = _context12.next) {
case 0:
return _context12.abrupt("return", this.createQueryRequest({
method: 'DELETE',
path: "/".concat(this.id)
}));
case 1:
case "end":
return _context12.stop();
}
}, _callee8, this);
}));
function _delete() {
return _delete2.apply(this, arguments);
}
return _delete;
}())
}, {
key: "createQueryRequest",
value: function createQueryRequest(request) {
var _this3 = this;
var path = request.path,
responseType = request.responseType;
var basePath = "services/data/v".concat(this.connection.version, "/jobs/query");
var url = new _URL(path ? basePath + path : basePath, this.connection.instanceUrl).toString();
var httpApi = new BulkApiV2(this.connection, {
responseType: responseType
});
httpApi.on('response', function (response) {
_this3.locator = response.headers['sforce-locator'];
_this3.logger.debug("sforce-locator: ".concat(_this3.locator));
});
return httpApi.request(_objectSpread(_objectSpread({}, request), {}, {
url: url
}));
}
}]);
}(EventEmitter);
/**
* Class for Bulk API V2 Ingest Job
*/
export var IngestJobV2 = /*#__PURE__*/function (_EventEmitter2) {
/**
*
*/
function IngestJobV2(conn, options) {
var _this4;
_classCallCheck(this, IngestJobV2);
_this4 = _callSuper(this, IngestJobV2);
_this4.connection = conn;
_this4.logger = _this4.connection._logLevel ? getLogger('bulk2:IngestJobV2').createInstance(_this4.connection._logLevel) : getLogger('bulk2:IngestJobV2');
_this4.pollingOptions = options.pollingOptions;
if ('id' in options) {
_this4._id = options.id;
} else {
_this4.bodyParams = options.bodyParams;
}
_this4.jobData = new JobDataV2({
createRequest: function createRequest(request) {
return _this4.createIngestRequest(request);
},
job: _this4
});
// default error handler to keep the latest error
_this4.on('error', function (error) {
return _this4.error = error;
});
return _this4;
}
/**
* Get the query job ID.
*
* @returns {string} query job Id.
*/
_inherits(IngestJobV2, _EventEmitter2);
return _createClass(IngestJobV2, [{
key: "id",
get: function get() {
return this.jobInfo ? this.jobInfo.id : this._id;
}
/**
* Get the query job info.
*
* @returns {Promise<QueryJobInfoV2>} ingest job information.
*/
}, {
key: "getInfo",
value: function getInfo() {
if (this.jobInfo) {
return this.jobInfo;
}
throw new Error('No internal job info. Make sure to call `await job.check`.');
}
/**
* Create a job representing a bulk operation in the org
*
* @returns {Promise<QueryJobInfoV2>} job information.
*/
}, {
key: "open",
value: (function () {
var _open2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee9() {
return _regeneratorRuntime.wrap(function _callee9$(_context13) {
while (1) switch (_context13.prev = _context13.next) {
case 0:
if (this.bodyParams) {
_context13.next = 2;
break;
}
throw new Error('Missing required body params to open a new ingest job.');
case 2:
_context13.prev = 2;
_context13.next = 5;
return this.createIngestRequest({
method: 'POST',
body: _JSON$stringify(this.bodyParams),
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
responseType: 'application/json'
});
case 5:
this.jobInfo = _context13.sent;
this.logger.debug("Successfully created job ".concat(this.id));
this.emit('open');
_context13.next = 14;
break;
case 10:
_context13.prev = 10;
_context13.t0 = _context13["catch"](2);
this.emit('error', _context13.t0);
throw _context13.t0;
case 14:
return _context13.abrupt("return", this.jobInfo);
case 15:
case "end":
return _context13.stop();
}
}, _callee9, this, [[2, 10]]);
}));
function open() {
return _open2.apply(this, arguments);
}
return open;
}()
/** Upload data for a job in CSV format
*
* @param input CSV as a string, or array of records or readable stream
*/
)
}, {
key: "uploadData",
value: (function () {
var _uploadData = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee10(input) {
return _regeneratorRuntime.wrap(function _callee10$(_context14) {
while (1) switch (_context14.prev = _context14.next) {
case 0:
_context14.next = 2;
return this.jobData.execute(input).result;
case 2:
this.logger.debug("Successfully uploaded data to job ".concat(this.id));
case 3:
case "end":
return _context14.stop();
}
}, _callee10, this);
}));
function uploadData(_x4) {
return _uploadData.apply(this, arguments);
}
return uploadData;
}()
/**
* Close opened job
*
* This method will notify the org that the upload of job data is complete and is ready for processing.
*/
)
}, {
key: "close",
value: (function () {
var _close = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee11() {
var state;
return _regeneratorRuntime.wrap(function _callee11$(_context15) {
while (1) switch (_context15.prev = _context15.next) {
case 0:
_context15.prev = 0;
state = 'UploadComplete';
_context15.next = 4;
return this.createIngestRequest({
method: 'PATCH',
path: "/".concat(this.id),
body: _JSON$stringify({
state: state
}),
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
responseType: 'application/json'
});
case 4:
this.jobInfo = _context15.sent;
this.logger.debug("Successfully closed job ".concat(this.id));
this.emit('close');
_context15.next = 13;
break;
case 9:
_context15.prev = 9;
_context15.t0 = _context15["catch"](0);
this.emit('error', _context15.t0);
throw _context15.t0;
case 13:
case "end":
return _context15.stop();
}
}, _callee11, this, [[0, 9]]);
}));
function close() {
return _close.apply(this, arguments);
}
return close;
}()
/**
* Set the status to abort
*/
)
}, {
key: "abort",
value: (function () {
var _abort2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee12() {
var state;
return _regeneratorRuntime.wrap(function _callee12$(_context16) {
while (1) switch (_context16.prev = _context16.next) {
case 0:
_context16.prev = 0;
state = 'Aborted';
_context16.next = 4;
return this.createIngestRequest({
method: 'PATCH',
path: "/".concat(this.id),
body: _JSON$stringify({
state: state
}),
headers: {
'Content-Type': 'application/json; charset=utf-8'
},
responseType: 'application/json'
});
case 4:
this.jobInfo = _context16.sent;
this.logger.debug("Successfully aborted job ".concat(this.id));
this.emit('aborted');
_context16.next = 13;
break;
case 9:
_context16.prev = 9;
_context16.t0 = _context16["catch"](0);
this.emit('error', _context16.t0);
throw _context16.t0;
case 13:
case "end":
return _context16.stop();
}
}, _callee12, this, [[0, 9]]);
}));
function abort() {
return _abort2.apply(this, arguments);
}
return abort;
}()
/**
* Poll for the state of the processing for the job.
*
* This method will only throw after a timeout. To capture a
* job failure while polling you must set a listener for the
* `failed` event before calling it:
*
* job.on('failed', (err) => console.error(err))
* await job.poll()
*
* @param interval Polling interval in milliseconds
* @param timeout Polling timeout in milliseconds
* @returns {Promise<void>} A promise that resolves when the job finishes successfully
*/
)
}, {
key: "poll",
value: (function () {
var _poll2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee13() {
var _context17, _context18;
var interval,
timeout,
jobId,
startTime,
endTime,
res,
timeoutError,
_args13 = arguments;
return _regeneratorRuntime.wrap(function _callee13$(_context19) {
while (1) switch (_context19.prev = _context19.next) {
case 0:
interval = _args13.length > 0 && _args13[0] !== undefined ? _args13[0] : this.pollingOptions.pollInterval;
timeout = _args13.length > 1 && _args13[1] !== undefined ? _args13[1] : this.pollingOptions.pollTimeout;
jobId = this.id;
startTime = _Date$now();
endTime = startTime + timeout;
if (!(timeout === 0)) {
_context19.next = 7;
break;
}
throw new JobPollingTimeoutError("Skipping polling because of timeout = 0ms. Job Id = ".concat(jobId), jobId);
case 7:
this.logger.debug('Start polling for job status');
this.logger.debug(_concatInstanceProperty(_context17 = "Polling options: timeout:".concat(timeout, "ms | interval: ")).call(_context17, interval, "ms."));
case 9:
if (!(endTime > _Date$now())) {
_context19.next = 36;
break;
}
_context19.prev = 10;
_context19.next = 13;
return this.check();
case 13:
res = _context19.sent;
_context19.t0 = res.state;
_context19.next = _context19.t0 === 'Open' ? 17 : _context19.t0 === 'Aborted' ? 18 : _context19.t0 === 'UploadComplete' ? 19 : _context19.t0 === 'InProgress' ? 19 : _context19.t0 === 'Failed' ? 23 : _context19.t0 === 'JobComplete' ? 25 : 28;
break;
case 17:
throw new Error('Job is still open. Make sure close the job by `close` method on the job instance before polling.');
case 18:
throw new Error('Job has been aborted');
case 19:
this.emit('inProgress', res);
_context19.next = 22;
return delay(interval);
case 22:
return _context19.abrupt("break", 28);
case 23:
this.logger.debug(res);
throw new Error("Ingest job failed to complete due to: ".concat(res.errorMessage));
case 25:
this.logger.debug("Job ".concat(this.id, " was successfully processed."));
this.emit('jobComplete', res);
return _context19.abrupt("return");
case 28:
_context19.next = 34;
break;
case 30:
_context19.prev = 30;
_context19.t1 = _context19["catch"](10);
this.emit('error', _context19.t1);
throw _context19.t1;
case 34:
_context19.next = 9;
break;
case 36:
timeoutError = new JobPollingTimeoutError(_concatInstanceProperty(_context18 = "Polling timed out after ".concat(timeout, "ms. Job Id = ")).call(_context18, jobId), jobId);
this.emit('error', timeoutError);
throw timeoutError;
case 39:
case "end":
return _context19.stop();
}
}, _callee13, this, [[10, 30]]);
}));
function poll() {
return _poll2.apply(this, arguments);
}
return poll;
}()
/**
* Check the latest batch status in server
*/
)
}, {
key: "check",
value: (function () {
var _check2 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee14() {
var jobInfo;
return _regeneratorRuntime.wrap(function _callee14$(_context20) {
while (1) switch (_context20.prev = _context20.next) {
case 0:
_context20.prev = 0;
_context20.next = 3;
return this.createIngestRequest({
method: 'GET',
path: "/".concat(this.id),
responseType: 'application/json'
});
case 3:
jobInfo = _context20.sent;
this.jobInfo = jobInfo;
return _context20.abrupt("return", jobInfo);
case 8:
_context20.prev = 8;
_context20.t0 = _context20["catch"](0);
this.emit('error', _context20.t0);
throw _context20.t0;
case 12:
case "end":
return _context20.stop();
}
}, _callee14, this, [[0, 8]]);
}));
function check() {
return _check2.apply(this, arguments);
}
return check;
}()
/** Return all record results
*
* This method will return successful, failed and unprocessed records
*
* @returns Promise<IngestJobV2Results>
*/
)
}, {
key: "getAllResults",
value: (function () {
var _getAllResults = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee15() {
var _yield$Promise$all, _yield$Promise$all2, successfulResults, failedResults, unprocessedRecords;
return _regeneratorRuntime.wrap(function _callee15$(_context21) {
while (1) switch (_context21.prev = _context21.next) {
case 0:
_context21.next = 2;
return _Promise.all([this.getSuccessfulResults(), this.getFailedResults(), this.getUnprocessedRecords()]);
case 2:
_yield$Promise$all = _context21.sent;
_yield$Promise$all2 = _slicedToArray(_yield$Promise$all, 3);
successfulResults = _yield$Promise$all2[0];
failedResults = _yield$Promise$all2[1];
unprocessedRecords = _yield$Promise$all2[2];
return _context21.abrupt("return", {
successfulResults: successfulResults,
failedResults: failedResults,
unprocessedRecords: unprocessedRecords
});
case 8:
case "end":
return _context21.stop();
}
}, _callee15, this);
}));
function getAllResults() {
return _getAllResults.apply(this, arguments);
}
return getAllResults;
}()
/** Return successful results
*
* The order of records returned is not guaranteed to match the ordering of the uploaded data.
*
* @param {boolean} raw Get results as a CSV string
* @returns Promise<IngestJobV2SuccessfulResults>
*/
)
}, {
key: "getSuccessfulResults",
value: function () {
var _getSuccessfulResults = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee16(raw) {
var reqOpts, results;
return _regeneratorRuntime.wrap(function _callee16$(_context22) {
while (1) switch (_context22.prev = _context22.next) {
case 0:
reqOpts = {
method: 'GET',
path: "/".concat(this.id, "/successfulResults")
};
if (!raw) {
_context22.next = 3;
break;
}
return _context22.abrupt("return", this.createIngestRequest(_objectSpread(_objectSpread({}, reqOpts), {}, {
responseType: 'text/plain'
})));
case 3:
if (!this.bulkJobSuccessfulResults) {
_context22.next = 5;
break;
}
return _context22.abrupt("return", this.bulkJobSuccessfulResults);
case 5:
_context22.next = 7;
return this.createIngestRequest({
method: 'GET',
path: "/".concat(this.id, "/successfulResults"),
responseType: 'text/csv'
});
case 7:
results = _context22.sent;
this.bulkJobSuccessfulResults = results !== null && results !== void 0 ? results : [];
return _context22.abrupt("return", this.bulkJobSuccessfulResults);
case 10:
case "end":
return _context22.stop();
}
}, _callee16, this);
}));
function getSuccessfulResults(_x5) {
return _getSuccessfulResults.apply(this, arguments);
}
return getSuccessfulResults;
}()
/** Return failed results
*
* The order of records in the response is not guaranteed to match the ordering of records in the original job data.
*
* @param {boolean} raw Get results as a CSV string
* @returns Promise<IngestJobV2SuccessfulResults>
*/
}, {
key: "getFailedResults",
value: function () {
var _getFailedResults = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee17(raw) {
var reqOpts, results;
return _regeneratorRuntime.wrap(function _callee17$(_context23) {
while (1) switch (_context23.prev = _context23.next) {
case 0:
reqOpts = {
method: 'GET',
path: "/".concat(this.id, "/failedResults")
};
if (!raw) {
_context23.next = 3;
break;
}
return _context23.abrupt("return", this.createIngestRequest(_objectSpread(_objectSpread({}, reqOpts), {}, {
responseType: 'text/plain'
})));
case 3:
if (!this.bulkJobFailedResults) {
_context23.next = 5;
break;
}
return _context23.abrupt("return", this.bulkJobFailedResults);
case 5:
_context23.next = 7;
return this.createIngestRequest(_objectSpread(_objectSpread({}, reqOpts), {}, {
responseType: 'text/csv'
}));
case 7:
results = _context23.sent;
this.bulkJobFailedResults = results !== null && results !== void 0 ? results : [];
return _context23.abrupt("return", this.bulkJobFailedResults);
case 10:
case "end":
return _context23.stop();
}
}, _callee17, this);
}));
function getFailedResults(_x6) {
return _getFailedResults.apply(this, arguments);
}
return getFailedResults;
}()
/** Return unprocessed results
*
* The unprocessed records endpoint returns records as a CSV.
* If the request helper is able to parse it, you get the records
* as an array of objects.
* If unable to parse it (bad CSV), you get the raw response as a string.
*
* The order of records in the response is not guaranteed to match the ordering of records in the original job data.
*
* @param {boolean} raw Get results as a CSV string
* @returns Promise<IngestJobV2UnprocessedRecords>
*/
}, {
key: "getUnprocessedRecords",
value: function () {
var _getUnprocessedRecords = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee18(raw) {
var reqOpts, results;
return _regeneratorRuntime.wrap(function _callee18$(_context24) {
while (1) switch (_context24.prev = _context24.next) {
case 0:
reqOpts = {
method: 'GET',
path: "/".concat(this.id, "/unprocessedrecords")
};
if (!raw) {
_context24.next = 3;
break;
}
return _context24.abrupt("return", this.createIngestRequest(_objectSpread(_objectSpread({}, reqOpts), {}, {
responseType: 'text/plain'
})));
case 3:
if (!this.bulkJobUnprocessedRecords) {
_context24.next = 5;
break;
}
return _context24.abrupt("return", this.bulkJobUnprocessedRecords);
case 5:
_context24.next = 7;
return this.createIngestRequest(_objectSpread(_objectSpread({}, reqOpts), {}, {
responseType: 'text/csv'
}));
case 7:
results = _context24.sent;
this.bulkJobUnprocessedRecords = results !== null && results !== void 0 ? results : [];
return _context24.abrupt("return", this.bulkJobUnprocessedRecords);
case 10:
case "end":
return _context24.stop();
}
}, _callee18, this);
}));
function getUnprocessedRecords(_x7) {
return _getUnprocessedRecords.apply(this, arguments);
}
return getUnprocessedRecords;
}()
/**
* Deletes an ingest job.
*/
}, {
key: "delete",
value: (function () {
var _delete3 = _asyncToGenerator(/*#__PURE__*/_regeneratorRuntime.mark(function _callee19() {
return _regeneratorRuntime.wrap(function _callee19$(_context25) {
while (1) switch (_context25.prev = _context25.next) {
case 0: