sqlite_crypto 1.0.3 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +21 -0
- data/README.md +132 -162
- data/lib/sqlite_crypto/configuration.rb +12 -0
- data/lib/sqlite_crypto/generators/install_generator.rb +37 -0
- data/lib/sqlite_crypto/generators/templates/initializer.rb.tt +13 -0
- data/lib/sqlite_crypto/generators/uuid.rb +45 -0
- data/lib/sqlite_crypto/model_extensions.rb +1 -1
- data/lib/sqlite_crypto/version.rb +1 -1
- data/lib/sqlite_crypto.rb +17 -0
- metadata +5 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 628653b7be79d3206b90f05b059a29c2d38912101019bd70355804859e4f9c0a
|
|
4
|
+
data.tar.gz: dfd43d1ec8f3b34e1326923ca3da3e3137c9f78a3ebe54916726753e47d7e1fc
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 17bdceabe86c7d75a54013a330f9dde6017bb80373e70242831d7fed8880ad7a5c46196fbbf0c9d5b54443a839d359dd1a7fbac690e099e29c13f49e7c2fa548
|
|
7
|
+
data.tar.gz: 8c67565b5f8644e6d42d1a15e3347ad40006e8c2631222d9d3878697647e4e1c0f7e91f05905528941da569629c1dd0be39eaf3484702b2ae0871fdd93c07f1a
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,27 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [2.0.0] - 2026-01-08
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **UUIDv7 Support**: Time-sortable UUIDs with better database index performance
|
|
12
|
+
- New configuration option: `config.uuid_version = :v7` (default) or `:v4`
|
|
13
|
+
- Run `rails generate sqlite_crypto:install` to create initializer
|
|
14
|
+
- UUIDv7 requires Ruby 3.3+ (graceful error on older versions)
|
|
15
|
+
- `generates_uuid` now respects the configured version
|
|
16
|
+
- **Configuration System**: `SqliteCrypto.configure` block for gem settings
|
|
17
|
+
- **Install Generator**: `rails generate sqlite_crypto:install` creates initializer
|
|
18
|
+
- **Version Detection**: `SqliteCrypto::Generators::Uuid.v7_available?` helper
|
|
19
|
+
|
|
20
|
+
### Changed
|
|
21
|
+
- **Default UUID version changed to v7** for new projects (better performance)
|
|
22
|
+
- `generates_uuid` now uses centralized generator instead of direct `SecureRandom.uuid`
|
|
23
|
+
|
|
24
|
+
### Notes
|
|
25
|
+
- **Ruby 3.1/3.2 users**: Set `config.uuid_version = :v4` in initializer
|
|
26
|
+
- No schema changes required - UUIDv4 and v7 are storage-compatible
|
|
27
|
+
- Existing v4 UUIDs work alongside new v7 UUIDs in same table
|
|
28
|
+
|
|
8
29
|
## [1.0.3] - 2025-12-30
|
|
9
30
|
|
|
10
31
|
### Added
|
data/README.md
CHANGED
|
@@ -1,75 +1,86 @@
|
|
|
1
|
-
# SQLite
|
|
1
|
+
# SQLite Crypto
|
|
2
2
|
|
|
3
|
-
[](https://github.com/bart-oz/sqlite_crypto/releases)
|
|
4
4
|
[](LICENSE.txt)
|
|
5
|
+
[](https://github.com/bart-oz/sqlite_crypto)
|
|
5
6
|
[](https://github.com/bart-oz/sqlite_crypto/actions)
|
|
6
|
-
[](https://github.com/bart-oz/sqlite_crypto/actions)
|
|
7
8
|
[](https://github.com/bart-oz/sqlite_crypto)
|
|
8
9
|
|
|
9
|
-
|
|
10
|
+
**Drop-in UUID and ULID primary keys for Rails + SQLite3**
|
|
10
11
|
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
ULID: 01ARZ3NDEKTSV4RRFFQ69G5FAV (time-sortable, 26 chars)
|
|
12
|
+
```ruby
|
|
13
|
+
# Just use :uuid or :ulid instead of default integer IDs
|
|
14
|
+
create_table :users, id: :uuid do |t|
|
|
15
|
+
t.string :email
|
|
16
|
+
end
|
|
17
17
|
```
|
|
18
18
|
|
|
19
|
-
##
|
|
19
|
+
## What You Get
|
|
20
|
+
|
|
21
|
+
✅ **UUID primary keys** (v4 random or v7 time-sortable)<br/>
|
|
22
|
+
✅ **ULID primary keys** (time-sortable, 26 characters)<br/>
|
|
23
|
+
✅ **Automatic foreign key detection** - `t.references` just works<br/>
|
|
24
|
+
✅ **Model generators** - `generates_uuid :token`<br/>
|
|
25
|
+
✅ **Clean schema.rb** - No verbose type definitions<br/>
|
|
26
|
+
✅ **Zero dependencies** - Uses Ruby's built-in SecureRandom<br/>
|
|
27
|
+
|
|
28
|
+
## Quick Start
|
|
29
|
+
|
|
30
|
+
```bash
|
|
31
|
+
bundle add sqlite_crypto
|
|
32
|
+
rails generate sqlite_crypto:install
|
|
33
|
+
```
|
|
20
34
|
|
|
21
|
-
|
|
22
|
-
|---|-------------|----------|----------|
|
|
23
|
-
| **Performance** | Baseline | +2-5% slower | +5-10% slower |
|
|
24
|
-
| **Storage** | 8 bytes | 36 bytes (4.5x) | 26 bytes (3.2x) |
|
|
25
|
-
| **Security** | Guessable | Random | Random |
|
|
26
|
-
| **Collisions** | ⚠️ High in distributed systems | Virtually impossible | Virtually impossible |
|
|
27
|
-
| **Sortable** | Sequential | Random | Time-based |
|
|
28
|
-
| **Distributed** | Needs coordination | Generate anywhere | Generate anywhere |
|
|
35
|
+
## ID Type Comparison
|
|
29
36
|
|
|
30
|
-
|
|
37
|
+
| Type | Format | Performance | Use Case |
|
|
38
|
+
|------|--------|-------------|----------|
|
|
39
|
+
| **Integer** | `1, 2, 3...` | Baseline | Simple apps, no distribution |
|
|
40
|
+
| **UUIDv7** | `018d3f91-...` (36 chars) | ~1-3% slower inserts | ⭐ **Recommended** - Time-sortable + fast |
|
|
41
|
+
| **UUIDv4** | `550e8400-e29b-...` (36 chars) | ~2-5% slower inserts | Random IDs, legacy compatibility |
|
|
42
|
+
| **ULID** | `01ARZ3NDEK...` (26 chars) | ~3-7% slower inserts | Time-sortable, compact format |
|
|
31
43
|
|
|
32
|
-
|
|
44
|
+
### Why UUIDv7 is Recommended
|
|
33
45
|
|
|
34
|
-
|
|
35
|
-
|--------------|-----------|-----------|-----------|-----------|
|
|
36
|
-
| 3.1 | ✅ | ✅ | ❌ | ❌ |
|
|
37
|
-
| 3.2 | ✅ | ✅ | ✅ | ✅ |
|
|
38
|
-
| 3.3 | ✅ | ✅ | ✅ | ✅ |
|
|
39
|
-
| 3.4 | ✅ | ✅ | ✅ | ✅ |
|
|
40
|
-
| 4.0 | ✅ | ✅ | ✅ | ✅ |
|
|
46
|
+
UUIDv7 embeds a timestamp in the first 48 bits, making IDs naturally sortable by creation time:
|
|
41
47
|
|
|
42
|
-
|
|
48
|
+
```
|
|
49
|
+
UUIDv7: 018d3f91-8f4a-7000-9e7b-4a5c8d2e1f3a ← Time-based (inserts cluster at end)
|
|
50
|
+
UUIDv4: 6ba7b810-9dad-11d1-80b4-00c04fd430c8 ← Random (causes index fragmentation)
|
|
51
|
+
```
|
|
43
52
|
|
|
44
|
-
**
|
|
53
|
+
**Performance Impact:**
|
|
54
|
+
- New records insert at the **end of B-tree index** (not random positions)
|
|
55
|
+
- Reduces page splits and fragmentation
|
|
56
|
+
- ~40% faster index writes vs UUIDv4 at scale (10k+ records)
|
|
45
57
|
|
|
46
|
-
|
|
58
|
+
**Requirements:** Ruby 3.3+ (falls back to v4 on older versions)
|
|
47
59
|
|
|
48
|
-
|
|
49
|
-
* ULID primary keys with time-sortable validation
|
|
50
|
-
* Migration DSL helpers (`t.uuid`, `t.ulid`)
|
|
51
|
-
* Automatic foreign key type detection
|
|
52
|
-
* Model extensions for UUID/ULID generation
|
|
53
|
-
* Clean schema.rb output
|
|
54
|
-
* Zero configuration required
|
|
60
|
+
## Configuration
|
|
55
61
|
|
|
56
|
-
|
|
62
|
+
### Choose UUID Version (v4 or v7)
|
|
57
63
|
|
|
58
|
-
|
|
64
|
+
After running `rails generate sqlite_crypto:install`:
|
|
59
65
|
|
|
60
66
|
```ruby
|
|
61
|
-
|
|
67
|
+
# config/initializers/sqlite_crypto.rb
|
|
68
|
+
SqliteCrypto.configure do |config|
|
|
69
|
+
config.uuid_version = :v7 # Recommended (requires Ruby 3.3+)
|
|
70
|
+
# config.uuid_version = :v4 # Use this for Ruby 3.1/3.2
|
|
71
|
+
end
|
|
62
72
|
```
|
|
63
73
|
|
|
64
|
-
|
|
74
|
+
**Ruby Version Support:**
|
|
75
|
+
- Ruby 3.3+ → v4 and v7
|
|
76
|
+
- Ruby 3.1/3.2 → v4 only
|
|
65
77
|
|
|
66
|
-
|
|
67
|
-
|
|
78
|
+
Check programmatically:
|
|
79
|
+
```ruby
|
|
80
|
+
SqliteCrypto::Generators::Uuid.v7_available? # => true/false
|
|
68
81
|
```
|
|
69
82
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
## Usage
|
|
83
|
+
## Usage Examples
|
|
73
84
|
|
|
74
85
|
### UUID Primary Keys
|
|
75
86
|
|
|
@@ -78,13 +89,18 @@ class CreateUsers < ActiveRecord::Migration[8.1]
|
|
|
78
89
|
def change
|
|
79
90
|
create_table :users, id: :uuid do |t|
|
|
80
91
|
t.string :email
|
|
81
|
-
t.string :name
|
|
82
92
|
t.timestamps
|
|
83
93
|
end
|
|
84
94
|
end
|
|
85
95
|
end
|
|
86
96
|
```
|
|
87
97
|
|
|
98
|
+
Result:
|
|
99
|
+
```ruby
|
|
100
|
+
user = User.create!(email: "alice@example.com")
|
|
101
|
+
user.id # => "018d3f91-8f4a-7000-9e7b-4a5c8d2e1f3a" (UUIDv7)
|
|
102
|
+
```
|
|
103
|
+
|
|
88
104
|
### ULID Primary Keys
|
|
89
105
|
|
|
90
106
|
```ruby
|
|
@@ -92,199 +108,153 @@ class CreatePosts < ActiveRecord::Migration[8.1]
|
|
|
92
108
|
def change
|
|
93
109
|
create_table :posts, id: :ulid do |t|
|
|
94
110
|
t.string :title
|
|
95
|
-
t.text :content
|
|
96
111
|
t.timestamps
|
|
97
112
|
end
|
|
98
113
|
end
|
|
99
114
|
end
|
|
100
115
|
```
|
|
101
116
|
|
|
102
|
-
|
|
103
|
-
|
|
117
|
+
Result:
|
|
104
118
|
```ruby
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
change_table :orders do |t|
|
|
108
|
-
t.uuid :external_id
|
|
109
|
-
t.ulid :tracking_number
|
|
110
|
-
end
|
|
111
|
-
end
|
|
112
|
-
end
|
|
119
|
+
post = Post.create!(title: "Hello World")
|
|
120
|
+
post.id # => "01ARZ3NDEKTSV4RRFFQ69G5FAV" (26 chars, time-sortable)
|
|
113
121
|
```
|
|
114
122
|
|
|
115
|
-
### Foreign Keys
|
|
123
|
+
### Automatic Foreign Keys
|
|
116
124
|
|
|
117
|
-
The gem automatically detects
|
|
125
|
+
The gem **automatically detects** parent table ID types:
|
|
118
126
|
|
|
119
127
|
```ruby
|
|
120
|
-
# Users
|
|
128
|
+
# Users have UUID primary keys
|
|
121
129
|
create_table :users, id: :uuid do |t|
|
|
122
130
|
t.string :name
|
|
123
131
|
end
|
|
124
132
|
|
|
125
|
-
# Posts automatically get varchar(36)
|
|
133
|
+
# Posts automatically get varchar(36) foreign keys
|
|
126
134
|
create_table :posts do |t|
|
|
127
|
-
t.references :user
|
|
135
|
+
t.references :user # Auto-detected as varchar(36)!
|
|
128
136
|
t.string :title
|
|
129
137
|
end
|
|
130
138
|
```
|
|
131
139
|
|
|
132
140
|
Works with ULID too:
|
|
133
|
-
|
|
134
141
|
```ruby
|
|
135
|
-
# Categories table has ULID primary key
|
|
136
142
|
create_table :categories, id: :ulid do |t|
|
|
137
143
|
t.string :name
|
|
138
144
|
end
|
|
139
145
|
|
|
140
|
-
# Articles automatically get varchar(26) category_id foreign key
|
|
141
146
|
create_table :articles do |t|
|
|
142
|
-
t.references :category #
|
|
143
|
-
t.string :title
|
|
147
|
+
t.references :category # Auto-detected as varchar(26)!
|
|
144
148
|
end
|
|
145
149
|
```
|
|
146
150
|
|
|
147
|
-
###
|
|
148
|
-
|
|
149
|
-
Use `:to_table` option for non-standard table names:
|
|
151
|
+
### Generate UUIDs/ULIDs for Any Column
|
|
150
152
|
|
|
151
153
|
```ruby
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
154
|
+
class User < ApplicationRecord
|
|
155
|
+
generates_uuid :token # Auto-generate on create
|
|
156
|
+
generates_ulid :reference, unique: true # With uniqueness validation
|
|
155
157
|
end
|
|
158
|
+
|
|
159
|
+
user = User.create!(email: "test@example.com")
|
|
160
|
+
user.token # => "018d3f91-..." (auto-generated)
|
|
161
|
+
user.reference # => "01ARZ3NDEK..." (auto-generated + validated)
|
|
156
162
|
```
|
|
157
163
|
|
|
158
|
-
|
|
164
|
+
## Requirements
|
|
159
165
|
|
|
160
|
-
|
|
166
|
+
- **Ruby**: 3.1+ (3.3+ for UUIDv7)
|
|
167
|
+
- **Rails**: 7.1, 7.2, 8.0, 8.1
|
|
168
|
+
- **Database**: SQLite3
|
|
161
169
|
|
|
162
|
-
|
|
163
|
-
class User < ApplicationRecord
|
|
164
|
-
# Generate UUID for 'token' column on create
|
|
165
|
-
generates_uuid :token
|
|
166
|
-
end
|
|
170
|
+
## Performance Benchmarks
|
|
167
171
|
|
|
168
|
-
|
|
169
|
-
# Generate ULID for 'reference' column with uniqueness validation
|
|
170
|
-
generates_ulid :reference, unique: true
|
|
171
|
-
end
|
|
172
|
-
```
|
|
172
|
+
Run your own benchmarks: `bundle exec rspec --tag performance`
|
|
173
173
|
|
|
174
|
-
**
|
|
175
|
-
- `generates_uuid(attribute, unique: false)` - Generates SecureRandom.uuid
|
|
176
|
-
- `generates_ulid(attribute, unique: false)` - Generates time-sortable ULID
|
|
177
|
-
- `unique: true` - Adds uniqueness validation
|
|
178
|
-
- Preserves existing values (won't overwrite if already set)
|
|
179
|
-
- Works with any string column, not just primary keys
|
|
174
|
+
**Typical results (M1 Mac, SQLite3, 10k records):**
|
|
180
175
|
|
|
181
|
-
|
|
176
|
+
| Operation | Integer (baseline) | UUIDv4 | UUIDv7 | ULID |
|
|
177
|
+
|-----------|-------------------|--------|--------|------|
|
|
178
|
+
| Insert (10k) | 1.00x | 1.02x | 1.01x | 1.05x |
|
|
179
|
+
| Query by ID | 1.00x | 1.03x | 1.03x | 1.04x |
|
|
180
|
+
| Index size | 100% | 145% | 145% | 130% |
|
|
182
181
|
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
def change
|
|
186
|
-
add_column :users, :token, :string, limit: 36
|
|
187
|
-
add_index :users, :token, unique: true
|
|
188
|
-
end
|
|
189
|
-
end
|
|
190
|
-
```
|
|
182
|
+
**Key takeaway:** UUIDv7 has nearly identical performance to v4, with better write scaling.
|
|
183
|
+
## Advanced Usage
|
|
191
184
|
|
|
192
|
-
###
|
|
185
|
+
### Custom Table Names
|
|
193
186
|
|
|
194
|
-
|
|
187
|
+
Use `:to_table` for non-standard associations:
|
|
195
188
|
|
|
196
189
|
```ruby
|
|
197
|
-
create_table
|
|
198
|
-
t.
|
|
199
|
-
t.timestamps
|
|
200
|
-
end
|
|
201
|
-
|
|
202
|
-
create_table "posts", force: :cascade do |t|
|
|
203
|
-
t.string "user_id", limit: 36 # Clean foreign key
|
|
204
|
-
t.string "title"
|
|
190
|
+
create_table :posts do |t|
|
|
191
|
+
t.references :author, to_table: :users # Uses users table's ID type
|
|
205
192
|
end
|
|
206
193
|
```
|
|
207
194
|
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
1. **Type Registration**: Registers `:uuid` and `:ulid` types with ActiveRecord for SQLite3
|
|
211
|
-
2. **Validation**: UUIDs validate 36-char format, ULIDs validate 26-char format
|
|
212
|
-
3. **Migration Helpers**: `t.uuid()` and `t.ulid()` methods in migrations
|
|
213
|
-
4. **Smart References**: `t.references` detects parent table's primary key type
|
|
214
|
-
5. **Model Extensions**: `generates_uuid` and `generates_ulid` for automatic generation
|
|
215
|
-
6. **Schema Dumper**: Outputs clean `id: :uuid` instead of verbose type definitions
|
|
216
|
-
|
|
217
|
-
## Requirements
|
|
218
|
-
|
|
219
|
-
- Rails 7.1+ (tested on 7.1, 7.2, 8.0, 8.1)
|
|
220
|
-
- Ruby 3.1+
|
|
221
|
-
- SQLite3
|
|
222
|
-
|
|
223
|
-
## Migrating Existing Apps
|
|
224
|
-
|
|
225
|
-
### New Tables Only (Recommended)
|
|
195
|
+
### Mixing ID Types
|
|
226
196
|
|
|
227
|
-
|
|
197
|
+
Different tables can use different ID types:
|
|
228
198
|
|
|
229
199
|
```ruby
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
# posts: id (integer), user_id (integer)
|
|
233
|
-
|
|
234
|
-
# New tables use UUID/ULID
|
|
235
|
-
create_table :invoices, id: :uuid do |t|
|
|
236
|
-
t.references :user # Still integer (auto-detected from users table)
|
|
237
|
-
t.decimal :amount
|
|
200
|
+
create_table :users, id: :uuid do |t|
|
|
201
|
+
t.string :email
|
|
238
202
|
end
|
|
239
203
|
|
|
240
204
|
create_table :sessions, id: :ulid do |t|
|
|
241
|
-
t.references :user #
|
|
242
|
-
t.string :token
|
|
205
|
+
t.references :user # Auto-detected as varchar(36)
|
|
243
206
|
end
|
|
244
|
-
```
|
|
245
207
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
208
|
+
create_table :logs do |t| # Integer ID (default)
|
|
209
|
+
t.string :message
|
|
210
|
+
end
|
|
211
|
+
```
|
|
249
212
|
|
|
250
|
-
|
|
213
|
+
### ID Prefixes (Stripe-style)
|
|
251
214
|
|
|
252
215
|
```ruby
|
|
253
216
|
class Invoice < ApplicationRecord
|
|
254
|
-
before_create :
|
|
217
|
+
before_create :add_prefix
|
|
255
218
|
|
|
256
219
|
private
|
|
257
|
-
|
|
258
|
-
def generate_prefixed_id
|
|
220
|
+
def add_prefix
|
|
259
221
|
self.id = "inv_#{SecureRandom.uuid}" if id.nil?
|
|
260
222
|
end
|
|
261
223
|
end
|
|
262
224
|
```
|
|
263
225
|
|
|
264
|
-
|
|
226
|
+
## Migrating Existing Apps
|
|
265
227
|
|
|
266
|
-
|
|
228
|
+
Use UUID/ULID only for **new tables**:
|
|
267
229
|
|
|
268
230
|
```ruby
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
create_table :sessions, id: :ulid do |t|
|
|
274
|
-
t.string :token
|
|
275
|
-
end
|
|
231
|
+
# Keep existing integer IDs
|
|
232
|
+
# users: id (integer)
|
|
233
|
+
# posts: id (integer), user_id (integer)
|
|
276
234
|
|
|
277
|
-
|
|
278
|
-
|
|
235
|
+
# New tables use UUID/ULID
|
|
236
|
+
create_table :invoices, id: :uuid do |t|
|
|
237
|
+
t.references :user # Still integer (auto-detected)
|
|
238
|
+
t.decimal :amount
|
|
279
239
|
end
|
|
280
240
|
```
|
|
281
241
|
|
|
242
|
+
## How It Works
|
|
243
|
+
|
|
244
|
+
1. **Type Registration** - Registers `:uuid` and `:ulid` with ActiveRecord's SQLite3 adapter
|
|
245
|
+
2. **Validation** - UUIDs: 36-char format, ULIDs: 26-char format
|
|
246
|
+
3. **Migration Helpers** - `t.uuid()` and `t.ulid()` in migrations
|
|
247
|
+
4. **Smart References** - `t.references` detects parent table ID type
|
|
248
|
+
5. **Model Extensions** - `generates_uuid`/`generates_ulid` for auto-generation
|
|
249
|
+
6. **Schema Dumper** - Clean output: `id: :uuid` instead of verbose definitions
|
|
250
|
+
|
|
282
251
|
## Development
|
|
283
252
|
|
|
284
253
|
```bash
|
|
285
254
|
bundle install
|
|
286
|
-
bundle exec rspec
|
|
287
|
-
bundle exec standardrb
|
|
255
|
+
bundle exec rspec # Run tests
|
|
256
|
+
bundle exec standardrb # Lint
|
|
257
|
+
bundle exec rspec --tag performance # Benchmarks
|
|
288
258
|
```
|
|
289
259
|
|
|
290
260
|
## Contributing
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module SqliteCrypto
|
|
4
|
+
class Configuration
|
|
5
|
+
attr_accessor :uuid_version
|
|
6
|
+
|
|
7
|
+
def initialize
|
|
8
|
+
# Default to v7 on Ruby 3.3+, v4 on older versions
|
|
9
|
+
@uuid_version = (Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.3.0")) ? :v7 : :v4
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "rails/generators"
|
|
4
|
+
require "rails/generators/base"
|
|
5
|
+
|
|
6
|
+
module SqliteCrypto
|
|
7
|
+
module Generators
|
|
8
|
+
class InstallGenerator < Rails::Generators::Base
|
|
9
|
+
source_root File.expand_path("templates", __dir__)
|
|
10
|
+
|
|
11
|
+
desc "Creates SqliteCrypto initializer for UUID/ULID configuration"
|
|
12
|
+
|
|
13
|
+
def create_initializer_file
|
|
14
|
+
template "initializer.rb.tt", "config/initializers/sqlite_crypto.rb"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def display_post_install_message
|
|
18
|
+
say ""
|
|
19
|
+
say "SqliteCrypto installed!", :green
|
|
20
|
+
say ""
|
|
21
|
+
say "Configuration created at config/initializers/sqlite_crypto.rb"
|
|
22
|
+
say ""
|
|
23
|
+
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new("3.3.0")
|
|
24
|
+
say "✓ Ruby #{RUBY_VERSION} detected - UUIDv7 is available (default)", :green
|
|
25
|
+
else
|
|
26
|
+
say "⚠ Ruby #{RUBY_VERSION} detected - UUIDv7 requires Ruby 3.3+", :yellow
|
|
27
|
+
say " Update initializer to use: config.uuid_version = :v4"
|
|
28
|
+
end
|
|
29
|
+
say ""
|
|
30
|
+
say "Next steps:"
|
|
31
|
+
say " 1. Review config/initializers/sqlite_crypto.rb"
|
|
32
|
+
say " 2. Use id: :uuid in migrations for UUID primary keys"
|
|
33
|
+
say ""
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
SqliteCrypto.configure do |config|
|
|
4
|
+
# UUID generation version: :v4 (random) or :v7 (time-sortable)
|
|
5
|
+
#
|
|
6
|
+
# :v7 - Time-sortable UUIDs with better database index performance
|
|
7
|
+
# Recommended for new projects. Requires Ruby 3.3+
|
|
8
|
+
#
|
|
9
|
+
# :v4 - Random UUIDs, works on all Ruby versions (3.1+)
|
|
10
|
+
# Use if you need Ruby 3.1/3.2 compatibility
|
|
11
|
+
#
|
|
12
|
+
config.uuid_version = :v7 # UUIDv7 is set as default
|
|
13
|
+
end
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "securerandom"
|
|
4
|
+
|
|
5
|
+
module SqliteCrypto
|
|
6
|
+
module Generators
|
|
7
|
+
class Uuid
|
|
8
|
+
MINIMUM_RUBY_FOR_V7 = Gem::Version.new("3.3.0")
|
|
9
|
+
CURRENT_RUBY = Gem::Version.new(RUBY_VERSION)
|
|
10
|
+
|
|
11
|
+
class << self
|
|
12
|
+
def generate(version: SqliteCrypto.config.uuid_version)
|
|
13
|
+
case version
|
|
14
|
+
when :v4
|
|
15
|
+
generate_v4
|
|
16
|
+
when :v7
|
|
17
|
+
generate_v7
|
|
18
|
+
else
|
|
19
|
+
raise ArgumentError, "Unsupported UUID version: #{version}"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def v7_available?
|
|
24
|
+
CURRENT_RUBY >= MINIMUM_RUBY_FOR_V7
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
private
|
|
28
|
+
|
|
29
|
+
def generate_v4
|
|
30
|
+
SecureRandom.uuid
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def generate_v7
|
|
34
|
+
if v7_available?
|
|
35
|
+
SecureRandom.uuid_v7
|
|
36
|
+
else
|
|
37
|
+
raise ArgumentError, "UUIDv7 requires Ruby 3.3+. " \
|
|
38
|
+
"Current: Ruby #{RUBY_VERSION}. " \
|
|
39
|
+
"Use config.uuid_version = :v4 or upgrade Ruby."
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -9,7 +9,7 @@ module SqliteCrypto
|
|
|
9
9
|
module ClassMethods
|
|
10
10
|
def generates_uuid(attribute, unique: false)
|
|
11
11
|
before_create do
|
|
12
|
-
self[attribute] ||=
|
|
12
|
+
self[attribute] ||= SqliteCrypto::Generators::Uuid.generate
|
|
13
13
|
end
|
|
14
14
|
|
|
15
15
|
validates attribute, uniqueness: true if unique
|
data/lib/sqlite_crypto.rb
CHANGED
|
@@ -1,13 +1,30 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "sqlite_crypto/version"
|
|
4
|
+
require "sqlite_crypto/configuration"
|
|
4
5
|
require "sqlite_crypto/railtie" if defined?(Rails)
|
|
5
6
|
require "sqlite_crypto/schema_dumper" if defined?(ActiveRecord)
|
|
6
7
|
require "sqlite_crypto/schema_definitions"
|
|
8
|
+
require "sqlite_crypto/generators/uuid"
|
|
7
9
|
|
|
8
10
|
module SqliteCrypto
|
|
9
11
|
class Error < StandardError; end
|
|
10
12
|
|
|
13
|
+
class << self
|
|
14
|
+
def configuration
|
|
15
|
+
@configuration ||= Configuration.new
|
|
16
|
+
end
|
|
17
|
+
alias_method :config, :configuration
|
|
18
|
+
|
|
19
|
+
def configure
|
|
20
|
+
yield(configuration)
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def reset_configuration!
|
|
24
|
+
@configuration = Configuration.new
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
11
28
|
def self.load_extensions
|
|
12
29
|
# Placeholder for future extension loading logic
|
|
13
30
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: sqlite_crypto
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version:
|
|
4
|
+
version: 2.0.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- BartOz
|
|
@@ -63,6 +63,10 @@ files:
|
|
|
63
63
|
- LICENSE.txt
|
|
64
64
|
- README.md
|
|
65
65
|
- lib/sqlite_crypto.rb
|
|
66
|
+
- lib/sqlite_crypto/configuration.rb
|
|
67
|
+
- lib/sqlite_crypto/generators/install_generator.rb
|
|
68
|
+
- lib/sqlite_crypto/generators/templates/initializer.rb.tt
|
|
69
|
+
- lib/sqlite_crypto/generators/uuid.rb
|
|
66
70
|
- lib/sqlite_crypto/migration_helpers.rb
|
|
67
71
|
- lib/sqlite_crypto/model_extensions.rb
|
|
68
72
|
- lib/sqlite_crypto/railtie.rb
|