Skip to content

Commit f17c55b

Browse files
committed
remove youid
1 parent 1983263 commit f17c55b

7 files changed

Lines changed: 127 additions & 30 deletions

File tree

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55

66
[TypeID (v0.3)](https://github.com/jetify-com/typeid) implementation in Gleam.
77

8+
Works on Erlang and Javascript.
9+
810
## Installation
911

1012
```sh
@@ -60,3 +62,5 @@ Further documentation can be found at <https://hexdocs.pm/typeid_gleam>.
6062
```sh
6163
gleam test # Run the tests
6264
```
65+
66+
Many thanks to lpil for the [youid](https://github.com/lpil/youid) UUID implementation

gleam.toml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,12 @@ repository = { type = "github", user = "okkdev", repo = "typeid_gleam" }
99
# For a full reference of all the available options, you can have a look at
1010
# https://gleam.run/writing-gleam/gleam-toml/.
1111

12+
internal_modules = ["typeid/uuid"]
13+
1214
[dependencies]
1315
gleam_stdlib = ">= 0.44.0 and < 2.0.0"
1416
gleam_regexp = ">= 1.1.1 and < 2.0.0"
1517
gleam_time = ">= 1.2.0 and < 2.0.0"
16-
youid = ">= 1.5.1 and < 2.0.0"
1718

1819
[dev-dependencies]
1920
gleeunit = ">= 1.0.0 and < 2.0.0"

manifest.toml

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,11 @@
22
# You typically do not need to edit this file
33

44
packages = [
5-
{ name = "gleam_crypto", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_crypto", source = "hex", outer_checksum = "50774BAFFF1144E7872814C566C5D653D83A3EBF23ACC3156B757A1B6819086E" },
65
{ name = "gleam_json", version = "3.0.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_json", source = "hex", outer_checksum = "5BA154440B22D9800955B1AB854282FA37B97F30F409D76B0824D0A60C934188" },
76
{ name = "gleam_regexp", version = "1.1.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_regexp", source = "hex", outer_checksum = "9C215C6CA84A5B35BB934A9B61A9A306EC743153BE2B0425A0D032E477B062A9" },
87
{ name = "gleam_stdlib", version = "0.60.0", build_tools = ["gleam"], requirements = [], otp_app = "gleam_stdlib", source = "hex", outer_checksum = "621D600BB134BC239CB2537630899817B1A42E60A1D46C5E9F3FAE39F88C800B" },
98
{ name = "gleam_time", version = "1.2.0", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleam_time", source = "hex", outer_checksum = "D71F1AFF7FEB534FF55E5DC58E534E9201BA75A444619788A2E4DEA4EBD87D16" },
109
{ name = "gleeunit", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_stdlib"], otp_app = "gleeunit", source = "hex", outer_checksum = "D33B7736CF0766ED3065F64A1EBB351E72B2E8DE39BAFC8ADA0E35E92A6A934F" },
11-
{ name = "youid", version = "1.5.1", build_tools = ["gleam"], requirements = ["gleam_crypto", "gleam_stdlib", "gleam_time"], otp_app = "youid", source = "hex", outer_checksum = "580E909FD704DB16416D5CB080618EDC2DA0F1BE4D21B490C0683335E3FFC5AF" },
1210
]
1311

1412
[requirements]
@@ -17,4 +15,3 @@ gleam_regexp = { version = ">= 1.1.1 and < 2.0.0" }
1715
gleam_stdlib = { version = ">= 0.44.0 and < 2.0.0" }
1816
gleam_time = { version = ">= 1.2.0 and < 2.0.0" }
1917
gleeunit = { version = ">= 1.0.0 and < 2.0.0" }
20-
youid = { version = ">= 1.5.1 and < 2.0.0" }

src/typeid.ffi.mjs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { BitArray } from "./gleam.mjs"
2+
3+
export function strongRandomBytes(n) {
4+
const array = new Uint8Array(n)
5+
globalThis.crypto.getRandomValues(array)
6+
return new BitArray(array)
7+
}

src/typeid.gleam

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import gleam/list
44
import gleam/regexp
55
import gleam/result
66
import gleam/string
7-
import youid/uuid
7+
import typeid/uuid
88

99
const default_typeid = TypeId(prefix: "", suffix: "")
1010

@@ -27,7 +27,7 @@ pub opaque type TypeId(a) {
2727
/// let assert Ok(id) = new("user")
2828
/// ```
2929
pub fn new(prefix prefix: String) -> Result(TypeId(a), String) {
30-
from_uuid(prefix, uuid.v7_string())
30+
from_uuid(prefix, uuid.v7())
3131
}
3232

3333
/// Generate a TypeID using the supplied prefix and UUID.
@@ -46,9 +46,7 @@ pub fn from_uuid(
4646
True -> {
4747
case uuid.from_string(uuid) {
4848
Ok(uuid) -> {
49-
let suffix =
50-
uuid.to_bit_array(uuid)
51-
|> encode_base32
49+
let suffix = encode_base32(uuid)
5250

5351
TypeId(prefix:, suffix:)
5452
|> Ok
@@ -123,9 +121,7 @@ pub fn decode(prefix kind: String) -> decode.Decoder(TypeId(a)) {
123121
/// ```
124122
pub fn uuid(typeid: TypeId(a)) -> String {
125123
let assert Ok(bits) = decode_base32(typeid.suffix)
126-
let assert Ok(uuid) = uuid.from_bit_array(bits)
127-
128-
uuid.to_string(uuid)
124+
uuid.to_string(bits)
129125
}
130126

131127
/// Returns the prefix of the TypeId.

src/typeid/uuid.gleam

Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
import gleam/int
2+
import gleam/string
3+
import gleam/time/timestamp
4+
5+
@external(erlang, "crypto", "strong_rand_bytes")
6+
@external(javascript, "../typeid.ffi.mjs", "strongRandomBytes")
7+
fn strong_random_bytes(a: Int) -> BitArray
8+
9+
pub fn v7() -> String {
10+
let #(sec, ns) =
11+
timestamp.system_time()
12+
|> timestamp.to_unix_seconds_and_nanoseconds()
13+
let stamp = sec * 1000 + ns / 1_000_000
14+
let assert <<a:size(12), b:size(62), _:size(6)>> = strong_random_bytes(10)
15+
let value = <<stamp:48, 7:4, a:12, 2:2, b:62>>
16+
17+
to_string(value)
18+
}
19+
20+
pub fn to_string(uuid: BitArray) -> String {
21+
do_to_string(uuid, 0, "")
22+
}
23+
24+
pub fn from_string(str: String) -> Result(BitArray, Nil) {
25+
do_to_bit_array(str, 0, <<>>)
26+
}
27+
28+
fn do_to_string(ints: BitArray, position: Int, acc: String) -> String {
29+
case position {
30+
8 | 13 | 18 | 23 -> do_to_string(ints, position + 1, acc <> "-")
31+
_ ->
32+
case ints {
33+
<<i:size(4), rest:bits>> -> {
34+
let string = int.to_base16(i) |> string.lowercase
35+
do_to_string(rest, position + 1, acc <> string)
36+
}
37+
_ -> acc
38+
}
39+
}
40+
}
41+
42+
fn do_to_bit_array(
43+
str: String,
44+
index: Int,
45+
acc: BitArray,
46+
) -> Result(BitArray, Nil) {
47+
case string.pop_grapheme(str) {
48+
Error(Nil) if index == 32 -> Ok(acc)
49+
Ok(#("-", rest)) if index < 32 -> do_to_bit_array(rest, index, acc)
50+
Ok(#(c, rest)) if index < 32 ->
51+
case hex_to_int(c) {
52+
Ok(i) -> do_to_bit_array(rest, index + 1, <<acc:bits, i:size(4)>>)
53+
Error(_) -> Error(Nil)
54+
}
55+
_ -> Error(Nil)
56+
}
57+
}
58+
59+
fn hex_to_int(c: String) -> Result(Int, Nil) {
60+
let i = case c {
61+
"0" -> 0
62+
"1" -> 1
63+
"2" -> 2
64+
"3" -> 3
65+
"4" -> 4
66+
"5" -> 5
67+
"6" -> 6
68+
"7" -> 7
69+
"8" -> 8
70+
"9" -> 9
71+
"a" | "A" -> 10
72+
"b" | "B" -> 11
73+
"c" | "C" -> 12
74+
"d" | "D" -> 13
75+
"e" | "E" -> 14
76+
"f" | "F" -> 15
77+
_ -> 16
78+
}
79+
case i {
80+
16 -> Error(Nil)
81+
x -> Ok(x)
82+
}
83+
}

test/typeid_gleam_test.gleam

Lines changed: 27 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -81,89 +81,98 @@ pub fn random_test() {
8181
// Valid tests
8282

8383
pub fn nil_test() {
84-
let assert Ok(id) =
85-
typeid.from_uuid("", "00000000-0000-0000-0000-000000000000")
84+
let uuid = "00000000-0000-0000-0000-000000000000"
85+
let assert Ok(id) = typeid.from_uuid("", uuid)
8686
assert "" == typeid.prefix(id)
87+
assert uuid == typeid.uuid(id)
8788
assert "00000000000000000000000000" == typeid.suffix(id)
8889
assert "00000000000000000000000000" == typeid.to_string(id)
8990

9091
assert Ok(id) == typeid.parse("00000000000000000000000000")
9192
}
9293

9394
pub fn one_test() {
94-
let assert Ok(id) =
95-
typeid.from_uuid("", "00000000-0000-0000-0000-000000000001")
95+
let uuid = "00000000-0000-0000-0000-000000000001"
96+
let assert Ok(id) = typeid.from_uuid("", uuid)
9697
assert "" == typeid.prefix(id)
98+
assert uuid == typeid.uuid(id)
9799
assert "00000000000000000000000001" == typeid.suffix(id)
98100
assert "00000000000000000000000001" == typeid.to_string(id)
99101

100102
assert Ok(id) == typeid.parse("00000000000000000000000001")
101103
}
102104

103105
pub fn ten_test() {
104-
let assert Ok(id) =
105-
typeid.from_uuid("", "00000000-0000-0000-0000-00000000000a")
106+
let uuid = "00000000-0000-0000-0000-00000000000a"
107+
let assert Ok(id) = typeid.from_uuid("", uuid)
106108
assert "" == typeid.prefix(id)
109+
assert uuid == typeid.uuid(id)
107110
assert "0000000000000000000000000a" == typeid.suffix(id)
108111
assert "0000000000000000000000000a" == typeid.to_string(id)
109112

110113
assert Ok(id) == typeid.parse("0000000000000000000000000a")
111114
}
112115

113116
pub fn sixteen_test() {
114-
let assert Ok(id) =
115-
typeid.from_uuid("", "00000000-0000-0000-0000-000000000010")
117+
let uuid = "00000000-0000-0000-0000-000000000010"
118+
let assert Ok(id) = typeid.from_uuid("", uuid)
116119
assert "" == typeid.prefix(id)
120+
assert uuid == typeid.uuid(id)
117121
assert "0000000000000000000000000g" == typeid.suffix(id)
118122
assert "0000000000000000000000000g" == typeid.to_string(id)
119123

120124
assert Ok(id) == typeid.parse("0000000000000000000000000g")
121125
}
122126

123127
pub fn thirty_two_test() {
124-
let assert Ok(id) =
125-
typeid.from_uuid("", "00000000-0000-0000-0000-000000000020")
128+
let uuid = "00000000-0000-0000-0000-000000000020"
129+
let assert Ok(id) = typeid.from_uuid("", uuid)
126130
assert "" == typeid.prefix(id)
131+
assert uuid == typeid.uuid(id)
127132
assert "00000000000000000000000010" == typeid.suffix(id)
128133
assert "00000000000000000000000010" == typeid.to_string(id)
129134

130135
assert Ok(id) == typeid.parse("00000000000000000000000010")
131136
}
132137

133138
pub fn max_valid_test() {
134-
let assert Ok(id) =
135-
typeid.from_uuid("", "ffffffff-ffff-ffff-ffff-ffffffffffff")
139+
let uuid = "ffffffff-ffff-ffff-ffff-ffffffffffff"
140+
let assert Ok(id) = typeid.from_uuid("", uuid)
136141
assert "" == typeid.prefix(id)
142+
assert uuid == typeid.uuid(id)
137143
assert "7zzzzzzzzzzzzzzzzzzzzzzzzz" == typeid.suffix(id)
138144
assert "7zzzzzzzzzzzzzzzzzzzzzzzzz" == typeid.to_string(id)
139145

140146
assert Ok(id) == typeid.parse("7zzzzzzzzzzzzzzzzzzzzzzzzz")
141147
}
142148

143149
pub fn valid_alphabet_test() {
144-
let assert Ok(id) =
145-
typeid.from_uuid("prefix", "0110c853-1d09-52d8-d73e-1194e95b5f19")
150+
let uuid = "0110c853-1d09-52d8-d73e-1194e95b5f19"
151+
let assert Ok(id) = typeid.from_uuid("prefix", uuid)
146152
assert "prefix" == typeid.prefix(id)
153+
assert uuid == typeid.uuid(id)
147154
assert "0123456789abcdefghjkmnpqrs" == typeid.suffix(id)
148155
assert "prefix_0123456789abcdefghjkmnpqrs" == typeid.to_string(id)
149156

150157
assert Ok(id) == typeid.parse("prefix_0123456789abcdefghjkmnpqrs")
151158
}
152159

153160
pub fn valid_uuidv7_test() {
154-
let assert Ok(id) =
155-
typeid.from_uuid("prefix", "01890a5d-ac96-774b-bcce-b302099a8057")
161+
let uuid = "01890a5d-ac96-774b-bcce-b302099a8057"
162+
let assert Ok(id) = typeid.from_uuid("prefix", uuid)
156163
assert "prefix" == typeid.prefix(id)
164+
assert uuid == typeid.uuid(id)
157165
assert "01h455vb4pex5vsknk084sn02q" == typeid.suffix(id)
158166
assert "prefix_01h455vb4pex5vsknk084sn02q" == typeid.to_string(id)
159167

160168
assert Ok(id) == typeid.parse("prefix_01h455vb4pex5vsknk084sn02q")
161169
}
162170

163171
pub fn prefix_underscore_test() {
164-
let assert Ok(id) =
165-
typeid.from_uuid("pre_fix", "00000000-0000-0000-0000-000000000000")
172+
let uuid = "00000000-0000-0000-0000-000000000000"
173+
let assert Ok(id) = typeid.from_uuid("pre_fix", uuid)
166174
assert "pre_fix" == typeid.prefix(id)
175+
assert uuid == typeid.uuid(id)
167176
assert "00000000000000000000000000" == typeid.suffix(id)
168177
assert "pre_fix_00000000000000000000000000" == typeid.to_string(id)
169178

0 commit comments

Comments
 (0)