Prefix does not allow underscores · Issue #7 · jetify-com/typeid-sql · GitHub
Skip to content

Prefix does not allow underscores #7

Open

Description

@sjakos

Looks like the spec allows for underscores in the prefix, however the typeid_parse function only splits on the first _

Activity

  1. loreto commented on Aug 7, 2024

    @loreto
    Contributor

    Hi @sjakos: yes, you're right. It's because we haven't updated this sql implementation to the 0.3 spec (which introduced the _ support in the prefix). It's still following version 0.2.

    Let me see if I can find some time to update it this week.

  2. sjakos commented on Aug 7, 2024

    @sjakos
    Author

    I missed that detail, thanks for the clarification. Are there other changes that would need to happen for the move from 0.2 to 0.3?

  3. sakopov commented on Aug 26, 2024

    @sakopov

    Needed to get this working for my own needs. Here's my updated 03_typeid.sql script which handles new spec updates around prefixes.

    -- Implementation of typeids in SQL (Postgres).
    -- This file:
    -- + Defines a `typeid` type: a composite type consisting of a type prefix,
    --   and a UUID
    -- + Defines functions to generate and validate typeids in SQL.
    
    -- Create a `typeid` type.
    create type "typeid" as ("type" varchar(63), "uuid" uuid);
    
    -- Function that generates a random typeid of the given type.
    -- This depends on the `uuid_generate_v7` function defined in `uuid_v7.sql`.
    create or replace function typeid_generate(prefix text)
    returns typeid
    as $$
    begin
      if (prefix is null) or (prefix = '') then
        return ('', uuid_generate_v7())::typeid;
      end if;
      if not prefix ~ '^([a-z]([a-z_]{0,61}[a-z])?)?$' then
        raise exception 'typeid prefix must match the regular expression ([a-z]([a-z_]{0,61}[a-z])?)?';
      end if;
      return (prefix, uuid_generate_v7())::typeid;
    end
    $$
    language plpgsql
    volatile;
    
    -- Function that generates a type_id of given type, and returns the parsed typeid as text.
    create or replace function typeid_generate_text(prefix text)
    returns text
    as $$
    begin
      if (prefix is null) or (prefix = '') then
        return typeid_print(('', uuid_generate_v7())::typeid);
      end if;
      if not prefix ~ '^([a-z]([a-z_]{0,61}[a-z])?)?$' then
        raise exception 'typeid prefix must match the regular expression ([a-z]([a-z_]{0,61}[a-z])?)?';
      end if;
      return typeid_print((prefix, uuid_generate_v7())::typeid);
    end
    $$
    language plpgsql
    volatile;
    
    -- Function that checks if a typeid is valid, for the given type prefix.
    create or replace function typeid_check(tid typeid, expected_type text)
    returns boolean
    as $$
    declare
      prefix text;
    begin
      prefix = (tid).type;
      return prefix = expected_type;
    end
    $$
    language plpgsql
    immutable;
    
    -- Function that checks if a typeid is valid, for the given type_id in text format and type prefix, returns boolean.
    create or replace function typeid_check_text(typeid_str text, expected_type text)
    returns boolean
    as $$
    declare
      prefix text;
      tid typeid;
    begin
      tid = typeid_parse(typeid_str);
      prefix = (tid).type;
      return prefix = expected_type;
    end
    $$
    language plpgsql
    immutable;
    
    -- Function that parses a string into a typeid.
    create or replace function typeid_parse(typeid_str text)
    returns typeid
    as $$
    declare
      prefix text;
      suffix text;
    begin
      if (typeid_str is null) then
        return null;
      end if;
      if position('_' in typeid_str) = 0 then
        return ('', base32_decode(typeid_str))::typeid;
      end if;
      prefix = substring(typeid_str from 1 for (length(typeid_str) - position('_' in reverse(typeid_str))));
      suffix = substring(typeid_str from (length(prefix) + 2));
      if prefix is null or prefix = '' then
        raise exception 'typeid prefix cannot be empty with a delimiter';
      end if;
      -- prefix must match the regular expression ([a-z]([a-z_]{0,61}[a-z])?)?
      if not prefix ~ '^([a-z]([a-z_]{0,61}[a-z])?)?$' then
        raise exception 'typeid prefix must match the regular expression ([a-z]([a-z_]{0,61}[a-z])?)?';
      end if;
    
      return (prefix, base32_decode(suffix))::typeid;
    end
    $$
    language plpgsql
    immutable;
    
    -- Function that serializes a typeid into a string.
    create or replace function typeid_print(tid typeid)
    returns text
    as $$
    declare
      prefix text;
      suffix text;
    begin
      if (tid is null) then
        return null;
      end if;
      prefix = (tid).type;
      suffix = base32_encode((tid).uuid);
      if not prefix ~ '^([a-z]([a-z_]{0,61}[a-z])?)?$' then
        raise exception 'typeid prefix must match the regular expression ([a-z]([a-z_]{0,61}[a-z])?)?';
      end if;
      if prefix = '' then
        return suffix;
      end if;
      return (prefix || '_' || suffix);
    end
    $$
    language plpgsql
    immutable;
  4. loreto commented on Aug 27, 2024

    @loreto
    Contributor

    @sakopov Thanks for sharing! Are you open to contributing the above code back to the project under the Apache license? (If yes, I'll put together a PR based on it)

  5. sakopov commented on Aug 28, 2024

    @sakopov

    @loreto Absolutely, feel free.

  6. loreto commented on Sep 6, 2024

    @loreto
    Contributor

    Thank you @sjakos for sending jetify-com/opensource#363
    Just tagging it here so that the issue has a link to the PR discussion.

  7. c-nv-s commented on Mar 5, 2025

    @c-nv-s

    any update on getting a corrected patch incorporated? this would be very useful for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions