sqlite_crypto 1.0.2 → 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 +29 -0
- data/README.md +132 -161
- 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 +6 -100
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,35 @@ 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
|
+
|
|
29
|
+
## [1.0.3] - 2025-12-30
|
|
30
|
+
|
|
31
|
+
### Added
|
|
32
|
+
- **Ruby 4.0.0 Support**: Added compatibility with Ruby 4.0.0 released on December 25, 2025
|
|
33
|
+
- Added `benchmark` gem as test dependency (removed from Ruby 4.0.0 stdlib)
|
|
34
|
+
- Reorganized gemspec to include only runtime dependencies
|
|
35
|
+
- Moved development and test dependencies to Gemfile
|
|
36
|
+
|
|
8
37
|
## [1.0.2] - 2025-12-21
|
|
9
38
|
|
|
10
39
|
### Fixed
|
data/README.md
CHANGED
|
@@ -1,74 +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 | ✅ | ✅ | ✅ | ✅ |
|
|
46
|
+
UUIDv7 embeds a timestamp in the first 48 bits, making IDs naturally sortable by creation time:
|
|
40
47
|
|
|
41
|
-
|
|
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
|
+
```
|
|
42
52
|
|
|
43
|
-
**
|
|
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)
|
|
44
57
|
|
|
45
|
-
|
|
58
|
+
**Requirements:** Ruby 3.3+ (falls back to v4 on older versions)
|
|
46
59
|
|
|
47
|
-
|
|
48
|
-
* ULID primary keys with time-sortable validation
|
|
49
|
-
* Migration DSL helpers (`t.uuid`, `t.ulid`)
|
|
50
|
-
* Automatic foreign key type detection
|
|
51
|
-
* Model extensions for UUID/ULID generation
|
|
52
|
-
* Clean schema.rb output
|
|
53
|
-
* Zero configuration required
|
|
60
|
+
## Configuration
|
|
54
61
|
|
|
55
|
-
|
|
62
|
+
### Choose UUID Version (v4 or v7)
|
|
56
63
|
|
|
57
|
-
|
|
64
|
+
After running `rails generate sqlite_crypto:install`:
|
|
58
65
|
|
|
59
66
|
```ruby
|
|
60
|
-
|
|
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
|
|
61
72
|
```
|
|
62
73
|
|
|
63
|
-
|
|
74
|
+
**Ruby Version Support:**
|
|
75
|
+
- Ruby 3.3+ → v4 and v7
|
|
76
|
+
- Ruby 3.1/3.2 → v4 only
|
|
64
77
|
|
|
65
|
-
|
|
66
|
-
|
|
78
|
+
Check programmatically:
|
|
79
|
+
```ruby
|
|
80
|
+
SqliteCrypto::Generators::Uuid.v7_available? # => true/false
|
|
67
81
|
```
|
|
68
82
|
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
## Usage
|
|
83
|
+
## Usage Examples
|
|
72
84
|
|
|
73
85
|
### UUID Primary Keys
|
|
74
86
|
|
|
@@ -77,13 +89,18 @@ class CreateUsers < ActiveRecord::Migration[8.1]
|
|
|
77
89
|
def change
|
|
78
90
|
create_table :users, id: :uuid do |t|
|
|
79
91
|
t.string :email
|
|
80
|
-
t.string :name
|
|
81
92
|
t.timestamps
|
|
82
93
|
end
|
|
83
94
|
end
|
|
84
95
|
end
|
|
85
96
|
```
|
|
86
97
|
|
|
98
|
+
Result:
|
|
99
|
+
```ruby
|
|
100
|
+
user = User.create!(email: "alice@example.com")
|
|
101
|
+
user.id # => "018d3f91-8f4a-7000-9e7b-4a5c8d2e1f3a" (UUIDv7)
|
|
102
|
+
```
|
|
103
|
+
|
|
87
104
|
### ULID Primary Keys
|
|
88
105
|
|
|
89
106
|
```ruby
|
|
@@ -91,199 +108,153 @@ class CreatePosts < ActiveRecord::Migration[8.1]
|
|
|
91
108
|
def change
|
|
92
109
|
create_table :posts, id: :ulid do |t|
|
|
93
110
|
t.string :title
|
|
94
|
-
t.text :content
|
|
95
111
|
t.timestamps
|
|
96
112
|
end
|
|
97
113
|
end
|
|
98
114
|
end
|
|
99
115
|
```
|
|
100
116
|
|
|
101
|
-
|
|
102
|
-
|
|
117
|
+
Result:
|
|
103
118
|
```ruby
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
change_table :orders do |t|
|
|
107
|
-
t.uuid :external_id
|
|
108
|
-
t.ulid :tracking_number
|
|
109
|
-
end
|
|
110
|
-
end
|
|
111
|
-
end
|
|
119
|
+
post = Post.create!(title: "Hello World")
|
|
120
|
+
post.id # => "01ARZ3NDEKTSV4RRFFQ69G5FAV" (26 chars, time-sortable)
|
|
112
121
|
```
|
|
113
122
|
|
|
114
|
-
### Foreign Keys
|
|
123
|
+
### Automatic Foreign Keys
|
|
115
124
|
|
|
116
|
-
The gem automatically detects
|
|
125
|
+
The gem **automatically detects** parent table ID types:
|
|
117
126
|
|
|
118
127
|
```ruby
|
|
119
|
-
# Users
|
|
128
|
+
# Users have UUID primary keys
|
|
120
129
|
create_table :users, id: :uuid do |t|
|
|
121
130
|
t.string :name
|
|
122
131
|
end
|
|
123
132
|
|
|
124
|
-
# Posts automatically get varchar(36)
|
|
133
|
+
# Posts automatically get varchar(36) foreign keys
|
|
125
134
|
create_table :posts do |t|
|
|
126
|
-
t.references :user
|
|
135
|
+
t.references :user # Auto-detected as varchar(36)!
|
|
127
136
|
t.string :title
|
|
128
137
|
end
|
|
129
138
|
```
|
|
130
139
|
|
|
131
140
|
Works with ULID too:
|
|
132
|
-
|
|
133
141
|
```ruby
|
|
134
|
-
# Categories table has ULID primary key
|
|
135
142
|
create_table :categories, id: :ulid do |t|
|
|
136
143
|
t.string :name
|
|
137
144
|
end
|
|
138
145
|
|
|
139
|
-
# Articles automatically get varchar(26) category_id foreign key
|
|
140
146
|
create_table :articles do |t|
|
|
141
|
-
t.references :category #
|
|
142
|
-
t.string :title
|
|
147
|
+
t.references :category # Auto-detected as varchar(26)!
|
|
143
148
|
end
|
|
144
149
|
```
|
|
145
150
|
|
|
146
|
-
###
|
|
147
|
-
|
|
148
|
-
Use `:to_table` option for non-standard table names:
|
|
151
|
+
### Generate UUIDs/ULIDs for Any Column
|
|
149
152
|
|
|
150
153
|
```ruby
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
+
class User < ApplicationRecord
|
|
155
|
+
generates_uuid :token # Auto-generate on create
|
|
156
|
+
generates_ulid :reference, unique: true # With uniqueness validation
|
|
154
157
|
end
|
|
158
|
+
|
|
159
|
+
user = User.create!(email: "test@example.com")
|
|
160
|
+
user.token # => "018d3f91-..." (auto-generated)
|
|
161
|
+
user.reference # => "01ARZ3NDEK..." (auto-generated + validated)
|
|
155
162
|
```
|
|
156
163
|
|
|
157
|
-
|
|
164
|
+
## Requirements
|
|
158
165
|
|
|
159
|
-
|
|
166
|
+
- **Ruby**: 3.1+ (3.3+ for UUIDv7)
|
|
167
|
+
- **Rails**: 7.1, 7.2, 8.0, 8.1
|
|
168
|
+
- **Database**: SQLite3
|
|
160
169
|
|
|
161
|
-
|
|
162
|
-
class User < ApplicationRecord
|
|
163
|
-
# Generate UUID for 'token' column on create
|
|
164
|
-
generates_uuid :token
|
|
165
|
-
end
|
|
170
|
+
## Performance Benchmarks
|
|
166
171
|
|
|
167
|
-
|
|
168
|
-
# Generate ULID for 'reference' column with uniqueness validation
|
|
169
|
-
generates_ulid :reference, unique: true
|
|
170
|
-
end
|
|
171
|
-
```
|
|
172
|
+
Run your own benchmarks: `bundle exec rspec --tag performance`
|
|
172
173
|
|
|
173
|
-
**
|
|
174
|
-
- `generates_uuid(attribute, unique: false)` - Generates SecureRandom.uuid
|
|
175
|
-
- `generates_ulid(attribute, unique: false)` - Generates time-sortable ULID
|
|
176
|
-
- `unique: true` - Adds uniqueness validation
|
|
177
|
-
- Preserves existing values (won't overwrite if already set)
|
|
178
|
-
- Works with any string column, not just primary keys
|
|
174
|
+
**Typical results (M1 Mac, SQLite3, 10k records):**
|
|
179
175
|
|
|
180
|
-
|
|
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% |
|
|
181
181
|
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
def change
|
|
185
|
-
add_column :users, :token, :string, limit: 36
|
|
186
|
-
add_index :users, :token, unique: true
|
|
187
|
-
end
|
|
188
|
-
end
|
|
189
|
-
```
|
|
182
|
+
**Key takeaway:** UUIDv7 has nearly identical performance to v4, with better write scaling.
|
|
183
|
+
## Advanced Usage
|
|
190
184
|
|
|
191
|
-
###
|
|
185
|
+
### Custom Table Names
|
|
192
186
|
|
|
193
|
-
|
|
187
|
+
Use `:to_table` for non-standard associations:
|
|
194
188
|
|
|
195
189
|
```ruby
|
|
196
|
-
create_table
|
|
197
|
-
t.
|
|
198
|
-
t.timestamps
|
|
199
|
-
end
|
|
200
|
-
|
|
201
|
-
create_table "posts", force: :cascade do |t|
|
|
202
|
-
t.string "user_id", limit: 36 # Clean foreign key
|
|
203
|
-
t.string "title"
|
|
190
|
+
create_table :posts do |t|
|
|
191
|
+
t.references :author, to_table: :users # Uses users table's ID type
|
|
204
192
|
end
|
|
205
193
|
```
|
|
206
194
|
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
1. **Type Registration**: Registers `:uuid` and `:ulid` types with ActiveRecord for SQLite3
|
|
210
|
-
2. **Validation**: UUIDs validate 36-char format, ULIDs validate 26-char format
|
|
211
|
-
3. **Migration Helpers**: `t.uuid()` and `t.ulid()` methods in migrations
|
|
212
|
-
4. **Smart References**: `t.references` detects parent table's primary key type
|
|
213
|
-
5. **Model Extensions**: `generates_uuid` and `generates_ulid` for automatic generation
|
|
214
|
-
6. **Schema Dumper**: Outputs clean `id: :uuid` instead of verbose type definitions
|
|
215
|
-
|
|
216
|
-
## Requirements
|
|
217
|
-
|
|
218
|
-
- Rails 7.1+ (tested on 7.1, 7.2, 8.0, 8.1)
|
|
219
|
-
- Ruby 3.1+
|
|
220
|
-
- SQLite3
|
|
221
|
-
|
|
222
|
-
## Migrating Existing Apps
|
|
223
|
-
|
|
224
|
-
### New Tables Only (Recommended)
|
|
195
|
+
### Mixing ID Types
|
|
225
196
|
|
|
226
|
-
|
|
197
|
+
Different tables can use different ID types:
|
|
227
198
|
|
|
228
199
|
```ruby
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
# posts: id (integer), user_id (integer)
|
|
232
|
-
|
|
233
|
-
# New tables use UUID/ULID
|
|
234
|
-
create_table :invoices, id: :uuid do |t|
|
|
235
|
-
t.references :user # Still integer (auto-detected from users table)
|
|
236
|
-
t.decimal :amount
|
|
200
|
+
create_table :users, id: :uuid do |t|
|
|
201
|
+
t.string :email
|
|
237
202
|
end
|
|
238
203
|
|
|
239
204
|
create_table :sessions, id: :ulid do |t|
|
|
240
|
-
t.references :user #
|
|
241
|
-
t.string :token
|
|
205
|
+
t.references :user # Auto-detected as varchar(36)
|
|
242
206
|
end
|
|
243
|
-
```
|
|
244
207
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
208
|
+
create_table :logs do |t| # Integer ID (default)
|
|
209
|
+
t.string :message
|
|
210
|
+
end
|
|
211
|
+
```
|
|
248
212
|
|
|
249
|
-
|
|
213
|
+
### ID Prefixes (Stripe-style)
|
|
250
214
|
|
|
251
215
|
```ruby
|
|
252
216
|
class Invoice < ApplicationRecord
|
|
253
|
-
before_create :
|
|
217
|
+
before_create :add_prefix
|
|
254
218
|
|
|
255
219
|
private
|
|
256
|
-
|
|
257
|
-
def generate_prefixed_id
|
|
220
|
+
def add_prefix
|
|
258
221
|
self.id = "inv_#{SecureRandom.uuid}" if id.nil?
|
|
259
222
|
end
|
|
260
223
|
end
|
|
261
224
|
```
|
|
262
225
|
|
|
263
|
-
|
|
226
|
+
## Migrating Existing Apps
|
|
264
227
|
|
|
265
|
-
|
|
228
|
+
Use UUID/ULID only for **new tables**:
|
|
266
229
|
|
|
267
230
|
```ruby
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
create_table :sessions, id: :ulid do |t|
|
|
273
|
-
t.string :token
|
|
274
|
-
end
|
|
231
|
+
# Keep existing integer IDs
|
|
232
|
+
# users: id (integer)
|
|
233
|
+
# posts: id (integer), user_id (integer)
|
|
275
234
|
|
|
276
|
-
|
|
277
|
-
|
|
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
|
|
278
239
|
end
|
|
279
240
|
```
|
|
280
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
|
+
|
|
281
251
|
## Development
|
|
282
252
|
|
|
283
253
|
```bash
|
|
284
254
|
bundle install
|
|
285
|
-
bundle exec rspec
|
|
286
|
-
bundle exec standardrb
|
|
255
|
+
bundle exec rspec # Run tests
|
|
256
|
+
bundle exec standardrb # Lint
|
|
257
|
+
bundle exec rspec --tag performance # Benchmarks
|
|
287
258
|
```
|
|
288
259
|
|
|
289
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
|
|
@@ -51,104 +51,6 @@ dependencies:
|
|
|
51
51
|
- - "~>"
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
53
|
version: '1.0'
|
|
54
|
-
- !ruby/object:Gem::Dependency
|
|
55
|
-
name: bundler
|
|
56
|
-
requirement: !ruby/object:Gem::Requirement
|
|
57
|
-
requirements:
|
|
58
|
-
- - ">="
|
|
59
|
-
- !ruby/object:Gem::Version
|
|
60
|
-
version: '2.0'
|
|
61
|
-
type: :development
|
|
62
|
-
prerelease: false
|
|
63
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
-
requirements:
|
|
65
|
-
- - ">="
|
|
66
|
-
- !ruby/object:Gem::Version
|
|
67
|
-
version: '2.0'
|
|
68
|
-
- !ruby/object:Gem::Dependency
|
|
69
|
-
name: rake
|
|
70
|
-
requirement: !ruby/object:Gem::Requirement
|
|
71
|
-
requirements:
|
|
72
|
-
- - ">="
|
|
73
|
-
- !ruby/object:Gem::Version
|
|
74
|
-
version: '12.0'
|
|
75
|
-
type: :development
|
|
76
|
-
prerelease: false
|
|
77
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
78
|
-
requirements:
|
|
79
|
-
- - ">="
|
|
80
|
-
- !ruby/object:Gem::Version
|
|
81
|
-
version: '12.0'
|
|
82
|
-
- !ruby/object:Gem::Dependency
|
|
83
|
-
name: rspec-rails
|
|
84
|
-
requirement: !ruby/object:Gem::Requirement
|
|
85
|
-
requirements:
|
|
86
|
-
- - "~>"
|
|
87
|
-
- !ruby/object:Gem::Version
|
|
88
|
-
version: '6.0'
|
|
89
|
-
type: :development
|
|
90
|
-
prerelease: false
|
|
91
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
92
|
-
requirements:
|
|
93
|
-
- - "~>"
|
|
94
|
-
- !ruby/object:Gem::Version
|
|
95
|
-
version: '6.0'
|
|
96
|
-
- !ruby/object:Gem::Dependency
|
|
97
|
-
name: simplecov
|
|
98
|
-
requirement: !ruby/object:Gem::Requirement
|
|
99
|
-
requirements:
|
|
100
|
-
- - "~>"
|
|
101
|
-
- !ruby/object:Gem::Version
|
|
102
|
-
version: '0.22'
|
|
103
|
-
type: :development
|
|
104
|
-
prerelease: false
|
|
105
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
106
|
-
requirements:
|
|
107
|
-
- - "~>"
|
|
108
|
-
- !ruby/object:Gem::Version
|
|
109
|
-
version: '0.22'
|
|
110
|
-
- !ruby/object:Gem::Dependency
|
|
111
|
-
name: sqlite3
|
|
112
|
-
requirement: !ruby/object:Gem::Requirement
|
|
113
|
-
requirements:
|
|
114
|
-
- - ">="
|
|
115
|
-
- !ruby/object:Gem::Version
|
|
116
|
-
version: 1.6.0
|
|
117
|
-
type: :development
|
|
118
|
-
prerelease: false
|
|
119
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
120
|
-
requirements:
|
|
121
|
-
- - ">="
|
|
122
|
-
- !ruby/object:Gem::Version
|
|
123
|
-
version: 1.6.0
|
|
124
|
-
- !ruby/object:Gem::Dependency
|
|
125
|
-
name: standard
|
|
126
|
-
requirement: !ruby/object:Gem::Requirement
|
|
127
|
-
requirements:
|
|
128
|
-
- - "~>"
|
|
129
|
-
- !ruby/object:Gem::Version
|
|
130
|
-
version: '1.30'
|
|
131
|
-
type: :development
|
|
132
|
-
prerelease: false
|
|
133
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
134
|
-
requirements:
|
|
135
|
-
- - "~>"
|
|
136
|
-
- !ruby/object:Gem::Version
|
|
137
|
-
version: '1.30'
|
|
138
|
-
- !ruby/object:Gem::Dependency
|
|
139
|
-
name: appraisal
|
|
140
|
-
requirement: !ruby/object:Gem::Requirement
|
|
141
|
-
requirements:
|
|
142
|
-
- - "~>"
|
|
143
|
-
- !ruby/object:Gem::Version
|
|
144
|
-
version: '2.5'
|
|
145
|
-
type: :development
|
|
146
|
-
prerelease: false
|
|
147
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
148
|
-
requirements:
|
|
149
|
-
- - "~>"
|
|
150
|
-
- !ruby/object:Gem::Version
|
|
151
|
-
version: '2.5'
|
|
152
54
|
description: A lightweight, modular gem providing transparent UUID/ULID primary key
|
|
153
55
|
configuration for Rails applications using SQLite.
|
|
154
56
|
email:
|
|
@@ -161,6 +63,10 @@ files:
|
|
|
161
63
|
- LICENSE.txt
|
|
162
64
|
- README.md
|
|
163
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
|
|
164
70
|
- lib/sqlite_crypto/migration_helpers.rb
|
|
165
71
|
- lib/sqlite_crypto/model_extensions.rb
|
|
166
72
|
- lib/sqlite_crypto/railtie.rb
|
|
@@ -190,7 +96,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
190
96
|
- !ruby/object:Gem::Version
|
|
191
97
|
version: '0'
|
|
192
98
|
requirements: []
|
|
193
|
-
rubygems_version:
|
|
99
|
+
rubygems_version: 4.0.3
|
|
194
100
|
specification_version: 4
|
|
195
101
|
summary: Seamless UUID/ULID support for Rails 8 with SQLite
|
|
196
102
|
test_files: []
|