/**
* @file Manages Tooling APIs
* @author Shinichi Tomita <shinichi.tomita@gmail.com>
*/
'use strict';
var jsforce = require('../core'),
_ = require('lodash/core'),
Cache = require('../cache');
/**
* API class for Tooling API call
*
* @class
* @param {Connection} conn - Connection
*/
var Tooling = function(conn) {
this._conn = conn;
this._logger = conn._logger;
var delegates = [
"query",
"queryMore",
"create",
"insert",
"retrieve",
"update",
"upsert",
"del",
"delete",
"destroy",
"describe",
"describeGlobal",
"sobject"
];
delegates.forEach(function(method) {
this[method] = conn.constructor.prototype[method];
}, 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);
this.initialize();
};
/**
* 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));
};
/**
* @private
*/
Tooling.prototype._baseUrl = function() {
return this._conn._baseUrl() + "/tooling";
};
/**
* @private
*/
Tooling.prototype.request = function() {
return this._conn.request.apply(this._conn, arguments);
};
/**
* Execute query by using SOQL
*
* @param {String} soql - SOQL string
* @param {Callback.<QueryResult>} [callback] - Callback function
* @returns {Query.<QueryResult>}
*/
/**
* Query next record set by using query locator
*
* @method Tooling#query
* @param {String} locator - Next record set locator
* @param {Callback.<QueryResult>} [callback] - Callback function
* @returns {Query.<QueryResult>}
*/
/**
* Retrieve specified records
*
* @method Tooling#queryMore
* @param {String} type - SObject Type
* @param {String|Array.<String>} ids - A record ID or array of record IDs
* @param {Callback.<Record|Array.<Record>>} [callback] - Callback function
* @returns {Promise.<Record|Array.<Record>>}
*/
/**
* Synonym of Tooling#create()
*
* @method Tooling#insert
* @param {String} type - SObject Type
* @param {Object|Array.<Object>} records - A record or array of records to create
* @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback function
* @returns {Promise.<RecordResult|Array.<RecordResult>>}
*/
/**
* Create records
*
* @method Tooling#create
* @param {String} type - SObject Type
* @param {Record|Array.<Record>} records - A record or array of records to create
* @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback function
* @returns {Promise.<RecordResult|Array.<RecordResult>>}
*/
/**
* Update records
*
* @method Tooling#update
* @param {String} type - SObject Type
* @param {Record|Array.<Record>} records - A record or array of records to update
* @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback function
* @returns {Promise.<RecordResult|Array.<RecordResult>>}
*/
/**
* Upsert records
*
* @method Tooling#upsert
* @param {String} type - SObject Type
* @param {Record|Array.<Record>} records - Record or array of records to upsert
* @param {String} extIdField - External ID field name
* @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback
* @returns {Promise.<RecordResult|Array.<RecordResult>>}
*/
/**
* Synonym of Tooling#destroy()
*
* @method Tooling#delete
* @param {String} type - SObject Type
* @param {String|Array.<String>} ids - A ID or array of IDs to delete
* @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback
* @returns {Promise.<RecordResult|Array.<RecordResult>>}
*/
/**
* Synonym of Tooling#destroy()
*
* @method Tooling#del
* @param {String} type - SObject Type
* @param {String|Array.<String>} ids - A ID or array of IDs to delete
* @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback
* @returns {Promise.<RecordResult|Array.<RecordResult>>}
*/
/**
* Delete records
*
* @method Tooling#destroy
* @param {String} type - SObject Type
* @param {String|Array.<String>} ids - A ID or array of IDs to delete
* @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback
* @returns {Promise.<RecordResult|Array.<RecordResult>>}
*/
/**
* Synonym of Tooling#describe()
*
* @method Tooling#describeSObject
* @param {String} type - SObject Type
* @param {Callback.<DescribeSObjectResult>} [callback] - Callback function
* @returns {Promise.<DescribeSObjectResult>}
*/
/**
* Describe SObject metadata
*
* @method Tooling#describe
* @param {String} type - SObject Type
* @param {Callback.<DescribeSObjectResult>} [callback] - Callback function
* @returns {Promise.<DescribeSObjectResult>}
*/
/**
* Describe global SObjects
*
* @method Tooling#describeGlobal
* @param {Callback.<DescribeGlobalResult>} [callback] - Callback function
* @returns {Promise.<DescribeGlobalResult>}
*/
/**
* Get SObject instance
*
* @method Tooling#sobject
* @param {String} type - SObject Type
* @returns {SObject}
*/
/**
* @typedef {Object} Tooling~ExecuteAnonymousResult
* @prop {Boolean} compiled - Flag if the query is compiled successfully
* @prop {String} compileProblem - Error reason in compilation
* @prop {Boolean} success - Flag if the code is executed successfully
* @prop {Number} line - Line number for the error
* @prop {Number} column - Column number for the error
* @prop {String} exceptionMessage - Exception message
* @prop {String} exceptionStackTrace - Exception stack trace
*/
/**
* Executes Apex code anonymously
*
* @param {String} body - Anonymous Apex code
* @param {Callback.<Tooling~ExecuteAnonymousResult>} [callback] - Callback function
* @returns {Promise.<Tooling~ExecuteAnonymousResult>}
*/
Tooling.prototype.executeAnonymous = function(body, callback) {
var url = this._baseUrl() + "/executeAnonymous?anonymousBody=" + encodeURIComponent(body);
return this.request(url).thenCall(callback);
};
/**
* Executes Apex tests asynchronously
*
* @param {Array.<String>} classids - Comma separated list of class IDs
* @param {Callback.<Tooling~ExecuteAnonymousResult>} [callback] - Callback function
* @returns {Promise.<Tooling~ExecuteAnonymousResult>}
*/
Tooling.prototype.runTestsAsynchronous = function(classids, callback) {
var url = this._baseUrl() + "/runTestsAsynchronous/?classids=" + classids.join(',');
return this.request(url).thenCall(callback);
};
/**
* @typedef {Object} Tooling~CompletionsResult
* @prop {Object} publicDeclarations
*/
/**
* Retrieves available code completions of the referenced type
*
* @param {String} [type] - completion type (default 'apex')
* @param {Callback.<Tooling~CompletionsResult>} [callback] - Callback function
* @returns {Promise.<Tooling~CompletionsResult>}
*/
Tooling.prototype.completions = function(type, callback) {
if (!_.isString(type)) {
callback = type;
type = 'apex';
}
var url = this._baseUrl() + "/completions?type=" + encodeURIComponent(type);
return this.request(url).thenCall(callback);
};
/*--------------------------------------------*/
/*
* Register hook in connection instantiation for dynamically adding this API module features
*/
jsforce.on('connection:new', function(conn) {
conn.tooling = new Tooling(conn);
});
module.exports = Tooling;