2

Theres a bit documentation out there how to convert ULID to UUID but not so much when you need to convert UUID to ULID.

I'm looking at this UUID / ULID generator / converter https://www.ulidtools.com/

but I'm not quite sure how I would replicate the UUID to ULID conversion, the source is too obfuscated for me to understand.

I'm not sure where to even begin, is this conversion even safe ? will it guarantee a unique conversion ?

user3621898
  • 589
  • 5
  • 24

3 Answers3

2

I've had the same issue and I took a look at ulidtools.com then after digging into its source code for a while I found that it uses this package behind the seen.

import pkg from "id128";
const { Ulid, Uuid4 } = pkg;

const ulid = Ulid.generate();
const ulidToUuid = Uuid4.fromRaw(ulid.toRaw());
const uuidToUlid = Ulid.fromRaw(ulidToUuid.toRaw());

console.table([
  {
    generated_ulid: ulid.toCanonical(),
    converted_to_uuid: ulidToUuid.toCanonical(),
    converted_back_to_ulid: uuidToUlid.toCanonical(),
  },
]);

1

Based on @ImanHosseiniPour answer I came up with the following:

TIMESTAMP + UUID = ULID

import { Ulid, Uuid4 } from "id128";
import { factory, decodeTime } from 'ulid'

const genUlid = factory();

function convertUuidToUlid(
  timestamp: Date, 
  canonicalUuid: string,
): Ulid {
  const uuid = Uuid4.fromCanonical(canonicalUuid);
  const convertedUlid = Ulid.fromRaw(uuid.toRaw())
  const ulidTimestamp = genUlid(timestamp.valueOf()).slice(0, 10)
  const ulidRandom = convertedUlid.toCanonical().slice(10);
  
  return Ulid.fromCanonical(ulidTimestamp + ulidRandom)
}

const timestamp = new Date()
const uuid = 'f0df59ea-bfe2-43a8-98d4-8213348daeb6'
const ulid = convertUuidToUlid(timestamp, uuid)
const originalUuid = Uuid4.fromRaw(ulid.toRaw());

console.table({
  timestamp: timestamp.valueOf(),
  uuid,
  ulid: ulid.toCanonical(),
  decodedTime: decodeTime(ulid.toCanonical()),
  originalUuid: originalUuid.toCanonical(),
});

Keep in mind that reverse engineering the ULID into a UUID will make the two first chunks different from the original since we incorporated the timestamp

Renato Gama
  • 16,431
  • 12
  • 58
  • 92
0

Pure Javascript Method for conversion:

Converting a UUID to a ULID guarantee a unique code. ULIDs are unique 128-bit identifiers that are generated based on a combination of the current timestamp.

function convertUUIDtoULID(uuid) {
  const uuidBinary = uuid.split("-").map((hex) => parseInt(hex, 16));
  return uuidBinary
    .slice(0, 8)
    .map((byte) => byte.toString(32))
    .concat(uuidBinary.slice(8).map((byte) => byte.toString(32)))
    .join("");
}

const uuid = "454391df-b950-42ea-a2c0-92d62c215d67";
const ulid = convertUUIDtoULID(uuid);
console.log(ulid);
  • The function takes in a string of UUID format as an input
  • It splits the UUID string at each "-" character and converts each resulting hexadecimal string into a decimal number using the parseInt() function with base 16.
  • It creates a new array of the first 8 decimal numbers from the UUID and converts each number to a base-32 string using the toString() function with base 32.
  • It concatenates this array with a new array of the remaining decimal numbers from the UUID, also converted to base-32 strings.
  • The resulting array of base-32 strings is joined together into a single string, which is returned as the ULID.
  • The example UUID string is passed into the function and the resulting ULID string is logged to the console.

You can also use [https://www.npmjs.com/package/ulid] for converting UUID to ULID

sanukj
  • 7
  • 2
  • Thank you, i tried the npm package but couldnt get it working ULID.ulid({uuid}) generates different ulid each time its called – user3621898 Dec 13 '22 at 18:06
  • Then you must be passing in a different UUID each time. – Tim Roberts Dec 13 '22 at 20:21
  • This shouldn't be an accepted answer. I tried with `20227cf5-89cf-5215-964b-d65dc7829965` and it outputs `G24V7L12EFKGL15IB6MBN3O56B5` which is an invalid ULID. – Simo Dec 30 '22 at 17:32