sqlite_crypto 2.1.0 → 2.3.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 31acfd48736d083cd848127dcffbfefc620be1e3694e3f69e19b0d0c09d3aad9
4
- data.tar.gz: 59daf83e4a32c19a97e7dc2a311e395a46a70f40222963c9e271575d82ac4c04
3
+ metadata.gz: 5092437393d977d0bc5bd3ab75fec48c2518ff2ab0296bf6bb1abc42cdd1dfd9
4
+ data.tar.gz: 85e2ba284a68ee0cdf113895771788e5d60ee324631672f414f96756f08c5a9c
5
5
  SHA512:
6
- metadata.gz: '03968e8bd73633bf3a5150a46b2fe72f84a11ece19f735c4be8406dd954a3168e38cca89394b547e8e8d3f728e6d211933b1fd13792a5bdcebdfc522287547c8'
7
- data.tar.gz: bbbd062951f49856e4b74cd90c4bb8a67c5d2dab2547bebffb40643b1eb4b14c0a6c0f269ed8e53356b3e09922541d2c8c95fdc8d64a0e1aa0d6d82d09a752e7
6
+ metadata.gz: 66a702bb87cf9ebb082a4f0a727df6fd3f8232e47295cf5d56d3e7a03d7604c29d7692ddd556753a4cf9a0e1076885273b748c65e67adede97f0cc8e44e7718e
7
+ data.tar.gz: 2d6c01a90e63dfd79947c010de863c0b0180c83056d5c72a7d9a6dd0a3e901c5ecebb6ff91c2c78c589e22a108b3183d9d382be612346ac5f3c23262fffd342d
data/CHANGELOG.md CHANGED
@@ -5,6 +5,38 @@ 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.3.0] - 2026-07-15
9
+
10
+ ### Security
11
+ - Refreshed lockfiles, picking up fixes for transitive CVEs in `sqlite3`, `nokogiri`, `json`, `crass`, and `concurrent-ruby`
12
+
13
+ ### Changed
14
+ - Updated `.ruby-version` from `4.0.3` to `4.0.6`
15
+ - CI: cache bundler installs per Rails version, run `bundler-audit` from the bundle, and drop the empty coverage-threshold step
16
+ - Narrowed the runtime dependency from `rails` to `activerecord` + `railties`, dropping the `action_text-trix` pin it required
17
+ - **Tightened ULID validation**: rejects `I`, `L`, `O`, `U`, which Crockford base32 excludes
18
+
19
+ ### Fixed
20
+ - **Reads no longer raise on malformed legacy IDs**: `Type::Base#deserialize` returns stored values as-is instead of re-validating them, so a corrupted row no longer crashes every read of it. Writes (`#cast`/`#serialize`) still validate strictly
21
+ - **Primary-key type cache invalidation**: `_sqlite_crypto_pk_type` now clears on `reset_column_information` instead of going stale after a migration
22
+ - **Adapter guard for auto ID generation**: primary-key detection now only applies to SQLite3 connections, not any string(36/26) primary key regardless of adapter
23
+ - **`references`/`belongs_to` with `to_table` and `foreign_key: true`**: the foreign key now targets the correct table instead of the pluralized association name
24
+
25
+ ## [2.2.0] - 2026-05-08
26
+
27
+ ### Added
28
+ - **Theme-aware README logo**: Added dark-mode/light-mode logo switching via `<picture>` in `README.md`
29
+ - **Shared ID type mapping module**: Added `SqliteCrypto::IdTypes` to centralize UUID/ULID limit and type detection logic
30
+ - Unit specs for `SqliteCrypto::IdTypes`
31
+
32
+ ### Changed
33
+ - Refactored schema dumper, migration helpers, model extensions, and SQLite adapter extension to use `SqliteCrypto::IdTypes`
34
+ - Updated `.ruby-version` from `4.0.0` to `4.0.3`
35
+ - Refreshed README badges and compatibility notes
36
+
37
+ ### Fixed
38
+ - Removed repeated migration fixture loading warning by replacing `load` with `require_relative` in migration integration spec
39
+
8
40
  ## [2.1.0] - 2026-03-22
9
41
 
10
42
  ### Added
@@ -156,4 +188,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
156
188
  ### Fixed
157
189
  - Rails version compatibility for migrations (supports Rails 7.1 through 8.1)
158
190
  - Schema dumper prepend timing by loading sqlite3_adapter explicitly
159
- - ULID foreign key detection with proper table name pluralization
191
+ - ULID foreign key detection with proper table name pluralization
data/README.md CHANGED
@@ -1,11 +1,28 @@
1
- # SQLite Crypto
2
-
3
- [![Version](https://img.shields.io/badge/version-2.0.2-blue.svg)](https://github.com/bart-oz/sqlite_crypto/releases)
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)
6
- [![Tests](https://img.shields.io/badge/tests-passing-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)
8
- [![Status](https://img.shields.io/badge/status-active-success.svg)](https://github.com/bart-oz/sqlite_crypto)
1
+ <p align="center">
2
+ <picture>
3
+ <source media="(prefers-color-scheme: dark)" srcset=".github/workflows/logo_dark.svg">
4
+ <source media="(prefers-color-scheme: light)" srcset=".github/workflows/logo_light.svg">
5
+ <img alt="sqlite_crypto logo" src=".github/workflows/logo_light.svg" width="220">
6
+ </picture>
7
+ </p>
8
+
9
+ <p align="center">
10
+ <a href="https://github.com/bart-oz/sqlite_crypto/releases">
11
+ <img src="https://img.shields.io/badge/version-2.3.0-blue.svg" alt="Version">
12
+ </a>
13
+ <a href="LICENSE.txt">
14
+ <img src="https://img.shields.io/badge/license-MIT-blue.svg" alt="License">
15
+ </a>
16
+ <a href="https://github.com/bart-oz/sqlite_crypto">
17
+ <img src="https://img.shields.io/badge/types-ULID,_UUIDv7/v4-brightgreen.svg" alt="Types supported">
18
+ </a>
19
+ <a href="https://github.com/bart-oz/sqlite_crypto/actions/workflows/ci.yml">
20
+ <img src="https://github.com/bart-oz/sqlite_crypto/actions/workflows/ci.yml/badge.svg" alt="Tests">
21
+ </a>
22
+ <a href="https://github.com/bart-oz/sqlite_crypto">
23
+ <img src="https://img.shields.io/badge/status-active-success.svg" alt="Status">
24
+ </a>
25
+ </p>
9
26
 
10
27
  ## Overview
11
28
 
@@ -24,11 +41,11 @@ end
24
41
  - Automatic foreign key type detection
25
42
  - Model-level ID generation
26
43
  - Clean schema.rb output
27
- - Zero external dependencies
44
+ - Lightweight runtime dependencies (`activerecord`, `railties`, `sqlite3`, `ulid` — no full `rails` metagem)
28
45
 
29
46
  ## Compatibility
30
47
 
31
- **Ruby & Rails:**
48
+ **Ruby & Rails tested in CI:**
32
49
 
33
50
  | | Rails 7.1 | Rails 7.2 | Rails 8.0 | Rails 8.1 |
34
51
  |-------|-----------|-----------|-----------|-----------|
@@ -38,6 +55,11 @@ end
38
55
  | Ruby 3.4 | ✓ | ✓ | ✓ | ✓ |
39
56
  | Ruby 4.0 | ✓ | ✓ | ✓ | ✓ |
40
57
 
58
+ **Upstream lifecycle note (as of 2026-07-15):**
59
+ - Ruby 3.1 is EOL; Ruby 3.2 is EOL. Latest stable Ruby is 4.0.6.
60
+ - Rails 7.1 is EOL.
61
+ - Rails 7.2 is security-fixes-only; Rails 8.0 and 8.1 are actively supported.
62
+
41
63
  **UUID Versions:**
42
64
 
43
65
  | Version | Ruby 3.1/3.2 | Ruby 3.3+ |
@@ -237,4 +259,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/bart-o
237
259
 
238
260
  ## License
239
261
 
240
- The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
262
+ The gem is available as open source under the terms of the [MIT License](LICENSE.txt).
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module SqliteCrypto
4
+ module IdTypes
5
+ UUID_LENGTH = 36
6
+ ULID_LENGTH = 26
7
+
8
+ TYPE_TO_LIMIT = {
9
+ uuid: UUID_LENGTH,
10
+ ulid: ULID_LENGTH
11
+ }.freeze
12
+ LIMIT_TO_TYPE = TYPE_TO_LIMIT.invert.freeze
13
+
14
+ module_function
15
+
16
+ def string_limit_for(type)
17
+ TYPE_TO_LIMIT[type]
18
+ end
19
+
20
+ def type_from_string_limit(limit)
21
+ LIMIT_TO_TYPE[limit]
22
+ end
23
+
24
+ def type_from_sql_type(sql_type)
25
+ case sql_type.to_s.downcase
26
+ when "varchar(#{UUID_LENGTH})", "uuid" then :uuid
27
+ when "varchar(#{ULID_LENGTH})", "ulid" then :ulid
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_record/connection_adapters/sqlite3_adapter"
4
+ require "sqlite_crypto/id_types"
4
5
 
5
6
  module SqliteCrypto
6
7
  module MigrationHelpers
@@ -17,11 +18,17 @@ module SqliteCrypto
17
18
  module References
18
19
  def references(*args, **options)
19
20
  ref_name = args.first
20
- ref_table = options.delete(:to_table) || ref_name.to_s.pluralize
21
+ explicit_to_table = options.delete(:to_table)
22
+ ref_table = explicit_to_table || ref_name.to_s.pluralize
21
23
 
22
24
  if (primary_key_type = detect_primary_key_type(ref_table))
23
25
  options[:type] ||= :string
24
- options[:limit] ||= (primary_key_type == :uuid) ? 36 : 26
26
+ options[:limit] ||= IdTypes.string_limit_for(primary_key_type)
27
+ end
28
+
29
+ if explicit_to_table && options[:foreign_key]
30
+ fk_options = options[:foreign_key].is_a?(Hash) ? options[:foreign_key] : {}
31
+ options[:foreign_key] = fk_options.reverse_merge(to_table: explicit_to_table)
25
32
  end
26
33
 
27
34
  super
@@ -43,10 +50,7 @@ module SqliteCrypto
43
50
  pk_column = find_primary_key_column(table_name, conn)
44
51
  return nil unless pk_column
45
52
 
46
- case pk_column.sql_type.downcase
47
- when "varchar(36)", "uuid" then :uuid
48
- when "varchar(26)", "ulid" then :ulid
49
- end
53
+ IdTypes.type_from_sql_type(pk_column.sql_type)
50
54
  end
51
55
 
52
56
  def find_primary_key_column(table_name, conn)
@@ -1,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "ulid"
4
+ require "sqlite_crypto/id_types"
4
5
 
5
6
  module SqliteCrypto
6
7
  module ModelExtensions
@@ -49,11 +50,17 @@ module SqliteCrypto
49
50
  @_sqlite_crypto_pk_type = _detect_sqlite_crypto_pk_type
50
51
  end
51
52
 
53
+ def reset_column_information
54
+ remove_instance_variable(:@_sqlite_crypto_pk_type) if defined?(@_sqlite_crypto_pk_type)
55
+ super
56
+ end
57
+
52
58
  private
53
59
 
54
60
  def _detect_sqlite_crypto_pk_type
55
61
  return nil if abstract_class?
56
62
  return nil unless table_exists?
63
+ return nil unless connection.adapter_name == "SQLite"
57
64
 
58
65
  pk = primary_key
59
66
  return nil unless pk
@@ -62,10 +69,7 @@ module SqliteCrypto
62
69
  return nil unless column
63
70
  return nil unless column.type == :string
64
71
 
65
- case column.limit
66
- when 36 then :uuid
67
- when 26 then :ulid
68
- end
72
+ IdTypes.type_from_string_limit(column.limit)
69
73
  rescue ActiveRecord::StatementInvalid
70
74
  nil
71
75
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "sqlite_crypto/id_types"
4
+
3
5
  module SqliteCrypto
4
6
  module SchemaDumper
5
7
  private
@@ -7,11 +9,10 @@ module SqliteCrypto
7
9
  def column_spec_for_primary_key(column)
8
10
  return super unless column.name == "id" && column.type == :string
9
11
 
10
- case column.limit
11
- when 36 then {id: :uuid}
12
- when 26 then {id: :ulid}
13
- else super
14
- end
12
+ primary_key_type = IdTypes.type_from_string_limit(column.limit)
13
+ return super unless primary_key_type
14
+
15
+ {id: primary_key_type}
15
16
  end
16
17
  end
17
18
  end
@@ -1,11 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "sqlite_crypto/id_types"
4
+
3
5
  module SqliteCrypto
4
6
  module Sqlite3AdapterExtension
5
7
  def native_database_types
6
8
  super.merge(
7
- uuid: {name: "varchar", limit: 36},
8
- ulid: {name: "varchar", limit: 26}
9
+ uuid: {name: "varchar", limit: IdTypes::UUID_LENGTH},
10
+ ulid: {name: "varchar", limit: IdTypes::ULID_LENGTH}
9
11
  )
10
12
  end
11
13
  end
@@ -4,8 +4,7 @@ module SqliteCrypto
4
4
  module Type
5
5
  class Base < ActiveRecord::Type::String
6
6
  def deserialize(value)
7
- return if value.nil?
8
- cast(value)
7
+ value&.to_s
9
8
  end
10
9
 
11
10
  def cast(value)
@@ -25,7 +24,7 @@ module SqliteCrypto
25
24
  end
26
25
 
27
26
  def changed_in_place?(raw_old_value, new_value)
28
- cast(raw_old_value) != cast(new_value)
27
+ deserialize(raw_old_value) != cast(new_value)
29
28
  end
30
29
 
31
30
  private
@@ -5,7 +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
8
+ # Crockford base32 excludes I, L, O, U to avoid confusion with 1, 0.
9
+ ULID_PATTERN = /\A[0-7][0-9A-HJKMNP-TV-Z]{25}\z/i
9
10
 
10
11
  def type
11
12
  :ulid
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module SqliteCrypto
4
- VERSION = "2.1.0"
4
+ VERSION = "2.3.0"
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
@@ -5,6 +5,7 @@ require "sqlite_crypto/configuration"
5
5
  require "sqlite_crypto/railtie" if defined?(Rails)
6
6
  require "sqlite_crypto/schema_dumper" if defined?(ActiveRecord)
7
7
  require "sqlite_crypto/schema_definitions"
8
+ require "sqlite_crypto/id_types"
8
9
  require "sqlite_crypto/generators/uuid"
9
10
 
10
11
  module SqliteCrypto
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: 2.1.0
4
+ version: 2.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - BartOz
@@ -10,7 +10,21 @@ cert_chain: []
10
10
  date: 1980-01-02 00:00:00.000000000 Z
11
11
  dependencies:
12
12
  - !ruby/object:Gem::Dependency
13
- name: rails
13
+ name: activerecord
14
+ requirement: !ruby/object:Gem::Requirement
15
+ requirements:
16
+ - - ">="
17
+ - !ruby/object:Gem::Version
18
+ version: 7.1.0
19
+ type: :runtime
20
+ prerelease: false
21
+ version_requirements: !ruby/object:Gem::Requirement
22
+ requirements:
23
+ - - ">="
24
+ - !ruby/object:Gem::Version
25
+ version: 7.1.0
26
+ - !ruby/object:Gem::Dependency
27
+ name: railties
14
28
  requirement: !ruby/object:Gem::Requirement
15
29
  requirements:
16
30
  - - ">="
@@ -53,8 +67,7 @@ dependencies:
53
67
  version: '1.0'
54
68
  description: UUID and ULID primary key support for Rails with SQLite3. Provides automatic
55
69
  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.
70
+ Supports UUIDv4 (random), UUIDv7 (time-ordered), and ULID (compact, time-sortable).
58
71
  email:
59
72
  - bartek.ozdoba@gmail.com
60
73
  executables: []
@@ -69,6 +82,7 @@ files:
69
82
  - lib/sqlite_crypto.rb
70
83
  - lib/sqlite_crypto/configuration.rb
71
84
  - lib/sqlite_crypto/generators/uuid.rb
85
+ - lib/sqlite_crypto/id_types.rb
72
86
  - lib/sqlite_crypto/migration_helpers.rb
73
87
  - lib/sqlite_crypto/model_extensions.rb
74
88
  - lib/sqlite_crypto/railtie.rb
@@ -98,7 +112,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
98
112
  - !ruby/object:Gem::Version
99
113
  version: '0'
100
114
  requirements: []
101
- rubygems_version: 4.0.3
115
+ rubygems_version: 4.0.16
102
116
  specification_version: 4
103
117
  summary: UUID (v4/v7) and ULID primary keys for Rails + SQLite3
104
118
  test_files: []