Source: sobject.js

  1. /**
  2. * @file Represents Salesforce SObject
  3. * @author Shinichi Tomita <shinichi.tomita@gmail.com>
  4. */
  5. 'use strict';
  6. var _ = require('lodash/core'),
  7. Record = require('./record'),
  8. Query = require('./query'),
  9. Cache = require('./cache'),
  10. QuickAction = require('./quick-action');
  11. /**
  12. * A class for organizing all SObject access
  13. *
  14. * @constructor
  15. */
  16. var SObject = module.exports = function(conn, type) {
  17. this._conn = conn;
  18. this.type = type;
  19. var cacheOptions = { key: "describe." + this.type };
  20. this.describe$ = conn.cache.makeCacheable(this.describe, this, cacheOptions);
  21. this.describe = conn.cache.makeResponseCacheable(this.describe, this, cacheOptions);
  22. cacheOptions = { key: "layouts." + this.type };
  23. this.layouts$ = conn.cache.makeCacheable(this.layouts, this, cacheOptions);
  24. this.layouts = conn.cache.makeResponseCacheable(this.layouts, this, cacheOptions);
  25. cacheOptions = { key: "compactLayouts." + this.type };
  26. this.compactLayouts$ = conn.cache.makeCacheable(this.compactLayouts, this, cacheOptions);
  27. this.compactLayouts = conn.cache.makeResponseCacheable(this.compactLayouts, this, cacheOptions);
  28. cacheOptions = { key: "approvalLayouts." + this.type };
  29. this.approvalLayouts$ = conn.cache.makeCacheable(this.approvalLayouts, this, cacheOptions);
  30. this.approvalLayouts = conn.cache.makeResponseCacheable(this.approvalLayouts, this, cacheOptions);
  31. };
  32. /**
  33. * Synonym of SObject#create()
  34. *
  35. * @method SObject#insert
  36. * @param {Record|Array.<Record>} records - A record or array of records to create
  37. * @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback function
  38. * @returns {Promise.<RecordResult|Array.<RecordResult>>}
  39. */
  40. /**
  41. * Create records
  42. *
  43. * @method SObject#create
  44. * @param {Record|Array.<Record>} records - A record or array of records to create
  45. * @param {Object} [options] - Options for rest api.
  46. * @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback function
  47. * @returns {Promise.<RecordResult|Array.<RecordResult>>}
  48. */
  49. SObject.prototype.insert =
  50. SObject.prototype.create = function(records, options, callback) {
  51. if (typeof options === 'function') {
  52. callback = options;
  53. options = {};
  54. }
  55. return this._conn.create(this.type, records, options, callback);
  56. };
  57. /**
  58. * Retrieve specified records
  59. *
  60. * @param {String|Array.<String>} ids - A record ID or array of record IDs
  61. * @param {Object} [options] - Options for rest api.
  62. * @param {Callback.<Record|Array.<Record>>} [callback] - Callback function
  63. * @returns {Promise.<Record|Array.<Record>>}
  64. */
  65. SObject.prototype.retrieve = function(ids, options, callback) {
  66. if (typeof options === 'function') {
  67. callback = options;
  68. options = {};
  69. }
  70. return this._conn.retrieve(this.type, ids, options, callback);
  71. };
  72. /**
  73. * Update records
  74. *
  75. * @param {Record|Array.<Record>} records - A record or array of records to update
  76. * @param {Object} [options] - Options for rest api.
  77. * @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback function
  78. * @returns {Promise.<RecordResult|Array.<RecordResult>>}
  79. */
  80. SObject.prototype.update = function(records, options, callback) {
  81. if (typeof options === 'function') {
  82. callback = options;
  83. options = {};
  84. }
  85. return this._conn.update(this.type, records, options, callback);
  86. };
  87. /**
  88. * Upsert records
  89. *
  90. * @param {Record|Array.<Record>} records - Record or array of records to upsert
  91. * @param {String} extIdField - External ID field name
  92. * @param {Object} [options] - Options for rest api.
  93. * @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback
  94. * @returns {Promise.<RecordResult|Array.<RecordResult>>}
  95. */
  96. SObject.prototype.upsert = function(records, extIdField, options, callback) {
  97. if (typeof options === 'function') {
  98. callback = options;
  99. options = {};
  100. }
  101. return this._conn.upsert(this.type, records, extIdField, options, callback);
  102. };
  103. /**
  104. * Synonym of SObject#destroy()
  105. *
  106. * @method SObject#delete
  107. * @param {String|Array.<String>} ids - A ID or array of IDs to delete
  108. * @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback function
  109. * @returns {Promise.<RecordResult|Array.<RecordResult>>}
  110. */
  111. /**
  112. * Synonym of SObject#destroy()
  113. *
  114. * @method SObject#del
  115. * @param {String|Array.<String>} ids - A ID or array of IDs to delete
  116. * @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback function
  117. * @returns {Promise.<RecordResult|Array.<RecordResult>>}
  118. */
  119. /**
  120. * Delete records
  121. *
  122. * @method SObject#destroy
  123. * @param {String|Array.<String>} ids - A ID or array of IDs to delete
  124. * @param {Object} [options] - Options for rest api.
  125. * @param {Callback.<RecordResult|Array.<RecordResult>>} [callback] - Callback function
  126. * @returns {Promise.<RecordResult|Array.<RecordResult>>}
  127. */
  128. SObject.prototype["delete"] =
  129. SObject.prototype.del =
  130. SObject.prototype.destroy = function(ids, options, callback) {
  131. if (typeof options === 'function') {
  132. callback = options;
  133. options = {};
  134. }
  135. return this._conn.destroy(this.type, ids, options, callback);
  136. };
  137. /**
  138. * Describe SObject metadata
  139. *
  140. * @param {Callback.<DescribeSObjectResult>} [callback] - Callback function
  141. * @returns {Promise.<DescribeSObjectResult>}
  142. */
  143. SObject.prototype.describe = function(callback) {
  144. return this._conn.describe(this.type, callback);
  145. };
  146. /**
  147. * Get record representation instance by given id
  148. *
  149. * @param {String} id - A record ID
  150. * @returns {RecordReference}
  151. */
  152. SObject.prototype.record = function(id) {
  153. return new Record(this._conn, this.type, id);
  154. };
  155. /**
  156. * Find and fetch records which matches given conditions
  157. *
  158. * @param {Object|String} [conditions] - Conditions in JSON object (MongoDB-like), or raw SOQL WHERE clause string.
  159. * @param {Object|Array.<String>|String} [fields] - Fields to fetch. Format can be in JSON object (MongoDB-like), array of field names, or comma-separated field names.
  160. * @param {Object} [options] - Query options.
  161. * @param {Number} [options.limit] - Maximum number of records the query will return.
  162. * @param {Number} [options.offset] - Offset number where begins returning results.
  163. * @param {Number} [options.skip] - Synonym of options.offset.
  164. * @param {Callback.<Array.<Record>>} [callback] - Callback function
  165. * @returns {Query.<Array.<Record>>}
  166. */
  167. SObject.prototype.find = function(conditions, fields, options, callback) {
  168. if (typeof conditions === 'function') {
  169. callback = conditions;
  170. conditions = {};
  171. fields = null;
  172. options = null;
  173. } else if (typeof fields === 'function') {
  174. callback = fields;
  175. fields = null;
  176. options = null;
  177. } else if (typeof options === 'function') {
  178. callback = options;
  179. options = null;
  180. }
  181. options = options || {};
  182. var config = {
  183. fields: fields,
  184. includes: options.includes,
  185. table: this.type,
  186. conditions: conditions,
  187. limit: options.limit,
  188. offset: options.offset || options.skip
  189. };
  190. var query = new Query(this._conn, config);
  191. query.setResponseTarget(Query.ResponseTargets.Records);
  192. if (callback) { query.run(callback); }
  193. return query;
  194. };
  195. /**
  196. * Fetch one record which matches given conditions
  197. *
  198. * @param {Object|String} [conditions] - Conditions in JSON object (MongoDB-like), or raw SOQL WHERE clause string.
  199. * @param {Object|Array.<String>|String} [fields] - Fields to fetch. Format can be in JSON object (MongoDB-like), array of field names, or comma-separated field names.
  200. * @param {Object} [options] - Query options.
  201. * @param {Number} [options.limit] - Maximum number of records the query will return.
  202. * @param {Number} [options.offset] - Offset number where begins returning results.
  203. * @param {Number} [options.skip] - Synonym of options.offset.
  204. * @param {Callback.<Record>} [callback] - Callback function
  205. * @returns {Query.<Record>}
  206. */
  207. SObject.prototype.findOne = function(conditions, fields, options, callback) {
  208. if (typeof conditions === 'function') {
  209. callback = conditions;
  210. conditions = {};
  211. fields = null;
  212. options = null;
  213. } else if (typeof fields === 'function') {
  214. callback = fields;
  215. fields = null;
  216. options = null;
  217. } else if (typeof options === 'function') {
  218. callback = options;
  219. options = null;
  220. }
  221. options = _.extend(options || {}, { limit: 1 });
  222. var query = this.find(conditions, fields, options);
  223. query.setResponseTarget(Query.ResponseTargets.SingleRecord);
  224. if (callback) { query.run(callback); }
  225. return query;
  226. };
  227. /**
  228. * Find and fetch records only by specifying fields to fetch.
  229. *
  230. * @param {Object|Array.<String>|String} [fields] - Fields to fetch. Format can be in JSON object (MongoDB-like), array of field names, or comma-separated field names.
  231. * @param {Callback.<Array.<Record>>} [callback] - Callback function
  232. * @returns {Query.<Array.<Record>>}
  233. */
  234. SObject.prototype.select = function(fields, callback) {
  235. return this.find(null, fields, null, callback);
  236. };
  237. /**
  238. * Count num of records which matches given conditions
  239. *
  240. * @param {Object|String} [conditions] - Conditions in JSON object (MongoDB-like), or raw SOQL WHERE clause string.
  241. * @param {Callback.<Number>} [callback] - Callback function
  242. * @returns {Query.<Number>}
  243. */
  244. SObject.prototype.count = function(conditions, callback) {
  245. if (typeof conditions === 'function') {
  246. callback = conditions;
  247. conditions = {};
  248. }
  249. var query = this.find(conditions, { "count()" : true });
  250. query.setResponseTarget("Count");
  251. if (callback) { query.run(callback); }
  252. return query;
  253. };
  254. /**
  255. * Call Bulk#load() to execute bulkload, returning batch object
  256. *
  257. * @param {String} operation - Bulk load operation ('insert', 'update', 'upsert', 'delete', or 'hardDelete')
  258. * @param {Object} [options] - Options for bulk loading operation
  259. * @param {String} [options.extIdField] - External ID field name (used when upsert operation).
  260. * @param {Array.<Record>|stream.Stream|String} [input] - Input source for bulkload. Accepts array of records, CSv string, and CSV data input stream.
  261. * @param {Callback.<Array.<RecordResult>>} [callback] - Callback function
  262. * @returns {Bulk~Batch}
  263. */
  264. SObject.prototype.bulkload = function(operation, options, input, callback) {
  265. return this._conn.bulk.load(this.type, operation, options, input, callback);
  266. };
  267. /**
  268. * Synonym of SObject#createBulk()
  269. *
  270. * @method SObject#insertBulk
  271. * @param {Array.<Record>|stream.Stream|String} [input] - Input source for bulk insert. Accepts array of records, CSv string, and CSV data input stream.
  272. * @param {Callback.<Array.<RecordResult>>} [callback] - Callback function
  273. * @returns {Bulk~Batch}
  274. */
  275. /**
  276. * Bulkly insert input data using bulk API
  277. *
  278. * @method SObject#createBulk
  279. * @param {Array.<Record>|stream.Stream|String} [input] - Input source for bulk insert. Accepts array of records, CSv string, and CSV data input stream.
  280. * @param {Callback.<Array.<RecordResult>>} [callback] - Callback function
  281. * @returns {Bulk~Batch}
  282. */
  283. SObject.prototype.insertBulk =
  284. SObject.prototype.createBulk = function(input, callback) {
  285. return this.bulkload("insert", input, callback);
  286. };
  287. /**
  288. * Bulkly update records by input data using bulk API
  289. *
  290. * @param {Array.<Record>|stream.Stream|String} [input] - Input source for bulk update Accepts array of records, CSv string, and CSV data input stream.
  291. * @param {Callback.<Array.<RecordResult>>} [callback] - Callback function
  292. * @returns {Bulk~Batch}
  293. */
  294. SObject.prototype.updateBulk = function(input, callback) {
  295. return this.bulkload("update", input, callback);
  296. };
  297. /**
  298. * Bulkly upsert records by input data using bulk API
  299. *
  300. * @param {Array.<Record>|stream.Stream|String} [input] - Input source for bulk upsert. Accepts array of records, CSv string, and CSV data input stream.
  301. * @param {String} [options.extIdField] - External ID field name
  302. * @param {Callback.<Array.<RecordResult>>} [callback] - Callback function
  303. * @returns {Bulk~Batch}
  304. */
  305. SObject.prototype.upsertBulk = function(input, extIdField, callback) {
  306. return this.bulkload("upsert", { extIdField: extIdField }, input, callback);
  307. };
  308. /**
  309. * Synonym of SObject#destroyBulk()
  310. *
  311. * @method SObject#deleteBulk
  312. * @param {Array.<Record>|stream.Stream|String} [input] - Input source for bulk delete. Accepts array of records, CSv string, and CSV data input stream.
  313. * @param {Callback.<Array.<RecordResult>>} [callback] - Callback function
  314. * @returns {Bulk~Batch}
  315. */
  316. /**
  317. * Bulkly delete records specified by input data using bulk API
  318. *
  319. * @method SObject#destroyBulk
  320. * @param {Array.<Record>|stream.Stream|String} [input] - Input source for bulk delete. Accepts array of records, CSv string, and CSV data input stream.
  321. * @param {Callback.<Array.<RecordResult>>} [callback] - Callback function
  322. * @returns {Bulk~Batch}
  323. */
  324. SObject.prototype.deleteBulk =
  325. SObject.prototype.destroyBulk = function(input, callback) {
  326. return this.bulkload("delete", input, callback);
  327. };
  328. /**
  329. * Synonym of SObject#destroyHardBulk()
  330. *
  331. * @method SObject#deleteHardBulk
  332. * @param {Array.<Record>|stream.Stream|String} [input] - Input source for bulk delete. Accepts array of records, CSv string, and CSV data input stream.
  333. * @param {Callback.<Array.<RecordResult>>} [callback] - Callback function
  334. * @returns {Bulk~Batch}
  335. */
  336. /**
  337. * Bulkly hard delete records specified in input data using bulk API
  338. *
  339. * @method SObject#destroyHardBulk
  340. * @param {Array.<Record>|stream.Stream|String} [input] - Input source for bulk delete. Accepts array of records, CSv string, and CSV data input stream.
  341. * @param {Callback.<Array.<RecordResult>>} [callback] - Callback function
  342. * @returns {Bulk~Batch}
  343. */
  344. SObject.prototype.deleteHardBulk =
  345. SObject.prototype.destroyHardBulk = function(input, callback) {
  346. return this.bulkload("hardDelete", input, callback);
  347. };
  348. /**
  349. * Retrieve recently accessed records
  350. *
  351. * @param {Callback.<Array.<RecordResult>>} [callback] - Callback function
  352. * @returns {Promise.<Array.<RecordResult>>}
  353. */
  354. SObject.prototype.recent = function (callback) {
  355. return this._conn.recent(this.type, callback);
  356. };
  357. /**
  358. * Retrieve the updated records
  359. *
  360. * @param {String|Date} start - start date or string representing the start of the interval
  361. * @param {String|Date} end - start date or string representing the end of the interval, must be > start
  362. * @param {Callback.<UpdatedRecordsInfo>} [callback] - Callback function
  363. * @returns {Promise.<UpdatedRecordsInfo>}
  364. */
  365. SObject.prototype.updated = function (start, end, callback) {
  366. return this._conn.updated(this.type, start, end, callback);
  367. };
  368. /**
  369. * Retrieve the deleted records
  370. *
  371. * @param {String|Date} start - start date or string representing the start of the interval
  372. * @param {String|Date} end - start date or string representing the end of the interval, must be > start
  373. * @param {Callback.<DeletedRecordsInfo>} [callback] - Callback function
  374. * @returns {Promise.<DeletedRecordsInfo>}
  375. */
  376. SObject.prototype.deleted = function (start, end, callback) {
  377. return this._conn.deleted(this.type, start, end, callback);
  378. };
  379. /**
  380. * @typedef {Object} LayoutInfo
  381. * @prop {Array.<Object>} layouts - Array of layouts
  382. * @prop {Array.<Object>} recordTypeMappings - Array of record type mappings
  383. */
  384. /**
  385. * Describe layout information for SObject
  386. *
  387. * @param {String} [layoutName] - Name of named layout. (e.g. UserAlt in User SObject)
  388. * @param {Callback.<LayoutInfo>} [callback] - Callback function
  389. * @returns {Promise.<LayoutInfo>}
  390. */
  391. SObject.prototype.layouts = function(layoutName, callback) {
  392. if (typeof layoutName === 'function') {
  393. callback = layoutName;
  394. layoutName = null;
  395. }
  396. var url = "/sobjects/" + this.type + "/describe/" + (layoutName ? "namedLayouts/"+layoutName : "layouts");
  397. return this._conn.request(url, callback);
  398. };
  399. /**
  400. * @typedef {Object} CompactLayoutInfo
  401. * @prop {Array.<Object>} compactLayouts - Array of compact layouts
  402. * @prop {String} defaultCompactLayoutId - ID of default compact layout
  403. * @prop {Array.<Object>} recordTypeCompactLayoutMappings - Array of record type mappings
  404. */
  405. /**
  406. * Describe compact layout information defined for SObject
  407. *
  408. * @param {Callback.<CompactLayoutInfo>} [callback] - Callback function
  409. * @returns {Promise.<CompactLayoutInfo>}
  410. */
  411. SObject.prototype.compactLayouts = function(callback) {
  412. var url = "/sobjects/" + this.type + "/describe/compactLayouts";
  413. return this._conn.request(url, callback);
  414. };
  415. /**
  416. * @typedef {Object} ApprovalLayoutInfo
  417. * @prop {Array.<Object>} approvalLayouts - Array of approval layouts
  418. */
  419. /**
  420. * Describe compact layout information defined for SObject
  421. *
  422. * @param {Callback.<ApprovalLayoutInfo>} [callback] - Callback function
  423. * @returns {Promise.<ApprovalLayoutInfo>}
  424. */
  425. SObject.prototype.approvalLayouts = function(callback) {
  426. var url = "/sobjects/" + this.type + "/describe/approvalLayouts";
  427. return this._conn.request(url, callback);
  428. };
  429. /**
  430. * Returns the list of list views for the SObject
  431. *
  432. * @param {Callback.<ListViewsInfo>} [callback] - Callback function
  433. * @returns {Promise.<ListViewsInfo>}
  434. */
  435. SObject.prototype.listviews = function(callback) {
  436. var url = this._conn._baseUrl() + '/sobjects/' + this.type + '/listviews';
  437. return this._conn.request(url, callback);
  438. };
  439. /**
  440. * Returns the list view info in specifed view id
  441. *
  442. * @param {String} id - List view ID
  443. * @returns {ListView}
  444. */
  445. SObject.prototype.listview = function(id) {
  446. return new ListView(this._conn, this.type, id);
  447. };
  448. /**
  449. * Returns all registered quick actions for the SObject
  450. *
  451. * @param {Callback.<Array.<QuickAction~QuickActionInfo>>} [callback] - Callback function
  452. * @returns {Promise.<Array.<QuickAction~QuickActionInfo>>}
  453. */
  454. SObject.prototype.quickActions = function(callback) {
  455. return this._conn.request("/sobjects/" + this.type + "/quickActions").thenCall(callback);
  456. };
  457. /**
  458. * Get reference for specified quick aciton in the SObject
  459. *
  460. * @param {String} actionName - Name of the quick action
  461. * @returns {QuickAction}
  462. */
  463. SObject.prototype.quickAction = function(actionName) {
  464. return new QuickAction(this._conn, "/sobjects/" + this.type + "/quickActions/" + actionName);
  465. };
  466. /**
  467. * A class for organizing list view information
  468. *
  469. * @protected
  470. * @class ListView
  471. * @param {Connection} conn - Connection instance
  472. * @param {SObject} type - SObject type
  473. * @param {String} id - List view ID
  474. */
  475. var ListView = function(conn, type, id) {
  476. this._conn = conn;
  477. this.type = type;
  478. this.id = id;
  479. };
  480. /**
  481. * Executes query for the list view and returns the resulting data and presentation information.
  482. *
  483. * @param {Callback.<ListViewResultInfo>} [callback] - Callback function
  484. * @returns {Promise.<ListViewResultInfo>}
  485. */
  486. ListView.prototype.results = function(callback) {
  487. var url = this._conn._baseUrl() + '/sobjects/' + this.type + '/listviews/' + this.id + '/results';
  488. return this._conn.request(url, callback);
  489. };
  490. /**
  491. * Returns detailed information about a list view
  492. *
  493. * @param {Callback.<ListViewDescribeInfo>} [callback] - Callback function
  494. * @returns {Promise.<ListViewDescribeInfo>}
  495. */
  496. ListView.prototype.describe = function(callback) {
  497. var url = this._conn._baseUrl() + '/sobjects/' + this.type + '/listviews/' + this.id + '/describe';
  498. return this._conn.request(url, callback);
  499. };
  500. /**
  501. * Explain plan for executing list view
  502. *
  503. * @param {Callback.<ExplainInfo>} [callback] - Callback function
  504. * @returns {Promise.<ExplainInfo>}
  505. */
  506. ListView.prototype.explain = function(callback) {
  507. var url = "/query/?explain=" + this.id;
  508. return this._conn.request(url, callback);
  509. };