Skip to content

Commit be313e1

Browse files
committed
feat(sql): implement TypeID specification 0.3.0 in typeid-sql
1 parent 76ee07e commit be313e1

File tree

4 files changed

+115
-40
lines changed

4 files changed

+115
-40
lines changed

typeid/typeid-sql/README.md

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,32 @@ Then you can add in [the operator overload functions for typeid](https://github.
144144
Some users have reported issues with the above operator when using Rails and ActiveRecord – we
145145
recommend removing `COMMUTATOR` from the operator definition if you encounter issues.
146146

147+
## Tests
148+
149+
The tests in [`supabase/tests/`](./supabase/tests/) are using [pgTAP](https://supabase.com/docs/guides/database/extensions/pgtap) as test runner.
150+
151+
You need to install the dependencies for supabase:
152+
```sh
153+
yarn install
154+
```
155+
156+
Afterwards you can start a local supabase instance which will run the tests with the following command:
157+
```sh
158+
yarn supabase start
159+
```
160+
161+
Once started, you can run the tests again with the following command:
162+
```sh
163+
yarn supabase test db
164+
```
165+
166+
You can stop the supabase instance with the following command:
167+
```sh
168+
yarn supabase stop
169+
```
170+
171+
See also [Testing Your Database](https://supabase.com/docs/guides/database/testing) for more details.
172+
147173
## Future work (contributions welcome)
148174

149175
- Include examples not just for Postgres, but for other databases like MySQL as well.

typeid/typeid-sql/sql/03_typeid.sql

Lines changed: 16 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,13 @@
88
create type "typeid" as ("type" varchar(63), "uuid" uuid);
99

1010
-- Function that generates a random typeid of the given type.
11-
-- This depends on the `uuid_generate_v7` function defined in `uuid_v7.sql`.
11+
-- This depends on the `uuid_generate_v7` function defined in `01_uuidv7.sql`.
1212
create or replace function typeid_generate(prefix text)
1313
returns typeid
1414
as $$
1515
begin
16-
if (prefix is null) or not (prefix ~ '^[a-z]{0,63}$') then
17-
raise exception 'typeid prefix must match the regular expression [a-z]{0,63}';
16+
if (prefix is null) or not (prefix ~ '^([a-z]([a-z_]{0,61}[a-z])?)?$') then
17+
raise exception 'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$';
1818
end if;
1919
return (prefix, uuid_generate_v7())::typeid;
2020
end
@@ -27,8 +27,8 @@ create or replace function typeid_generate_text(prefix text)
2727
returns text
2828
as $$
2929
begin
30-
if (prefix is null) or not (prefix ~ '^[a-z]{0,63}$') then
31-
raise exception 'typeid prefix must match the regular expression [a-z]{0,63}';
30+
if (prefix is null) or not (prefix ~ '^([a-z]([a-z_]{0,61}[a-z])?)?$') then
31+
raise exception 'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$';
3232
end if;
3333
return typeid_print((prefix, uuid_generate_v7())::typeid);
3434
end
@@ -73,21 +73,26 @@ as $$
7373
declare
7474
prefix text;
7575
suffix text;
76+
matches text[];
7677
begin
7778
if (typeid_str is null) then
7879
return null;
7980
end if;
8081
if position('_' in typeid_str) = 0 then
8182
return ('', base32_decode(typeid_str))::typeid;
8283
end if;
83-
prefix = split_part(typeid_str, '_', 1);
84-
suffix = split_part(typeid_str, '_', 2);
84+
matches = regexp_match(typeid_str, '^([a-z_]{0,63})_([a-z0-9]{26})$');
85+
if array_length(matches, 1) != 2 then
86+
raise exception 'invalid typeid';
87+
end if;
88+
prefix = matches[1];
89+
suffix = matches[2];
8590
if prefix is null or prefix = '' then
8691
raise exception 'typeid prefix cannot be empty with a delimiter';
8792
end if;
8893
-- prefix must match the regular expression [a-z]{0,63}
89-
if not prefix ~ '^[a-z]{0,63}$' then
90-
raise exception 'typeid prefix must match the regular expression [a-z]{0,63}';
94+
if not prefix ~ '^([a-z]([a-z_]{0,61}[a-z])?)?$' then
95+
raise exception 'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$';
9196
end if;
9297

9398
return (prefix, base32_decode(suffix))::typeid;
@@ -109,8 +114,8 @@ begin
109114
end if;
110115
prefix = (tid).type;
111116
suffix = base32_encode((tid).uuid);
112-
if (prefix is null) or not (prefix ~ '^[a-z]{0,63}$') then
113-
raise exception 'typeid prefix must match the regular expression [a-z]{0,63}';
117+
if (prefix is null) or not (prefix ~ '^([a-z]([a-z_]{0,61}[a-z])?)?$') then
118+
raise exception 'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$';
114119
end if;
115120
if prefix = '' then
116121
return suffix;

typeid/typeid-sql/supabase/tests/03_typed_text.test.sql

Lines changed: 32 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
-- Start transaction and plan the tests.
22
BEGIN;
3-
SELECT plan(7);
3+
SELECT plan(9);
44

55
create table tests (
66
"tid" text CHECK(typeid_check_text(tid, 'generated'))
@@ -17,12 +17,40 @@ SELECT is(
1717
'Generate typeid text with a specific prefix using typeid_generate_text'
1818
);
1919

20+
-- - name: generate-text-underscore
21+
-- typeid: "ge_ne_ra_ted_00000000000000000000000000"
22+
-- description: "Generate a typeid with a specific prefix with multiple underscores using typeid_generate_text"
23+
INSERT INTO tests (tid) VALUES (typeid_generate_text('ge_ne_ra_ted'));
24+
SELECT is(
25+
typeid_check_text((SELECT tid FROM tests), 'ge_ne_ra_ted'),
26+
true,
27+
'Generate typeid text with a specific prefix with multiple underscores using typeid_generate_text'
28+
);
29+
2030
-- - name: generate-text-invalid-prefix
2131
-- typeid: "12345_00000000000000000000000000"
2232
-- description: "Attempt to generate a typeid with an invalid prefix"
2333
SELECT throws_ok(
2434
$$ INSERT INTO tests (tid) VALUES (typeid_generate_text('12345')); $$,
25-
'typeid prefix must match the regular expression [a-z]{0,63}',
35+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
36+
'Generate typeid text with an invalid prefix should throw an error'
37+
);
38+
39+
-- - name: generate-text-invalid-prefix-leading-underscore
40+
-- typeid: "_generated_00000000000000000000000000"
41+
-- description: "Attempt to generate a typeid with an invalid prefix with leading underscore"
42+
SELECT throws_ok(
43+
$$ INSERT INTO tests (tid) VALUES (typeid_generate_text('_generated')); $$,
44+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
45+
'Generate typeid text with an invalid prefix should throw an error'
46+
);
47+
48+
-- - name: generate-text-invalid-prefix-trailing-underscore
49+
-- typeid: "generated__00000000000000000000000000"
50+
-- description: "Attempt to generate a typeid with an invalid prefix with trailing underscore"
51+
SELECT throws_ok(
52+
$$ INSERT INTO tests (tid) VALUES (typeid_generate_text('generated_')); $$,
53+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
2654
'Generate typeid text with an invalid prefix should throw an error'
2755
);
2856

@@ -43,7 +71,7 @@ SELECT is(
4371
-- INSERT INTO tests (tid) VALUES ('12345_00000000000000000000000000');
4472
SELECT throws_ok(
4573
$$ INSERT into tests (tid) VALUES (typeid_parse('12345_00000000000000000000000000')); $$,
46-
'typeid prefix must match the regular expression [a-z]{0,63}',
74+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
4775
'Parse invalid: prefix-underscore'
4876
);
4977

@@ -62,20 +90,10 @@ SELECT is(
6290
-- description: "Attempt to generate a typeid with an invalid prefix"
6391
SELECT throws_ok(
6492
$$ INSERT INTO tests (tid) VALUES (typeid_generate_text('12345')); $$,
65-
'typeid prefix must match the regular expression [a-z]{0,63}',
93+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
6694
'Generate typeid text with an invalid prefix should throw an error'
6795
);
6896

69-
-- - name: check-text-valid
70-
-- typeid: "generated_00000000000000000000000000"
71-
-- description: "Check if a generated typeid text is valid"
72-
INSERT INTO tests (tid) VALUES (typeid_generate_text('generated'));
73-
SELECT is(
74-
typeid_check_text((SELECT tid FROM tests limit 1), 'generated'),
75-
true,
76-
'Check if a generated typeid text is valid using typeid_check_text'
77-
);
78-
7997

8098
-- Finish the tests and clean up.
8199
SELECT * FROM finish();

typeid/typeid-sql/supabase/tests/03_typeid.test.sql

Lines changed: 41 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
-- Start transaction and plan the tests.
22
BEGIN;
3-
SELECT plan(41);
3+
SELECT plan(42);
44

55
create table tests (
66
"tid" typeid
@@ -113,6 +113,26 @@ SELECT is(
113113
'Print valid: valid-alphabet'
114114
);
115115

116+
-- - name: valid-prefix-underscores
117+
-- typeid: "pre_fix_0123456789abcdefghjkmnpqrs"
118+
-- prefix: "pre_fix"
119+
-- uuid: "0110c853-1d09-52d8-d73e-1194e95b5f19"
120+
SELECT is(
121+
typeid_parse('pre_fix_0123456789abcdefghjkmnpqrs'),
122+
('pre_fix', '0110c853-1d09-52d8-d73e-1194e95b5f19')::typeid,
123+
'Parse valid: valid-prefix-underscores'
124+
);
125+
SELECT is(
126+
typeid_print(('pre_fix', '0110c853-1d09-52d8-d73e-1194e95b5f19')),
127+
'pre_fix_0123456789abcdefghjkmnpqrs',
128+
'Print valid: valid-alphabet-underscores'
129+
);
130+
SELECT is(
131+
typeid_print(('pre_____fix', '0110c853-1d09-52d8-d73e-1194e95b5f19')),
132+
'pre_____fix_0123456789abcdefghjkmnpqrs',
133+
'Print valid: valid-alphabet-underscores'
134+
);
135+
116136
-- - name: valid-uuidv7
117137
-- typeid: "prefix_01h455vb4pex5vsknk084sn02q"
118138
-- prefix: "prefix"
@@ -135,13 +155,13 @@ SELECT is(
135155
-- description: "The prefix should be lowercase with no uppercase letters"
136156
SELECT throws_ok(
137157
$$ INSERT into tests (tid) VALUES (typeid_parse('PREFIX_00000000000000000000000000')); $$,
138-
'typeid prefix must match the regular expression [a-z]{0,63}',
158+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
139159
'Parse invalid: prefix-uppercase'
140160
);
141161

142162
SELECT throws_ok(
143163
$$ INSERT into tests (tid) VALUES (typeid_generate('PREFIX')); $$,
144-
'typeid prefix must match the regular expression [a-z]{0,63}',
164+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
145165
'Parse invalid: prefix-uppercase'
146166
);
147167

@@ -150,13 +170,13 @@ SELECT throws_ok(
150170
-- description: "The prefix can't have numbers, it needs to be alphabetic"
151171
SELECT throws_ok(
152172
$$ INSERT into tests (tid) VALUES (typeid_parse('12345_00000000000000000000000000')); $$,
153-
'typeid prefix must match the regular expression [a-z]{0,63}',
173+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
154174
'Parse invalid: prefix-numeric'
155175
);
156176

157177
SELECT throws_ok(
158178
$$ INSERT into tests (tid) VALUES (typeid_generate('12345')); $$,
159-
'typeid prefix must match the regular expression [a-z]{0,63}',
179+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
160180
'Parse invalid: prefix-numeric'
161181
);
162182

@@ -165,13 +185,13 @@ SELECT throws_ok(
165185
-- description: "The prefix can't have symbols, it needs to be alphabetic"
166186
SELECT throws_ok(
167187
$$ INSERT into tests (tid) VALUES (typeid_parse('pre.fix_00000000000000000000000000')); $$,
168-
'typeid prefix must match the regular expression [a-z]{0,63}',
188+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
169189
'Parse invalid: prefix-period'
170190
);
171191

172192
SELECT throws_ok(
173193
$$ INSERT into tests (tid) VALUES (typeid_generate('pre.fix')); $$,
174-
'typeid prefix must match the regular expression [a-z]{0,63}',
194+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
175195
'Parse invalid: prefix-period'
176196
);
177197

@@ -185,8 +205,14 @@ SELECT throws_ok(
185205
);
186206

187207
SELECT throws_ok(
188-
$$ INSERT into tests (tid) VALUES (typeid_generate('pre_fix')); $$,
189-
'typeid prefix must match the regular expression [a-z]{0,63}',
208+
$$ INSERT into tests (tid) VALUES (typeid_generate('_prefix')); $$,
209+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
210+
'Parse invalid: prefix-underscore'
211+
);
212+
213+
SELECT throws_ok(
214+
$$ INSERT into tests (tid) VALUES (typeid_generate('prefix_')); $$,
215+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
190216
'Parse invalid: prefix-underscore'
191217
);
192218

@@ -195,13 +221,13 @@ SELECT throws_ok(
195221
-- description: "The prefix can only have ascii letters"
196222
SELECT throws_ok(
197223
$$ INSERT into tests (tid) VALUES (typeid_parse('préfix_00000000000000000000000000')); $$,
198-
'typeid prefix must match the regular expression [a-z]{0,63}',
224+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
199225
'Parse invalid: prefix-non-ascii'
200226
);
201227

202228
SELECT throws_ok(
203229
$$ INSERT into tests (tid) VALUES (typeid_generate('préfix')); $$,
204-
'typeid prefix must match the regular expression [a-z]{0,63}',
230+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
205231
'Parse invalid: prefix-non-ascii'
206232
);
207233

@@ -210,13 +236,13 @@ SELECT throws_ok(
210236
-- description: "The prefix can't have any spaces"
211237
SELECT throws_ok(
212238
$$ INSERT into tests (tid) VALUES (typeid_parse(' prefix_00000000000000000000000000')); $$,
213-
'typeid prefix must match the regular expression [a-z]{0,63}',
239+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
214240
'Parse invalid: prefix-spaces'
215241
);
216242

217243
SELECT throws_ok(
218244
$$ INSERT into tests (tid) VALUES (typeid_generate(' prefix')); $$,
219-
'typeid prefix must match the regular expression [a-z]{0,63}',
245+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
220246
'Parse invalid: prefix-spaces'
221247
);
222248

@@ -226,13 +252,13 @@ SELECT throws_ok(
226252
-- description: "The prefix can't be 64 characters, it needs to be 63 characters or less"
227253
SELECT throws_ok(
228254
$$ INSERT into tests (tid) VALUES (typeid_parse('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl_00000000000000000000000000')); $$,
229-
'typeid prefix must match the regular expression [a-z]{0,63}',
255+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
230256
'Parse invalid: prefix-64-chars'
231257
);
232258

233259
SELECT throws_ok(
234260
$$ INSERT into tests (tid) VALUES (typeid_generate('abcdefghijklmnopqrstuvwxyzabcdefghijklmnopqrstuvwxyzabcdefghijkl')); $$,
235-
'typeid prefix must match the regular expression [a-z]{0,63}',
261+
'typeid prefix must match the regular expression ^([a-z]([a-z_]{0,61}[a-z])?)?$',
236262
'Parse invalid: prefix-64-chars'
237263
);
238264

0 commit comments

Comments
 (0)