I am thinking if the database can do the generation task for you i.e.
how to bind your primary key to any algorithm that can generate such
shorthand forms
Since you mention a salt, I assume you're looking for short strings
that are hard to guess or reproduce by an outsider, despite
being originated with a database sequence.
The permuteseq extension
essentially does that.
The function that produces a short string from an integer has
to be provided, for instance:
CREATE FUNCTION id_to_alpha(n int) RETURNS text
LANGUAGE plpgsql IMMUTABLE STRICT AS $$
DECLARE
alphabet text:='abcdefghijklmnopqrstuvwxyz012345678';
sign_char char:='9';
base int:=length(alphabet);
_n bigint:=abs(n);
output text:='';
BEGIN
LOOP
output := output || substr(alphabet, 1+(_n%base)::int, 1);
_n := _n / base;
EXIT WHEN _n=0;
END LOOP;
RETURN CASE WHEN (n<0) THEN output || sign_char::text ELSE output END;
RETURN output;
END; $$;
Then you may set the short id slug in a BEFORE INSERT trigger, like this:
CREATE EXTENSION permuteseq;
CREATE TABLE things(
id serial,
short_id text,
name varchar(10) not null
);
-- keep the sequence short for short output strings
ALTER SEQUENCE things_id_seq MAXVALUE 1000000;
CREATE FUNCTION generate_short_id() RETURNS TRIGGER AS $$
DECLARE
secret bigint := 123456789; -- change for a different secret sequence
BEGIN
NEW.short_id := id_to_alpha(range_encrypt_element(NEW.id, 1, 10000000, secret)::int);
RETURN NEW;
END;
$$ LANGUAGE plpgsql;
CREATE TRIGGER things_trigger BEFORE INSERT ON things
FOR EACH ROW EXECUTE PROCEDURE generate_short_id();
Testing it:
INSERT INTO things(name) SELECT 'foo' FROM generate_series(1,10);
SELECT * FROM things;
id | short_id | name
----+----------+------
1 | wf3hg | foo
2 | tm6lg | foo
3 | riqbg | foo
4 | p6jp | foo
5 | h3r3c | foo
6 | 3sx5d | foo
7 | w8ecd | foo
8 | km3le | foo
9 | llt1e | foo
10 | xwtxc | foo
In this example, there is both id and short_id in the table, but id
is technically redundant with short_id. You could create a sequence
outside of the table without the SERIALsyntax like this, and not
even have id in the table:
CREATE SEQUENCE seq_pk MAXVALUE 1000000;
CREATE TABLE things2(
short_id TEXT
DEFAULT id_to_alpha(permute_nextval('seq_pk'::regclass, 123456::bigint)::int)
PRIMARY KEY,
name text
);
INSERT INTO things2(name) values('foo');
SELECT * FROM things2;
short_id | name
----------+------
znyh | foo
If you can't use permuteseq, as an alternative still based on
encrypting the ID, you may look at the plpgsql implementation of
SKIP32,
or XTEA for 64-bit (bigint)
which won't require a compilation or being superuser. The drawback is
that you cannot fine-tune the size of the output by changing the
sequence's range.
1. key 1doesn't tell me what the "1" is or what the "key" is.