Created
March 4, 2016 09:38
-
-
Save nfroidure/f2ce4990c0b6d6e1eb62 to your computer and use it in GitHub Desktop.
Generating a MongoDB ObjectId in SalesForce Apex
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public with sharing class MongoObjectId { | |
private static final Integer COUNTER_MASK = 16777215; // 0xFFFFFF | |
private static final Integer PID_MASK = 65535; // 0xFFFF | |
private static final String MACHINE_PART = '050135'; | |
private static final String[] hexMap = '0123456789abcdef'.split(''); | |
private static Integer counter = -1; | |
public static void seed() { | |
// Seed once or force reseed when testing | |
if(-1 == counter || Test.isRunningTest()) { | |
counter = Integer.valueOf(Math.mod( | |
Integer.valueOf(TestStubs.random() * COUNTER_MASK), | |
COUNTER_MASK | |
)); | |
} | |
System.debug('counter'); | |
System.debug(counter); | |
} | |
public static String decToHex(Long x, Integer length) { | |
String result = ''; | |
while (x != 0) { | |
Integer modulus = Integer.valueOf(Math.mod(x, 16)); | |
result = hexMap[modulus] + result; | |
x /= 16; | |
} | |
while(result.length() < length) { | |
result = '0' + result; | |
} | |
return result; | |
} | |
public static String userIdToPid(String userId) { | |
Integer pid = 0; | |
for(Integer x = userId.length() - 1; x >= 0; x--) { | |
pid = Math.mod(pid + userId.codePointAt(x), PID_MASK); | |
} | |
return decToHex(pid, 4); | |
} | |
public static String generate() { | |
// Ensure the counter was seeded | |
seed(); | |
// Get current timestamp | |
Integer timestamp = Integer.valueOf(TestStubs.now().getTime() / 1000); | |
// Compute pid from userId | |
String pid = userIdToPid(TestStubs.getUserId()); | |
// Increment the internal counter | |
counter = counter + 1; | |
counter = counter & COUNTER_MASK; | |
List<String> parts = new List<String> { | |
decToHex(timestamp, 8), | |
MACHINE_PART, | |
pid, | |
decToHex(counter, 6) | |
}; | |
System.debug('counter'); | |
System.debug(counter); | |
System.debug('Timestamp'); | |
System.debug(timestamp); | |
return String.join(parts, ''); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@isTest(seeAllData=false) | |
private class TestMongoObjectId { | |
static testMethod void testToHex() { | |
Test.startTest(); | |
System.assertEquals('000ff', MongoObjectId.decToHex( | |
255, | |
5 | |
)); | |
System.assertEquals('000fe', MongoObjectId.decToHex( | |
254, | |
5 | |
)); | |
System.assertEquals('0012730c57800', MongoObjectId.decToHex( | |
1267833600000L, | |
13 | |
)); | |
Test.stopTest(); | |
} | |
static testMethod void testUserIdToPid() { | |
Test.startTest(); | |
System.assertEquals('01d7', MongoObjectId.userIdToPid( | |
'1664BABA' | |
)); | |
Test.stopTest(); | |
} | |
static testMethod void testGenerate() { | |
Test.startTest(); | |
TestStubs.testRandom = 0.5; | |
TestStubs.testNow = 1267833600000L; | |
TestStubs.testUserId = '1664BABA'; | |
String id = MongoObjectId.generate(); | |
System.assertEquals(24, id.length()); | |
System.assertEquals('4b919b0005013501d7800000', id); | |
Test.stopTest(); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public with sharing class TestStubs { | |
@TestVisible | |
private static Long testNow {get; set;} | |
@TestVisible | |
private static Decimal testRandom {get; set;} | |
@TestVisible | |
private static String testUserId {get; set;} | |
public static DateTime now() { | |
if(Test.isRunningTest() && (null != testNow)) { | |
return DateTime.newInstance(testNow); | |
} else { | |
return System.now(); | |
} | |
} | |
public static Decimal random() { | |
if(Test.isRunningTest() && (null != testRandom)) { | |
return testRandom; | |
} else { | |
return Math.random(); | |
} | |
} | |
public static String getUserId() { | |
if(Test.isRunningTest() && (null != testUserId)) { | |
return testUserId; | |
} else { | |
return UserInfo.getUserId(); | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
@isTest(seeAllData=false) | |
private class TestTestStubs { | |
static testMethod void testRandomStub() { | |
Test.startTest(); | |
TestStubs.testRandom = 0.5; | |
System.assertEquals(TestStubs.testRandom, TestStubs.random()); | |
Test.stopTest(); | |
} | |
static testMethod void testNowStub() { | |
Test.startTest(); | |
TestStubs.testNow = 1267833600000L; | |
System.assertEquals(TestStubs.testNow, TestStubs.now().getTime()); | |
Test.stopTest(); | |
} | |
static testMethod void testUserIdStub() { | |
Test.startTest(); | |
TestStubs.testUserId = '1664BABA'; | |
System.assertEquals((TestStubs.testUserId), TestStubs.getUserId()); | |
Test.stopTest(); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment