Skip to content

Instantly share code, notes, and snippets.

@mz026
Last active October 4, 2016 07:21
Show Gist options
  • Save mz026/beaf097b055cf7a143028d654e2d12be to your computer and use it in GitHub Desktop.
Save mz026/beaf097b055cf7a143028d654e2d12be to your computer and use it in GitHub Desktop.
Random id generator of postgres
class AddRandomIdGenerator < ActiveRecord::Migration
# ref: http://www.rightbrainnetworks.com/blog/base36-conversion-in-postgresql/
# ref: http://rob.conery.io/2014/05/29/a-better-id-generator-for-postgresql/
def up
func_sql = <<-SQL
CREATE OR REPLACE FUNCTION base36_encode(IN digits bigint, IN min_width int = 0)
RETURNS varchar AS $$
DECLARE
chars char[];
ret varchar;
val bigint;
BEGIN
chars := ARRAY['0','1','2','3','4','5','6','7','8','9'
,'a','b','c','d','e','f','g','h','i','j','k','l','m'
,'n','o','p','q','r','s','t','u','v','w','x','y','z'];
val := digits;
ret := '';
IF val < 0 THEN
val := val * -1;
END IF;
WHILE val != 0 LOOP
ret := chars[(val % 36)+1] || ret;
val := val / 36;
END LOOP;
IF min_width > 0 AND char_length(ret) < min_width THEN
ret := lpad(ret, min_width, '0');
END IF;
RETURN ret;
END;
$$ LANGUAGE 'plpgsql' IMMUTABLE;
SQL
execute func_sql
sql = <<-SQL
create sequence global_id_sequence;
CREATE OR REPLACE FUNCTION generate_random_id() RETURNS varchar AS $$
DECLARE
our_epoch bigint := 1472533855842;
seq_id bigint;
now_millis bigint;
result bigint;
ret varchar;
BEGIN
SELECT nextval('global_id_sequence') % 1024 INTO seq_id;
SELECT FLOOR(EXTRACT(EPOCH FROM clock_timestamp()) * 1000) INTO now_millis;
result := (now_millis - our_epoch) << 10;
result := result | (seq_id);
ret := base36_encode(result);
RETURN ret;
END;
$$ LANGUAGE PLPGSQL;
SQL
execute sql
end
def down
execute "drop function if exists generate_random_id()"
execute "drop function if exists base36_encode()"
execute "drop sequence if exists global_id_sequence"
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment