Skip to content

Instantly share code, notes, and snippets.

@kylewelsby
Last active April 27, 2017 08:25
Show Gist options
  • Save kylewelsby/9c596c875b4ed16b6b77bc3501aaea30 to your computer and use it in GitHub Desktop.
Save kylewelsby/9c596c875b4ed16b6b77bc3501aaea30 to your computer and use it in GitHub Desktop.
The ability to generate an ULID from a legacy integer ID. Useful for syncing data between systems.
require 'time'
class User
def id
'507f1f77bcf86cd799439011'
end
def created_at
Time.parse('2017-04-24 12:15:20 +0200')
end
end
user = User.new
ulid = CustomULID.generate("Legacy::Ea2::#{user.class}", user.id, user.created_at)
puts ulid
ulid2 = CustomULID.generate("Legacy::Ea2::#{user.class}", user.id, user.created_at)
puts ulid2
puts ulid == ulid2
ulid3 = CustomULID.generate("Legacy::Ea2::#{user.class}", '507f191e810c19729de860ea', user.created_at)
puts ulid3
puts ulid == ulid3
puts CustomULID.generate("Legacy::Ea2::Person", '507f191e810c19729de860ea', user.created_at)
require 'digest/sha1'
class CustomULID
ENCODING = '0123456789ABCDEFGHJKMNPQRSTVWXYZ' # Crockford's Base32
RANDOM_BYTES = 10
ENCODED_LENGTH = 26
BIT_LENGTH = 128
BITS_PER_B32_CHAR = 5
MASK = 0x1f
def self.generate(class_name, id, created_at)
time = [(created_at.to_f * 10_000).to_i].pack("Q>")[2..-1]
word = [id, Digest::SHA1.hexdigest(class_name)].pack("a5a5")
bytes = (time + word)
(hi, lo) = bytes.unpack("Q>Q")
input = (hi << 64) | lo
(1..ENCODED_LENGTH).to_a.reduce("") do |s, n|
shift = BIT_LENGTH - BITS_PER_B32_CHAR * n
s + ENCODING[(input >> shift) & MASK]
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment