Created
December 13, 2024 16:35
-
-
Save vinnymac/3c0b1e0bd33b0bdbebc48b2f0410945c to your computer and use it in GitHub Desktop.
Slugify postgres functions for creating slugs from arbitrary text strings
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CREATE EXTENSION IF NOT EXISTS "unaccent"; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CREATE OR REPLACE FUNCTION slugify(input text) RETURNS text | |
AS $$ | |
BEGIN | |
input := unaccent(input); | |
input := lower(input); | |
-- remove single and double quotes | |
input := regexp_replace(input, '[''"]+', '', 'gi'); | |
-- replace anything that's not a letter, number, hyphen, or underscore with a hyphen | |
input := regexp_replace(input, '[^a-z0-9\-_]+', '-', 'gi'); | |
-- trim hyphens if they exist on the ends of the string | |
input := regexp_replace(input, '\-+$', ''); | |
input := regexp_replace(input, '^\-', ''); | |
RETURN input; | |
END; | |
$$ LANGUAGE plpgsql STRICT IMMUTABLE PARALLEL SAFE; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
CREATE OR REPLACE FUNCTION slugify(input text, table_name text, column_name text) | |
RETURNS text AS $$ | |
DECLARE | |
base_slug text; | |
final_slug text; | |
counter integer := 1; | |
max_length integer := 15; | |
existing_slug text; | |
BEGIN | |
-- Generate the initial base slug | |
base_slug := unaccent(input); | |
base_slug := lower(base_slug); | |
-- Remove single and double quotes | |
base_slug := regexp_replace(base_slug, '[''"]+', '', 'gi'); | |
-- Replace anything that's not a letter, number, hyphen, or underscore with a hyphen | |
base_slug := regexp_replace(base_slug, '[^a-z0-9\-_]+', '-', 'gi'); | |
-- Trim hyphens from the ends | |
base_slug := regexp_replace(base_slug, '\-+$', ''); | |
base_slug := regexp_replace(base_slug, '^\-', ''); | |
-- Truncate the base slug to leave room for the counter | |
-- Max length minus 4 characters (for potential "-999" suffix) | |
base_slug := substring(base_slug, 1, max_length - 4); | |
-- Remove any trailing hyphen after truncation | |
base_slug := regexp_replace(base_slug, '\-+$', ''); | |
-- Try the base slug first | |
final_slug := base_slug; | |
-- Check if the slug exists using dynamic SQL | |
LOOP | |
EXECUTE format('SELECT %I FROM %I WHERE %I = $1 LIMIT 1', | |
column_name, table_name, column_name) | |
INTO existing_slug | |
USING final_slug; | |
EXIT WHEN existing_slug IS NULL; | |
-- If slug exists, append counter and increment | |
final_slug := base_slug || '-' || counter; | |
counter := counter + 1; | |
-- Ensure the final slug with counter doesn't exceed max length | |
IF length(final_slug) > max_length THEN | |
-- Truncate base_slug further to accommodate counter | |
base_slug := substring(base_slug, 1, max_length - length(counter::text) - 1); | |
final_slug := base_slug || '-' || counter; | |
END IF; | |
END LOOP; | |
RETURN final_slug; | |
END; | |
$$ LANGUAGE plpgsql STRICT; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment