sqlite_crypto 1.0.3 → 2.0.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 12ea964ba36c09b8c7e9744815cdc00c5a01faf12f1c7f59d35b8b7f8c2745d8
4
- data.tar.gz: f64a0179468f9f080f8cbd73af82cdaaeaa97b32c7dc65bb266332641ea3c602
3
+ metadata.gz: f7728bff2a398f6ed1fe0ce0888055586b7619d45954728240ef32ba33cd1650
4
+ data.tar.gz: fb5715411594706283fd93969b4f97709f468870f428105c1cb5ebdefb8d5c56
5
5
  SHA512:
6
- metadata.gz: c72db90ece738364c5c6474e81adb82a2429b6ec8d41271dadf1666076954ba819c33cbfeacbcc93787cd917aacce5af2b9e381e660f02d348ba8137b3502caf
7
- data.tar.gz: 49ea138522ab69884e191d9c6e26ad32831c14b719b2f787271d6183dc9e0f06ae513eb909d89bb460174f8944b2343aeeb45847a7ba95bfb1c0a0557288a15e
6
+ metadata.gz: 7d0efcd9f607384d1e33ee2c55643408cae5d4a0382885dee40ef6bc0dc142f62d4085cc85f529fd2e76694ffc624651aa7802f85bc0de789716a0b3d7c1aa27
7
+ data.tar.gz: 9954abb7f5068e1b85f9e636ce1abe0d921baa94b9b7394711745bba9bf349655611dcbd925b6ba0fe1c4d1405f2ae434bf863c7234ed864de17b5748b3efadd
data/CHANGELOG.md CHANGED
@@ -5,6 +5,49 @@ 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.1] - 2026-01-14
9
+
10
+ ### Security
11
+ - **CRITICAL:**
12
+ - Fixed regex anchor vulnerability in UUID/ULID validators
13
+ - Fixed action_text-trix XSS vulnerability by updating the version to '>= 2.1.16'
14
+
15
+ ### Changed
16
+ - **Eager configuration validation**: Setting `uuid_version = :v7` on Ruby < 3.3 now fails at boot time with clear error message instead of runtime failure
17
+ - **Namespace cleanup**: `uuid` and `ulid` schema helpers now scoped to `ActiveRecord::Schema` instead of global `Object`
18
+ - **Performance**: Cached Ruby version check in `V7_AVAILABLE` constant (eliminates repeated `Gem::Version` comparisons)
19
+ - **Boot time**: Added lazy loading with `ActiveSupport.on_load(:active_record)` hook for faster Rails initialization
20
+ - **Migration performance**: Memoized primary key type detection to avoid redundant database queries
21
+
22
+ ### Removed
23
+ - Unused `SqliteCrypto::Error` class
24
+ - Unused `SqliteCrypto.load_extensions` placeholder method
25
+
26
+ ### Internal
27
+ - Simplified configuration defaults to reuse `Generators::Uuid.v7_available?` logic
28
+ - Improved code organization and removed dead code
29
+
30
+ ## [2.0.0] - 2026-01-08
31
+
32
+ ### Added
33
+ - **UUIDv7 Support**: Time-sortable UUIDs with better database index performance
34
+ - New configuration option: `config.uuid_version = :v7` (default) or `:v4`
35
+ - Run `rails generate sqlite_crypto:install` to create initializer
36
+ - UUIDv7 requires Ruby 3.3+ (graceful error on older versions)
37
+ - `generates_uuid` now respects the configured version
38
+ - **Configuration System**: `SqliteCrypto.configure` block for gem settings
39
+ - **Install Generator**: `rails generate sqlite_crypto:install` creates initializer
40
+ - **Version Detection**: `SqliteCrypto::Generators::Uuid.v7_available?` helper
41
+
42
+ ### Changed
43
+ - **Default UUID version changed to v7** for new projects (better performance)
44
+ - `generates_uuid` now uses centralized generator instead of direct `SecureRandom.uuid`
45
+
46
+ ### Notes
47
+ - **Ruby 3.1/3.2 users**: Set `config.uuid_version = :v4` in initializer
48
+ - No schema changes required - UUIDv4 and v7 are storage-compatible
49
+ - Existing v4 UUIDs work alongside new v7 UUIDs in same table
50
+
8
51
  ## [1.0.3] - 2025-12-30
9
52
 
10
53
  ### Added
data/README.md CHANGED
@@ -1,281 +1,206 @@
1
- # SQLite crypto
1
+ # SQLite Crypto
2
2
 
3
- [![Version](https://img.shields.io/badge/version-1.0.3-blue.svg)](https://github.com/bart-oz/sqlite_crypto/releases)
3
+ [![Version](https://img.shields.io/badge/version-2.0.0-blue.svg)](https://github.com/bart-oz/sqlite_crypto/releases)
4
4
  [![License](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE.txt)
5
+ [![types supported](https://img.shields.io/badge/types-ULID,_UUIDv7/v4-brightgreen.svg)](https://github.com/bart-oz/sqlite_crypto)
5
6
  [![Tests](https://img.shields.io/badge/tests-passing-brightgreen.svg)](https://github.com/bart-oz/sqlite_crypto/actions)
6
- [![Coverage](https://img.shields.io/badge/coverage-99.06%25-brightgreen.svg)](https://github.com/bart-oz/sqlite_crypto/actions)
7
+ [![Coverage](https://img.shields.io/badge/coverage-98.06%25-brightgreen.svg)](https://github.com/bart-oz/sqlite_crypto/actions)
7
8
  [![Status](https://img.shields.io/badge/status-active-success.svg)](https://github.com/bart-oz/sqlite_crypto)
8
9
 
9
- Seamless UUID and ULID primary key support for Rails with SQLite3.
10
+ ## Overview
10
11
 
11
- ### ID Format Comparison
12
+ Seamless UUID and ULID primary key support for Rails applications using SQLite3. Handles type registration, validation, foreign key detection, and schema generation automatically.
12
13
 
14
+ ```ruby
15
+ create_table :users, id: :uuid do |t|
16
+ t.string :email
17
+ t.timestamps
18
+ end
13
19
  ```
14
- INTEGER: 1, 2, 3, ... (sequential, guessable)
15
- UUID: 550e8400-e29b-41d4-a716-446655440000 (random, 36 chars)
16
- ULID: 01ARZ3NDEKTSV4RRFFQ69G5FAV (time-sortable, 26 chars)
17
- ```
18
-
19
- ## Why Use UUID/ULID Instead of Integer IDs?
20
-
21
- | | **Integer** | **UUID** | **ULID** |
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 |
29
20
 
30
- **Performance testing**: Run `bundle exec rspec --tag performance` to benchmark on your hardware. Specs test scaling from 100 → 10,000 records across inserts, queries, updates, and deletes.
21
+ **Key capabilities:**
22
+ - UUID primary keys (v4 random or v7 time-ordered)
23
+ - ULID primary keys (time-sortable, compact)
24
+ - Automatic foreign key type detection
25
+ - Model-level ID generation
26
+ - Clean schema.rb output
27
+ - Zero external dependencies
31
28
 
32
- ## Gem Compatibility
29
+ ## Compatibility
33
30
 
34
- | Ruby Version | Rails 7.1 | Rails 7.2 | Rails 8.0 | Rails 8.1 |
35
- |--------------|-----------|-----------|-----------|-----------|
36
- | 3.1 | ✅ | ✅ | ❌ | ❌ |
37
- | 3.2 | ✅ | ✅ | ✅ | ✅ |
38
- | 3.3 | ✅ | ✅ | ✅ | ✅ |
39
- | 3.4 | ✅ | ✅ | ✅ | ✅ |
40
- | 4.0 | ✅ | ✅ | ✅ | ✅ |
31
+ **Ruby & Rails:**
41
32
 
42
- **Recommended**: Ruby 3.3+ with Rails 8.0+
33
+ | | Rails 7.1 | Rails 7.2 | Rails 8.0 | Rails 8.1 |
34
+ |-------|-----------|-----------|-----------|-----------|
35
+ | Ruby 3.1 | ✓ | ✓ | - | - |
36
+ | Ruby 3.2 | ✓ | ✓ | ✓ | ✓ |
37
+ | Ruby 3.3 | ✓ | ✓ | ✓ | ✓ |
38
+ | Ruby 3.4 | ✓ | ✓ | ✓ | ✓ |
39
+ | Ruby 4.0 | ✓ | ✓ | ✓ | ✓ |
43
40
 
44
- **Support Policy**: Actively maintained with updates for new Ruby and Rails versions.
41
+ **UUID Versions:**
45
42
 
46
- ## Features
43
+ | Version | Ruby 3.1/3.2 | Ruby 3.3+ |
44
+ |---------|--------------|-----------|
45
+ | v4 (random) | ✓ | ✓ |
46
+ | v7 (time-ordered) | - | ✓ |
47
47
 
48
- * UUID primary keys with automatic validation
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
48
+ **Database:** SQLite3
55
49
 
56
50
  ## Installation
57
51
 
58
- Add to your Gemfile:
59
-
60
52
  ```ruby
53
+ # Gemfile
61
54
  gem "sqlite_crypto"
62
55
  ```
63
56
 
64
- Then run:
65
-
66
57
  ```bash
67
58
  bundle install
59
+ rails generate sqlite_crypto:install
68
60
  ```
69
61
 
70
- That's it! No generators or configuration needed.
62
+ The generator creates `config/initializers/sqlite_crypto.rb` for configuration.
71
63
 
72
- ## Usage
64
+ ## Configuration
73
65
 
74
- ### UUID Primary Keys
66
+ **1. Configure UUID Version**
75
67
 
76
68
  ```ruby
77
- class CreateUsers < ActiveRecord::Migration[8.1]
78
- def change
79
- create_table :users, id: :uuid do |t|
80
- t.string :email
81
- t.string :name
82
- t.timestamps
83
- end
84
- end
69
+ # config/initializers/sqlite_crypto.rb
70
+ SqliteCrypto.configure do |config|
71
+ config.uuid_version = :v7 # or :v4
85
72
  end
86
73
  ```
87
74
 
88
- ### ULID Primary Keys
75
+ The gem automatically selects a default based on your Ruby version (v7 for Ruby 3.3+, v4 otherwise).
76
+
77
+ **2. Create Tables with UUID/ULID**
89
78
 
90
79
  ```ruby
91
- class CreatePosts < ActiveRecord::Migration[8.1]
80
+ class CreateUsers < ActiveRecord::Migration[8.0]
92
81
  def change
93
- create_table :posts, id: :ulid do |t|
94
- t.string :title
95
- t.text :content
82
+ create_table :users, id: :uuid do |t|
83
+ t.string :email
96
84
  t.timestamps
97
85
  end
98
86
  end
99
87
  end
100
88
  ```
101
89
 
102
- ### UUID/ULID Columns
90
+ **3. Use Your Models**
103
91
 
104
92
  ```ruby
105
- class AddTrackingIds < ActiveRecord::Migration[8.1]
106
- def change
107
- change_table :orders do |t|
108
- t.uuid :external_id
109
- t.ulid :tracking_number
110
- end
111
- end
112
- end
93
+ user = User.create!(email: "test@example.com")
94
+ user.id # => "018d3f91-8f4a-7000-9e7b-4a5c8d2e1f3a"
113
95
  ```
114
96
 
115
- ### Foreign Keys (Automatic Detection)
97
+ ## Usage
98
+
99
+ **Primary Keys**
116
100
 
117
- The gem automatically detects UUID/ULID primary keys and creates matching foreign keys:
101
+ Create tables with UUID or ULID primary keys:
118
102
 
119
103
  ```ruby
120
- # Users table has UUID primary key
104
+ # UUID
121
105
  create_table :users, id: :uuid do |t|
122
- t.string :name
106
+ t.string :email
123
107
  end
124
108
 
125
- # Posts automatically get varchar(36) user_id foreign key
126
- create_table :posts do |t|
127
- t.references :user # Automatically creates varchar(36) foreign key!
109
+ # ULID
110
+ create_table :posts, id: :ulid do |t|
128
111
  t.string :title
129
112
  end
130
113
  ```
131
114
 
132
- Works with ULID too:
115
+ **Foreign Keys**
116
+
117
+ Foreign key types are automatically detected from parent tables:
133
118
 
134
119
  ```ruby
135
- # Categories table has ULID primary key
136
- create_table :categories, id: :ulid do |t|
120
+ create_table :users, id: :uuid do |t|
137
121
  t.string :name
138
122
  end
139
123
 
140
- # Articles automatically get varchar(26) category_id foreign key
141
- create_table :articles do |t|
142
- t.references :category # Automatically creates varchar(26) foreign key!
143
- t.string :title
144
- end
145
- ```
146
-
147
- ### Custom Table Names
148
-
149
- Use `:to_table` option for non-standard table names:
150
-
151
- ```ruby
152
124
  create_table :posts do |t|
153
- t.references :author, to_table: :users # Uses users table's UUID type
125
+ t.references :user # Automatically varchar(36)
154
126
  t.string :title
155
127
  end
156
128
  ```
157
129
 
158
- ### Model Extensions (Auto-Generate UUIDs/ULIDs)
130
+ **Model-Level Generation**
159
131
 
160
- Automatically generate UUID or ULID values for any column:
132
+ Generate UUIDs or ULIDs for any column:
161
133
 
162
134
  ```ruby
163
135
  class User < ApplicationRecord
164
- # Generate UUID for 'token' column on create
165
- generates_uuid :token
166
- end
167
-
168
- class Order < ApplicationRecord
169
- # Generate ULID for 'reference' column with uniqueness validation
170
- generates_ulid :reference, unique: true
136
+ generates_uuid :api_token
137
+ generates_ulid :tracking_id, unique: true
171
138
  end
172
- ```
173
-
174
- **Features:**
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
180
-
181
- **Example migration:**
182
139
 
183
- ```ruby
184
- class AddTokenToUsers < ActiveRecord::Migration[8.1]
185
- def change
186
- add_column :users, :token, :string, limit: 36
187
- add_index :users, :token, unique: true
188
- end
189
- end
140
+ user = User.create!
141
+ user.api_token # => "550e8400-e29b-41d4-a716-446655440000"
142
+ user.tracking_id # => "01ARZ3NDEKTSV4RRFFQ69G5FAV"
190
143
  ```
191
144
 
192
- ### Schema Output
193
-
194
- Your `db/schema.rb` will be clean and readable:
195
-
196
- ```ruby
197
- create_table "users", id: :uuid, force: :cascade do |t|
198
- t.string "email"
199
- t.timestamps
200
- end
145
+ ## ID Types
201
146
 
202
- create_table "posts", force: :cascade do |t|
203
- t.string "user_id", limit: 36 # Clean foreign key
204
- t.string "title"
205
- end
206
- ```
147
+ **Characteristics**
207
148
 
208
- ## How It Works
149
+ | Type | Length | Format | Ordering | Ruby Version |
150
+ |------|--------|--------|----------|--------------|
151
+ | Integer | 8 bytes | Sequential numbers | Sequential | Any |
152
+ | UUIDv4 | 36 chars | `xxxxxxxx-xxxx-4xxx-...` | Random | 3.1+ |
153
+ | UUIDv7 | 36 chars | `xxxxxxxx-xxxx-7xxx-...` | Time-based | 3.3+ |
154
+ | ULID | 26 chars | `01ARZ3NDEK...` | Time-based | 3.1+ |
209
155
 
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
156
+ **Performance**
216
157
 
217
- ## Requirements
158
+ Benchmarks with 10,000 records on SQLite3:
218
159
 
219
- - Rails 7.1+ (tested on 7.1, 7.2, 8.0, 8.1)
220
- - Ruby 3.1+
221
- - SQLite3
160
+ | Type | Insert | Query | Index Size |
161
+ |------|--------|-------|------------|
162
+ | Integer | 1.00x | 1.00x | 100% |
163
+ | UUIDv4 | 1.02x | 1.03x | 145% |
164
+ | UUIDv7 | 1.01x | 1.03x | 145% |
165
+ | ULID | 1.05x | 1.04x | 130% |
222
166
 
223
- ## Migrating Existing Apps
167
+ Run your own: `bundle exec rspec --tag performance`
224
168
 
225
- ### New Tables Only (Recommended)
169
+ ## Advanced Usage
226
170
 
227
- The safest approach is to use UUID/ULID only for new tables:
171
+ **Non-Standard Table Names**
228
172
 
229
173
  ```ruby
230
- # Existing tables keep integer IDs
231
- # users: id (integer)
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
238
- end
239
-
240
- create_table :sessions, id: :ulid do |t|
241
- t.references :user # Still integer
242
- t.string :token
174
+ create_table :posts do |t|
175
+ t.references :author, to_table: :users
243
176
  end
244
177
  ```
245
178
 
246
- ## Advanced Patterns
247
-
248
- ### ID Prefixes (Optional)
249
-
250
- For Stripe-style prefixed IDs (`inv_`, `usr_`, etc.), add to your models:
179
+ **Mixed ID Types**
251
180
 
252
181
  ```ruby
253
- class Invoice < ApplicationRecord
254
- before_create :generate_prefixed_id
182
+ create_table :users, id: :uuid do |t|
183
+ t.string :email
184
+ end
255
185
 
256
- private
186
+ create_table :sessions, id: :ulid do |t|
187
+ t.references :user
188
+ end
257
189
 
258
- def generate_prefixed_id
259
- self.id = "inv_#{SecureRandom.uuid}" if id.nil?
260
- end
190
+ create_table :logs do |t| # Integer ID
191
+ t.text :message
261
192
  end
262
193
  ```
263
194
 
264
- ### Mixing Types
195
+ ## Migrating Existing Apps
265
196
 
266
- You can use different primary key types in the same app:
197
+ Add UUID/ULID to new tables while keeping integer IDs on existing tables:
267
198
 
268
199
  ```ruby
269
- create_table :users, id: :uuid do |t|
270
- t.string :email
271
- end
272
-
273
- create_table :sessions, id: :ulid do |t|
274
- t.string :token
275
- end
276
-
277
- create_table :logs do |t| # Standard integer ID
278
- t.string :message
200
+ # Existing tables unchanged
201
+ create_table :invoices, id: :uuid do |t|
202
+ t.references :user # Detects integer from users table
203
+ t.decimal :amount
279
204
  end
280
205
  ```
281
206
 
@@ -289,8 +214,8 @@ bundle exec standardrb
289
214
 
290
215
  ## Contributing
291
216
 
292
- See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
217
+ Bug reports and pull requests are welcome on GitHub at https://github.com/bart-oz/sqlite_crypto.
293
218
 
294
219
  ## License
295
220
 
296
- MIT License - see [LICENSE.txt](LICENSE.txt)
221
+ The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SqliteCrypto
4
+ class Configuration
5
+ attr_reader :uuid_version
6
+
7
+ def initialize
8
+ # Default to v7 on Ruby 3.3+, v4 on older versions
9
+ @uuid_version = Generators::Uuid.v7_available? ? :v7 : :v4
10
+ end
11
+
12
+ def uuid_version=(version)
13
+ validate_uuid_version!(version)
14
+ @uuid_version = version
15
+ end
16
+
17
+ private
18
+
19
+ def validate_uuid_version!(version)
20
+ valid_versions = [:v4, :v7]
21
+ unless valid_versions.include?(version)
22
+ raise ArgumentError, "Invalid UUID version: #{version}. Must be one of #{valid_versions.join(", ")}"
23
+ end
24
+
25
+ if version == :v7 && !Generators::Uuid.v7_available?
26
+ raise ArgumentError,
27
+ "UUIDv7 requires Ruby 3.3+. Current: #{RUBY_VERSION}. " \
28
+ "Use config.uuid_version = :v4 or upgrade Ruby."
29
+ end
30
+ end
31
+ end
32
+ 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
+ V7_AVAILABLE = (Gem::Version.new(RUBY_VERSION) >= MINIMUM_RUBY_FOR_V7)
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
+ V7_AVAILABLE
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
@@ -32,6 +32,11 @@ module SqliteCrypto
32
32
  private
33
33
 
34
34
  def detect_primary_key_type(table_name)
35
+ @pk_type_cache ||= {}
36
+ @pk_type_cache[table_name] ||= fetch_primary_key_type(table_name)
37
+ end
38
+
39
+ def fetch_primary_key_type(table_name)
35
40
  conn = @conn || @base || (respond_to?(:connection) ? connection : nil)
36
41
  return nil unless conn&.table_exists?(table_name)
37
42
 
@@ -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] ||= SecureRandom.uuid
12
+ self[attribute] ||= SqliteCrypto::Generators::Uuid.generate
13
13
  end
14
14
 
15
15
  validates attribute, uniqueness: true if unique
@@ -10,13 +10,17 @@ module SqliteCrypto
10
10
  config.sqlite_crypto = ActiveSupport::OrderedOptions.new
11
11
 
12
12
  initializer "sqlite_crypto.register_types" do
13
- ActiveRecord::Type.register(:uuid, SqliteCrypto::Type::Uuid, adapter: :sqlite3)
14
- ActiveRecord::Type.register(:ulid, SqliteCrypto::Type::ULID, adapter: :sqlite3)
13
+ ActiveSupport.on_load(:active_record) do
14
+ ActiveRecord::Type.register(:uuid, SqliteCrypto::Type::Uuid, adapter: :sqlite3)
15
+ ActiveRecord::Type.register(:ulid, SqliteCrypto::Type::ULID, adapter: :sqlite3)
16
+ end
15
17
  end
16
18
 
17
19
  initializer "sqlite_crypto.native_types" do
18
- require "active_record/connection_adapters/sqlite3_adapter"
19
- ActiveRecord::ConnectionAdapters::SQLite3Adapter.prepend(SqliteCrypto::Sqlite3AdapterExtension)
20
+ ActiveSupport.on_load(:active_record) do
21
+ require "active_record/connection_adapters/sqlite3_adapter"
22
+ ActiveRecord::ConnectionAdapters::SQLite3Adapter.prepend(SqliteCrypto::Sqlite3AdapterExtension)
23
+ end
20
24
  end
21
25
 
22
26
  initializer "sqlite_crypto.schema_dumper", after: "active_record.initialize_database" do
@@ -13,5 +13,7 @@ module SqliteCrypto
13
13
  end
14
14
  end
15
15
 
16
- # Extend the main object context for schema.rb loading
17
- Object.include(SqliteCrypto::SchemaDefinitions)
16
+ # Extend ActiveRecord::Schema context for schema.rb loading (not global Object)
17
+ if defined?(ActiveRecord::Schema)
18
+ ActiveRecord::Schema.include(SqliteCrypto::SchemaDefinitions)
19
+ end
@@ -5,6 +5,8 @@ require "sqlite_crypto/type/base"
5
5
  module SqliteCrypto
6
6
  module Type
7
7
  class ULID < Base
8
+ ULID_PATTERN = /\A[0-7][0-9A-Z]{25}\z/i
9
+
8
10
  def type
9
11
  :ulid
10
12
  end
@@ -12,7 +14,7 @@ module SqliteCrypto
12
14
  private
13
15
 
14
16
  def valid?(value)
15
- value.match?(/^[0-7][0-9A-Z]{25}$/i)
17
+ ULID_PATTERN.match?(value)
16
18
  end
17
19
  end
18
20
  end
@@ -5,6 +5,8 @@ require "sqlite_crypto/type/base"
5
5
  module SqliteCrypto
6
6
  module Type
7
7
  class Uuid < Base
8
+ UUID_PATTERN = /\A[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\z/i
9
+
8
10
  def type
9
11
  :uuid
10
12
  end
@@ -12,7 +14,7 @@ module SqliteCrypto
12
14
  private
13
15
 
14
16
  def valid?(value)
15
- value.match?(/^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i)
17
+ UUID_PATTERN.match?(value)
16
18
  end
17
19
  end
18
20
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SqliteCrypto
4
- VERSION = "1.0.3"
4
+ VERSION = "2.0.1"
5
5
  RUBY_MINIMUM_VERSION = "3.1.0"
6
6
  RAILS_MINIMUM_VERSION = "7.1.0"
7
7
  end
data/lib/sqlite_crypto.rb CHANGED
@@ -1,14 +1,25 @@
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
- class Error < StandardError; end
11
+ class << self
12
+ def configuration
13
+ @configuration ||= Configuration.new
14
+ end
15
+ alias_method :config, :configuration
10
16
 
11
- def self.load_extensions
12
- # Placeholder for future extension loading logic
17
+ def configure
18
+ yield(configuration)
19
+ end
20
+
21
+ def reset_configuration!
22
+ @configuration = Configuration.new
23
+ end
13
24
  end
14
25
  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: 1.0.3
4
+ version: 2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - BartOz
@@ -51,8 +51,10 @@ dependencies:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
53
  version: '1.0'
54
- description: A lightweight, modular gem providing transparent UUID/ULID primary key
55
- configuration for Rails applications using SQLite.
54
+ description: UUID and ULID primary key support for Rails with SQLite3. Provides automatic
55
+ type registration, validation, foreign key detection, and clean schema generation.
56
+ Supports UUIDv4 (random), UUIDv7 (time-ordered), and ULID (compact, time-sortable)
57
+ with zero external dependencies.
56
58
  email:
57
59
  - bartek.ozdoba@gmail.com
58
60
  executables: []
@@ -63,6 +65,10 @@ files:
63
65
  - LICENSE.txt
64
66
  - README.md
65
67
  - lib/sqlite_crypto.rb
68
+ - lib/sqlite_crypto/configuration.rb
69
+ - lib/sqlite_crypto/generators/install_generator.rb
70
+ - lib/sqlite_crypto/generators/templates/initializer.rb.tt
71
+ - lib/sqlite_crypto/generators/uuid.rb
66
72
  - lib/sqlite_crypto/migration_helpers.rb
67
73
  - lib/sqlite_crypto/model_extensions.rb
68
74
  - lib/sqlite_crypto/railtie.rb
@@ -94,5 +100,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
94
100
  requirements: []
95
101
  rubygems_version: 4.0.3
96
102
  specification_version: 4
97
- summary: Seamless UUID/ULID support for Rails 8 with SQLite
103
+ summary: UUID (v4/v7) and ULID primary keys for Rails + SQLite3
98
104
  test_files: []