mirror of
https://github.com/documenso/documenso.git
synced 2025-11-17 10:11:35 +10:00
134 lines
5.2 KiB
PL/PgSQL
134 lines
5.2 KiB
PL/PgSQL
/*
|
|
* Copyright 2024 Viascom Ltd liab. Co
|
|
*
|
|
* Licensed to the Apache Software Foundation (ASF) under one
|
|
* or more contributor license agreements. See the NOTICE file
|
|
* distributed with this work for additional information
|
|
* regarding copyright ownership. The ASF licenses this file
|
|
* to you under the Apache License, Version 2.0 (the
|
|
* "License"); you may not use this file except in compliance
|
|
* with the License. You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
|
|
CREATE EXTENSION IF NOT EXISTS pgcrypto;
|
|
|
|
-- The `nanoid()` function generates a compact, URL-friendly unique identifier.
|
|
-- Based on the given size and alphabet, it creates a randomized string that's ideal for
|
|
-- use-cases requiring small, unpredictable IDs (e.g., URL shorteners, generated file names, etc.).
|
|
-- While it comes with a default configuration, the function is designed to be flexible,
|
|
-- allowing for customization to meet specific needs.
|
|
DROP FUNCTION IF EXISTS nanoid(int, text, float);
|
|
CREATE OR REPLACE FUNCTION nanoid(
|
|
size int DEFAULT 21, -- The number of symbols in the NanoId String. Must be greater than 0.
|
|
alphabet text DEFAULT '_-0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ', -- The symbols used in the NanoId String. Must contain between 1 and 255 symbols.
|
|
additionalBytesFactor float DEFAULT 1.6 -- The additional bytes factor used for calculating the step size. Must be equal or greater then 1.
|
|
)
|
|
RETURNS text -- A randomly generated NanoId String
|
|
LANGUAGE plpgsql
|
|
VOLATILE
|
|
PARALLEL SAFE
|
|
-- Uncomment the following line if you have superuser privileges
|
|
-- LEAKPROOF
|
|
AS
|
|
$$
|
|
DECLARE
|
|
alphabetArray text[];
|
|
alphabetLength int := 64;
|
|
mask int := 63;
|
|
step int := 34;
|
|
BEGIN
|
|
IF size IS NULL OR size < 1 THEN
|
|
RAISE EXCEPTION 'The size must be defined and greater than 0!';
|
|
END IF;
|
|
|
|
IF alphabet IS NULL OR length(alphabet) = 0 OR length(alphabet) > 255 THEN
|
|
RAISE EXCEPTION 'The alphabet can''t be undefined, zero or bigger than 255 symbols!';
|
|
END IF;
|
|
|
|
IF additionalBytesFactor IS NULL OR additionalBytesFactor < 1 THEN
|
|
RAISE EXCEPTION 'The additional bytes factor can''t be less than 1!';
|
|
END IF;
|
|
|
|
alphabetArray := regexp_split_to_array(alphabet, '');
|
|
alphabetLength := array_length(alphabetArray, 1);
|
|
mask := (2 << cast(floor(log(alphabetLength - 1) / log(2)) as int)) - 1;
|
|
step := cast(ceil(additionalBytesFactor * mask * size / alphabetLength) AS int);
|
|
|
|
IF step > 1024 THEN
|
|
step := 1024; -- The step size % can''t be bigger then 1024!
|
|
END IF;
|
|
|
|
RETURN nanoid_optimized(size, alphabet, mask, step);
|
|
END
|
|
$$;
|
|
|
|
-- Generates an optimized random string of a specified size using the given alphabet, mask, and step.
|
|
-- This optimized version is designed for higher performance and lower memory overhead.
|
|
-- No checks are performed! Use it only if you really know what you are doing.
|
|
DROP FUNCTION IF EXISTS nanoid_optimized(int, text, int, int);
|
|
CREATE OR REPLACE FUNCTION nanoid_optimized(
|
|
size int, -- The desired length of the generated string.
|
|
alphabet text, -- The set of characters to choose from for generating the string.
|
|
mask int, -- The mask used for mapping random bytes to alphabet indices. Should be `(2^n) - 1` where `n` is a power of 2 less than or equal to the alphabet size.
|
|
step int -- The number of random bytes to generate in each iteration. A larger value may speed up the function but increase memory usage.
|
|
)
|
|
RETURNS text -- A randomly generated NanoId String
|
|
LANGUAGE plpgsql
|
|
VOLATILE
|
|
PARALLEL SAFE
|
|
-- Uncomment the following line if you have superuser privileges
|
|
-- LEAKPROOF
|
|
AS
|
|
$$
|
|
DECLARE
|
|
idBuilder text := '';
|
|
counter int := 0;
|
|
bytes bytea;
|
|
alphabetIndex int;
|
|
alphabetArray text[];
|
|
alphabetLength int := 64;
|
|
BEGIN
|
|
alphabetArray := regexp_split_to_array(alphabet, '');
|
|
alphabetLength := array_length(alphabetArray, 1);
|
|
|
|
LOOP
|
|
bytes := gen_random_bytes(step);
|
|
FOR counter IN 0..step - 1
|
|
LOOP
|
|
alphabetIndex := (get_byte(bytes, counter) & mask) + 1;
|
|
IF alphabetIndex <= alphabetLength THEN
|
|
idBuilder := idBuilder || alphabetArray[alphabetIndex];
|
|
IF length(idBuilder) = size THEN
|
|
RETURN idBuilder;
|
|
END IF;
|
|
END IF;
|
|
END LOOP;
|
|
END LOOP;
|
|
END
|
|
$$;
|
|
|
|
-- CUSTOM FUNCTION FOR GENERIC PREFIXED IDS
|
|
CREATE OR REPLACE FUNCTION generate_prefix_id(prefix TEXT)
|
|
RETURNS TEXT AS $$
|
|
BEGIN
|
|
RETURN prefix || '_' || nanoid(16, 'abcdefhiklmnorstuvwxyz');
|
|
END;
|
|
$$ LANGUAGE plpgsql VOLATILE;
|
|
|
|
-- CUSTOM FUNCTION FOR GENERIC IDS
|
|
CREATE OR REPLACE FUNCTION generate_id()
|
|
RETURNS TEXT AS $$
|
|
BEGIN
|
|
RETURN nanoid(16, 'abcdefhiklmnorstuvwxyz');
|
|
END;
|
|
$$ LANGUAGE plpgsql VOLATILE;
|