Skip to main content

Sequential Unique Short & Sortable Identifier

Project description

Serial-Id

codecov Code Climate Issue Count

Sequential Unique Short & Sortable Identifier

It is a short sequential identifier that is random but sortable and only uses 80 bits. First 40 bits are for timestamp and rest of the 40 bits are used for randomness.

Why's Serial-Id?

This is a conversion of ahawker/ulid 128 bits implementation to short 80 bits identifier with purpose of sortability and uses Crockford's Base32 encoding

Installation

To install serial-id from github:

    $ pip install --upgrade git+https://github.com/mysteryjeans/serial-id.git

To install serial-id from source:

    $ git clone https://github.com/mysteryjeans/serial-id.git
    $ cd serial-id && python setup.py install

Usage

Create a brand new SerialId.

The timestamp value (40-bits) is from time.time() with centiseconds precision.

The randomness value (40-bits) is from os.urandom().

import serialid
serialid.new()
<SerialId('4t8ax5bs-6gvqk2sy')>

Sequential Ids but with randomness

Create a new SerialId from an existing 80-bit value with guaranteed sort order.

import serialid
seq_ids = []
new_sid = serialid.new()

for _ in range(0, 1000):
    new_sid = serialid.new_seq(new_sid)
    seq_ids.append(new_sid)

seq_ids[:10]

Create a new SerialId from an existing timestamp value, such as a datetime object.

Supports timestamp values as int, float, str, bytes, bytearray, memoryview, datetime, Timestamp, and SerialId types.

import datetime, serialid
serialid.from_timestamp(datetime.datetime(1999, 1, 1))
<SerialId('4t8ax5bs-6gvqk2sy')>

Create a new SerialId from an existing randomness value.

Supports randomness values as int, float, str, bytes, bytearray, memoryview, Randomness types.

import os, serialid
randomness = os.urandom(10)
serialid.from_randomness(randomness)
<SerialId('4t8ax5bs-sgx82mz4')>

For cases when you don't necessarily control the data type (input from external system), you can use the parse method which will attempt to make the correct determination for you. Please note that this will be slightly slower than creating the instance from the respective from_* method as it needs to make a number of type/conditional checks.

Supports values as int, float, str, bytes, bytearray, memoryview, and SerialId types.

import serialid
value = db.model.get_id()  ## Unsure about datatype -- Could be int or string?
serialid.parse(value) # Parses from str, int, float, bytes ...
<SerialId('4t8ax5bs-vp61yjkk')>

Once you have a SerailId object, there are a number of ways to interact with it.

The timestamp method will give you a snapshot view of the first 40-bits of the SerialId while the randomness method will give you a snapshot of the last 40-bits.

import serialid
id = serialid.new()
id
<SerialId('4t8ax5bs-vp61yjkk')>
id.timestamp()
<Timestamp('4t8ax5bs')>
id.randomness()
<Randomness('vp61yjkk')>

The SerialId, Timestamp, and Randomness classes all derive from the same base class, a MemoryView.

A MemoryView provides the bin, bytes, hex, int, oct, and str, methods for changing any values representation.

import serialid
u = serialid.new()
u
<SerialId('4t8ax5bs-vp61yjkk')
u.timestamp()
<Timestamp('4t8ax5bs')>
u.timestamp().int
165636436000
u.timestamp().bytes
b'&\x90\xb3j\x13'
u.timestamp().datetime
datetime.datetime(2022, 6, 28, 2, 12, 1, 190000)
u.randomness().bytes
b'\x01c.)\xfa'
u.bytes[5:] == u.randomness().bytes
True
u.str
'4t8ax5bs-vp61yjkk'
u.int
182119165340642244955695
u.bin
'0b100110100100001011001100100001111000001001111100111101001011100000111000101111'
u.hex
'0x2690b321e09f3d2e0e2f'
u.oct
'0o46441314417011747513407057'

A MemoryView also provides rich comparison functionality.

import datetime, time, serialid
u1 = serialid.new()
time.sleep(5)
u2 = serialid.new()
u1 < u2
True
u3 = serialid.from_timestamp(datetime.datetime(2039, 1, 1))
u1 < u2 < u3
True
[u.timestamp().datetime for u in sorted([u2, u3, u1])]
[datetime.datetime(2022, 6, 28, 2, 24, 56, 700000),
 datetime.datetime(2022, 6, 28, 2, 25, 1, 710000),
 datetime.datetime(2039, 1, 1, 0, 0)]

Contributing

If you would like to contribute, simply fork the repository, push your changes and send a pull request. Pull requests will be brought into the master branch via a rebase and fast-forward merge with the goal of having a linear branch history with no merge commits.

License

MIT License

Why not ULID?

SerailId provides:

  • 80-bit sortable Ids
  • 1099511627776 unique Serial Ids per centisecond 100th of a second
  • Lexicographically sortable!
  • Canonically encoded as a 16 character string, as opposed to the 24 character ULID
  • Uses Crockford's base32 for better efficiency and readability (5 bits per character)
  • Case insensitive
  • No special characters (URL safe)

Specification

Below is the current specification of ULID as implemented in this repository.

The binary format is implemented.

  4t8ax5bs           vp61yjkk

|----------|       |----------|
 Timestamp          Randomness
   8chars             8chars
   40bits             40bits

Components

Timestamp

  • 40 bit integer
  • UNIX-time in centiseconds
  • Won't run out of space till the year 2322 (300 years).

Randomness

  • 40 bits
  • Cryptographically secure source of randomness, if possible

Sorting

The left-most character must be sorted first, and the right-most character sorted last (lexical order). The default ASCII character set must be used. Within the same centiseconds, use serialid.new_seq to guaranteed sort order

Encoding

Crockford's Base32 is used as shown. This alphabet excludes the letters I, L, O, and U to avoid confusion and abuse.

0123456789abcdefghjkmnpqrstvwxyz

String Representation

ttttttttrrrrrrrr

where
t is Timestamp
r is Randomness

Links

Project details


Release history Release notifications | RSS feed

This version

0.1

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

serial-id-0.1.tar.gz (12.7 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

serial_id-0.1-py3.9.egg (13.7 kB view details)

Uploaded Egg

File details

Details for the file serial-id-0.1.tar.gz.

File metadata

  • Download URL: serial-id-0.1.tar.gz
  • Upload date:
  • Size: 12.7 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.9.13

File hashes

Hashes for serial-id-0.1.tar.gz
Algorithm Hash digest
SHA256 8f97b50869851e39da7597c515f5da5b2d3d0d9f75edfb81c1b74005ea530928
MD5 871c662f97bc27bd1b5b78a8f314ae72
BLAKE2b-256 c4d7fa28df150a1aa8e9e96b7d222b4373592ae2b7997e6f3124b6732a45ee94

See more details on using hashes here.

File details

Details for the file serial_id-0.1-py3.9.egg.

File metadata

  • Download URL: serial_id-0.1-py3.9.egg
  • Upload date:
  • Size: 13.7 kB
  • Tags: Egg
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.1 CPython/3.9.13

File hashes

Hashes for serial_id-0.1-py3.9.egg
Algorithm Hash digest
SHA256 4b7120f3b33f36c47da67da8d2c3ab83df7f7ee4ec5ff33c9fc9d9fb4a7bd25a
MD5 4956aa6ebff0b4cdf4b132979cd53b8c
BLAKE2b-256 9e5e4668afa5ebb4a2fe763bf986e50cc9e83677859f456c0b1dfa36a022cd39

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page