Browse files

major updates:

- insert operation adds id back to sobject
- getFieldValues now clears the cache of the sobject
- inserting documents, attachments, and content versions working
- updating the same also works
- lots of examples updated and added
  • Loading branch information...
1 parent 4c3d06b commit c88e3aec38dd97015b0d5a93045fff7ed4977617 @kevinohara80 committed Mar 3, 2013
View
0 examples/attachment.js → examples/attachment-getbody.js
File renamed without changes.
View
64 examples/attachment-insert-update.js
@@ -0,0 +1,64 @@
+var nforce = require('../');
+var fs = require('fs');
+var path = require('path');
+var sfuser = process.env.SFUSER;
+var sfpass = process.env.SFPASS;
+var docPath = path.resolve(__dirname, './documents/testdoc.docx');
+
+var oauth;
+
+var org = nforce.createConnection({
+ clientId: '3MVG9rFJvQRVOvk5nd6A4swCyck.4BFLnjFuASqNZmmxzpQSFWSTe6lWQxtF3L5soyVLfjV3yBKkjcePAsPzi',
+ clientSecret: '9154137956044345875',
+ redirectUri: 'http://localhost:3000/oauth/_callback'
+});
+
+function updateAttachment(att) {
+ console.log('Updating attachment');
+ att.attachment.body = fs.readFileSync(docPath);
+
+ org.update(att, oauth, function(err, res) {
+ if(err) console.log(err);
+ else console.log('OK');
+ });
+
+}
+
+function attachDocument(leadId) {
+ console.log('Creating attachment');
+ var att = nforce.createSObject('Attachment', {
+ Name: 'TestDocument',
+ Description: 'This is a test document',
+ ParentId: leadId,
+ attachment: {
+ fileName: 'testdoc.docx',
+ body: fs.readFileSync(docPath)
+ }
+ });
+ org.insert(att, oauth, function(err, resp) {
+ if(err) console.error(err);
+ else {
+ console.log(resp);
+ updateAttachment(att);
+ }
+ });
+}
+
+function findALead() {
+ console.log('Finding a lead to attach to');
+ var q = 'SELECT Id, LastName FROM Lead LIMIT 1';
+ org.query(q, oauth, function(err, res) {
+ if(err) return console.error(err);
+ if(!res.records || !res.records.length) return console.error('No leads');
+ console.log('Attaching to Lead: ' + res.records[0].LastName);
+ attachDocument(res.records[0].Id);
+ });
+}
+
+// start
+console.log('Authenticating with SFDC');
+org.authenticate({ username: sfuser, password: sfpass}, function(err, res) {
+ if(err) return console.error('unable to authenticate to sfdc');
+ oauth = res;
+ findALead();
+});
View
22 examples/crud.js
@@ -1,6 +1,7 @@
var nforce = require('../');
var sfuser = process.env.SFUSER;
var sfpass = process.env.SFPASS;
+
var oauth;
var org = nforce.createConnection({
@@ -9,11 +10,8 @@ var org = nforce.createConnection({
redirectUri: 'http://localhost:3000/oauth/_callback'
});
-function deleteLead(id) {
- var ld = nforce.createSObject('Lead', { id: id });
-
+function deleteLead(ld) {
console.log('attempting to delete lead');
-
org.delete(ld, oauth, function(err, resp) {
if(err) {
console.error('--> unable to delete lead');
@@ -24,41 +22,35 @@ function deleteLead(id) {
});
}
-function updateLead(id) {
- var ld = nforce.createSObject('Lead', { id: id });
+function updateLead(ld) {
+ console.log('attempting to update lead');
ld.Company = 'JJ Inc.';
-
- console.log('attempting to update lead')
-
org.update(ld, oauth, function(err, resp) {
if(err) {
console.error('--> unable to update lead');
console.error('--> ' + JSON.stringify(err));
} else {
console.log('--> lead updated');
- deleteLead(id);
+ deleteLead(ld);
}
});
}
function insertLead() {
+ console.log('Attempting to insert lead');
var ld = nforce.createSObject('Lead', {
FirstName: 'Bobby',
LastName: 'Tester',
Company: 'ABC Widgets',
Email: 'bobbytester@testertest.com'
});
-
- console.log('Attempting to insert lead');
-
org.insert(ld, oauth, function(err, resp) {
if(err) {
console.error('--> unable to insert lead');
console.error('--> ' + JSON.stringify(err));
} else {
console.log('--> lead inserted');
- console.log('--> ' + JSON.stringify(resp));
- updateLead(resp.id);
+ updateLead(ld);
}
});
}
View
129 index.js
@@ -7,6 +7,7 @@ var Record = require('./lib/record');
var QueryStream = require('./lib/querystream');
var FDCStream = require('./lib/fdcstream');
var faye = require('faye');
+var mime = require('mime');
// constants
@@ -207,7 +208,7 @@ Connection.prototype.getIdentity = function(oauth, callback) {
if(!callback) callback = function(){}
if(!validateOAuth(oauth)) return callback(new Error('Invalid oauth object argument'), null);
var opts = { uri: oauth.id, method: 'GET'}
- return apiRequest(opts, oauth, callback);
+ return apiRequest(opts, oauth, null, callback);
}
Connection.prototype.getVersions = function(callback) {
@@ -226,7 +227,7 @@ Connection.prototype.getResources = function(oauth, callback) {
if(!validateOAuth(oauth)) return callback(new Error('Invalid oauth object argument'), null);
var uri = oauth.instance_url + '/services/data/' + this.apiVersion;
var opts = { uri: uri, method: 'GET' }
- return apiRequest(opts, oauth, callback);
+ return apiRequest(opts, oauth, null, callback);
}
Connection.prototype.getSObjects = function(oauth, callback) {
@@ -235,7 +236,7 @@ Connection.prototype.getSObjects = function(oauth, callback) {
if(!validateOAuth(oauth)) return callback(new Error('Invalid oauth object argument'), null);
var uri = oauth.instance_url + '/services/data/' + this.apiVersion + '/sobjects';
var opts = { uri: uri, method: 'GET' }
- return apiRequest(opts, oauth, function(err, resp){
+ return apiRequest(opts, oauth, null, function(err, resp){
if(err) {
callback(err, null);
} else {
@@ -258,7 +259,7 @@ Connection.prototype.getMetadata = function(data, oauth, callback) {
if(!validateOAuth(oauth)) return callback(new Error('Invalid oauth object argument'), null);
var uri = oauth.instance_url + '/services/data/' + this.apiVersion + '/sobjects/' + data;
var opts = { uri: uri, method: 'GET' }
- return apiRequest(opts, oauth, callback);
+ return apiRequest(opts, oauth, null, callback);
}
Connection.prototype.getDescribe = function(data, oauth, callback) {
@@ -269,62 +270,106 @@ Connection.prototype.getDescribe = function(data, oauth, callback) {
if(!validateOAuth(oauth)) return callback(new Error('Invalid oauth object argument'), null);
var uri = oauth.instance_url + '/services/data/' + this.apiVersion + '/sobjects/' + data + '/describe';
var opts = { uri: uri, method: 'GET' }
- return apiRequest(opts, oauth, callback);
+ return apiRequest(opts, oauth, null, callback);
}
Connection.prototype.insert = function(data, oauth, callback) {
- var type, opts, uri;
+ var type, opts, entity, fieldValues;
+
if(!callback) callback = function(){}
+
if(typeof data.attributes.type !== 'string') {
return callback(new Error('Type must be in the form of a string'), null);
}
- var fieldvalues = data.getFieldValues();
+
+ type = data.attributes.type.toLowerCase();
+
+ fieldvalues = data.getFieldValues();
if(typeof fieldvalues !== 'object') {
return callback(new Error('fieldValues must be in the form of an object'), null);
}
+
if(!validateOAuth(oauth)) return callback(new Error('Invalid oauth object argument'), null);
- uri = oauth.instance_url + '/services/data/' + this.apiVersion + '/sobjects/' + data.attributes.type;
- if(data.attributes.type.toLowerCase() === 'document') {
- opts = {
- uri: uri,
- method: 'POST',
- multipart: [
- {
- 'Content-Disposition': 'form-data; name="entity_document"',
- 'Content-Type': 'application/json',
- body: JSON.stringify(fieldvalues)
- },
- {
- 'Content-Type': data.attachment.contentType,
- 'Content-Disposition': 'form-data; name="Body"; filename="' + data.attachment.fileName + '"',
- body: data.attachment.body
- }
- ]
- }
+
+ opts = {
+ uri: oauth.instance_url + '/services/data/' + this.apiVersion + '/sobjects/' + type,
+ method: 'POST'
+ };
+
+ if(type === 'document' || type === 'attachment' || type === 'contentversion') {
+
+ entity = (type === 'contentversion') ? 'content' : type;
+
+ opts.multipart = [
+ {
+ 'content-disposition': 'form-data; name="entity_' + entity + '"',
+ 'content-type': 'application/json',
+ body: JSON.stringify(fieldvalues)
+ },
+ {
+ 'content-type': mime.lookup(data.attachment.fileName),
+ 'content-disposition': 'form-data; name="Body"; filename="' + data.attachment.fileName + '"',
+ body: data.attachment.body
+ }
+ ];
+
} else {
- opts = { uri: uri, method: 'POST', body: JSON.stringify(fieldvalues) }
+ opts.body = JSON.stringify(fieldvalues);
}
- return apiRequest(opts, oauth, callback);
+
+ return apiRequest(opts, oauth, data, callback);
}
Connection.prototype.update = function(data, oauth, callback) {
+ var type, opts, entity, fieldValues;
+
if(!callback) callback = function(){}
+
if(typeof data.attributes.type !== 'string') {
return callback(new Error('Type must be in the form of a string'), null);
}
- var id = findId(data);
+
+ type = data.attributes.type.toLowerCase();
+
+ id = findId(data);
if(!id) {
return callback(new Error('You must specify an id in the form of a string'));
}
- var fieldvalues = data.getFieldValues();
+
+ fieldvalues = data.getFieldValues();
if(typeof fieldvalues !== 'object') {
return callback(new Error('fieldValues must be in the form of an object'), null);
}
+
if(!validateOAuth(oauth)) return callback(new Error('Invalid oauth object argument'), null);
- var uri = oauth.instance_url + '/services/data/' + this.apiVersion
- + '/sobjects/' + data.attributes.type + '/' + data.getId();
- var opts = { uri: uri, method: 'PATCH', body: JSON.stringify(fieldvalues) }
- return apiRequest(opts, oauth, callback);
+
+ opts = {
+ uri: oauth.instance_url + '/services/data/' + this.apiVersion + '/sobjects/' + type + '/' + id,
+ method: 'PATCH'
+ };
+
+ if(type === 'document' || type === 'attachment' || type === 'contentversion') {
+
+ entity = (type === 'contentversion') ? 'content' : type;
+
+ opts.multipart = [
+ {
+ 'content-disposition': 'form-data; name="entity_' + entity + '"',
+ 'content-type': 'application/json',
+ body: JSON.stringify(fieldvalues)
+ },
+ {
+ 'content-type': mime.lookup(data.attachment.fileName),
+ 'content-disposition': 'form-data; name="Body"; filename="' + data.attachment.fileName + '"',
+ body: data.attachment.body
+ }
+ ];
+
+ } else {
+ opts.body = JSON.stringify(fieldvalues);
+ }
+
+ return apiRequest(opts, oauth, data, callback);
}
Connection.prototype.upsert = function(data, oauth, callback) {
@@ -343,7 +388,7 @@ Connection.prototype.upsert = function(data, oauth, callback) {
var uri = oauth.instance_url + '/services/data/' + this.apiVersion + '/sobjects/'
+ data.attributes.type + '/' + data.attributes.externalIdField + '/' + data.attributes.externalId;
var opts = { uri: uri, method: 'PATCH', body: JSON.stringify(fieldvalues) }
- return apiRequest(opts, oauth, callback);
+ return apiRequest(opts, oauth, data, callback);
}
Connection.prototype.delete = function(data, oauth, callback) {
@@ -359,7 +404,7 @@ Connection.prototype.delete = function(data, oauth, callback) {
var uri = oauth.instance_url + '/services/data/' + this.apiVersion + '/sobjects/'
+ data.attributes.type + '/' + data.getId();
var opts = { uri: uri, method: 'DELETE'}
- return apiRequest(opts, oauth, callback);
+ return apiRequest(opts, oauth, data, callback);
}
Connection.prototype.getRecord = function(data, oauth, callback) {
@@ -384,7 +429,7 @@ Connection.prototype.getRecord = function(data, oauth, callback) {
uri += '?' + qs.stringify(query);
}
var opts = { uri: uri, method: 'GET'}
- return apiRequest(opts, oauth, function(err, resp){
+ return apiRequest(opts, oauth, null, function(err, resp){
if(!err) {
resp = new Record(resp);
}
@@ -451,7 +496,7 @@ Connection.prototype.query = function(query, oauth, callback) {
var uri = oauth.instance_url + '/services/data/' + this.apiVersion + '/query';
var opts = { uri: uri, method: 'GET', qs: { q: query } }
- apiRequest(opts, oauth, function(err, resp){
+ apiRequest(opts, oauth, null, function(err, resp){
if(!err) {
if(resp.records && resp.records.length > 0) {
stream.write(JSON.stringify(resp));
@@ -483,7 +528,7 @@ Connection.prototype.search = function(search, oauth, callback) {
if(!validateOAuth(oauth)) return callback(new Error('Invalid oauth object argument'), null);
var uri = oauth.instance_url + '/services/data/' + this.apiVersion + '/search';
var opts = { uri: uri, method: 'GET', qs: { q: search } }
- return apiRequest(opts, oauth, function(err, resp){
+ return apiRequest(opts, oauth, null, function(err, resp){
if(!err) {
if(resp.length) {
var recs = [];
@@ -505,7 +550,7 @@ Connection.prototype.getUrl = function(url, oauth, callback) {
if(!validateOAuth(oauth)) return callback(new Error('Invalid oauth object argument'), null);
var uri = oauth.instance_url + url;
var opts = { uri: uri, method: 'GET' }
- return apiRequest(opts, oauth, callback);
+ return apiRequest(opts, oauth, null, callback);
}
// chatter api methods
@@ -609,7 +654,7 @@ var apiBlobRequest = function(opts, oauth, callback) {
});
}
-var apiRequest = function(opts, oauth, callback) {
+var apiRequest = function(opts, oauth, sobject, callback) {
opts.headers = {
'Authorization': 'OAuth ' + oauth.access_token
@@ -624,6 +669,8 @@ var apiRequest = function(opts, oauth, callback) {
return request(opts, function(err, res, body) {
if(!err && res.statusCode == 200 || res.statusCode == 201 || res.statusCode == 202 || res.statusCode == 204) {
if(body) body = JSON.parse(body);
+ // attach the id back to the sobject on insert
+ if(sobject && body && body.id && !sobject.Id && !sobject.id && !sobject.ID) sobject.Id = body.id;
callback(null, body);
} else if(!err) {
if(body) body = JSON.parse(body);
@@ -673,7 +720,7 @@ Connection.prototype.apexRest = function(restRequest, oauth, callback) {
}
opts.uri+=params;
}
- apiRequest(opts, oauth, callback);
+ apiRequest(opts, oauth, null, callback);
}
// exports
View
26 lib/record.js
@@ -37,19 +37,39 @@ var Record = function(d) {
}
for (var fieldKey in that) {
+
+ // get new properties that were added after instantiation
if(fieldKey !== 'attributes'
&& fieldKey !== 'attachment'
- && fieldKey !== 'Id'
- && fieldKey !== 'id'
- && fieldKey !== 'ID'
+ && fieldKey.toLowerCase() !== 'id'
&& fieldKey.substring(0,1) !== '_'
&& !that.__lookupGetter__(fieldKey)
&& typeof that[fieldKey] !== 'function') {
if(!fvs[fieldKey]) {
fvs[fieldKey] = that[fieldKey];
}
}
+
+ // create getters/setters for the new properties
+ // and store the data
+ if(!that.__lookupGetter__(fieldKey)) {
+ (function(record, key, data) {
+ data[key] = that[key];
+ record.__defineGetter__(key, function() {
+ return data[key];
+ });
+ record.__defineSetter__(key, function(val) {
+ data[key] = val;
+ _fieldValues[key] = val;
+ });
+ }(that, fieldKey, data));
+ }
+
}
+
+ // clear the cache
+ _fieldValues = {};
+
return fvs;
}
View
3 package.json
@@ -17,7 +17,8 @@
"main": "index.js",
"dependencies": {
"request": "*",
- "faye": "~0.8.3"
+ "faye": "~0.8.3",
+ "mime": "~1.2.9"
},
"devDependencies": {
"mocha": "*",
View
17 test/connection.js
@@ -137,8 +137,9 @@ describe('index', function(){
obj.Name.should.equal('Test Me');
obj.should.have.property('Custom_Field__c');
obj.Custom_Field__c.should.equal('Blah');
- obj.getFieldValues().should.have.property('Name', 'Test Me');
- obj.getFieldValues().should.have.property('Custom_Field__c', 'Blah');
+ var fv = obj.getFieldValues();
+ fv.should.have.property('Name', 'Test Me');
+ fv.should.have.property('Custom_Field__c', 'Blah');
});
it('should allow instantiation with id', function() {
@@ -150,6 +151,18 @@ describe('index', function(){
obj.should.have.property('Id');
obj.Id.should.equal('asalesforceid');
});
+
+ it('should clear the cache after calling getFieldValues', function() {
+ var obj = nforce.createSObject('Test_Object__c', {
+ Name: 'Test Me',
+ Custom_Field__c: 'Blah',
+ Id: 'asalesforceid'
+ });
+ var fvBefore = obj.getFieldValues();
+ var fvAfter = obj.getFieldValues();
+ fvBefore.should.have.keys('Name', 'Custom_Field__c');
+ fvAfter.should.not.have.keys('Name', 'Custom_Field__c', 'Id');
+ });
});
View
25 test/record.js
@@ -104,8 +104,6 @@ describe('lib/record', function(){
myRecord.Custom_Field__c = 'This is something';
//myRecord.getFieldValues().length.should.equal(2);
should.equal(Object.keys(myRecord.getFieldValues()).length, 2);
- myRecord.Phone = '2488843403';
- should.equal(Object.keys(myRecord.getFieldValues()).length, 3);
});
it('should not contain the Id', function() {
@@ -130,6 +128,29 @@ describe('lib/record', function(){
}
myRecord.getFieldValues().should.not.have.keys('attachment');
});
+
+ it('should clear the cache after calling it once', function(){
+ var myRecord = new Record(accountRec);
+ myRecord.Test_Field__c = 'blah';
+ var fvBefore = myRecord.getFieldValues();
+ var fvAfter = myRecord.getFieldValues();
+ fvBefore.should.have.keys('Test_Field__c');
+ fvAfter.should.not.have.keys('Test_Field__c');
+ should.equal(0, Object.keys(fvAfter).length);
+ });
+
+ it('should create a new cache', function() {
+ var myRecord = new Record(accountRec);
+ myRecord.Test_Field__c = 'blah';
+ var fvClear = myRecord.getFieldValues();
+ myRecord.Test_Field2__c = 'foo';
+ var fvAfter = myRecord.getFieldValues();
+ fvClear.should.have.keys('Test_Field__c');
+ fvClear.should.not.have.keys('Test_Field2__c');
+ fvAfter.should.have.keys('Test_Field2__c');
+ fvAfter.should.not.have.keys('Test_Field__c');
+ fvAfter.Test_Field2__c.should.equal('foo');
+ });
});

0 comments on commit c88e3ae

Please sign in to comment.