after_migrate 0.2.2 → 0.2.4

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: 62f5a309584cee52788e0ea45c222648cc58c4db46bc08ce6188c6325f6c62dc
4
- data.tar.gz: e36efca18e936086cdace33a4fe422c2d34f63502ddf01c53090cf8048ed92c6
3
+ metadata.gz: 52bea11a45a6765c9bff5e82d42d527595e7ef6c91e84028ca2dde978d8d527e
4
+ data.tar.gz: 3dcd46239d300faa855998e427585870899a0ea0d013e21fb6eb770ecd5f5be4
5
5
  SHA512:
6
- metadata.gz: 2590c965f71fc07b5171cea88869115516687331138b0a6a20b5c4bdd3008a13be1c7a7382dd8886112a02e076904d57f59e2f24db44bfa23d1c36dd30700b40
7
- data.tar.gz: 4a2f1dd2df2bb18e8f663b1ca150db22a6d4d5474b651ea0ee693129640926266ce77168e370921cab4ac214620a601fe02f6204a97829575ec7e417c944a7d4
6
+ metadata.gz: e21f8c6f9db4d2db100b5ef4c93f87ce0a7b69af5a7da29b79ce91a4a47e585ffdce9f33726929aed3962693ad9afee40418a40dc76a813dc2ee717b5333a59d
7
+ data.tar.gz: d6da80e272cc1895bb753b6fa01b423fc8eb9c3ea4f93d34d691f64743d1269689c3147764d953114957907d36fea5cac8910b03baac009fea08984924c4154b
data/CHANGELOG.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  All notable changes to this project will be documented in this file.
4
4
 
5
+ ## [0.2.4] - 2026-06-01
6
+
7
+ ### Added
8
+ - `config.store_options` for store-specific settings, e.g. `config.store_options_for(:redis)[:client]`
9
+
10
+ ### Changed
11
+ - Store-specific configuration now flows through `config.store_options` while preserving compatibility accessors such as `config.store_path`, `config.redis`, `config.redis_key_prefix`, and `config.redis_ttl`
12
+ - `config.run_id` now defaults from `AFTER_MIGRATE_RUN_ID`, falling back to `default`
13
+
14
+ ## [0.2.3] - 2026-06-01
15
+
16
+ ### Added
17
+ - Redis-backed store via `config.store = :redis` for sharing collected migration tables across processes
18
+ - `config.redis` for passing a Redis client, connection pool, or callable client provider
19
+ - `config.redis_key_prefix` and `config.redis_ttl` for namespacing and expiring Redis store keys
20
+ - Redis store support for run isolation via `config.run_id`
21
+ - Redis store specs for persistence, merging, reset behavior, connection pools, `Redis.new` fallback, and missing-client errors
22
+
23
+ ### Changed
24
+ - Store cache keys now include Redis-specific configuration, so changing Redis store settings rebuilds the active store instance
25
+
5
26
  ## [0.2.2] - 2026-05-31
6
27
 
7
28
  ### Added
@@ -100,5 +100,94 @@ module AfterMigrate
100
100
  end
101
101
  end
102
102
  end
103
+
104
+ class RedisStore < Memory
105
+ attr_reader :key_prefix, :run_id, :ttl
106
+
107
+ def initialize(redis:, key_prefix: 'after_migrate', run_id: nil, ttl: 24 * 60 * 60)
108
+ super()
109
+ @redis = redis
110
+ @key_prefix = key_prefix.to_s
111
+ @run_id = run_id.to_s.presence || 'default'
112
+ @ttl = ttl.to_i
113
+ end
114
+
115
+ def affected_tables
116
+ load_into_memory
117
+ super
118
+ end
119
+
120
+ def merge_tables(schema, table_names)
121
+ return if table_names.blank?
122
+
123
+ with_redis do |redis|
124
+ redis.sadd(index_key, schema)
125
+ redis.sadd(schema_key(schema), table_names.to_a)
126
+ expire_keys(redis, schema)
127
+ end
128
+ merge_into_memory(schema => table_names)
129
+ end
130
+
131
+ def reset!
132
+ super
133
+ with_redis do |redis|
134
+ schemas = redis.smembers(index_key)
135
+ keys = schemas.map { |schema| schema_key(schema) }
136
+ redis.del(*(keys + [index_key])) if keys.any?
137
+ redis.del(index_key) if keys.empty?
138
+ end
139
+ end
140
+
141
+ private
142
+
143
+ def load_into_memory
144
+ with_redis do |redis|
145
+ redis.smembers(index_key).each do |schema|
146
+ merge_into_memory(schema => redis.smembers(schema_key(schema)))
147
+ end
148
+ end
149
+ end
150
+
151
+ def merge_into_memory(schemas)
152
+ schemas.each do |schema, table_names|
153
+ set = @affected_tables.compute_if_absent(schema) { Concurrent::Set.new }
154
+ set.merge(table_names)
155
+ end
156
+ end
157
+
158
+ def index_key
159
+ "#{base_key}:schemas"
160
+ end
161
+
162
+ def schema_key(schema)
163
+ "#{base_key}:schema:#{schema}"
164
+ end
165
+
166
+ def base_key
167
+ "#{key_prefix}:#{run_id}"
168
+ end
169
+
170
+ def expire_keys(redis, schema)
171
+ return unless ttl.positive?
172
+
173
+ redis.expire(index_key, ttl)
174
+ redis.expire(schema_key(schema), ttl)
175
+ end
176
+
177
+ def with_redis(&block)
178
+ redis = resolved_redis
179
+ return redis.with { |connection| block.call(connection) } if redis.respond_to?(:with)
180
+
181
+ block.call(redis)
182
+ end
183
+
184
+ def resolved_redis
185
+ client = @redis.respond_to?(:call) ? @redis.call : @redis
186
+ return client if client
187
+ return Redis.new if defined?(Redis)
188
+
189
+ raise 'AfterMigrate Redis store requires config.redis or the redis gem'
190
+ end
191
+ end
103
192
  end
104
193
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module AfterMigrate
4
- VERSION = '0.2.2'
4
+ VERSION = '0.2.4'
5
5
  end
data/lib/after_migrate.rb CHANGED
@@ -8,7 +8,8 @@ require 'after_migrate/railtie'
8
8
 
9
9
  module AfterMigrate
10
10
  class Configuration
11
- attr_accessor :enabled, :verbose, :vacuum, :analyze, :rake_tasks_enhanced, :defer, :store, :store_path, :run_id
11
+ attr_accessor :enabled, :verbose, :vacuum, :analyze, :rake_tasks_enhanced, :defer,
12
+ :store, :run_id, :store_options
12
13
 
13
14
  def initialize
14
15
  @enabled = true
@@ -18,8 +19,53 @@ module AfterMigrate
18
19
  @rake_tasks_enhanced = true
19
20
  @defer = true
20
21
  @store = :memory
21
- @store_path = 'tmp/after_migrate/affected_tables.json'
22
- @run_id = nil
22
+ @run_id = ENV.fetch('AFTER_MIGRATE_RUN_ID', 'default')
23
+ @store_options = {
24
+ file: {
25
+ path: 'tmp/after_migrate/affected_tables.json'
26
+ },
27
+ redis: {
28
+ client: nil,
29
+ key_prefix: 'after_migrate',
30
+ ttl: 24 * 60 * 60
31
+ }
32
+ }
33
+ end
34
+
35
+ def store_path
36
+ store_options_for(:file)[:path]
37
+ end
38
+
39
+ def store_path=(value)
40
+ store_options_for(:file)[:path] = value
41
+ end
42
+
43
+ def redis
44
+ store_options_for(:redis)[:client]
45
+ end
46
+
47
+ def redis=(value)
48
+ store_options_for(:redis)[:client] = value
49
+ end
50
+
51
+ def redis_key_prefix
52
+ store_options_for(:redis)[:key_prefix]
53
+ end
54
+
55
+ def redis_key_prefix=(value)
56
+ store_options_for(:redis)[:key_prefix] = value
57
+ end
58
+
59
+ def redis_ttl
60
+ store_options_for(:redis)[:ttl]
61
+ end
62
+
63
+ def redis_ttl=(value)
64
+ store_options_for(:redis)[:ttl] = value
65
+ end
66
+
67
+ def store_options_for(store_name)
68
+ store_options[store_name.to_sym] ||= {}
23
69
  end
24
70
  end
25
71
 
@@ -58,21 +104,48 @@ module AfterMigrate
58
104
  end
59
105
 
60
106
  def store
61
- key = [configuration.store.to_s, configuration.store_path.to_s, configuration.run_id.to_s]
62
- @store = nil if @store_key != key
63
- @store_key = key
107
+ @store = nil if @store_key != store_key
108
+ @store_key = store_key
64
109
  @store ||= build_store
65
110
  end
66
111
 
67
112
  private
68
113
 
114
+ def store_key
115
+ [
116
+ configuration.store.to_s,
117
+ configuration.run_id.to_s,
118
+ configuration.store_options_for(configuration.store).hash
119
+ ]
120
+ end
121
+
69
122
  def build_store
70
123
  case configuration.store.to_s
71
124
  when 'file'
72
- Stores::FileStore.new(path: configuration.store_path, run_id: configuration.run_id)
125
+ file_store
126
+ when 'redis'
127
+ redis_store
73
128
  else
74
129
  Stores::Memory.new
75
130
  end
76
131
  end
132
+
133
+ def file_store
134
+ options = configuration.store_options_for(:file)
135
+ Stores::FileStore.new(
136
+ path: options.fetch(:path),
137
+ run_id: options.fetch(:run_id, configuration.run_id)
138
+ )
139
+ end
140
+
141
+ def redis_store
142
+ options = configuration.store_options_for(:redis)
143
+ Stores::RedisStore.new(
144
+ redis: options[:client],
145
+ key_prefix: options.fetch(:key_prefix),
146
+ run_id: options.fetch(:run_id, configuration.run_id),
147
+ ttl: options.fetch(:ttl)
148
+ )
149
+ end
77
150
  end
78
151
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: after_migrate
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.2.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nikolay Moskvin