standard_id 0.56.1 → 0.57.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: 076ceacf137b604ea48f42f6955f7eb9786656cab0112adc5967f06d5b6a178b
4
- data.tar.gz: cb179e91df123b9d5c996626a6af219b170faa1e458c6d185dc6ad597f32c044
3
+ metadata.gz: c50961cc2c4446bd495efdebca4ad54a871c371fab3c63e0ff1dd6792b44e1ff
4
+ data.tar.gz: be9ebdaedf84eedfed63f98ade1e8fb37bfc90112b7ba4532aa8d179aefb03b9
5
5
  SHA512:
6
- metadata.gz: e8f41357e84dbe80520836d321dd3f65e1b81329fe50c34e5c005975612fb77a1bf3d919eb87289c6ddf3ba29f95a22bc84ac45c7d1c9815411ae3efcb6161ae
7
- data.tar.gz: 7c9637e8e58f301576d8d5564843b19ae2d58599aa94427cf8ffd3985385badbdb5a9b2b2fe9052fa4ef3a55989b59c1362e5a95e39d933c1cd444062830f0c7
6
+ metadata.gz: 55f8de3f738e3363e452842bcea0b68fbff7798e59039bdac698de7b0b5d1c1fffdb58fe693e60671aa6c9cc2743059fc3d3269e11bde54a84d7bbb23e64b8f5
7
+ data.tar.gz: 9c0e08fdb33cc59058c5be1be6f65b7308bb497738a8a338de1072e5cbd105f59417cbd65c4902e6f937ff53544bbd755cf7e8b8e349b2bd058583cc75eaa2bc
data/CHANGELOG.md CHANGED
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
7
7
 
8
8
  ## [Unreleased]
9
9
 
10
+ ## [0.57.0] - 2026-10-28
11
+
12
+ ### Added
13
+
14
+ - **Migration `20261028000000_add_value_lookup_indexes_to_standard_id_tables`.** Adds a
15
+ `[type, value]` index on `standard_id_identifiers`, which serves the `find_by(value:)` lookup behind
16
+ every sign-in, OTP start, social login and password reset (the only index containing `value` led
17
+ with `account_id`, so each lookup was a sequential scan). Also adds a partial
18
+ `client_application_id` index on `standard_id_refresh_tokens` for `PurgeStaleDynamicClientsJob`.
19
+ Both are built `CONCURRENTLY` on PostgreSQL and are idempotent. Run
20
+ `bin/rails standard_id:install:migrations && bin/rails db:migrate`.
21
+
10
22
  ## [0.56.1] - 2026-10-27
11
23
 
12
24
  ### Fixed
@@ -0,0 +1,73 @@
1
+ class AddValueLookupIndexesToStandardIdTables < ActiveRecord::Migration[8.0]
2
+ # Indexes for two lookups nothing in the schema serves (deep audit
3
+ # DBP-002/DBP-011, 2026-10-27):
4
+ #
5
+ # - standard_id_identifiers [type, value]: every sign-in, OTP start, social
6
+ # login and password reset resolves its identifier with
7
+ # `EmailIdentifier.find_by(value:)` / `PhoneNumberIdentifier.find_by(value:)`
8
+ # (STI adds `type = ?`). The only index containing `value` leads with
9
+ # account_id, so each lookup is a sequential scan. Not unique: the same
10
+ # value may belong to more than one account.
11
+ # - standard_id_refresh_tokens client_application_id: PurgeStaleDynamicClientsJob
12
+ # reads refresh tokens per client (`client.refresh_tokens`) and by
13
+ # `client_application_id IS NOT NULL`. Partial, because tokens not bound
14
+ # to an application (social sign-in refreshes, rows minted before
15
+ # 20261020000000) leave it NULL.
16
+ #
17
+ # At today's table sizes these scans are cheap (Sentry, 14 days: the
18
+ # identifier lookup is p50 2-4ms, p95 9-15ms in every host); the cost grows
19
+ # with every account. Idempotent (if_not_exists / if_exists), CONCURRENTLY
20
+ # on Postgres, and an INVALID index left by a failed concurrent build is
21
+ # dropped and rebuilt, same conventions as 20260924000000.
22
+ disable_ddl_transaction!
23
+
24
+ INDEXES = [
25
+ {
26
+ table: :standard_id_identifiers,
27
+ columns: [:type, :value],
28
+ name: "index_standard_id_identifiers_on_type_and_value"
29
+ },
30
+ {
31
+ table: :standard_id_refresh_tokens,
32
+ columns: :client_application_id,
33
+ name: "index_standard_id_refresh_tokens_on_client_application_id",
34
+ where: "client_application_id IS NOT NULL"
35
+ }
36
+ ].freeze
37
+
38
+ def up
39
+ INDEXES.each do |index|
40
+ if postgres? && invalid_postgres_index?(index[:name])
41
+ remove_index index[:table], name: index[:name], if_exists: true, **concurrent
42
+ end
43
+
44
+ add_index index[:table], index[:columns],
45
+ name: index[:name], where: index[:where], if_not_exists: true, **concurrent
46
+ end
47
+ end
48
+
49
+ def down
50
+ INDEXES.each do |index|
51
+ remove_index index[:table], name: index[:name], if_exists: true, **concurrent
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def postgres?
58
+ connection.adapter_name.downcase.include?("postgres")
59
+ end
60
+
61
+ def concurrent
62
+ postgres? ? { algorithm: :concurrently } : {}
63
+ end
64
+
65
+ def invalid_postgres_index?(name)
66
+ select_value(<<~SQL.squish).present?
67
+ SELECT 1
68
+ FROM pg_index i
69
+ INNER JOIN pg_class c ON c.oid = i.indexrelid
70
+ WHERE c.relname = #{connection.quote(name)} AND NOT i.indisvalid
71
+ SQL
72
+ end
73
+ end
@@ -1,3 +1,3 @@
1
1
  module StandardId
2
- VERSION = "0.56.1"
2
+ VERSION = "0.57.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: standard_id
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.56.1
4
+ version: 0.57.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jaryl Sim
@@ -249,6 +249,7 @@ files:
249
249
  - db/migrate/20261020000000_add_client_application_id_to_standard_id_refresh_tokens.rb
250
250
  - db/migrate/20261020120000_add_registration_access_token_digest_to_standard_id_client_applications.rb
251
251
  - db/migrate/20261022000000_add_signup_source_to_standard_id_identifiers.rb
252
+ - db/migrate/20261028000000_add_value_lookup_indexes_to_standard_id_tables.rb
252
253
  - lib/generators/standard_id/install/install_generator.rb
253
254
  - lib/generators/standard_id/install/templates/standard_id.rb
254
255
  - lib/generators/standard_id/install/templates/standard_id_reference.rb