Skip to content

Commit

Permalink
feat: add uuidv7
Browse files Browse the repository at this point in the history
  • Loading branch information
coolaj86 committed Oct 15, 2024
1 parent aa3f468 commit 27d881e
Show file tree
Hide file tree
Showing 4 changed files with 233 additions and 0 deletions.
115 changes: 115 additions & 0 deletions uuidv7/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
---
title: uuidv7
homepage: https://github.com/coolaj86/uuidv7
tagline: |
uuidv7: generate UUID v7 strings, command line edition
---

To update or switch versions, run `webi uuidv7@stable`.

## Cheat Sheet

> `uuidv7` exists because _somebody_ was tired of searching "UUID v7 generator"
> just to get a test value for a little ditty now and then. Though, the time
> spent creating it will probably never be recouped...
```sh
uuidv7
```

```text
01928d73-d8ed-7211-a314-7081d763271d
```

## Table of Contents

- Files
- Generating Many `UUIDv7`s
- Roll Your Own UUID v7 Generator
- Understanding the UUID v7 spec
- UUID v7, by the String
- UUID v7, by the Byte

### Files

These are the files / directories that are created and/or modified with this
install:

```text
~/.config/envman/PATH.env
~/.local/bin/uuidv7
~/.local/opt/uuidv7/
```

### How to Generate Many v7 UUIDs at Once

```sh
uuidv7 ; uuidv7 ; uuidv7
```

```text
01928d74-3ff7-796f-8417-0fee6da50a5a
01928d74-3ff9-73f7-8ce1-71e741cfa56f
01928d74-3ffb-7e06-abe9-3fe20e5cb5f2
```

### How could I roll my own UUID v7 generator?

It's not that hard. There are examples in many languages here:

- https://github.com/coolaj86/uuidv7

See the simplified spec examples below.

### What's the UUID v7 spec, in simple terms?

See the explanation here:

- https://github.com/coolaj86/uuidv7

A snapshot of that is copied here, for convenience:

### UUID v7, by the Characters

There are 36 characters total: 32 hex (`0123456789abcdef`) + 4 dashes (`-`)

```text
8 time 4 time 1v + 3ra ½v + 3½rb 12 random b
019212d3 - 87f4 - 7d25 - 902e - b8d39fe07f08
```

- 8ch hex time high
- `-`
- 4ch hex time low
- `-`
- 4ch hex version + "random a"
- 1ch hex version: `7`
- 3ch hex "random a"
- `-`
- 4ch hex variant + "random b"
- 1ch hex version: `8`, `9`, `a`, `b`
- 3ch hex "random b"
- `-`
- 12ch hex randam a
- 4ch hex random a
- 8ch hex random a

### UUID v7, by the Bits

There are 128 bits total: \
48 time and 80 random, with 4 version and 2 variant bits substituted

```text
48 time 4ver, 12ra 2var, 14rb random b
019212d3-87f4 - 7d25 - 902e - b8d39fe07f08
```

- 48 bits of timestamp
- 32-bit high (minutes to years)
- 16-bit low (seconds & milliseconds)
- 16 bits of version + random
- 4-bit version (`0b0111`)
- 12-bit random
- 64-bits variant + random
- 2-bit variant (`0b10`)
- 62-bit random
55 changes: 55 additions & 0 deletions uuidv7/install.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#!/usr/bin/env pwsh

##################
# Install uuidv7 #
##################

# Every package should define these variables
$pkg_cmd_name = "uuidv7"

$pkg_dst_cmd = "$Env:USERPROFILE\.local\bin\uuidv7.exe"
$pkg_dst = "$pkg_dst_cmd"

$pkg_src_cmd = "$Env:USERPROFILE\.local\opt\uuidv7-v$Env:WEBI_VERSION\bin\uuidv7.exe"
$pkg_src_bin = "$Env:USERPROFILE\.local\opt\uuidv7-v$Env:WEBI_VERSION\bin"
$pkg_src_dir = "$Env:USERPROFILE\.local\opt\uuidv7-v$Env:WEBI_VERSION"
$pkg_src = "$pkg_src_cmd"

New-Item "$Env:USERPROFILE\Downloads\webi" -ItemType Directory -Force | Out-Null
$pkg_download = "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE"

# Fetch archive
IF (!(Test-Path -Path "$Env:USERPROFILE\Downloads\webi\$Env:WEBI_PKG_FILE")) {
Write-Output "Downloading uuidv7 from $Env:WEBI_PKG_URL to $pkg_download"
& curl.exe -A "$Env:WEBI_UA" -fsSL "$Env:WEBI_PKG_URL" -o "$pkg_download.part"
& Move-Item "$pkg_download.part" "$pkg_download"
}

IF (!(Test-Path -Path "$pkg_src_cmd")) {
Write-Output "Installing uuidv7"

# TODO: create package-specific temp directory
# Enter tmp
Push-Location .local\tmp

# Remove any leftover tmp cruft
Remove-Item -Path ".\uuidv7-v*" -Recurse -ErrorAction Ignore
Remove-Item -Path ".\uuidv7.exe" -Recurse -ErrorAction Ignore

# Unpack archive file into this temporary directory
# Windows BSD-tar handles zip. Imagine that.
Write-Output "Unpacking $pkg_download"
& tar xf "$pkg_download"

# Settle unpacked archive into place
Write-Output "Install Location: $pkg_src_cmd"
New-Item "$pkg_src_bin" -ItemType Directory -Force | Out-Null
Move-Item -Path ".\uuidv7.exe" -Destination "$pkg_src_bin"

# Exit tmp
Pop-Location
}

Write-Output "Copying into '$pkg_dst_cmd' from '$pkg_src_cmd'"
Remove-Item -Path "$pkg_dst_cmd" -Recurse -ErrorAction Ignore | Out-Null
Copy-Item -Path "$pkg_src" -Destination "$pkg_dst" -Recurse
40 changes: 40 additions & 0 deletions uuidv7/install.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#!/bin/sh
# shellcheck disable=SC2034

__init_uuidv7() {
set -e
set -u

##################
# Install uuidv7 #
##################

# Every package should define these 6 variables
pkg_cmd_name="uuidv7"

pkg_dst_cmd="${HOME}/.local/bin/uuidv7"
pkg_dst="${pkg_dst_cmd}"

pkg_src_cmd="${HOME}/.local/opt/uuidv7-v${WEBI_VERSION}/bin/uuidv7"
pkg_src_dir="${HOME}/.local/opt/uuidv7-v${WEBI_VERSION}"
pkg_src="${pkg_src_cmd}"

pkg_install() {
# $HOME/.local/opt/uuidv7-v1.0.1/bin
mkdir -p "$(dirname "${pkg_src_cmd}")"

# mv ./uuidv7* "$HOME/.local/opt/uuidv7-v1.0.1/bin/uuidv7"
mv ./"${pkg_cmd_name}"* "${pkg_src_cmd}"

# chmod a+x "$HOME/.local/opt/uuidv7-v1.0.1/bin/uuidv7"
chmod a+x "${pkg_src_cmd}"
}

pkg_get_current_version() {
# TODO https://github.com/coolaj86/uuidv7/issues/10
echo '1.0.1'
}

}

__init_uuidv7
23 changes: 23 additions & 0 deletions uuidv7/releases.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
'use strict';

let Releases = module.exports;

let GitHub = require('../_common/github.js');
let owner = 'coolaj86';
let repo = 'uuidv7';

Releases.latest = async function () {
let all = await GitHub.getDistributables(null, owner, repo);
return all;
};

if (module === require.main) {
(async function () {
let normalize = require('../_webi/normalize.js');
let all = await Releases.latest();
all = normalize(all);
// just select the first 5 for demonstration
all.releases = all.releases.slice(0, 5);
console.info(JSON.stringify(all, null, 2));
})();
}

0 comments on commit 27d881e

Please sign in to comment.