cache = function () {
this._entries = {};
}n/a
date = function (literal) {
this._literal = literal;
}n/a
http_api = function (conn, options) {
options = options || {};
this._conn = conn;
this.on('resume', function(err) { conn.emit('resume', err); });
this._responseType = options.responseType;
this._transport = options.transport || conn._transport;
this._noContentResponse = options.noContentResponse;
}n/a
logger = function (logLevel) {
if (typeof logLevel === 'string') {
logLevel = LogLevels[logLevel];
}
if (!logLevel) {
logLevel = LogLevels.INFO;
}
this._logLevel = logLevel;
}n/a
function Promise(fn) {
if (typeof this !== 'object') {
throw new TypeError('Promises must be constructed via new');
}
if (typeof fn !== 'function') {
throw new TypeError('not a function');
}
this._45 = 0;
this._81 = 0;
this._65 = null;
this._54 = null;
if (fn === noop) return;
doResolve(fn, this);
}...
* http://promises-aplus.github.io/promises-spec/
*
* Delegate to deferred promise, return promise instance for batch result
*
* @method Chatter~Request#then
*/
Request.prototype.then = function(onResolve, onReject) {
return this.promise().then(onResolve, onReject);
};
/**
* Promise/A+ extension
* Call "then" using given node-style callback function
*
* @method Chatter~Request#thenCall
...query = function (conn, config, options) {
Query.super_.call(this, { objectMode: true });
this._conn = conn;
if (_.isString(config)) { // if query config is string, it is given in SOQL.
this._soql = config;
} else if (config.locator && config.locator.indexOf("/") >= 0) { // if locator given in url for next records
this._locator = config.locator.split("/").pop();
} else {
this._config = config;
this.select(config.fields);
if (config.includes) {
this.include(config.includes);
}
}
this._options = _.defaults({
maxFetch: 10000,
autoFetch: false,
scanAll: false,
responseTarget: ResponseTargets.QueryResult
}, options || {});
this._executed = false;
this._finished = false;
this._chaining = false;
this._deferred = Promise.defer();
var self = this;
}...
var count = -1;
async.waterfall([
function(next) {
conn.sobject(config.bigTable).count({}, next);
},
function(_count, next) {
count = _count;
conn.bulk.query("SELECT Id, Name FROM " + config.bigTable)
.on('record', function(rec) { records.push(rec); })
.on('error', function(err) { next(err); })
.stream().pipe(fstream)
.on('finish', function() { next(null, records); });
}
], function(err, records) {
if (err) { throw err; }
...quick_action = function (conn, path) {
this._conn = conn;
this._path = path;
}n/a
record = function (conn, type, id) {
this._conn = conn;
this.type = type;
this.id = id;
}...
});
/**
*
*/
describe("update account", function() {
it("should update successfully", function(done) {
conn.sobject('Account').record(account.Id).update({ Name : "Hello2
x22; }, function(err, ret) {
if (err) { throw err; }
assert.ok(ret.success);
}.check(done));
});
describe("then retrieve the account", function() {
it("should return updated account object", function(done) {
...record_stream = function () {
RecordStream.super_.call(this, { objectMode: true });
}n/a
soap = function (conn, options) {
SOAP.super_.apply(this, arguments);
this._endpointUrl = options.endpointUrl;
this._xmlns = options.xmlns || 'urn:partner.soap.sforce.com';
}n/a
sobject = function (conn, type) {
this._conn = conn;
this.type = type;
var cacheOptions = { key: "describe." + this.type };
this.describe$ = conn.cache.makeCacheable(this.describe, this, cacheOptions);
this.describe = conn.cache.makeResponseCacheable(this.describe, this, cacheOptions);
cacheOptions = { key: "layouts." + this.type };
this.layouts$ = conn.cache.makeCacheable(this.layouts, this, cacheOptions);
this.layouts = conn.cache.makeResponseCacheable(this.layouts, this, cacheOptions);
cacheOptions = { key: "compactLayouts." + this.type };
this.compactLayouts$ = conn.cache.makeCacheable(this.compactLayouts, this, cacheOptions);
this.compactLayouts = conn.cache.makeResponseCacheable(this.compactLayouts, this, cacheOptions);
cacheOptions = { key: "approvalLayouts." + this.type };
this.approvalLayouts$ = conn.cache.makeCacheable(this.approvalLayouts, this, cacheOptions);
this.approvalLayouts = conn.cache.makeResponseCacheable(this.approvalLayouts, this, cacheOptions);
}...
};
Channel.prototype.push = function(events, callback) {
var isArray = _.isArray(events);
events = isArray ? events : [ events ];
var conn = this._streaming._conn;
if (!this._id) {
this._id = conn.sobject('StreamingChannel').findOne({ Name: this._name },
x27;Id')
.then(function(rec) { return rec.Id });
}
return this._id.then(function(id) {
var channelUrl = '/sobjects/StreamingChannel/' + id + '/push';
return conn.requestPost(channelUrl, { pushEvents: events });
}).then(function(rets) {
return isArray ? rets : rets[0];
...cache = function () {
this._entries = {};
}n/a
clear = function (key) {
for (var k in this._entries) {
if (!key || k.indexOf(key) === 0) {
this._entries[k].clear();
}
}
}...
/**
* Initialize tooling API
* @protected
*/
Tooling.prototype.initialize = function() {
this.sobjects = {};
this.cache.clear();
this.cache.get('describeGlobal').on('value', _.bind(function(res) {
if (res.result) {
var types = _.map(res.result.sobjects, function(so) { return so.name; });
types.forEach(this.sobject, this);
}
}, this));
};
...get = function (key) {
if (key && this._entries[key]) {
return this._entries[key];
} else {
var entry = new CacheEntry();
this._entries[key] = entry;
return entry;
}
}...
},
getConnectionTypes: function() {
return Transport.getConnectionTypes();
},
selectTransport: function(transportTypes) {
Transport.get(this, transportTypes, this._disabled, function(transport) {
this.debug('Selected ? transport for ?', transport.connectionType, URI.stringify(transport.endpoint));
if (transport === this._transport) return;
if (this._transport) this._transport.close();
this._transport = transport;
this.connectionType = transport.connectionType;
...makeCacheable = function (fn, scope, options) {
var cache = this;
options = options || {};
var $fn = function() {
var args = Array.prototype.slice.apply(arguments);
var callback = args.pop();
if (!_.isFunction(callback)) {
args.push(callback);
}
var key = _.isString(options.key) ? options.key :
_.isFunction(options.key) ? options.key.apply(scope, args) :
createCacheKey(options.namespace, args);
var entry = cache.get(key);
if (!_.isFunction(callback)) { // if callback is not given in last arg, return cached result (immediate).
var value = entry.get();
if (!value) { throw new Error('Function call result is not cached yet.'); }
if (value.error) { throw value.error; }
return value.result;
}
entry.get(function(value) {
callback(value.error, value.result);
});
if (!entry.fetching) { // only when no other client is calling function
entry.fetching = true;
args.push(function(err, result) {
entry.set({ error: err, result: result });
});
fn.apply(scope || this, args);
}
};
$fn.clear = function() {
var key = _.isString(options.key) ? options.key :
_.isFunction(options.key) ? options.key.apply(scope, arguments) :
createCacheKey(options.namespace, arguments);
cache.clear(key);
};
return $fn;
}...
}, this);
this.cache = new Cache();
var cacheOptions = {
key: function(type) { return type ? "describe." + type : "describe"; }
};
this.describe$ = this.cache.makeCacheable(this.describe, this, cacheOptions);
this.describe = this.cache.makeResponseCacheable(this.describe, this, cacheOptions);
this.describeSObject$ = this.describe$;
this.describeSObject = this.describe;
cacheOptions = { key: 'describeGlobal' };
this.describeGlobal$ = this.cache.makeCacheable(this.describeGlobal, this, cacheOptions);
this.describeGlobal = this.cache.makeResponseCacheable(this.describeGlobal, this, cacheOptions);
...makeResponseCacheable = function (fn, scope, options) {
var cache = this;
options = options || {};
return function() {
var args = Array.prototype.slice.apply(arguments);
var callback = args.pop();
if (!_.isFunction(callback)) {
args.push(callback);
callback = null;
}
var key = _.isString(options.key) ? options.key :
_.isFunction(options.key) ? options.key.apply(scope, args) :
createCacheKey(options.namespace, args);
var entry = cache.get(key);
entry.fetching = true;
if (callback) {
args.push(function(err, result) {
entry.set({ error: err, result: result });
callback(err, result);
});
}
var ret, error;
try {
ret = fn.apply(scope || this, args);
} catch(e) {
error = e;
}
if (ret && _.isFunction(ret.then)) { // if the returned value is promise
if (!callback) {
return ret.then(function(result) {
entry.set({ error: undefined, result: result });
return result;
}, function(err) {
entry.set({ error: err, result: undefined });
throw err;
});
} else {
return ret;
}
} else {
entry.set({ error: error, result: ret });
if (error) { throw error; }
return ret;
}
};
}...
this.cache = new Cache();
var cacheOptions = {
key: function(type) { return type ? "describe." + type : "describe"; }
};
this.describe$ = this.cache.makeCacheable(this.describe, this, cacheOptions);
this.describe = this.cache.makeResponseCacheable(this.describe, this, cacheOptions);
this.describeSObject$ = this.describe$;
this.describeSObject = this.describe;
cacheOptions = { key: 'describeGlobal' };
this.describeGlobal$ = this.cache.makeCacheable(this.describeGlobal, this, cacheOptions);
this.describeGlobal = this.cache.makeResponseCacheable(this.describeGlobal, this, cacheOptions);
...createRequest = function (signedRequest) {
return function(params, callback) {
var response;
var str = new Duplex();
str._read = function(size) {
if (response) {
str.push(response.body);
}
};
var bufs = [];
var sent = false;
str._write = function(chunk, encoding, callback) {
bufs.push(chunk.toString(encoding));
callback();
};
str.on('finish', function() {
if (!sent) {
send(bufs.join(''));
sent = true;
}
});
if (params.body || params.body === "" || !/^(put|post|patch)$/i.test(params.method)) {
send(params.body);
sent = true;
}
function send(body) {
var settings = {
client: signedRequest.client,
method: params.method,
data: body
};
if (params.headers) {
settings.headers = {};
for (var name in params.headers) {
if (name.toLowerCase() === 'content-type') {
settings.contentType = params.headers[name];
} else {
settings.headers[name] = params.headers[name];
}
}
}
settings.success = function(data) {
var headers = parseHeaders(data.responseHeaders);
var body = data.payload;
if (!_.isString(body)) {
body = JSON.stringify(body);
}
response = {
statusCode : data.status,
headers: headers,
body: body
};
if (callback) {
callback(null, response, response.body);
}
str.end();
};
settings.failure = function(err) {
if (callback) {
callback(err);
}
};
Sfdc.canvas.client.ajax(params.url, settings);
}
return str;
};
}...
this._jsonpParam = jsonpParam;
};
inherits(JsonpTransport, Transport);
/** @protected **/
JsonpTransport.prototype._getHttpRequestModule = function() {
return jsonp.createRequest(this._jsonpParam);
};
JsonpTransport.supported = jsonp.supported;
/**
* Class for Sfdc Canvas request transport
...function parseCSV(str, options) {
options = _.extend({}, options, { columns: true });
return csvParseSync(str, options);
}...
});
if (ret.error) { throw ret.error; }
return ret.result;
}
/** @private */
function parseCSV(str) {
return require('./csv').parseCSV(str);
}
/** @private */
function parseText(str) { return str; }
/**
...function parseCSVStream(options) {
options = _.extend({}, options, { columns: true });
return csvParse(options);
}...
RecordStream.map(function(record) {
return convertRecordForSerialization(record, options);
}),
CSV.serializeCSVStream(options)
);
},
parse: function(options) {
return CSV.parseCSVStream(options);
}
};
/**
* @private
*/
var DataStreamConverters = RecordStream.DataStreamConverters = {
...function serializeCSVStream(options) {
options = _.extend({}, options, { header: true });
return csvStringify(options);
}...
var CSVStreamConverter = {
serialize: function(options) {
options = options || {};
return createPipelineStream(
RecordStream.map(function(record) {
return convertRecordForSerialization(record, options);
}),
CSV.serializeCSVStream(options)
);
},
parse: function(options) {
return CSV.parseCSVStream(options);
}
};
...function toCSV(records, options) {
options = _.extend({}, options, { header: true });
return csvStringifySync(records, options);
}n/a
date = function (literal) {
this._literal = literal;
}n/a
LAST_N_DAYS = function (num) { return new SfDate(literal + ":" + num); }...
*
*/
describe("Query with Date field for date literal", function() {
var soql = SOQLBuilder.createSOQL({
table: "Opportunity",
conditions: {
$and : [
{ CloseDate: { $gte : SfDate.LAST_N_DAYS(10) } },
{ CloseDate: { $lte : SfDate.TOMORROW } },
{ CloseDate: { $gt : SfDate.toDateLiteral(new Date(1288958400000)) }},
{ CreatedDate: { $lt : SfDate.toDateTimeLiteral('2010-11-02T04:45:04+09:00') }}
]
}
});
...LAST_N_FISCAL_QUARTERS = function (num) { return new SfDate(literal + ":" + num); }n/a
LAST_N_FISCAL_YEARS = function (num) { return new SfDate(literal + ":" + num); }n/a
LAST_N_MONTHS = function (num) { return new SfDate(literal + ":" + num); }n/a
LAST_N_QUARTERS = function (num) { return new SfDate(literal + ":" + num); }n/a
LAST_N_WEEKS = function (num) { return new SfDate(literal + ":" + num); }n/a
LAST_N_YEARS = function (num) { return new SfDate(literal + ":" + num); }n/a
NEXT_N_DAYS = function (num) { return new SfDate(literal + ":" + num); }n/a
NEXT_N_FISCAL_QUARTERS = function (num) { return new SfDate(literal + ":" + num); }n/a
NEXT_N_FISCAL_YEARS = function (num) { return new SfDate(literal + ":" + num); }n/a
NEXT_N_MONTHS = function (num) { return new SfDate(literal + ":" + num); }n/a
NEXT_N_QUARTERS = function (num) { return new SfDate(literal + ":" + num); }n/a
NEXT_N_WEEKS = function (num) { return new SfDate(literal + ":" + num); }n/a
NEXT_N_YEARS = function (num) { return new SfDate(literal + ":" + num); }n/a
parseDate = function (str) {
var d = new Date();
var regexp = /^([\d]{4})-?([\d]{2})-?([\d]{2})(T([\d]{2}):?([\d]{2}):?([\d]{2})(.([\d]{3}))?(Z|([\+\-])([\d]{2}):?([\d]{2})))?$/;
var m = str.match(regexp);
if (m) {
d = new Date(0);
if (!m[4]) {
d.setFullYear(parseInt(m[1], 10));
d.setDate(parseInt(m[3], 10));
d.setMonth(parseInt(m[2], 10) - 1);
d.setHours(0);
d.setMinutes(0);
d.setSeconds(0);
d.setMilliseconds(0);
} else {
d.setUTCFullYear(parseInt(m[1], 10));
d.setUTCDate(parseInt(m[3], 10));
d.setUTCMonth(parseInt(m[2], 10) - 1);
d.setUTCHours(parseInt(m[5], 10));
d.setUTCMinutes(parseInt(m[6], 10));
d.setUTCSeconds(parseInt(m[7], 10));
d.setUTCMilliseconds(parseInt(m[9] || '0', 10));
if (m[10] && m[10] !== 'Z') {
var offset = parseInt(m[12],10) * 60 + parseInt(m[13], 10);
d.setTime((m[11] === '+' ? -1 : 1) * offset * 60 * 1000 +d.getTime());
}
}
return d;
} else {
throw new Error("Invalid date format is specified : " + str);
}
}...
* @param {String|Number|Date} date - Input date
* @returns {SfDate} - Salesforce date literal with ISO8601 date format
*/
SfDate.toDateLiteral = function(date) {
if (_.isNumber(date)) {
date = new Date(date);
} else if (_.isString(date)) {
date = SfDate.parseDate(date);
}
var yy = date.getFullYear();
var mm = date.getMonth()+1;
var dd = date.getDate();
var dstr = [ yy, zeropad(mm), zeropad(dd) ].join("-");
return new SfDate(dstr);
};
...toDateLiteral = function (date) {
if (_.isNumber(date)) {
date = new Date(date);
} else if (_.isString(date)) {
date = SfDate.parseDate(date);
}
var yy = date.getFullYear();
var mm = date.getMonth()+1;
var dd = date.getDate();
var dstr = [ yy, zeropad(mm), zeropad(dd) ].join("-");
return new SfDate(dstr);
}...
describe("Query with Date field for date literal", function() {
var soql = SOQLBuilder.createSOQL({
table: "Opportunity",
conditions: {
$and : [
{ CloseDate: { $gte : SfDate.LAST_N_DAYS(10) } },
{ CloseDate: { $lte : SfDate.TOMORROW } },
{ CloseDate: { $gt : SfDate.toDateLiteral(new Date(1288958400000)) }},
{ CreatedDate: { $lt : SfDate.toDateTimeLiteral('2010-11-02T04:45:04+09:00') }}
]
}
});
it("should equal to soql", function() {
assert.ok(soql ===
...toDateTimeLiteral = function (date) {
if (_.isNumber(date)) {
date = new Date(date);
} else if (_.isString(date)) {
date = SfDate.parseDate(date);
}
var yy = date.getUTCFullYear();
var mm = date.getUTCMonth()+1;
var dd = date.getUTCDate();
var hh = date.getUTCHours();
var mi = date.getUTCMinutes();
var ss = date.getUTCSeconds();
var dtstr =
[ yy, zeropad(mm), zeropad(dd) ].join("-") + "T" +
[ zeropad(hh), zeropad(mi), zeropad(ss) ].join(":") + "Z";
return new SfDate(dtstr);
}...
var soql = SOQLBuilder.createSOQL({
table: "Opportunity",
conditions: {
$and : [
{ CloseDate: { $gte : SfDate.LAST_N_DAYS(10) } },
{ CloseDate: { $lte : SfDate.TOMORROW } },
{ CloseDate: { $gt : SfDate.toDateLiteral(new Date(1288958400000)) }},
{ CreatedDate: { $lt : SfDate.toDateTimeLiteral('2010-11-02T04:45:04+09:00
') }}
]
}
});
it("should equal to soql", function() {
assert.ok(soql ===
"SELECT Id FROM Opportunity " +
...toJSON = function () { return this._literal; }n/a
toString = function () { return this._literal; }...
var deferred = Promise.defer();
if (_.isObject(zipInput) && _.isFunction(zipInput.pipe)) {
var bufs = [];
zipInput.on('data', function(d) {
bufs.push(d);
});
zipInput.on('end', function() {
deferred.resolve(Buffer.concat(bufs).toString('base64'));
});
// zipInput.resume();
} else if (zipInput instanceof Buffer) {
deferred.resolve(zipInput.toString('base64'));
} else if (zipInput instanceof String || typeof zipInput === 'string') {
deferred.resolve(zipInput);
} else {
...http_api = function (conn, options) {
options = options || {};
this._conn = conn;
this.on('resume', function(err) { conn.emit('resume', err); });
this._responseType = options.responseType;
this._transport = options.transport || conn._transport;
this._noContentResponse = options.noContentResponse;
}n/a
SessionRefreshDelegate = function (conn, refreshFn) {
this._conn = conn;
this._refreshFn = refreshFn;
this._refreshing = false;
}...
// Allow to delegate connection refresh to outer function
var self = this;
var refreshFn = options.refreshFn;
if (!refreshFn && this.oauth2.clientId && this.oauth2.clientSecret) {
refreshFn = oauthRefreshFn;
}
if (refreshFn) {
this._refreshDelegate = new HttpApi.SessionRefreshDelegate(this, refreshFn);
}
var cacheOptions = {
key: function(type) { return type ? "describe." + type : "describe"; }
};
this.describe$ = this.cache.makeCacheable(this.describe, this, cacheOptions);
this.describe = this.cache.makeResponseCacheable(this.describe, this, cacheOptions);
...function EventEmitter() {
EventEmitter.init.call(this);
}n/a
beforeSend = function (request) {
request.headers = request.headers || {};
if (this._conn.accessToken) {
request.headers.Authorization = "Bearer " + this._conn.accessToken;
}
if (this._conn.callOptions) {
var callOptions = [];
for (var name in this._conn.callOptions) {
callOptions.push(name + "=" + this._conn.callOptions[name]);
}
request.headers["Sforce-Call-Options"] = callOptions.join(', ');
}
}...
if (refreshDelegate && refreshDelegate._refreshing) {
refreshDelegate.once('resume', onResume);
return deferred.promise.thenCall(callback);
}
// hook before sending
self.beforeSend(request);
self.emit('request', request);
logger.debug("<request> method=" + request.method + ", url=" + request.url);
var requestTime = Date.now();
return this._transport.httpRequest(request).then(function(response) {
var responseTime = Date.now();
...getError = function (response, body) {
var error;
try {
error = this.parseError(body || this.parseResponseBody(response));
} catch(e) {}
error = _.isObject(error) && _.isString(error.message) ? error : {
errorCode: 'ERROR_HTTP_' + response.statusCode,
message : response.body
};
var err = new Error(error.message);
err.name = error.errorCode;
for (var key in error) { err[key] = error[key]; }
return err;
}...
// Refresh token if session has been expired and requires authentication
// when session refresh delegate is available
if (self.isSessionExpired(response) && refreshDelegate) {
refreshDelegate.refresh(requestTime, onResume);
return deferred.promise;
}
if (self.isErrorResponse(response)) {
var err = self.getError(response);
throw err;
}
return self.getResponseBody(response);
}, function(err) {
var responseTime = Date.now();
logger.debug("elappsed time : " + (responseTime - requestTime) + "msec");
logger.error(err);
...getRefreshDelegate = function () {
return this._conn._refreshDelegate;
}...
* @param {Callback.<Object>} callback - Callback function
* @returns {Promise.<Object>} -
*/
HttpApi.prototype.request = function(request, callback) {
var self = this;
var conn = this._conn;
var logger = conn._logger;
var refreshDelegate = this.getRefreshDelegate();
// remember previous instance url in case it changes after a refresh
var lastInstanceUrl = conn.instanceUrl;
var deferred = Promise.defer();
var onResume = function(err) {
if (err) {
...getResponseBody = function (response) {
if (response.statusCode === 204) { // No Content
return this._noContentResponse;
}
var body = this.parseResponseBody(response);
var err;
if (this.hasErrorInResponseBody(body)) {
err = this.getError(response, body);
throw err;
}
if (response.statusCode === 300) { // Multiple Choices
err = new Error('Multiple records found');
err.name = "MULTIPLE_CHOICES";
err.content = body;
throw err;
}
return body;
}...
refreshDelegate.refresh(requestTime, onResume);
return deferred.promise;
}
if (self.isErrorResponse(response)) {
var err = self.getError(response);
throw err;
}
return self.getResponseBody(response);
}, function(err) {
var responseTime = Date.now();
logger.debug("elappsed time : " + (responseTime - requestTime) + "msec");
logger.error(err);
throw err;
})
.thenCall(callback);
...getResponseContentType = function (response) {
return this._responseType || response.headers && response.headers["content-type"];
}...
return this._responseType || response.headers && response.headers["content-type"];
};
/**
*
*/
HttpApi.prototype.parseResponseBody = function(response) {
var contentType = this.getResponseContentType(response);
var parseBody = /^(text|application)\/xml(;|$)/.test(contentType) ? parseXML :
/^application\/json(;|$)/.test(contentType) ? parseJSON :
/^text\/csv(;|$)/.test(contentType) ? parseCSV :
parseText;
try {
return parseBody(response.body);
} catch(e) {
...hasErrorInResponseBody = function (body) {
return false;
}...
*/
HttpApi.prototype.getResponseBody = function(response) {
if (response.statusCode === 204) { // No Content
return this._noContentResponse;
}
var body = this.parseResponseBody(response);
var err;
if (this.hasErrorInResponseBody(body)) {
err = this.getError(response, body);
throw err;
}
if (response.statusCode === 300) { // Multiple Choices
err = new Error('Multiple records found');
err.name = "MULTIPLE_CHOICES";
err.content = body;
...isErrorResponse = function (response) {
return response.statusCode >= 400;
}...
self.emit('response', response);
// Refresh token if session has been expired and requires authentication
// when session refresh delegate is available
if (self.isSessionExpired(response) && refreshDelegate) {
refreshDelegate.refresh(requestTime, onResume);
return deferred.promise;
}
if (self.isErrorResponse(response)) {
var err = self.getError(response);
throw err;
}
return self.getResponseBody(response);
}, function(err) {
var responseTime = Date.now();
logger.debug("elappsed time : " + (responseTime - requestTime) + "msec");
...isSessionExpired = function (response) {
return response.statusCode === 401;
}...
var responseTime = Date.now();
logger.debug("elappsed time : " + (responseTime - requestTime) + "msec");
logger.debug("<response> status=" + response.statusCode + ", url=" + request.url);
self.emit('response', response);
// Refresh token if session has been expired and requires authentication
// when session refresh delegate is available
if (self.isSessionExpired(response) && refreshDelegate) {
refreshDelegate.refresh(requestTime, onResume);
return deferred.promise;
}
if (self.isErrorResponse(response)) {
var err = self.getError(response);
throw err;
}
...parseError = function (body) {
var errors = body;
return _.isArray(errors) ? errors[0] : errors;
}...
/**
* Get error message in response
* @protected
*/
HttpApi.prototype.getError = function(response, body) {
var error;
try {
error = this.parseError(body || this.parseResponseBody(response));
} catch(e) {}
error = _.isObject(error) && _.isString(error.message) ? error : {
errorCode: 'ERROR_HTTP_' + response.statusCode,
message : response.body
};
var err = new Error(error.message);
err.name = error.errorCode;
...parseResponseBody = function (response) {
var contentType = this.getResponseContentType(response);
var parseBody = /^(text|application)\/xml(;|$)/.test(contentType) ? parseXML :
/^application\/json(;|$)/.test(contentType) ? parseJSON :
/^text\/csv(;|$)/.test(contentType) ? parseCSV :
parseText;
try {
return parseBody(response.body);
} catch(e) {
return response.body;
}
}...
* Get response body
* @protected
*/
HttpApi.prototype.getResponseBody = function(response) {
if (response.statusCode === 204) { // No Content
return this._noContentResponse;
}
var body = this.parseResponseBody(response);
var err;
if (this.hasErrorInResponseBody(body)) {
err = this.getError(response, body);
throw err;
}
if (response.statusCode === 300) { // Multiple Choices
err = new Error('Multiple records found');
...request = function (request, callback) {
var self = this;
var conn = this._conn;
var logger = conn._logger;
var refreshDelegate = this.getRefreshDelegate();
// remember previous instance url in case it changes after a refresh
var lastInstanceUrl = conn.instanceUrl;
var deferred = Promise.defer();
var onResume = function(err) {
if (err) {
deferred.reject(err);
return;
}
// check to see if the token refresh has changed the instance url
if(lastInstanceUrl !== conn.instanceUrl){
// if the instance url has changed
// then replace the current request urls instance url fragment
// with the updated instance url
request.url = request.url.replace(lastInstanceUrl,conn.instanceUrl);
}
self.request(request).then(function(response) {
deferred.resolve(response);
}, function(err) {
deferred.reject(err);
});
};
if (refreshDelegate && refreshDelegate._refreshing) {
refreshDelegate.once('resume', onResume);
return deferred.promise.thenCall(callback);
}
// hook before sending
self.beforeSend(request);
self.emit('request', request);
logger.debug("<request> method=" + request.method + ", url=" + request.url);
var requestTime = Date.now();
return this._transport.httpRequest(request).then(function(response) {
var responseTime = Date.now();
logger.debug("elappsed time : " + (responseTime - requestTime) + "msec");
logger.debug("<response> status=" + response.statusCode + ", url=" + request.url);
self.emit('response', response);
// Refresh token if session has been expired and requires authentication
// when session refresh delegate is available
if (self.isSessionExpired(response) && refreshDelegate) {
refreshDelegate.refresh(requestTime, onResume);
return deferred.promise;
}
if (self.isErrorResponse(response)) {
var err = self.getError(response);
throw err;
}
return self.getResponseBody(response);
}, function(err) {
var responseTime = Date.now();
logger.debug("elappsed time : " + (responseTime - requestTime) + "msec");
logger.error(err);
throw err;
})
.thenCall(callback);
}...
* @param {Callback.<Analytics~ReportResult>} [callback] - Callback function
* @returns {Promise.<Analytics~ReportResult>}
*/
ReportInstance.prototype.retrieve = function(callback) {
var conn = this._conn,
report = this._report;
var url = [ conn._baseUrl(), "analytics", "reports", report.id, "instances", this.id ].join('
;/');
return conn.request(url).thenCall(callback);
};
/**
* Report object in Analytics API
*
* @protected
* @class Analytics~Report
...createRequest = function (jsonpParam, timeout) {
jsonpParam = jsonpParam || 'callback';
timeout = timeout || 10000;
return function(params, callback) {
if (params.method.toUpperCase() !== 'GET') {
return callback(new Error('JSONP only supports GET request.'));
}
var cbFuncName = '_jsforce_jsonpCallback_' + (++_index);
var callbacks = window;
var url = params.url;
url += url.indexOf('?')>0 ? '&' : '?';
url += jsonpParam + '=' + cbFuncName;
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = url;
document.documentElement.appendChild(script);
var pid = setTimeout(function() {
cleanup();
callback(new Error("JSONP call time out."));
}, timeout);
callbacks[cbFuncName] = function(res) {
cleanup();
callback(null, {
statusCode: 200,
headers: { "content-type": "application/json" },
body: JSON.stringify(res)
});
};
var cleanup = function() {
clearTimeout(pid);
document.documentElement.removeChild(script);
delete callbacks[cbFuncName];
};
};
}...
this._jsonpParam = jsonpParam;
};
inherits(JsonpTransport, Transport);
/** @protected **/
JsonpTransport.prototype._getHttpRequestModule = function() {
return jsonp.createRequest(this._jsonpParam);
};
JsonpTransport.supported = jsonp.supported;
/**
* Class for Sfdc Canvas request transport
...logger = function (logLevel) {
if (typeof logLevel === 'string') {
logLevel = LogLevels[logLevel];
}
if (!logLevel) {
logLevel = LogLevels.INFO;
}
this._logLevel = logLevel;
}n/a
debug = function (message) { this.log(level, message); }...
this._jobInfo = this._waitAssign().then(function() {
return bulk._request({
method : 'GET',
path : "/job/" + self.id,
responseType: "application/xml"
});
}).then(function(res) {
logger.debug(res.jobInfo);
self.id = res.jobInfo.id;
self.type = res.jobInfo.object;
self.operation = res.jobInfo.operation;
self.state = res.jobInfo.state;
return res.jobInfo;
});
return this._jobInfo.thenCall(callback);
...error = function (message) { this.log(level, message); }...
"url": "git://github.com/jsforce/jsforce.git"
},
"scripts": {
"build": "gulp build",
"build:all": "gulp build:all",
"build:test": "gulp build:test",
"doc": "jsdoc lib -d doc --recurse --lenient",
"prepublish": "node -e \"if(process.env.npm_package_version!==require('./lib/VERSION')){console
.error('The pacakge.json version is not matching to ./lib/VERSION.js');process
.exit(1)}\"",
"test": "npm run test:node",
"test:all": "npm run test:node && npm run test:browser",
"test:browser": "testem",
"test:node": "./test/bin/run-test"
},
"version": "1.7.2"
}
...fatal = function (message) { this.log(level, message); }n/a
info = function (message) { this.log(level, message); }...
var job = this.job;
var batchId = this.id;
if (!jobId || !batchId) {
throw new Error("Batch not started.");
}
return job.info().then(function(jobInfo) {
return bulk._request({
method : 'GET',
path : "/job/" + jobId + "/batch/" + batchId + "/result"
});
}).then(function(res) {
var results;
if (job.operation === 'query') {
...log = function (level, message) {
if (this._logLevel <= level) {
if (level < LogLevels.ERROR) {
console.log(message);
} else {
console.error(message);
}
}
}...
value = Math.abs(value)
if (isNaN(value) || value === Infinity) {
m = isNaN(value) ? 1 : 0
e = eMax
} else {
e = Math.floor(Math.log(value) / Math.LN2)
if (value * (c = Math.pow(2, -e)) < 1) {
e--
c *= 2
}
if (e + eBias >= 1) {
value += rt / c
} else {
...warn = function (message) { this.log(level, message); }...
} else if (keys.length > 1) {
proxy = env[name];
}
proxy = proxy || env['CGI_' + upcase];
} else {
proxy = env[name] || env[upcase];
if (proxy && !env[name])
console.warn('The environment variable ' + upcase +
' is discouraged. Use ' + name + '.');
}
return proxy;
}
}), {
get: function(dispatcher, allowed, disabled, callback, context) {
...function Promise(fn) {
if (typeof this !== 'object') {
throw new TypeError('Promises must be constructed via new');
}
if (typeof fn !== 'function') {
throw new TypeError('not a function');
}
this._45 = 0;
this._81 = 0;
this._65 = null;
this._54 = null;
if (fn === noop) return;
doResolve(fn, this);
}...
* http://promises-aplus.github.io/promises-spec/
*
* Delegate to deferred promise, return promise instance for batch result
*
* @method Chatter~Request#then
*/
Request.prototype.then = function(onResolve, onReject) {
return this.promise().then(onResolve, onReject);
};
/**
* Promise/A+ extension
* Call "then" using given node-style callback function
*
* @method Chatter~Request#thenCall
...function noop() {}n/a
all = function (arr) {
var args = Array.prototype.slice.call(arr);
return new Promise(function (resolve, reject) {
if (args.length === 0) return resolve([]);
var remaining = args.length;
function res(i, val) {
if (val && (typeof val === 'object' || typeof val === 'function')) {
if (val instanceof Promise && val.then === Promise.prototype.then) {
while (val._81 === 3) {
val = val._65;
}
if (val._81 === 1) return res(i, val._65);
if (val._81 === 2) reject(val._65);
val.then(function (val) {
res(i, val);
}, reject);
return;
} else {
var then = val.then;
if (typeof then === 'function') {
var p = new Promise(then.bind(val));
p.then(function (val) {
res(i, val);
}, reject);
return;
}
}
}
args[i] = val;
if (--remaining === 0) {
resolve(args);
}
}
for (var i = 0; i < args.length; i++) {
res(i, args[i]);
}
});
}...
options = options || {};
var self = this;
var isArray = _.isArray(ids);
ids = isArray ? ids : [ ids ];
if (ids.length > self.maxRequest) {
return Promise.reject(new Error("Exceeded max limit of concurrent call")).thenCall(callback);
}
return Promise.all(
_.map(ids, function(id) {
if (!id) { return Promise.reject(new Error('Invalid record ID. Specify valid record ID value')).thenCall(callback); }
var url = [ self._baseUrl(), "sobjects", type, id ].join('/');
return self.request({ method: 'GET', url: url, headers: options.headers });
})
).then(function(results) {
return !isArray && _.isArray(results) ? results[0] : results;
...defer = function () {
return new Deferred();
}...
* @param {String} [batchId] - Batch ID (if already available)
*/
var Batch = function(job, batchId) {
Batch.super_.call(this, { objectMode: true });
this.job = job;
this.id = batchId;
this._bulk = job._bulk;
this._deferred = Promise.defer();
this._setupDataStreams();
};
inherits(Batch, stream.Writable);
/**
...race = function (values) {
return new Promise(function (resolve, reject) {
values.forEach(function(value){
Promise.resolve(value).then(resolve, reject);
});
});
}n/a
reject = function (value) {
return new Promise(function (resolve, reject) {
reject(value);
});
}...
}
var rdeferred = Promise.defer();
this._result = rdeferred.promise;
this._result.then(function(res) {
self._deferred.resolve(res);
}, function(err) {
self._deferred.reject(err);
});
this.once('response', function(res) {
rdeferred.resolve(res);
});
this.once('error', function(err) {
rdeferred.reject(err);
});
...resolve = function (value) {
if (value instanceof Promise) return value;
if (value === null) return NULL;
if (value === undefined) return UNDEFINED;
if (value === true) return TRUE;
if (value === false) return FALSE;
if (value === 0) return ZERO;
if (value === '') return EMPTYSTRING;
if (typeof value === 'object' || typeof value === 'function') {
try {
var then = value.then;
if (typeof then === 'function') {
return new Promise(then.bind(value));
}
} catch (ex) {
return new Promise(function (resolve, reject) {
reject(ex);
});
}
}
return valuePromise(value);
}...
* Wait till the job is assigned to server
*
* @method Bulk~Job#info
* @param {Callback.<Bulk~JobInfo>} [callback] - Callback function
* @returns {Promise.<Bulk~JobInfo>}
*/
Job.prototype._waitAssign = function(callback) {
return (this.id ? Promise.resolve({ id: this.id }) : this.open()).thenCall(callback);
};
/**
* List all registered batch info in job
*
* @method Bulk~Job#list
...catch = function (onRejected) {
return this.then(null, onRejected);
}...
var rets = rrets[0], statusField = rrets[1];
leadIds = rets.map(function(r){ return r.id; });
convertedStatus = statusField.picklist.picklistValues
.filter(function(pv){ return pv.converted === 'true'; })
.map(function(pv){ return pv.fullName; })[0];
done();
})
.catch(done);
});
it("should convert lead", function(done) {
conn.soap.convertLead({
leadId: leadIds[0],
convertedStatus: convertedStatus
}, function(err, ret) {
...fail = function (onRejected) {
return this.then(null, onRejected);
}...
success: ret.Success === "true",
errors: ret.Error ? [ ret.Error ] : []
};
});
}
self.emit('response', results);
return results;
}).fail(function(err) {
self.emit('error', err);
throw err;
}).thenCall(callback);
};
/**
* Fetch query result as a record stream
...then = function (onFulfilled, onRejected) {
if (this.constructor !== Promise) {
return safeThen(this, onFulfilled, onRejected);
}
var res = new Promise(noop);
handle(this, new Handler(onFulfilled, onRejected, res));
return res;
}...
method : 'POST',
path : "/job",
body : body,
headers : {
"Content-Type" : "application/xml; charset=utf-8"
},
responseType: "application/xml"
}).then(function(res) {
self.emit("open", res.jobInfo);
self.id = res.jobInfo.id;
self.state = res.jobInfo.state;
return res.jobInfo;
}, function(err) {
self.emit("error", err);
throw err;
...thenCall = function (callback) {
if (_.isFunction(callback)) {
this.then(function(res) {
process.nextTick(function() {
callback(null, res);
});
}, function(err) {
process.nextTick(function() {
callback(err);
});
});
}
return this;
}...
* @param {Callback.<Analytics~ReportResult>} [callback] - Callback function
* @returns {Promise.<Analytics~ReportResult>}
*/
ReportInstance.prototype.retrieve = function(callback) {
var conn = this._conn,
report = this._report;
var url = [ conn._baseUrl(), "analytics", "reports", report.id, "instances", this.id ].join('
;/');
return conn.request(url).thenCall(callback);
};
/**
* Report object in Analytics API
*
* @protected
* @class Analytics~Report
...query = function (conn, config, options) {
Query.super_.call(this, { objectMode: true });
this._conn = conn;
if (_.isString(config)) { // if query config is string, it is given in SOQL.
this._soql = config;
} else if (config.locator && config.locator.indexOf("/") >= 0) { // if locator given in url for next records
this._locator = config.locator.split("/").pop();
} else {
this._config = config;
this.select(config.fields);
if (config.includes) {
this.include(config.includes);
}
}
this._options = _.defaults({
maxFetch: 10000,
autoFetch: false,
scanAll: false,
responseTarget: ResponseTargets.QueryResult
}, options || {});
this._executed = false;
this._finished = false;
this._chaining = false;
this._deferred = Promise.defer();
var self = this;
}...
var count = -1;
async.waterfall([
function(next) {
conn.sobject(config.bigTable).count({}, next);
},
function(_count, next) {
count = _count;
conn.bulk.query("SELECT Id, Name FROM " + config.bigTable)
.on('record', function(rec) { records.push(rec); })
.on('error', function(err) { next(err); })
.stream().pipe(fstream)
.on('finish', function() { next(null, records); });
}
], function(err, records) {
if (err) { throw err; }
...function Readable(options) {
Duplex = Duplex || require('./_stream_duplex');
if (!(this instanceof Readable)) return new Readable(options);
this._readableState = new ReadableState(options, this);
// legacy
this.readable = true;
if (options && typeof options.read === 'function') this._read = options.read;
Stream.call(this);
}n/a
_execute = function (options) {
var self = this;
var logger = this._conn._logger;
var responseTarget = options.responseTarget;
var autoFetch = options.autoFetch;
var maxFetch = options.maxFetch;
var scanAll = options.scanAll;
return Promise.resolve(
self._locator ?
self._conn._baseUrl() + "/query/" + self._locator :
self.toSOQL().then(function(soql) {
self.totalFetched = 0;
logger.debug("SOQL = " + soql);
return self._conn._baseUrl() + "/" + (scanAll ? "queryAll" : "query") + "?q=" + encodeURIComponent(soql);
})
).then(function(url) {
return self._conn.request({
method: 'GET',
url: url,
headers: options.headers
});
}).then(function(data) {
self.emit("fetch");
self.totalSize = data.totalSize;
var res;
switch(responseTarget) {
case ResponseTargets.SingleRecord:
res = data.records && data.records.length > 0 ? data.records[0] : null;
break;
case ResponseTargets.Records:
res = data.records;
break;
case ResponseTargets.Count:
res = data.totalSize;
break;
default:
res = data;
}
// only fire response event when it should be notified per fetch
if (responseTarget !== ResponseTargets.Records) {
self.emit("response", res, self);
}
// streaming record instances
var numRecords = (data.records && data.records.length) || 0;
for (var i=0; i<numRecords; i++) {
if (self.totalFetched >= maxFetch) {
self._finished = true;
break;
}
var record = data.records[i];
self.push(record);
self.emit('record', record, self.totalFetched++, self);
}
if (data.nextRecordsUrl) {
self._locator = data.nextRecordsUrl.split('/').pop();
}
self._finished = self._finished || data.done || !autoFetch;
if (self._finished) {
self.push(null);
} else {
self._execute(options);
}
return res;
});
}...
});
// flag to prevent re-execution
this._executed = true;
// start actual query
logger.debug('>>> Query start >>>');
this._execute(options).then(function() {
logger.debug('*** Query finished ***');
}).fail(function(err) {
logger.debug('--- Query error ---');
self.emit('error', err);
});
// return Query instance for chaining
..._expandFields = function () {
if (this._soql) {
return Promise.reject(new Error("Cannot expand fields for the query which has already built SOQL."));
}
var self = this;
var logger = self._conn._logger;
var conn = this._conn;
var table = this._config.table;
var fields = this._config.fields || [];
logger.debug('_expandFields: table = ' + table + ', fields = ' + fields.join(', '));
return Promise.all([
Promise.resolve(self._parent ? findRelationTable(table) : table)
.then(function(table) {
return Promise.all(
_.map(fields, function(field) { return expandAsteriskField(table, field); })
).then(function(expandedFields) {
self._config.fields = _.flatten(expandedFields);
});
}),
Promise.all(
_.map(self._children || [], function(childQuery) {
return childQuery._expandFields();
})
)
]);
function findRelationTable(rname) {
var ptable = self._parent._config.table;
logger.debug('finding table for relation "' + rname + '" in "' + ptable + '"...');
return describeCache(ptable).then(function(sobject) {
var upperRname = rname.toUpperCase();
var childRelation = _.find(sobject.childRelationships, function(cr) {
return (cr.relationshipName || '').toUpperCase() === upperRname;
});
return childRelation ? childRelation.childSObject :
Promise.reject(new Error("No child relationship found: " + rname ));
});
}
function describeCache(table) {
logger.debug('describe cache: '+table);
var deferred = Promise.defer();
conn.describe$(table, function(err, sobject) {
logger.debug('... done.');
if (err) { deferred.reject(err); }
else { deferred.resolve(sobject); }
});
return deferred.promise;
}
function expandAsteriskField(table, field) {
logger.debug('expanding field "'+ field + '" in "' + table + '"...');
var fpath = field.split('.');
return fpath[fpath.length - 1] === '*' ?
describeCache(table).then(function(sobject) {
logger.debug('table '+table+'has been described');
if (fpath.length > 1) {
var rname = fpath.shift();
var rfield = _.find(sobject.fields, function(f) {
return f.relationshipName &&
f.relationshipName.toUpperCase() === rname.toUpperCase();
});
if (rfield) {
var rtable = rfield.referenceTo.length === 1 ? rfield.referenceTo[0] : 'Name';
return expandAsteriskField(rtable, fpath.join('.')).then(function(fpaths) {
return _.map(fpaths, function(fpath) { return rname + '.' + fpath; });
});
} else {
return [];
}
} else {
return _.map(sobject.fields, function(f) { return f.name; });
}
}) :
Promise.resolve([ field ]);
}
}...
_.map(fields, function(field) { return expandAsteriskField(table, field); })
).then(function(expandedFields) {
self._config.fields = _.flatten(expandedFields);
});
}),
Promise.all(
_.map(self._children || [], function(childQuery) {
return childQuery._expandFields();
})
)
]);
function findRelationTable(rname) {
var ptable = self._parent._config.table;
logger.debug('finding table for relation "' + rname + '" in "' + ptable + '"...
x27;);
..._read = function (size) {
if (!this._finished && !this._executed) {
this.execute({ autoFetch: true });
}
}n/a
addListener = function (e, fn) {
if (e === 'record') {
var self = this;
this.on('readable', function() {
while(self.read() !== null) {} // discard buffered records
});
}
return Query.super_.prototype.on.call(this, e, fn);
}n/a
autoFetch = function (autoFetch) {
this._options.autoFetch = autoFetch;
return this;
}n/a
del = function (type, callback) {
if (typeof type === 'function') {
callback = type;
type = null;
}
type = type || (this._config && this._config.table);
if (!type) {
throw new Error("SOQL based query needs SObject type information to bulk delete.");
}
var batch = this._conn.sobject(type).deleteBulk();
var deferred = Promise.defer();
var handleError = function(err) {
if (err.name === 'ClientInputError') { deferred.resolve([]); } // if batch input receives no records
else { deferred.reject(err); }
};
this.on('error', handleError)
.pipe(batch)
.on('response', function(res) { deferred.resolve(res); })
.on('error', handleError);
return deferred.promise.thenCall(callback);
}n/a
delete = function (type, callback) {
if (typeof type === 'function') {
callback = type;
type = null;
}
type = type || (this._config && this._config.table);
if (!type) {
throw new Error("SOQL based query needs SObject type information to bulk delete.");
}
var batch = this._conn.sobject(type).deleteBulk();
var deferred = Promise.defer();
var handleError = function(err) {
if (err.name === 'ClientInputError') { deferred.resolve([]); } // if batch input receives no records
else { deferred.reject(err); }
};
this.on('error', handleError)
.pipe(batch)
.on('response', function(res) { deferred.resolve(res); })
.on('error', handleError);
return deferred.promise.thenCall(callback);
}...
/**
*
*/
describe("delete account info", function() {
it("should not get any account for delete account id", function(done) {
async.waterfall([
function(cb) {
conn.apex.delete('/JSforceTestApexRest/' + accountId, cb);
},
function(ret, cb) {
conn.sobject('Account').find({ Id: accountId }, cb);
}
], function(err, records) {
if (err) { throw err; }
assert.ok(records.length === 0);
...destroy = function (type, callback) {
if (typeof type === 'function') {
callback = type;
type = null;
}
type = type || (this._config && this._config.table);
if (!type) {
throw new Error("SOQL based query needs SObject type information to bulk delete.");
}
var batch = this._conn.sobject(type).deleteBulk();
var deferred = Promise.defer();
var handleError = function(err) {
if (err.name === 'ClientInputError') { deferred.resolve([]); } // if batch input receives no records
else { deferred.reject(err); }
};
this.on('error', handleError)
.pipe(batch)
.on('response', function(res) { deferred.resolve(res); })
.on('error', handleError);
return deferred.promise.thenCall(callback);
}...
* @returns {Promise.<RecordResult>}
*/
RecordReference.prototype.destroy = function(options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.destroy(this.type, this.id, options, callback);
};
/**
* Get blob field as stream
*
* @param {String} fieldName - Blob field name
* @returns {stream.Stream}
...exec = function (options, callback) {
var self = this;
var logger = this._conn._logger;
var deferred = this._deferred;
if (this._executed) {
deferred.reject(new Error("re-executing already executed query"));
return this;
}
if (this._finished) {
deferred.reject(new Error("executing already closed query"));
return this;
}
if (typeof options === "function") {
callback = options;
options = {};
}
options = options || {};
options = {
headers: options.headers || self._options.headers,
responseTarget: options.responseTarget || self._options.responseTarget,
autoFetch: options.autoFetch || self._options.autoFetch,
maxFetch: options.maxFetch || self._options.maxFetch,
scanAll: options.scanAll || self._options.scanAll
};
// callback and promise resolution;
var promiseCallback = function(err, res) {
if (_.isFunction(callback)) {
try {
res = callback(err, res);
err = null;
} catch(e) {
err = e;
}
}
if (err) {
deferred.reject(err);
} else {
deferred.resolve(res);
}
};
this.once('response', function(res) {
promiseCallback(null, res);
});
this.once('error', function(err) {
promiseCallback(err);
});
// collect fetched records in array
// only when response target is Records and
// either callback or chaining promises are available to this query.
this.once('fetch', function() {
if (options.responseTarget === ResponseTargets.Records && (self._chaining || callback)) {
logger.debug('--- collecting all fetched records ---');
var records = [];
var onRecord = function(record) {
records.push(record);
};
self.on('record', onRecord);
self.once('end', function() {
self.removeListener('record', onRecord);
self.emit('response', records, self);
});
}
});
// flag to prevent re-execution
this._executed = true;
// start actual query
logger.debug('>>> Query start >>>');
this._execute(options).then(function() {
logger.debug('*** Query finished ***');
}).fail(function(err) {
logger.debug('--- Query error ---');
self.emit('error', err);
});
// return Query instance for chaining
return this;
}...
mapped[prop] = noeval ? record[prop] : evalMapping(record[prop], rec);
}
return mapped;
});
function evalMapping(value, mapping) {
if (_.isString(value)) {
var m = /^\$\{(\w+)\}$/.exec(value);
if (m) { return mapping[m[1]]; }
return value.replace(/\$\{(\w+)\}/g, function($0, prop) {
var v = mapping[prop];
return _.isNull(v) || _.isUndefined(v) ? "" : String(v);
});
} else {
return value;
...execute = function (options, callback) {
var self = this;
var logger = this._conn._logger;
var deferred = this._deferred;
if (this._executed) {
deferred.reject(new Error("re-executing already executed query"));
return this;
}
if (this._finished) {
deferred.reject(new Error("executing already closed query"));
return this;
}
if (typeof options === "function") {
callback = options;
options = {};
}
options = options || {};
options = {
headers: options.headers || self._options.headers,
responseTarget: options.responseTarget || self._options.responseTarget,
autoFetch: options.autoFetch || self._options.autoFetch,
maxFetch: options.maxFetch || self._options.maxFetch,
scanAll: options.scanAll || self._options.scanAll
};
// callback and promise resolution;
var promiseCallback = function(err, res) {
if (_.isFunction(callback)) {
try {
res = callback(err, res);
err = null;
} catch(e) {
err = e;
}
}
if (err) {
deferred.reject(err);
} else {
deferred.resolve(res);
}
};
this.once('response', function(res) {
promiseCallback(null, res);
});
this.once('error', function(err) {
promiseCallback(err);
});
// collect fetched records in array
// only when response target is Records and
// either callback or chaining promises are available to this query.
this.once('fetch', function() {
if (options.responseTarget === ResponseTargets.Records && (self._chaining || callback)) {
logger.debug('--- collecting all fetched records ---');
var records = [];
var onRecord = function(record) {
records.push(record);
};
self.on('record', onRecord);
self.once('end', function() {
self.removeListener('record', onRecord);
self.emit('response', records, self);
});
}
});
// flag to prevent re-execution
this._executed = true;
// start actual query
logger.debug('>>> Query start >>>');
this._execute(options).then(function() {
logger.debug('*** Query finished ***');
}).fail(function(err) {
logger.debug('--- Query error ---');
self.emit('error', err);
});
// return Query instance for chaining
return this;
}...
if (err.name !== 'PollingTimeout') {
cleanup();
}
};
batch.on('response', cleanup);
batch.on('error', cleanupOnError);
batch.on('queue', function() { batch.poll(self.pollInterval, self.pollTimeout); });
return batch.execute(input, callback);
};
/**
* Execute bulk query and get record stream
*
* @param {String} soql - SOQL to execute in bulk job
* @returns {RecordStream.Parsable} - Record stream, convertible to CSV data stream
...explain = function (callback) {
var self = this;
var logger = this._conn._logger;
return self.toSOQL().then(function(soql) {
logger.debug("SOQL = " + soql);
var url = "/query/?explain=" + encodeURIComponent(soql);
return self._conn.request(url);
}).thenCall(callback);
}...
});
/**
*
*/
describe("explain query plan of report", function() {
it("should get explain result", function(done) {
conn.analytics.report(reportId).explain(function(err, result) {
if (err) { throw err; }
assert.ok(_.isArray(result.plans));
for (var i=0; i<result.plans.length; i++) {
var plan = result.plans[i];
assert.ok(_.isNumber(plan.cardinality));
assert.ok(_.isArray(plan.fields));
assert.ok(_.isString(plan.leadingOperationType));
...filter = function (fn) {
return this.pipe(RecordStream.map(fn));
}...
var name = protocol.replace(/:$/, '').toLowerCase() + '_proxy',
upcase = name.toUpperCase(),
env = process.env,
keys, proxy;
if (name === 'http_proxy' && env.REQUEST_METHOD) {
keys = Object.keys(env).filter(function(k) { return /^http_proxy$/i.test(k) });
if (keys.length === 1) {
if (keys[0] === name && env[upcase] === undefined)
proxy = env[name];
} else if (keys.length > 1) {
proxy = env[name];
}
proxy = proxy || env['CGI_' + upcase];
...include = function (childRelName, conditions, fields, options) {
if (this._soql) {
throw Error("Cannot include child relationship into the query which has already built SOQL.");
}
if (_.isObject(childRelName)) {
var includes = childRelName;
for (var crname in includes) {
var config = includes[crname];
this.include(crname, config.conditions, config.fields, config);
}
return;
}
var childConfig = {
table: childRelName,
conditions: conditions,
fields: fields,
limit: options && options.limit,
offset: options && (options.offset || options.skip),
sort: options && options.sort
};
if (!_.isArray(this._config.includes)) this._config.includes = [];
this._config.includes.push(childConfig);
var childQuery = new SubQuery(this._conn, this, childConfig);
this._children = this._children || [];
this._children.push(childQuery);
return childQuery;
}...
this._soql = config;
} else if (config.locator && config.locator.indexOf("/") >= 0) { // if locator given in url for next records
this._locator = config.locator.split("/").pop();
} else {
this._config = config;
this.select(config.fields);
if (config.includes) {
this.include(config.includes);
}
}
this._options = _.defaults({
maxFetch: 10000,
autoFetch: false,
scanAll: false,
responseTarget: ResponseTargets.QueryResult
...limit = function (limit) {
if (this._soql) {
throw Error("Cannot set limit for the query which has already built SOQL.");
}
this._config.limit = limit;
return this;
}...
/**
*
*/
describe("find records with multiple sort options and limit option", function() {
it("should return sorted records", function(done) {
Opportunity.find({}, { "Owner.Name" : 1, CloseDate : 1 })
.sort({ "Owner.Name" : 1, CloseDate : -1 })
.limit(10)
.exec(function(err, records) {
if (err) { throw err; }
assert.ok(_.isArray(records));
assert.ok(records.length > 0);
assert.ok(records.length < 11);
for (var i=0; i<records.length - 1; i++) {
var r1 = records[i], r2 = records[i+1];
...map = function (fn) {
return this.pipe(RecordStream.map(fn));
}...
});
}).then(function(res) {
var results;
if (job.operation === 'query') {
var conn = bulk._conn;
var resultIds = res['result-list'].result;
results = res['result-list'].result;
results = _.map(_.isArray(results) ? results : [ results ], function(id) {
return {
id: id,
batchId: batchId,
jobId: jobId
};
});
} else {
...maxFetch = function (maxFetch) {
this._options.maxFetch = maxFetch;
return this;
}n/a
offset = function (offset) {
if (this._soql) {
throw Error("Cannot set skip/offset for the query which has already built SOQL.");
}
this._config.offset = offset;
return this;
}n/a
on = function (e, fn) {
if (e === 'record') {
var self = this;
this.on('readable', function() {
while(self.read() !== null) {} // discard buffered records
});
}
return Query.super_.prototype.on.call(this, e, fn);
}...
return this._conn.request(url).thenCall(callback);
};
/*--------------------------------------------*/
/*
* Register hook in connection instantiation for dynamically adding this API module features
*/
jsforce.on('connection:new', function(conn) {
conn.analytics = new Analytics(conn);
});
module.exports = Analytics;
},{}]},{},[1])(1)
});
...orderby = function (sort, dir) {
if (this._soql) {
throw Error("Cannot set sort for the query which has already built SOQL.");
}
if (_.isString(sort) && _.isString(dir)) {
sort = [ [ sort, dir ] ];
}
this._config.sort = sort;
return this;
}n/a
run = function (options, callback) {
var self = this;
var logger = this._conn._logger;
var deferred = this._deferred;
if (this._executed) {
deferred.reject(new Error("re-executing already executed query"));
return this;
}
if (this._finished) {
deferred.reject(new Error("executing already closed query"));
return this;
}
if (typeof options === "function") {
callback = options;
options = {};
}
options = options || {};
options = {
headers: options.headers || self._options.headers,
responseTarget: options.responseTarget || self._options.responseTarget,
autoFetch: options.autoFetch || self._options.autoFetch,
maxFetch: options.maxFetch || self._options.maxFetch,
scanAll: options.scanAll || self._options.scanAll
};
// callback and promise resolution;
var promiseCallback = function(err, res) {
if (_.isFunction(callback)) {
try {
res = callback(err, res);
err = null;
} catch(e) {
err = e;
}
}
if (err) {
deferred.reject(err);
} else {
deferred.resolve(res);
}
};
this.once('response', function(res) {
promiseCallback(null, res);
});
this.once('error', function(err) {
promiseCallback(err);
});
// collect fetched records in array
// only when response target is Records and
// either callback or chaining promises are available to this query.
this.once('fetch', function() {
if (options.responseTarget === ResponseTargets.Records && (self._chaining || callback)) {
logger.debug('--- collecting all fetched records ---');
var records = [];
var onRecord = function(record) {
records.push(record);
};
self.on('record', onRecord);
self.once('end', function() {
self.removeListener('record', onRecord);
self.emit('response', records, self);
});
}
});
// flag to prevent re-execution
this._executed = true;
// start actual query
logger.debug('>>> Query start >>>');
this._execute(options).then(function() {
logger.debug('*** Query finished ***');
}).fail(function(err) {
logger.debug('--- Query error ---');
self.emit('error', err);
});
// return Query instance for chaining
return this;
}...
var len = queue.length;
while(len) {
currentQueue = queue;
queue = [];
while (++queueIndex < len) {
if (currentQueue) {
currentQueue[queueIndex].run();
}
}
queueIndex = -1;
len = queue.length;
}
currentQueue = null;
draining = false;
...scanAll = function (scanAll) {
this._options.scanAll = scanAll;
return this;
}...
*/
Connection.prototype.queryAll = function(soql, options, callback) {
if (typeof options === 'function') {
callback = options;
options = undefined;
}
var query = new Query(this, soql, options);
query.scanAll(true);
if (callback) {
query.run(callback);
}
return query;
};
/**
...select = function (fields) {
if (this._soql) {
throw Error("Cannot set select fields for the query which has already built SOQL.");
}
fields = fields || '*';
if (_.isString(fields)) {
fields = fields.split(/\s*,\s*/);
} else if (_.isObject(fields) && !_.isArray(fields)) {
var _fields = [];
for (var k in fields) {
if (fields[k]) { _fields.push(k); }
}
fields = _fields;
}
this._config.fields = fields;
return this;
}...
this._conn = conn;
if (_.isString(config)) { // if query config is string, it is given in SOQL.
this._soql = config;
} else if (config.locator && config.locator.indexOf("/") >= 0) { // if locator given in url for next records
this._locator = config.locator.split("/").pop();
} else {
this._config = config;
this.select(config.fields);
if (config.includes) {
this.include(config.includes);
}
}
this._options = _.defaults({
maxFetch: 10000,
autoFetch: false,
...setResponseTarget = function (responseTarget) {
if (responseTarget in ResponseTargets) {
this._options.responseTarget = responseTarget;
}
return this;
}...
includes: options.includes,
table: this.type,
conditions: conditions,
limit: options.limit,
offset: options.offset || options.skip
};
var query = new Query(this._conn, config, options);
query.setResponseTarget(Query.ResponseTargets.Records);
if (callback) { query.run(callback); }
return query;
};
/**
* Fetch one record which matches given conditions
*
...skip = function (offset) {
if (this._soql) {
throw Error("Cannot set skip/offset for the query which has already built SOQL.");
}
this._config.offset = offset;
return this;
}n/a
sort = function (sort, dir) {
if (this._soql) {
throw Error("Cannot set sort for the query which has already built SOQL.");
}
if (_.isString(sort) && _.isString(dir)) {
sort = [ [ sort, dir ] ];
}
this._config.sort = sort;
return this;
}...
/**
*
*/
describe("find records with sort option", function() {
it("should return sorted records", function(done) {
Opportunity.find({}, { CloseDate : 1 })
.sort("CloseDate", "desc")
.exec(function(err, records) {
if (err) { throw err; }
assert.ok(_.isArray(records));
assert.ok(records.length > 0);
for (var i=0; i<records.length - 1; i++) {
assert.ok(records[i].CloseDate >= records[i+1].CloseDate);
}
...stream = function (type, options) {
type = type || 'csv';
var converter = DataStreamConverters[type];
if (!converter) {
throw new Error('Converting [' + type + '] data stream is not supported.');
}
if (!this._dataStream) {
this._dataStream = new PassThrough();
this.pipe(converter.serialize(options))
.pipe(this._dataStream);
}
return this._dataStream;
}...
/**
* @private
*/
Batch.prototype._setupDataStreams = function() {
var batch = this;
var converterOptions = { nullValue : '#N/A' };
this._uploadStream = new RecordStream.Serializable();
this._uploadDataStream = this._uploadStream.stream('csv', converterOptions);
this._downloadStream = new RecordStream.Parsable();
this._downloadDataStream = this._downloadStream.stream('csv', converterOptions);
this.on('finish', function() {
batch._uploadStream.end();
});
this._uploadDataStream.once('readable', function() {
...then = function (onResolved, onReject) {
this._chaining = true;
if (!this._finished && !this._executed) { this.execute(); }
return this._deferred.promise.then.apply(this._deferred.promise, arguments);
}...
method : 'POST',
path : "/job",
body : body,
headers : {
"Content-Type" : "application/xml; charset=utf-8"
},
responseType: "application/xml"
}).then(function(res) {
self.emit("open", res.jobInfo);
self.id = res.jobInfo.id;
self.state = res.jobInfo.state;
return res.jobInfo;
}, function(err) {
self.emit("error", err);
throw err;
...thenCall = function (callback) {
if (_.isFunction(callback)) {
this.then(function(res) {
process.nextTick(function() {
callback(null, res);
});
}, function(err) {
process.nextTick(function() {
callback(err);
});
});
}
return this;
}...
* @param {Callback.<Analytics~ReportResult>} [callback] - Callback function
* @returns {Promise.<Analytics~ReportResult>}
*/
ReportInstance.prototype.retrieve = function(callback) {
var conn = this._conn,
report = this._report;
var url = [ conn._baseUrl(), "analytics", "reports", report.id, "instances", this.id ].join('
;/');
return conn.request(url).thenCall(callback);
};
/**
* Report object in Analytics API
*
* @protected
* @class Analytics~Report
...toSOQL = function (callback) {
var self = this;
return Promise.resolve(self._soql ||
self._expandFields().then(function() { return SOQLBuilder.createSOQL(self._config); })
).thenCall(callback);
}...
var autoFetch = options.autoFetch;
var maxFetch = options.maxFetch;
var scanAll = options.scanAll;
return Promise.resolve(
self._locator ?
self._conn._baseUrl() + "/query/" + self._locator :
self.toSOQL().then(function(soql) {
self.totalFetched = 0;
logger.debug("SOQL = " + soql);
return self._conn._baseUrl() + "/" + (scanAll ? "queryAll" : "query") + "?q=" + encodeURIComponent
(soql);
})
).then(function(url) {
return self._conn.request({
method: 'GET',
...update = function (mapping, type, callback) {
if (typeof type === 'function') {
callback = type;
type = null;
}
type = type || (this._config && this._config.table);
if (!type) {
throw new Error("SOQL based query needs SObject type information to bulk update.");
}
var updateStream = _.isFunction(mapping) ? RecordStream.map(mapping) : RecordStream.recordMapStream(mapping);
var batch = this._conn.sobject(type).updateBulk();
var deferred = Promise.defer();
var handleError = function(err) {
if (err.name === 'ClientInputError') { deferred.resolve([]); } // if batch input receives no records
else { deferred.reject(err); }
};
this.on('error', handleError)
.pipe(updateStream)
.on('error', handleError)
.pipe(batch)
.on('response', function(res) { deferred.resolve(res); })
.on('error', handleError);
return deferred.promise.thenCall(callback);
}...
RecordReference.prototype.update = function(record, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
record = _.clone(record);
record.Id = this.id;
return this._conn.update(this.type, record, options, callback);
};
/**
* Synonym of Record#destroy()
*
* @method RecordReference#delete
* @param {Object} [options] - Options for rest api.
...where = function (conditions) {
if (this._soql) {
throw Error("Cannot set where conditions for the query which has already built SOQL.");
}
this._config.conditions = conditions;
return this;
}n/a
quick_action = function (conn, path) {
this._conn = conn;
this._path = path;
}n/a
defaultValues = function (contextId, callback) {
if (typeof contextId === 'function') {
callback = contextId;
contextId = null;
}
var url = this._path + "/defaultValues";
if (contextId) {
url += "/" + contextId;
}
return this._conn.request(url).thenCall(callback);
}...
});
/**
*
*/
describe("get default values of the action", function() {
it("should return default field values", function(done) {
action.defaultValues(function(err, res) {
if (err) { throw err; }
assert.ok(_.isObject(res));
// assert.ok(res.Subject === null);
assert.ok(res.Description === null);
assert.ok(res.WhoId === null);
assert.ok(res.WhatId === null);
}.check(done));
...describe = function (callback) {
var url = this._path + "/describe";
return this._conn.request(url).thenCall(callback);
}...
/**
* Describe SObject metadata
*
* @param {Callback.<DescribeSObjectResult>} [callback] - Callback function
* @returns {Promise.<DescribeSObjectResult>}
*/
SObject.prototype.describe = function(callback) {
return this._conn.describe(this.type, callback);
};
/**
* Get record representation instance by given id
*
* @param {String} id - A record ID
* @returns {RecordReference}
...execute = function (contextId, record, callback) {
var body = {
contextId: contextId,
record: record
};
return this._conn.requestPost(this._path, body).thenCall(callback);
}...
if (err.name !== 'PollingTimeout') {
cleanup();
}
};
batch.on('response', cleanup);
batch.on('error', cleanupOnError);
batch.on('queue', function() { batch.poll(self.pollInterval, self.pollTimeout); });
return batch.execute(input, callback);
};
/**
* Execute bulk query and get record stream
*
* @param {String} soql - SOQL to execute in bulk job
* @returns {RecordStream.Parsable} - Record stream, convertible to CSV data stream
...record = function (conn, type, id) {
this._conn = conn;
this.type = type;
this.id = id;
}...
});
/**
*
*/
describe("update account", function() {
it("should update successfully", function(done) {
conn.sobject('Account').record(account.Id).update({ Name : "Hello2
x22; }, function(err, ret) {
if (err) { throw err; }
assert.ok(ret.success);
}.check(done));
});
describe("then retrieve the account", function() {
it("should return updated account object", function(done) {
...blob = function (fieldName) {
var url = [ this._conn._baseUrl(), 'sobjects', this.type, this.id, fieldName ].join('/');
return this._conn.request(url).stream();
}n/a
del = function (options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.destroy(this.type, this.id, options, callback);
}n/a
delete = function (options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.destroy(this.type, this.id, options, callback);
}...
/**
*
*/
describe("delete account info", function() {
it("should not get any account for delete account id", function(done) {
async.waterfall([
function(cb) {
conn.apex.delete('/JSforceTestApexRest/' + accountId, cb);
},
function(ret, cb) {
conn.sobject('Account').find({ Id: accountId }, cb);
}
], function(err, records) {
if (err) { throw err; }
assert.ok(records.length === 0);
...destroy = function (options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.destroy(this.type, this.id, options, callback);
}...
* @returns {Promise.<RecordResult>}
*/
RecordReference.prototype.destroy = function(options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.destroy(this.type, this.id, options, callback);
};
/**
* Get blob field as stream
*
* @param {String} fieldName - Blob field name
* @returns {stream.Stream}
...retrieve = function (options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.retrieve(this.type, this.id, options, callback);
}...
}
self.check(function(err, res) {
if (err) {
self.emit('error', err);
} else {
if (res.state === "Failed") {
if (parseInt(res.numberRecordsProcessed, 10) > 0) {
self.retrieve();
} else {
self.emit('error', new Error(res.stateMessage));
}
} else if (res.state === "Completed") {
self.retrieve();
} else {
self.emit('progress', res);
...update = function (record, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
record = _.clone(record);
record.Id = this.id;
return this._conn.update(this.type, record, options, callback);
}...
RecordReference.prototype.update = function(record, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
record = _.clone(record);
record.Id = this.id;
return this._conn.update(this.type, record, options, callback);
};
/**
* Synonym of Record#destroy()
*
* @method RecordReference#delete
* @param {Object} [options] - Options for rest api.
...record_stream = function () {
RecordStream.super_.call(this, { objectMode: true });
}n/a
Parsable = function () {
Parsable.super_.call(this);
this._dataStream = null;
}...
* @private
*/
Batch.prototype._setupDataStreams = function() {
var batch = this;
var converterOptions = { nullValue : '#N/A' };
this._uploadStream = new RecordStream.Serializable();
this._uploadDataStream = this._uploadStream.stream('csv', converterOptions);
this._downloadStream = new RecordStream.Parsable();
this._downloadDataStream = this._downloadStream.stream('csv', converterOptions);
this.on('finish', function() {
batch._uploadStream.end();
});
this._uploadDataStream.once('readable', function() {
batch.job.open().then(function() {
...Serializable = function () {
Serializable.super_.call(this);
this._dataStream = null;
}...
/**
* @private
*/
Batch.prototype._setupDataStreams = function() {
var batch = this;
var converterOptions = { nullValue : '#N/A' };
this._uploadStream = new RecordStream.Serializable();
this._uploadDataStream = this._uploadStream.stream('csv', converterOptions);
this._downloadStream = new RecordStream.Parsable();
this._downloadDataStream = this._downloadStream.stream('csv', converterOptions);
this.on('finish', function() {
batch._uploadStream.end();
});
...filter = function (fn) {
var filterStream = new RecordStream.Serializable();
filterStream._transform = function(record, enc, callback) {
if (fn(record)) { this.push(record); }
callback();
};
return filterStream;
}...
var name = protocol.replace(/:$/, '').toLowerCase() + '_proxy',
upcase = name.toUpperCase(),
env = process.env,
keys, proxy;
if (name === 'http_proxy' && env.REQUEST_METHOD) {
keys = Object.keys(env).filter(function(k) { return /^http_proxy$/i.test(k) });
if (keys.length === 1) {
if (keys[0] === name && env[upcase] === undefined)
proxy = env[name];
} else if (keys.length > 1) {
proxy = env[name];
}
proxy = proxy || env['CGI_' + upcase];
...map = function (fn) {
var mapStream = new RecordStream.Serializable();
mapStream._transform = function(record, enc, callback) {
var rec = fn(record) || record; // if not returned record, use same record
this.push(rec);
callback();
};
return mapStream;
}...
});
}).then(function(res) {
var results;
if (job.operation === 'query') {
var conn = bulk._conn;
var resultIds = res['result-list'].result;
results = res['result-list'].result;
results = _.map(_.isArray(results) ? results : [ results ], function(id) {
return {
id: id,
batchId: batchId,
jobId: jobId
};
});
} else {
...recordMapStream = function (record, noeval) {
return RecordStream.map(function(rec) {
var mapped = { Id: rec.Id };
for (var prop in record) {
mapped[prop] = noeval ? record[prop] : evalMapping(record[prop], rec);
}
return mapped;
});
function evalMapping(value, mapping) {
if (_.isString(value)) {
var m = /^\$\{(\w+)\}$/.exec(value);
if (m) { return mapping[m[1]]; }
return value.replace(/\$\{(\w+)\}/g, function($0, prop) {
var v = mapping[prop];
return _.isNull(v) || _.isUndefined(v) ? "" : String(v);
});
} else {
return value;
}
}
}...
callback = type;
type = null;
}
type = type || (this._config && this._config.table);
if (!type) {
throw new Error("SOQL based query needs SObject type information to bulk update.");
}
var updateStream = _.isFunction(mapping) ? RecordStream.map(mapping) : RecordStream.recordMapStream
(mapping);
var batch = this._conn.sobject(type).updateBulk();
var deferred = Promise.defer();
var handleError = function(err) {
if (err.name === 'ClientInputError') { deferred.resolve([]); } // if batch input receives no records
else { deferred.reject(err); }
};
this.on('error', handleError)
...function Transform(options) {
if (!(this instanceof Transform)) return new Transform(options);
Duplex.call(this, options);
this._transformState = new TransformState(this);
var stream = this;
// start out asking for a readable event once data is transformed.
this._readableState.needReadable = true;
// we have implemented the _read method, and done the other things
// that Readable wants before the first _read call, so unset the
// sync guard flag.
this._readableState.sync = false;
if (options) {
if (typeof options.transform === 'function') this._transform = options.transform;
if (typeof options.flush === 'function') this._flush = options.flush;
}
// When the writable side finishes, then flush out anything remaining.
this.once('prefinish', function () {
if (typeof this._flush === 'function') this._flush(function (er, data) {
done(stream, er, data);
});else done(stream);
});
}n/a
_transform = function (record, enc, callback) {
this.emit('record', record);
this.push(record);
callback();
}n/a
filter = function (fn) {
return this.pipe(RecordStream.filter(fn));
}...
var name = protocol.replace(/:$/, '').toLowerCase() + '_proxy',
upcase = name.toUpperCase(),
env = process.env,
keys, proxy;
if (name === 'http_proxy' && env.REQUEST_METHOD) {
keys = Object.keys(env).filter(function(k) { return /^http_proxy$/i.test(k) });
if (keys.length === 1) {
if (keys[0] === name && env[upcase] === undefined)
proxy = env[name];
} else if (keys.length > 1) {
proxy = env[name];
}
proxy = proxy || env['CGI_' + upcase];
...map = function (fn) {
return this.pipe(RecordStream.map(fn));
}...
});
}).then(function(res) {
var results;
if (job.operation === 'query') {
var conn = bulk._conn;
var resultIds = res['result-list'].result;
results = res['result-list'].result;
results = _.map(_.isArray(results) ? results : [ results ], function(id) {
return {
id: id,
batchId: batchId,
jobId: jobId
};
});
} else {
...soap = function (conn, options) {
SOAP.super_.apply(this, arguments);
this._endpointUrl = options.endpointUrl;
this._xmlns = options.xmlns || 'urn:partner.soap.sforce.com';
}n/a
super_ = function (conn, options) {
options = options || {};
this._conn = conn;
this.on('resume', function(err) { conn.emit('resume', err); });
this._responseType = options.responseType;
this._transport = options.transport || conn._transport;
this._noContentResponse = options.noContentResponse;
}n/a
_createEnvelope = function (message) {
var header = {};
var conn = this._conn;
if (conn.accessToken) {
header.SessionHeader = { sessionId: this._conn.accessToken };
}
if (conn.callOptions) {
header.CallOptions = conn.callOptions;
}
return [
'<?xml version="1.0" encoding="UTF-8"?>',
'<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"',
' xmlns:xsd="http://www.w3.org/2001/XMLSchema"',
' xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">',
'<soapenv:Header xmlns="' + this._xmlns + '">',
toXML(header),
'</soapenv:Header>',
'<soapenv:Body xmlns="' + this._xmlns + '">',
toXML(message),
'</soapenv:Body>',
'</soapenv:Envelope>'
].join('');
}...
}
}
}
}
/** @override **/
SOAP.prototype.beforeSend = function(request) {
request.body = this._createEnvelope(request.message);
};
/** @override **/
SOAP.prototype.isSessionExpired = function(response) {
return response.statusCode === 500 &&
/<faultcode>[a-zA-Z]+:INVALID_SESSION_ID<\/faultcode>/.test(response.body);
};
...beforeSend = function (request) {
request.body = this._createEnvelope(request.message);
}...
if (refreshDelegate && refreshDelegate._refreshing) {
refreshDelegate.once('resume', onResume);
return deferred.promise.thenCall(callback);
}
// hook before sending
self.beforeSend(request);
self.emit('request', request);
logger.debug("<request> method=" + request.method + ", url=" + request.url);
var requestTime = Date.now();
return this._transport.httpRequest(request).then(function(response) {
var responseTime = Date.now();
...getResponseBody = function (response) {
var body = SOAP.super_.prototype.getResponseBody.call(this, response);
return lookupValue(body, [ /:Envelope$/, /:Body$/, /.+/ ]);
}...
refreshDelegate.refresh(requestTime, onResume);
return deferred.promise;
}
if (self.isErrorResponse(response)) {
var err = self.getError(response);
throw err;
}
return self.getResponseBody(response);
}, function(err) {
var responseTime = Date.now();
logger.debug("elappsed time : " + (responseTime - requestTime) + "msec");
logger.error(err);
throw err;
})
.thenCall(callback);
...invoke = function (method, args, schema, callback) {
if (typeof schema === 'function') {
callback = schema;
schema = null;
}
var message = {};
message[method] = args;
return this.request({
method: 'POST',
url: this._endpointUrl,
headers: {
'Content-Type': 'text/xml',
'SOAPAction': '""'
},
message: message
}).then(function(res) {
return schema ? convertType(res, schema) : res;
}).thenCall(callback);
}...
* @private
*/
Metadata.prototype._invoke = function(method, message, callback) {
var soapEndpoint = new SOAP(this._conn, {
xmlns: "http://soap.sforce.com/2006/04/metadata",
endpointUrl: this._conn.instanceUrl + "/services/Soap/m/" + this._conn.version
});
return soapEndpoint.invoke(method, message).then(function(res) {
return res.result;
}).thenCall(callback);
};
/**
* @typedef {Object} Metadata~MetadataInfo
...isSessionExpired = function (response) {
return response.statusCode === 500 &&
/<faultcode>[a-zA-Z]+:INVALID_SESSION_ID<\/faultcode>/.test(response.body);
}...
var responseTime = Date.now();
logger.debug("elappsed time : " + (responseTime - requestTime) + "msec");
logger.debug("<response> status=" + response.statusCode + ", url=" + request.url);
self.emit('response', response);
// Refresh token if session has been expired and requires authentication
// when session refresh delegate is available
if (self.isSessionExpired(response) && refreshDelegate) {
refreshDelegate.refresh(requestTime, onResume);
return deferred.promise;
}
if (self.isErrorResponse(response)) {
var err = self.getError(response);
throw err;
}
...parseError = function (body) {
var error = lookupValue(body, [ /:Envelope$/, /:Body$/, /:Fault$/ ]);
return {
errorCode: error.faultcode,
message: error.faultstring
};
}...
/**
* Get error message in response
* @protected
*/
HttpApi.prototype.getError = function(response, body) {
var error;
try {
error = this.parseError(body || this.parseResponseBody(response));
} catch(e) {}
error = _.isObject(error) && _.isString(error.message) ? error : {
errorCode: 'ERROR_HTTP_' + response.statusCode,
message : response.body
};
var err = new Error(error.message);
err.name = error.errorCode;
...sobject = function (conn, type) {
this._conn = conn;
this.type = type;
var cacheOptions = { key: "describe." + this.type };
this.describe$ = conn.cache.makeCacheable(this.describe, this, cacheOptions);
this.describe = conn.cache.makeResponseCacheable(this.describe, this, cacheOptions);
cacheOptions = { key: "layouts." + this.type };
this.layouts$ = conn.cache.makeCacheable(this.layouts, this, cacheOptions);
this.layouts = conn.cache.makeResponseCacheable(this.layouts, this, cacheOptions);
cacheOptions = { key: "compactLayouts." + this.type };
this.compactLayouts$ = conn.cache.makeCacheable(this.compactLayouts, this, cacheOptions);
this.compactLayouts = conn.cache.makeResponseCacheable(this.compactLayouts, this, cacheOptions);
cacheOptions = { key: "approvalLayouts." + this.type };
this.approvalLayouts$ = conn.cache.makeCacheable(this.approvalLayouts, this, cacheOptions);
this.approvalLayouts = conn.cache.makeResponseCacheable(this.approvalLayouts, this, cacheOptions);
}...
};
Channel.prototype.push = function(events, callback) {
var isArray = _.isArray(events);
events = isArray ? events : [ events ];
var conn = this._streaming._conn;
if (!this._id) {
this._id = conn.sobject('StreamingChannel').findOne({ Name: this._name },
x27;Id')
.then(function(rec) { return rec.Id });
}
return this._id.then(function(id) {
var channelUrl = '/sobjects/StreamingChannel/' + id + '/push';
return conn.requestPost(channelUrl, { pushEvents: events });
}).then(function(rets) {
return isArray ? rets : rets[0];
...approvalLayouts = function (callback) {
var url = "/sobjects/" + this.type + "/describe/approvalLayouts";
return this._conn.request(url, callback);
}...
/**
*
*/
describe("list approval layout for SObject", function() {
it("should return Account approval layout information", function(done) {
Account.approvalLayouts(function(err, res) {
if (err) { throw err; }
assert.ok(_.isArray(res.approvalLayouts));
res.approvalLayouts.forEach(function(alayout) {
assert.ok(alayout.id === null || _.isString(alayout.id));
assert.ok(_.isString(alayout.name));
assert.ok(_.isString(alayout.label));
assert.ok(_.isArray(alayout.layoutItems));
...bulkload = function (operation, options, input, callback) {
return this._conn.bulk.load(this.type, operation, options, input, callback);
}...
* @method SObject#createBulk
* @param {Array.<Record>|stream.Stream|String} [input] - Input source for bulk insert. Accepts array of records, CSv string
, and CSV data input stream.
* @param {Callback.<Array.<RecordResult>>} [callback] - Callback function
* @returns {Bulk~Batch}
*/
SObject.prototype.insertBulk =
SObject.prototype.createBulk = function(input, callback) {
return this.bulkload("insert", input, callback);
};
/**
* Bulkly update records by input data using bulk API
*
* @param {Array.<Record>|stream.Stream|String} [input] - Input source for bulk update Accepts array of records, CSv string
, and CSV data input stream.
* @param {Callback.<Array.<RecordResult>>} [callback] - Callback function
...compactLayouts = function (callback) {
var url = "/sobjects/" + this.type + "/describe/compactLayouts";
return this._conn.request(url, callback);
}...
});
/**
*
*/
describe("list compact layout for SObject", function() {
it("should return Account comact layout information", function(done) {
Account.compactLayouts(function(err, res) {
if (err) { throw err; }
assert.ok(_.isArray(res.compactLayouts));
res.compactLayouts.forEach(function(clayout) {
assert.ok(clayout.id === null || _.isString(clayout.id));
assert.ok(_.isString(clayout.objectType));
assert.ok(_.isArray(clayout.actions));
assert.ok(_.isArray(clayout.fieldItems));
...count = function (conditions, callback) {
if (typeof conditions === 'function') {
callback = conditions;
conditions = {};
}
var query = this.find(conditions, { "count()" : true });
query.setResponseTarget("Count");
if (callback) { query.run(callback); }
return query;
}...
it("should get a record stream and file output", function(done) {
var file = __dirname + "/data/BulkQuery_export.csv";
var fstream = fs.createWriteStream(file);
var records = [];
var count = -1;
async.waterfall([
function(next) {
conn.sobject(config.bigTable).count({}, next);
},
function(_count, next) {
count = _count;
conn.bulk.query("SELECT Id, Name FROM " + config.bigTable)
.on('record', function(rec) { records.push(rec); })
.on('error', function(err) { next(err); })
.stream().pipe(fstream)
...create = function (records, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.create(this.type, records, options, callback);
}...
initialize: function(endpoint, options) {
this.info('New client created for ?', endpoint);
options = options || {};
validateOptions(options, ['interval', 'timeout', 'endpoints', 'proxy', 'retry',
x27;scheduler', 'websocketExtensions', 'tls', 'ca']);
this._channels = new Channel.Set();
this._dispatcher = Dispatcher.create(this, endpoint || this.DEFAULT_ENDPOINT, options
);
this._messageId = 0;
this._state = this.UNCONNECTED;
this._responseCallbacks = {};
this._advice = {
...createBulk = function (input, callback) {
return this.bulkload("insert", input, callback);
}n/a
del = function (ids, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.destroy(this.type, ids, options, callback);
}n/a
delete = function (ids, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.destroy(this.type, ids, options, callback);
}...
/**
*
*/
describe("delete account info", function() {
it("should not get any account for delete account id", function(done) {
async.waterfall([
function(cb) {
conn.apex.delete('/JSforceTestApexRest/' + accountId, cb);
},
function(ret, cb) {
conn.sobject('Account').find({ Id: accountId }, cb);
}
], function(err, records) {
if (err) { throw err; }
assert.ok(records.length === 0);
...deleteBulk = function (input, callback) {
return this.bulkload("delete", input, callback);
}...
callback = type;
type = null;
}
type = type || (this._config && this._config.table);
if (!type) {
throw new Error("SOQL based query needs SObject type information to bulk delete.");
}
var batch = this._conn.sobject(type).deleteBulk();
var deferred = Promise.defer();
var handleError = function(err) {
if (err.name === 'ClientInputError') { deferred.resolve([]); } // if batch input receives no records
else { deferred.reject(err); }
};
this.on('error', handleError)
.pipe(batch)
...deleteHardBulk = function (input, callback) {
return this.bulkload("hardDelete", input, callback);
}n/a
deleted = function (start, end, callback) {
return this._conn.deleted(this.type, start, end, callback);
}...
*
* @param {String|Date} start - start date or string representing the start of the interval
* @param {String|Date} end - start date or string representing the end of the interval, must be > start
* @param {Callback.<DeletedRecordsInfo>} [callback] - Callback function
* @returns {Promise.<DeletedRecordsInfo>}
*/
SObject.prototype.deleted = function (start, end, callback) {
return this._conn.deleted(this.type, start, end, callback);
};
/**
* @typedef {Object} LayoutInfo
* @prop {Array.<Object>} layouts - Array of layouts
* @prop {Array.<Object>} recordTypeMappings - Array of record type mappings
*/
...describe = function (callback) {
return this._conn.describe(this.type, callback);
}...
/**
* Describe SObject metadata
*
* @param {Callback.<DescribeSObjectResult>} [callback] - Callback function
* @returns {Promise.<DescribeSObjectResult>}
*/
SObject.prototype.describe = function(callback) {
return this._conn.describe(this.type, callback);
};
/**
* Get record representation instance by given id
*
* @param {String} id - A record ID
* @returns {RecordReference}
...destroy = function (ids, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.destroy(this.type, ids, options, callback);
}...
* @returns {Promise.<RecordResult>}
*/
RecordReference.prototype.destroy = function(options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.destroy(this.type, this.id, options, callback);
};
/**
* Get blob field as stream
*
* @param {String} fieldName - Blob field name
* @returns {stream.Stream}
...destroyBulk = function (input, callback) {
return this.bulkload("delete", input, callback);
}n/a
destroyHardBulk = function (input, callback) {
return this.bulkload("hardDelete", input, callback);
}n/a
find = function (conditions, fields, options, callback) {
if (typeof conditions === 'function') {
callback = conditions;
conditions = {};
fields = null;
options = null;
} else if (typeof fields === 'function') {
callback = fields;
fields = null;
options = null;
} else if (typeof options === 'function') {
callback = options;
options = null;
}
options = options || {};
var config = {
fields: fields,
includes: options.includes,
table: this.type,
conditions: conditions,
limit: options.limit,
offset: options.offset || options.skip
};
var query = new Query(this._conn, config, options);
query.setResponseTarget(Query.ResponseTargets.Records);
if (callback) { query.run(callback); }
return query;
}...
]);
function findRelationTable(rname) {
var ptable = self._parent._config.table;
logger.debug('finding table for relation "' + rname + '" in "' + ptable + '"...
x27;);
return describeCache(ptable).then(function(sobject) {
var upperRname = rname.toUpperCase();
var childRelation = _.find(sobject.childRelationships, function(cr) {
return (cr.relationshipName || '').toUpperCase() === upperRname;
});
return childRelation ? childRelation.childSObject :
Promise.reject(new Error("No child relationship found: " + rname ));
});
}
...findOne = function (conditions, fields, options, callback) {
if (typeof conditions === 'function') {
callback = conditions;
conditions = {};
fields = null;
options = null;
} else if (typeof fields === 'function') {
callback = fields;
fields = null;
options = null;
} else if (typeof options === 'function') {
callback = options;
options = null;
}
options = _.extend(options || {}, { limit: 1 });
var query = this.find(conditions, fields, options);
query.setResponseTarget(Query.ResponseTargets.SingleRecord);
if (callback) { query.run(callback); }
return query;
}...
};
Channel.prototype.push = function(events, callback) {
var isArray = _.isArray(events);
events = isArray ? events : [ events ];
var conn = this._streaming._conn;
if (!this._id) {
this._id = conn.sobject('StreamingChannel').findOne({ Name: this._name },
x27;Id')
.then(function(rec) { return rec.Id });
}
return this._id.then(function(id) {
var channelUrl = '/sobjects/StreamingChannel/' + id + '/push';
return conn.requestPost(channelUrl, { pushEvents: events });
}).then(function(rets) {
return isArray ? rets : rets[0];
...insert = function (records, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.create(this.type, records, options, callback);
}n/a
insertBulk = function (input, callback) {
return this.bulkload("insert", input, callback);
}n/a
layouts = function (layoutName, callback) {
if (typeof layoutName === 'function') {
callback = layoutName;
layoutName = null;
}
var url = "/sobjects/" + this.type + "/describe/" + (layoutName ? "namedLayouts/"+layoutName : "layouts");
return this._conn.request(url, callback);
}...
});
/**
*
*/
describe("list layout for SObject", function() {
it("should return Account layout information", function(done) {
Account.layouts(function(err, res) {
if (err) { throw err; }
assert.ok(_.isArray(res.layouts));
res.layouts.forEach(function(layout) {
assert.ok(layout.id === null || _.isString(layout.id));
assert.ok(_.isObject(layout.buttonLayoutSection));
assert.ok(_.isArray(layout.detailLayoutSections));
assert.ok(_.isArray(layout.editLayoutSections));
...listview = function (id) {
return new ListView(this._conn, this.type, id);
}...
});
/**
*
*/
describe("describe list view", function() {
it("should return described list view info for given list view id", function(done) {
Account.listview(listviewId).describe(function(err, result) {
if (err) { throw err; }
assert.ok(_.isObject(result));
assert.ok(_.isString(result.id));
assert.ok(_.isString(result.sobjectType));
assert.ok(_.isString(result.query) || result.query === null);
assert.ok(_.isArray(result.columns));
assert.ok(_.isArray(result.orderBy));
...listviews = function (callback) {
var url = this._conn._baseUrl() + '/sobjects/' + this.type + '/listviews';
return this._conn.request(url, callback);
}...
var listviewId;
/**
*
*/
describe("listup list views", function() {
it("should return list views definitions on the sobject", function(done) {
Account.listviews(function(err, result) {
if (err) { throw err; }
assert.ok(_.isObject(result));
assert.ok(_.isArray(result.listviews));
for (var i=0, len=result.listviews.length; i<len; i++) {
var listview = result.listviews[i];
assert.ok(_.isString(listview.id));
assert.ok(_.isString(listview.label));
...quickAction = function (actionName) {
return new QuickAction(this._conn, "/sobjects/" + this.type + "/quickActions/" + actionName);
}...
var action;
/**
*
*/
describe("get a global action", function() {
it("should return a global quick action reference", function() {
action = conn.quickAction('LogACall');
assert.ok(action instanceof QuickAction);
});
});
/**
*
*/
...quickActions = function (callback) {
return this._conn.request("/sobjects/" + this.type + "/quickActions").thenCall(callback);
}...
/**
*
*/
describe("list global actions", function() {
it("should return global actions", function(done) {
conn.quickActions(function(err, results) {
if (err) { throw err; }
assert.ok(_.isArray(results));
results.forEach(function(res) {
assert.ok(_.isString(res.type));
assert.ok(_.isString(res.name));
assert.ok(_.isString(res.label));
assert.ok(_.isObject(res.urls));
...recent = function (callback) {
return this._conn.recent(this.type, callback);
}...
/**
* Retrieve recently accessed records
*
* @param {Callback.<Array.<RecordResult>>} [callback] - Callback function
* @returns {Promise.<Array.<RecordResult>>}
*/
SObject.prototype.recent = function (callback) {
return this._conn.recent(this.type, callback);
};
/**
* Retrieve the updated records
*
* @param {String|Date} start - start date or string representing the start of the interval
* @param {String|Date} end - start date or string representing the end of the interval, must be > start
...record = function (id) {
return new Record(this._conn, this.type, id);
}...
});
/**
*
*/
describe("update account", function() {
it("should update successfully", function(done) {
conn.sobject('Account').record(account.Id).update({ Name : "Hello2
x22; }, function(err, ret) {
if (err) { throw err; }
assert.ok(ret.success);
}.check(done));
});
describe("then retrieve the account", function() {
it("should return updated account object", function(done) {
...retrieve = function (ids, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.retrieve(this.type, ids, options, callback);
}...
}
self.check(function(err, res) {
if (err) {
self.emit('error', err);
} else {
if (res.state === "Failed") {
if (parseInt(res.numberRecordsProcessed, 10) > 0) {
self.retrieve();
} else {
self.emit('error', new Error(res.stateMessage));
}
} else if (res.state === "Completed") {
self.retrieve();
} else {
self.emit('progress', res);
...select = function (fields, callback) {
return this.find(null, fields, null, callback);
}...
this._conn = conn;
if (_.isString(config)) { // if query config is string, it is given in SOQL.
this._soql = config;
} else if (config.locator && config.locator.indexOf("/") >= 0) { // if locator given in url for next records
this._locator = config.locator.split("/").pop();
} else {
this._config = config;
this.select(config.fields);
if (config.includes) {
this.include(config.includes);
}
}
this._options = _.defaults({
maxFetch: 10000,
autoFetch: false,
...update = function (records, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.update(this.type, records, options, callback);
}...
RecordReference.prototype.update = function(record, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
record = _.clone(record);
record.Id = this.id;
return this._conn.update(this.type, record, options, callback);
};
/**
* Synonym of Record#destroy()
*
* @method RecordReference#delete
* @param {Object} [options] - Options for rest api.
...updateBulk = function (input, callback) {
return this.bulkload("update", input, callback);
}...
type = null;
}
type = type || (this._config && this._config.table);
if (!type) {
throw new Error("SOQL based query needs SObject type information to bulk update.");
}
var updateStream = _.isFunction(mapping) ? RecordStream.map(mapping) : RecordStream.recordMapStream(mapping);
var batch = this._conn.sobject(type).updateBulk();
var deferred = Promise.defer();
var handleError = function(err) {
if (err.name === 'ClientInputError') { deferred.resolve([]); } // if batch input receives no records
else { deferred.reject(err); }
};
this.on('error', handleError)
.pipe(updateStream)
...updated = function (start, end, callback) {
return this._conn.updated(this.type, start, end, callback);
}...
*
* @param {String|Date} start - start date or string representing the start of the interval
* @param {String|Date} end - start date or string representing the end of the interval, must be > start
* @param {Callback.<UpdatedRecordsInfo>} [callback] - Callback function
* @returns {Promise.<UpdatedRecordsInfo>}
*/
SObject.prototype.updated = function (start, end, callback) {
return this._conn.updated(this.type, start, end, callback);
};
/**
* Retrieve the deleted records
*
* @param {String|Date} start - start date or string representing the start of the interval
* @param {String|Date} end - start date or string representing the end of the interval, must be > start
...upsert = function (records, extIdField, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.upsert(this.type, records, extIdField, options, callback);
}...
* @returns {Promise.<RecordResult|Array.<RecordResult>>}
*/
SObject.prototype.upsert = function(records, extIdField, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
return this._conn.upsert(this.type, records, extIdField, options, callback);
};
/**
* Synonym of SObject#destroy()
*
* @method SObject#delete
* @param {String|Array.<String>} ids - A ID or array of IDs to delete
...upsertBulk = function (input, extIdField, callback) {
return this.bulkload("upsert", { extIdField: extIdField }, input, callback);
}n/a
function createSOQL(query) {
var soql = [
"SELECT ",
createFieldsClause(query.fields, query.includes),
" FROM ",
query.table
].join("");
var cond = createConditionClause(query.conditions);
if (cond) {
soql += " WHERE " + cond;
}
var orderby = createOrderByClause(query.sort);
if (orderby) {
soql += " ORDER BY " + orderby;
}
if (query.limit) {
soql += " LIMIT " + query.limit;
}
if (query.offset) {
soql += " OFFSET " + query.offset;
}
return soql;
}...
*
* @param {Callback.<String>} [callback] - Callback function
* @returns {Promise.<String>}
*/
Query.prototype.toSOQL = function(callback) {
var self = this;
return Promise.resolve(self._soql ||
self._expandFields().then(function() { return SOQLBuilder.createSOQL(self._config); })
).thenCall(callback);
};
/**
* Create data stream of queried records.
* Automatically resume query if paused.
*
...