fixture_kit 0.14.0 → 0.16.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/lib/fixture_kit/cache.rb +24 -67
- data/lib/fixture_kit/coder.rb +21 -0
- data/lib/fixture_kit/coders/active_record_coder.rb +139 -0
- data/lib/fixture_kit/configuration.rb +7 -2
- data/lib/fixture_kit/file_cache.rb +23 -6
- data/lib/fixture_kit/memory_cache.rb +5 -5
- data/lib/fixture_kit/runner.rb +4 -0
- data/lib/fixture_kit/version.rb +1 -1
- data/lib/fixture_kit.rb +2 -1
- metadata +4 -3
- data/lib/fixture_kit/sql_subscriber.rb +0 -32
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ad80802447ed709427be32a3e090483bb304c97fbd6dfe66f4964cf6a2d2d5bc
|
|
4
|
+
data.tar.gz: 7d6f2e056126234ff6fab78be3b16c77d3346432a7f3fc3bb1ae2cc1606d7f29
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a4750ef54340da7fa136af3c046297ecd44a0d9fa96386e9a37bbe070cc5a8746c08f8bfce63815b5618c5ee7412a649f689ad884f0900ad9deb404579437688
|
|
7
|
+
data.tar.gz: 4e65d6fc64f2b5bb051667ed4e71d8bd6e8d1cdb951d1cecf45a15f083561f7cad749efba1d00e88002912611dcff197bdf78465c48d6e51838b434e197c373b
|
data/lib/fixture_kit/cache.rb
CHANGED
|
@@ -1,14 +1,12 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
|
-
require "active_support/core_ext/array/wrap"
|
|
4
|
-
|
|
5
3
|
module FixtureKit
|
|
6
4
|
class Cache
|
|
7
5
|
ANONYMOUS_DIRECTORY = "_anonymous"
|
|
8
6
|
|
|
9
7
|
include ConfigurationHelper
|
|
10
8
|
|
|
11
|
-
attr_reader :fixture, :
|
|
9
|
+
attr_reader :fixture, :content
|
|
12
10
|
|
|
13
11
|
def initialize(fixture)
|
|
14
12
|
@fixture = fixture
|
|
@@ -30,11 +28,11 @@ module FixtureKit
|
|
|
30
28
|
end
|
|
31
29
|
|
|
32
30
|
def exists?
|
|
33
|
-
|
|
31
|
+
content || file_cache.exists?
|
|
34
32
|
end
|
|
35
33
|
|
|
36
34
|
def clear_memory
|
|
37
|
-
@
|
|
35
|
+
@content = nil
|
|
38
36
|
end
|
|
39
37
|
|
|
40
38
|
def load
|
|
@@ -42,88 +40,47 @@ module FixtureKit
|
|
|
42
40
|
raise FixtureKit::CacheMissingError, "Cache does not exist for fixture '#{fixture.identifier}'"
|
|
43
41
|
end
|
|
44
42
|
|
|
45
|
-
@
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
# This should be revisited when Rails 8.2 makes it public.
|
|
50
|
-
connection.__send__(:execute_batch, statements, "FixtureKit Load")
|
|
51
|
-
end
|
|
43
|
+
@content ||= file_cache.read
|
|
44
|
+
|
|
45
|
+
FixtureKit.runner.coders.each do |coder|
|
|
46
|
+
coder.mount(content.data_for(coder.class))
|
|
52
47
|
end
|
|
53
48
|
|
|
54
|
-
Repository.new(
|
|
49
|
+
Repository.new(content.exposed)
|
|
55
50
|
end
|
|
56
51
|
|
|
57
52
|
def save
|
|
58
53
|
FixtureKit.runner.adapter.execute do |context|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
end
|
|
62
|
-
|
|
63
|
-
if fixture.parent
|
|
64
|
-
captured_models.concat(fixture.parent.cache.data.records.keys)
|
|
65
|
-
end
|
|
66
|
-
|
|
67
|
-
@data = MemoryCache.new(
|
|
68
|
-
records: generate_statements(captured_models),
|
|
54
|
+
@content = MemoryCache.new(
|
|
55
|
+
data: evaluate(FixtureKit.runner.coders, context),
|
|
69
56
|
exposed: file_cache.serialize_exposed(fixture.definition.exposed)
|
|
70
57
|
)
|
|
71
58
|
end
|
|
72
59
|
|
|
73
|
-
file_cache.write(
|
|
60
|
+
file_cache.write(content)
|
|
74
61
|
end
|
|
75
62
|
|
|
76
63
|
private
|
|
77
64
|
|
|
78
|
-
def
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
65
|
+
def evaluate(coders, context, data = {}, &block)
|
|
66
|
+
if coders.empty?
|
|
67
|
+
fixture.definition.evaluate(context, parent: fixture.parent&.mount)
|
|
68
|
+
else
|
|
69
|
+
coder, *remaining_coders = coders
|
|
83
70
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
rows = []
|
|
89
|
-
model.unscoped.order(:id).find_each do |record|
|
|
90
|
-
row_values = columns.map do |col|
|
|
91
|
-
value = record.read_attribute_before_type_cast(col)
|
|
92
|
-
model.connection.quote(value)
|
|
93
|
-
end
|
|
94
|
-
rows << "(#{row_values.join(", ")})"
|
|
71
|
+
parent_data = fixture.parent ? fixture.parent.cache.content.data_for(coder.class) : nil
|
|
72
|
+
data[coder.class] = coder.generate(parent_data: parent_data) do
|
|
73
|
+
evaluate(remaining_coders, context, data, &block)
|
|
95
74
|
end
|
|
96
|
-
|
|
97
|
-
sql = rows.empty? ? nil : build_insert_sql(model.table_name, columns, rows, model.connection)
|
|
98
|
-
statements[model] = sql
|
|
99
75
|
end
|
|
100
|
-
end
|
|
101
|
-
|
|
102
|
-
def build_delete_sql(model)
|
|
103
|
-
"DELETE FROM #{model.quoted_table_name}"
|
|
104
|
-
end
|
|
105
|
-
|
|
106
|
-
def build_insert_sql(table_name, columns, rows, connection)
|
|
107
|
-
quoted_table = connection.quote_table_name(table_name)
|
|
108
|
-
quoted_columns = columns.map { |c| connection.quote_column_name(c) }
|
|
109
76
|
|
|
110
|
-
|
|
77
|
+
data
|
|
111
78
|
end
|
|
112
79
|
|
|
113
|
-
def
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
connection = model.connection
|
|
118
|
-
grouped[connection] ||= []
|
|
119
|
-
|
|
120
|
-
table_key = [connection, model.table_name]
|
|
121
|
-
if deleted_tables.add?(table_key)
|
|
122
|
-
grouped[connection] << build_delete_sql(model)
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
grouped[connection] << sql if sql
|
|
126
|
-
end
|
|
80
|
+
def file_cache
|
|
81
|
+
@file_cache ||= FileCache.new(
|
|
82
|
+
File.join(configuration.cache_path, "#{identifier}.json")
|
|
83
|
+
)
|
|
127
84
|
end
|
|
128
85
|
end
|
|
129
86
|
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module FixtureKit
|
|
4
|
+
class Coder
|
|
5
|
+
def generate(parent_data: nil, &block)
|
|
6
|
+
raise NotImplementedError, "#{self.class} must implement #generate"
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def mount(data)
|
|
10
|
+
raise NotImplementedError, "#{self.class} must implement #mount"
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def encode(data)
|
|
14
|
+
data
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def decode(data)
|
|
18
|
+
data
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "active_support/notifications"
|
|
4
|
+
require "active_support/inflector"
|
|
5
|
+
|
|
6
|
+
module FixtureKit
|
|
7
|
+
class ActiveRecordCoder < FixtureKit::Coder
|
|
8
|
+
EVENT = "sql.active_record"
|
|
9
|
+
NAME_PATTERN = /\A(?<model_name>.+?) (?:(?:Bulk )?(?:Insert|Upsert)|Create|Destroy|(?:Update|Delete)(?: All)?)\z/
|
|
10
|
+
|
|
11
|
+
def generate(parent_data: nil, &block)
|
|
12
|
+
captured_models = Set.new
|
|
13
|
+
subscriber = lambda do |_event_name, _start, _finish, _id, payload|
|
|
14
|
+
name = payload[:name].to_s
|
|
15
|
+
model_name = name[NAME_PATTERN, :model_name]
|
|
16
|
+
next unless model_name
|
|
17
|
+
|
|
18
|
+
klass = ActiveSupport::Inflector.safe_constantize(model_name)
|
|
19
|
+
next unless klass.is_a?(Class) && klass < ActiveRecord::Base
|
|
20
|
+
|
|
21
|
+
captured_models.add(klass)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
ActiveSupport::Notifications.subscribed(subscriber, EVENT, monotonic: true, &block)
|
|
25
|
+
|
|
26
|
+
captured_models.map! { |model| base_table_model(model) }
|
|
27
|
+
captured_models.merge(parent_data.keys) if parent_data
|
|
28
|
+
|
|
29
|
+
generate_statements(captured_models)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def mount(data)
|
|
33
|
+
models_by_pool(data).each do |pool, models|
|
|
34
|
+
pool.with_connection do |connection|
|
|
35
|
+
statements = models.flat_map do |model|
|
|
36
|
+
[build_delete_sql(connection, model.table_name), data[model]].compact
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
connection.disable_referential_integrity do
|
|
40
|
+
# execute_batch is private in current supported Rails versions.
|
|
41
|
+
# This should be revisited when Rails 8.2 makes it public.
|
|
42
|
+
connection.__send__(:execute_batch, statements, "FixtureKit Insert")
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
verify_foreign_keys!(connection)
|
|
46
|
+
|
|
47
|
+
# Replayed INSERTs use explicit PKs, which Postgres sequences do not
|
|
48
|
+
# observe. Re-sync the sequence so subsequent Model.create calls don't
|
|
49
|
+
# collide with an id we just inserted. No-op on adapters whose PK
|
|
50
|
+
# generators advance from explicit-id INSERTs (MySQL, SQLite).
|
|
51
|
+
reset_primary_key_sequences(connection, models.map(&:table_name))
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def decode(data)
|
|
57
|
+
data.transform_keys do |model_name|
|
|
58
|
+
ActiveSupport::Inflector.constantize(model_name)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
private
|
|
63
|
+
|
|
64
|
+
def base_table_model(model)
|
|
65
|
+
model = model.superclass until model.superclass == ActiveRecord::Base || model.superclass.abstract_class?
|
|
66
|
+
model
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def generate_statements(models)
|
|
70
|
+
models.each_with_object({}) do |model, statements|
|
|
71
|
+
columns = insertable_columns(model)
|
|
72
|
+
column_names = columns.map(&:name)
|
|
73
|
+
|
|
74
|
+
rows = []
|
|
75
|
+
model.unscoped.order(:id).find_each do |record|
|
|
76
|
+
row_values = column_names.map do |col|
|
|
77
|
+
value = record.read_attribute_before_type_cast(col)
|
|
78
|
+
model.connection.quote(value)
|
|
79
|
+
end
|
|
80
|
+
rows << "(#{row_values.join(", ")})"
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
sql = rows.empty? ? nil : build_insert_sql(model.table_name, column_names, rows, model.connection)
|
|
84
|
+
statements[model] = sql
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def insertable_columns(model)
|
|
89
|
+
supports_virtual = model.connection.supports_virtual_columns?
|
|
90
|
+
model.columns.reject { |c| supports_virtual && c.virtual? }
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def build_delete_sql(connection, table_name)
|
|
94
|
+
"DELETE FROM #{connection.quote_table_name(table_name)}"
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def build_insert_sql(table_name, columns, rows, connection)
|
|
98
|
+
quoted_table = connection.quote_table_name(table_name)
|
|
99
|
+
quoted_columns = columns.map { |c| connection.quote_column_name(c) }
|
|
100
|
+
|
|
101
|
+
"INSERT INTO #{quoted_table} (#{quoted_columns.join(", ")}) VALUES #{rows.join(", ")}"
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def verify_foreign_keys!(connection)
|
|
105
|
+
return unless ActiveRecord.verify_foreign_keys_for_fixtures
|
|
106
|
+
|
|
107
|
+
begin
|
|
108
|
+
connection.check_all_foreign_keys_valid!
|
|
109
|
+
rescue ActiveRecord::StatementInvalid => e
|
|
110
|
+
raise FixtureKit::Error,
|
|
111
|
+
"Foreign key violations found in cached fixture data. The cache may be " \
|
|
112
|
+
"stale relative to your current schema or fixture definitions. " \
|
|
113
|
+
"Original error:\n\n#{e.message}"
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def reset_primary_key_sequences(connection, tables)
|
|
118
|
+
# Rails main (>= 8.2) batches the reset in one round-trip per connection.
|
|
119
|
+
# Older versions fall back to one query per table.
|
|
120
|
+
if connection.respond_to?(:reset_column_sequences!)
|
|
121
|
+
connection.reset_column_sequences!(tables.map { |t| [t] })
|
|
122
|
+
elsif connection.respond_to?(:reset_pk_sequence!)
|
|
123
|
+
tables.each { |t| connection.reset_pk_sequence!(t) }
|
|
124
|
+
end
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def models_by_pool(data)
|
|
128
|
+
seen = Set.new
|
|
129
|
+
|
|
130
|
+
data.each_with_object({}) do |(model, _), grouped|
|
|
131
|
+
pool = model.connection_pool
|
|
132
|
+
next unless seen.add?([pool, model.table_name])
|
|
133
|
+
|
|
134
|
+
grouped[pool] ||= []
|
|
135
|
+
grouped[pool] << model
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
end
|
|
@@ -4,14 +4,19 @@ module FixtureKit
|
|
|
4
4
|
class Configuration
|
|
5
5
|
attr_accessor :fixture_path
|
|
6
6
|
attr_accessor :cache_path
|
|
7
|
-
attr_reader :adapter_options, :callbacks
|
|
7
|
+
attr_reader :adapter_options, :callbacks, :coders
|
|
8
8
|
|
|
9
9
|
def initialize
|
|
10
10
|
@fixture_path = "fixture_kit"
|
|
11
11
|
@cache_path = "tmp/cache/fixture_kit"
|
|
12
|
-
@adapter_class =
|
|
12
|
+
@adapter_class = MinitestAdapter
|
|
13
13
|
@adapter_options = {}
|
|
14
14
|
@callbacks = Callbacks.new
|
|
15
|
+
@coders = Set.new([ActiveRecordCoder])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def register(coder)
|
|
19
|
+
@coders.add(coder)
|
|
15
20
|
end
|
|
16
21
|
|
|
17
22
|
def adapter(adapter_class = nil, **options)
|
|
@@ -17,12 +17,14 @@ module FixtureKit
|
|
|
17
17
|
end
|
|
18
18
|
|
|
19
19
|
def read
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
20
|
+
content = JSON.parse(File.read(path))
|
|
21
|
+
|
|
22
|
+
data = content.fetch("data").to_h do |coder_name, coder_data|
|
|
23
|
+
coder = coder_for(coder_name)
|
|
24
|
+
[coder.class, coder.decode(coder_data)]
|
|
23
25
|
end
|
|
24
26
|
|
|
25
|
-
exposed =
|
|
27
|
+
exposed = content.fetch("exposed").each_with_object({}) do |(name, value), hash|
|
|
26
28
|
if value.is_a?(Array)
|
|
27
29
|
hash[name.to_sym] = value.map { |r| { ActiveSupport::Inflector.constantize(r.keys.first) => r.values.first } }
|
|
28
30
|
else
|
|
@@ -30,12 +32,20 @@ module FixtureKit
|
|
|
30
32
|
end
|
|
31
33
|
end
|
|
32
34
|
|
|
33
|
-
MemoryCache.new(
|
|
35
|
+
MemoryCache.new(data: data, exposed: exposed)
|
|
34
36
|
end
|
|
35
37
|
|
|
36
38
|
def write(data)
|
|
39
|
+
content = {
|
|
40
|
+
data: data.data.to_h do |coder_class, coder_data|
|
|
41
|
+
coder = coder_for(coder_class.name)
|
|
42
|
+
[coder.class, coder.encode(coder_data)]
|
|
43
|
+
end,
|
|
44
|
+
exposed: data.exposed,
|
|
45
|
+
}
|
|
46
|
+
|
|
37
47
|
FileUtils.mkdir_p(File.dirname(path))
|
|
38
|
-
File.write(path, JSON.pretty_generate(
|
|
48
|
+
File.write(path, JSON.pretty_generate(content))
|
|
39
49
|
end
|
|
40
50
|
|
|
41
51
|
def serialize_exposed(exposed)
|
|
@@ -47,5 +57,12 @@ module FixtureKit
|
|
|
47
57
|
end
|
|
48
58
|
end
|
|
49
59
|
end
|
|
60
|
+
|
|
61
|
+
private
|
|
62
|
+
|
|
63
|
+
def coder_for(class_name)
|
|
64
|
+
@coder_for ||= FixtureKit.runner.coders.index_by { |c| c.class.name }
|
|
65
|
+
@coder_for.fetch(class_name)
|
|
66
|
+
end
|
|
50
67
|
end
|
|
51
68
|
end
|
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
|
|
3
3
|
module FixtureKit
|
|
4
4
|
class MemoryCache
|
|
5
|
-
attr_reader :
|
|
5
|
+
attr_reader :data, :exposed
|
|
6
6
|
|
|
7
|
-
def initialize(
|
|
8
|
-
@
|
|
7
|
+
def initialize(data:, exposed:)
|
|
8
|
+
@data = data
|
|
9
9
|
@exposed = exposed
|
|
10
10
|
freeze
|
|
11
11
|
end
|
|
12
12
|
|
|
13
|
-
def
|
|
14
|
-
|
|
13
|
+
def data_for(coder_class)
|
|
14
|
+
data.fetch(coder_class)
|
|
15
15
|
end
|
|
16
16
|
end
|
|
17
17
|
end
|
data/lib/fixture_kit/runner.rb
CHANGED
data/lib/fixture_kit/version.rb
CHANGED
data/lib/fixture_kit.rb
CHANGED
|
@@ -20,7 +20,6 @@ module FixtureKit
|
|
|
20
20
|
autoload :Definition, File.expand_path("fixture_kit/definition", __dir__)
|
|
21
21
|
autoload :Registry, File.expand_path("fixture_kit/registry", __dir__)
|
|
22
22
|
autoload :Repository, File.expand_path("fixture_kit/repository", __dir__)
|
|
23
|
-
autoload :SqlSubscriber, File.expand_path("fixture_kit/sql_subscriber", __dir__)
|
|
24
23
|
autoload :Cache, File.expand_path("fixture_kit/cache", __dir__)
|
|
25
24
|
autoload :FileCache, File.expand_path("fixture_kit/file_cache", __dir__)
|
|
26
25
|
autoload :MemoryCache, File.expand_path("fixture_kit/memory_cache", __dir__)
|
|
@@ -28,6 +27,8 @@ module FixtureKit
|
|
|
28
27
|
autoload :Adapter, File.expand_path("fixture_kit/adapter", __dir__)
|
|
29
28
|
autoload :MinitestAdapter, File.expand_path("fixture_kit/adapters/minitest_adapter", __dir__)
|
|
30
29
|
autoload :RSpecAdapter, File.expand_path("fixture_kit/adapters/rspec_adapter", __dir__)
|
|
30
|
+
autoload :Coder, File.expand_path("fixture_kit/coder", __dir__)
|
|
31
|
+
autoload :ActiveRecordCoder, File.expand_path("fixture_kit/coders/active_record_coder", __dir__)
|
|
31
32
|
|
|
32
33
|
extend Singleton
|
|
33
34
|
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: fixture_kit
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.16.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Ngan Pham
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-05-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: activesupport
|
|
@@ -160,6 +160,8 @@ files:
|
|
|
160
160
|
- lib/fixture_kit/analyzer/text_formatter.rb
|
|
161
161
|
- lib/fixture_kit/cache.rb
|
|
162
162
|
- lib/fixture_kit/callbacks.rb
|
|
163
|
+
- lib/fixture_kit/coder.rb
|
|
164
|
+
- lib/fixture_kit/coders/active_record_coder.rb
|
|
163
165
|
- lib/fixture_kit/configuration.rb
|
|
164
166
|
- lib/fixture_kit/configuration_helper.rb
|
|
165
167
|
- lib/fixture_kit/definition.rb
|
|
@@ -173,7 +175,6 @@ files:
|
|
|
173
175
|
- lib/fixture_kit/rspec.rb
|
|
174
176
|
- lib/fixture_kit/runner.rb
|
|
175
177
|
- lib/fixture_kit/singleton.rb
|
|
176
|
-
- lib/fixture_kit/sql_subscriber.rb
|
|
177
178
|
- lib/fixture_kit/version.rb
|
|
178
179
|
homepage: https://github.com/Gusto/fixture_kit
|
|
179
180
|
licenses:
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
require "active_support/notifications"
|
|
4
|
-
require "active_support/inflector"
|
|
5
|
-
|
|
6
|
-
module FixtureKit
|
|
7
|
-
class SqlSubscriber
|
|
8
|
-
EVENT = "sql.active_record"
|
|
9
|
-
NAME_PATTERN = /\A(?<model_name>.+?) (?:(?:Bulk )?(?:Insert|Upsert)|Create|Destroy|(?:Update|Delete)(?: All)?)\z/
|
|
10
|
-
|
|
11
|
-
def self.capture(&block)
|
|
12
|
-
models = Set.new
|
|
13
|
-
subscriber = lambda do |_event_name, _start, _finish, _id, payload|
|
|
14
|
-
name = payload[:name].to_s
|
|
15
|
-
model_name = name[NAME_PATTERN, :model_name]
|
|
16
|
-
next unless model_name
|
|
17
|
-
|
|
18
|
-
models.add(ActiveSupport::Inflector.constantize(model_name))
|
|
19
|
-
end
|
|
20
|
-
|
|
21
|
-
ActiveSupport::Notifications.subscribed(subscriber, EVENT, monotonic: true, &block)
|
|
22
|
-
|
|
23
|
-
models.map { |model| base_table_model(model) }.uniq
|
|
24
|
-
end
|
|
25
|
-
|
|
26
|
-
def self.base_table_model(model)
|
|
27
|
-
model = model.superclass until model.superclass == ActiveRecord::Base || model.superclass.abstract_class?
|
|
28
|
-
model
|
|
29
|
-
end
|
|
30
|
-
private_class_method :base_table_model
|
|
31
|
-
end
|
|
32
|
-
end
|