Skip to content

Commit 278dd99

Browse files
committed
wip
1 parent 84bbfb2 commit 278dd99

File tree

9 files changed

+470
-7
lines changed

9 files changed

+470
-7
lines changed

.cargo/config.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[target.'cfg(target_os="macos")']
2+
# Postgres symbols won't be available until runtime
3+
rustflags = ["-Clink-arg=-Wl,-undefined,dynamic_lookup"]

.gitignore

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
.DS_Store
2+
.idea/
3+
/target
4+
*.iml
5+
**/*.rs.bk
6+
Cargo.lock

CHANGELOG.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
# CHANGELOG
22

3-
@todo
3+
**v0.1.0:**
4+
- Initial implementation of [the spec](https://github.com/sqids/sqids-spec)

Cargo.toml

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
[package]
2+
name = "pg_sqids"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
crate-type = ["cdylib"]
8+
9+
[features]
10+
default = ["pg13"]
11+
pg11 = ["pgrx/pg11", "pgrx-tests/pg11" ]
12+
pg12 = ["pgrx/pg12", "pgrx-tests/pg12" ]
13+
pg13 = ["pgrx/pg13", "pgrx-tests/pg13" ]
14+
pg14 = ["pgrx/pg14", "pgrx-tests/pg14" ]
15+
pg15 = ["pgrx/pg15", "pgrx-tests/pg15" ]
16+
pg16 = ["pgrx/pg16", "pgrx-tests/pg16" ]
17+
pg_test = []
18+
19+
[dependencies]
20+
pgrx = "=0.11.4"
21+
sqids = "0.4.1"
22+
thiserror = "1.0.61"
23+
24+
[dev-dependencies]
25+
pgrx-tests = "=0.11.4"
26+
27+
[profile.dev]
28+
panic = "unwind"
29+
30+
[profile.release]
31+
panic = "unwind"
32+
opt-level = 3
33+
lto = "fat"
34+
codegen-units = 1
35+
36+
[package.metadata.pgrx]
37+
version = "0.1.0"

README.md

Lines changed: 133 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,142 @@
11
# [Sqids PostgreSQL](https://sqids.org/postgresql)
22

3-
Sqids (pronounced "squids") is a small library that lets you generate YouTube-looking IDs from numbers. It's good for link shortening, fast & URL-safe ID generation and decoding back into numbers for quicker database lookups.
3+
[Sqids](https://sqids.org/postgresql) (*pronounced "squids"*) is a small library that lets you **generate unique IDs from numbers**. It's good for link shortening, fast & URL-safe ID generation and decoding back into numbers for quicker database lookups.
44

5-
## Getting started
5+
Features:
66

7-
@todo
7+
- **Encode multiple numbers** - generate short IDs from one or several non-negative numbers
8+
- **Quick decoding** - easily decode IDs back into numbers
9+
- **Unique IDs** - generate unique IDs by shuffling the alphabet once
10+
- **ID padding** - provide minimum length to make IDs more uniform
11+
- **URL safe** - auto-generated IDs do not contain common profanity
12+
- **Randomized output** - Sequential input provides nonconsecutive IDs
13+
- **Many implementations** - Support for [40+ programming languages](https://sqids.org/)
814

9-
## Examples
15+
## 🧰 Use-cases
1016

11-
@todo
17+
Good for:
1218

13-
## License
19+
- Generating IDs for public URLs (eg: link shortening)
20+
- Generating IDs for internal systems (eg: event tracking)
21+
- Decoding for quicker database lookups (eg: by primary keys)
22+
23+
Not good for:
24+
25+
- Sensitive data (this is not an encryption library)
26+
- User IDs (can be decoded revealing user count)
27+
28+
## 🚀 Getting started
29+
30+
### Debugging
31+
32+
1. [Install Rust](https://www.rust-lang.org/) if you don't have it.
33+
34+
1. Install [pgrx](https://github.com/pgcentralfoundation/pgrx?tab=readme-ov-file#getting-started):
35+
36+
```bash
37+
cargo install --locked cargo-pgrx
38+
```
39+
40+
1. Install dependencies and run psql session:
41+
42+
```bash
43+
cargo build
44+
cargo pgrx run
45+
```
46+
47+
1. Install extension:
48+
49+
```sql
50+
DROP EXTENSION pg_sqids;
51+
CREATE EXTENSION pg_sqids;
52+
```
53+
54+
1. Run sample query:
55+
56+
```sql
57+
SELECT sqids_encode(1, 2, 3); -- 86Rf07
58+
```
59+
60+
### Installing
61+
62+
1. Create the extension:
63+
64+
```bash
65+
cargo pgrx package
66+
```
67+
68+
1. Extension files should be in `target/release`
69+
70+
1. Install the extension:
71+
72+
```sql
73+
DROP EXTENSION pg_sqids;
74+
CREATE EXTENSION pg_sqids;
75+
```
76+
77+
## 👩‍💻 Examples
78+
79+
Simple encode & decode:
80+
81+
```sql
82+
SELECT sqids_encode(1, 2, 3); -- 86Rf07
83+
SELECT sqids_decode('86Rf07'); -- {1,2,3}
84+
```
85+
86+
> **Note**
87+
> 🚧 Because of the algorithm's design, **multiple IDs can decode back into the same sequence of numbers**. If it's important to your design that IDs are canonical, you have to manually re-encode decoded numbers and check that the generated ID matches.
88+
89+
Enforce a *minimum* length for IDs:
90+
91+
```sql
92+
SELECT sqids_encode(10::smallint, 1, 2, 3); -- 86Rf07xd4z
93+
SELECT sqids_decode(10::smallint, '86Rf07xd4z'); -- {1,2,3}
94+
```
95+
96+
Randomize IDs by providing a custom alphabet:
97+
98+
```sql
99+
SELECT sqids_encode('k3G7QAe51FCsPW92uEOyq4Bg6Sp8YzVTmnU0liwDdHXLajZrfxNhobJIRcMvKt', 1, 2, 3); -- XRKUdQ
100+
SELECT sqids_decode('k3G7QAe51FCsPW92uEOyq4Bg6Sp8YzVTmnU0liwDdHXLajZrfxNhobJIRcMvKt', 'XRKUdQ'); -- {1,2,3}
101+
```
102+
103+
Prevent specific words from appearing anywhere in the auto-generated IDs:
104+
105+
```sql
106+
SELECT sqids_encode(array['86Rf07'], 1, 2, 3); -- se8ojk
107+
SELECT sqids_decode(array['86Rf07'], 'se8ojk'); -- {1,2,3}
108+
```
109+
110+
### Using multiple parameters
111+
112+
Alphabet + min length:
113+
114+
```sql
115+
SELECT sqids_encode('k3G7QAe51FCsPW92uEOyq4Bg6Sp8YzVTmnU0liwDdHXLajZrfxNhobJIRcMvKt', 10::smallint, 1, 2, 3); -- XRKUdQVBzg
116+
SELECT sqids_decode('k3G7QAe51FCsPW92uEOyq4Bg6Sp8YzVTmnU0liwDdHXLajZrfxNhobJIRcMvKt', 10::smallint, 'XRKUdQVBzg'); -- {1,2,3}
117+
```
118+
119+
Alphabet + blocklist:
120+
121+
```sql
122+
SELECT sqids_encode('k3G7QAe51FCsPW92uEOyq4Bg6Sp8YzVTmnU0liwDdHXLajZrfxNhobJIRcMvKt', array['XRKUdQ'], 1, 2, 3); -- WyXQfF
123+
SELECT sqids_decode('k3G7QAe51FCsPW92uEOyq4Bg6Sp8YzVTmnU0liwDdHXLajZrfxNhobJIRcMvKt', array['86Rf07'], 'WyXQfF'); -- {1,2,3}
124+
```
125+
126+
Min length + blocklist:
127+
128+
```sql
129+
SELECT sqids_encode(10::smallint, array['86Rf07'], 1, 2, 3); -- se8ojkCQvX
130+
SELECT sqids_decode(10::smallint, array['86Rf07'], 'se8ojkCQvX'); -- {1,2,3}
131+
```
132+
133+
Alphabet + min length + blocklist:
134+
135+
```sql
136+
SELECT sqids_encode('k3G7QAe51FCsPW92uEOyq4Bg6Sp8YzVTmnU0liwDdHXLajZrfxNhobJIRcMvKt', 10::smallint, array['XRKUdQVBzg'], 1, 2, 3); -- WyXQfFQ21T
137+
SELECT sqids_decode('k3G7QAe51FCsPW92uEOyq4Bg6Sp8YzVTmnU0liwDdHXLajZrfxNhobJIRcMvKt', 10::smallint, array['XRKUdQVBzg'], 'WyXQfFQ21T'); -- {1,2,3}
138+
```
139+
140+
## 📝 License
14141

15142
[MIT](LICENSE)

pg_sqids.control

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
comment = 'pg_sqids: Created by pgrx'
2+
default_version = '@CARGO_VERSION@'
3+
module_pathname = '$libdir/pg_sqids'
4+
relocatable = false
5+
superuser = true

src/error.rs

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
use pgrx::prelude::*;
2+
use std::fmt;
3+
use thiserror::Error;
4+
5+
#[derive(Error, Debug, Eq, PartialEq)]
6+
pub enum Error {
7+
#[error("Min length has to be between 0 and 255")]
8+
MinLengthRange,
9+
#[error("Numbers cannot be negative")]
10+
NegativeNumbers,
11+
}
12+
13+
pub enum PgError {
14+
SqidsError(sqids::Error),
15+
CustomError(Error),
16+
}
17+
18+
impl fmt::Display for PgError {
19+
fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result {
20+
match self {
21+
PgError::SqidsError(err) => error!("{}", err),
22+
PgError::CustomError(err) => error!("{}", err),
23+
}
24+
}
25+
}
26+
27+
impl From<sqids::Error> for PgError {
28+
fn from(err: sqids::Error) -> Self {
29+
PgError::SqidsError(err)
30+
}
31+
}

0 commit comments

Comments
 (0)