Gem Version Build Status Code Climate - Maintainability Test Coverage

Introduction

This gem provides functionality to compress and decompress two different types of objects:

  1. a contiguous range or multiple contiguous ranges of integer ID

  2. a set of UUID

as a single string.

Both Ruby and Javascript implementations are provided.

Javascript support for Rails is provided by means of a Rails engine (IdPack::Engine).

Further, for integer ID ranges, it provides serialization of a concept called sync_str, which stands for "synchronization string".

sync_str represents a mapping from ID to timestamp. It is typically generated on the client side for the server side. Armed with the sync_str, the server knows which objects the client requires, by comparing the timestamps from the sync_str with the update times of the corresponding objects from the database, so synchronization could be done with minimal waste of bandwidth.

Timestamps are really just integers, e.g. Time.now.to_i.

Installation

There are at least two ways to install this:

  1. The quickest way is to gem install on the terminal:

    gem install id_pack
  2. If your application has a Gemfile, add the following line:

    gem 'id_pack'
    

    And then execute:

    bundle

Usage

To experiment with the code, run bin/console for an interactive prompt.

require 'id_pack'

IdPacker

id_packer = IdPack::IdPacker.new

To encode/decode a set of IDs:

ids         = [5, 6, 21, 23, 25]
encoded_ids = id_packer.encode(ids)         #=> "_F~C_P.V"
decoded_ids = id_packer.decode(encoded_ids) #=> [5, 6, 21, 23, 25]
ids == decoded_ids                          #=> true

To work with sync_str:

ids_synced_at = {
  1  => 1510294889,
  2  => 1510292639,
  10 => 1510279639,
}

sync_str = id_packer.encode_sync_str(ids_synced_at)
#=> "IwVmAYCYHYE4DYDMsg,IxA,IwVgTCAMQ,ExA,IwZgDBQ,IwBiA,AxA"

decoded_sync_map = id_packer.decode_sync_str(sync_str)
#=> {1=>1510294889, 2=>1510292639, 10=>1510279639}

ids_synced_at == decoded_sync_map
#=> true

Advanced sync_str usage

IdPacker#decode_sync_str optionally supports a base_timestamp:

base_timestamp2   = 1000
decoded_sync_map2 = id_packer.decode_sync_str(sync_str, base_timestamp2)
#=> {1=>1510295889, 2=>1510293639, 10=>1510280639}

base_timestamp3   = - ids_synced_at.min[1]
decoded_sync_map3 = id_packer.decode_sync_str(sync_str, base_timestamp3)
#=> {1=>0, 2=>-2250, 10=>-15250}

base_timestamp4   = - ids_synced_at.max[1]
decoded_sync_map4 = id_packer.decode_sync_str(sync_str, base_timestamp4)
#=> {1=>15250, 2=>13000, 10=>0}

base_timestamp is typically specified to reverse any normalization of timestamps done on the client side (not shown in this README).

UuidPacker

uuid_packer = IdPack::UuidPacker.new
uuids         = [
  'ea8bed36-a73d-4fff-af36-32162274dfd1',
  '22347af1-7c60-48e0-8cc5-a30746812267',
  '3e514775-bfdb-44f9-92b2-c4c53a7dc89d',
]

To encode/decode a set of UUIDs, first, specify the set of encoding characters:

base_string = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+-_'

Also, decide whether we want to preserve the order of the UUIDs:

ordered = true
encoded_uuids = uuid_packer.alphanum_compress(uuids, base_string, ordered)
#=> "Rf2XIjQmNnr_8rzlbLfRV+ZEgWLgxaMxBxIGPo9eLES5E75coyNNSZ8i2_tdxRT4"

decoded_uuids = uuid_packer.alphanum_decompress(encoded_uuids, base_string)
#=> ["ea8bed36-a73d-4fff-af36-32162274dfd1", "22347af1-7c60-48e0-8cc5-a30746812267", "3e514775-bfdb-44f9-92b2-c4c53a7dc89d"]

uuids == decoded_uuids
#=> true

If we don’t care for the order:

ordered = false
unordered_encoded_uuids = uuid_packer.alphanum_compress(uuids, base_string, ordered)
unordered_decoded_uuids = uuid_packer.alphanum_decompress(unordered_encoded_uuids, base_string)

uuids == unordered_decoded_uuids
#=> false

uuids.sort == unordered_decoded_uuids.sort
#=> true

Development

After checking out the repo, run bin/setup to install dependencies. Then, run bundle exec rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/riboseinc/id_pack. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.

License

The gem is available as open source under the terms of the MIT License.