fixture_kit 0.15.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: abc9fb9ae8fd65e1d8a6e3ecc6ddb588b57c528424d521a5710998526df5a490
4
- data.tar.gz: 0c706753a232664188d72ff1caf456ebb18fa38002016f4a266566cf04944820
3
+ metadata.gz: ad80802447ed709427be32a3e090483bb304c97fbd6dfe66f4964cf6a2d2d5bc
4
+ data.tar.gz: 7d6f2e056126234ff6fab78be3b16c77d3346432a7f3fc3bb1ae2cc1606d7f29
5
5
  SHA512:
6
- metadata.gz: 2af988212619c3a3ac196f808d53aacf77192a4039f21d70b0cc1fd3592eb171ff485e35ee4925931418850688e1c1491d84266ab35bcfa84e38d918db8bc37f
7
- data.tar.gz: dcfd8912c6f5dea4a01482623a5b2f9f8f7d187e7d684ef04c2c755c830f15858307dc4917b45ecba164d48c43f24463fb0100676db89c5969a300e303cb0321
6
+ metadata.gz: a4750ef54340da7fa136af3c046297ecd44a0d9fa96386e9a37bbe070cc5a8746c08f8bfce63815b5618c5ee7412a649f689ad884f0900ad9deb404579437688
7
+ data.tar.gz: 4e65d6fc64f2b5bb051667ed4e71d8bd6e8d1cdb951d1cecf45a15f083561f7cad749efba1d00e88002912611dcff197bdf78465c48d6e51838b434e197c373b
@@ -15,7 +15,10 @@ module FixtureKit
15
15
  model_name = name[NAME_PATTERN, :model_name]
16
16
  next unless model_name
17
17
 
18
- captured_models.add(ActiveSupport::Inflector.constantize(model_name))
18
+ klass = ActiveSupport::Inflector.safe_constantize(model_name)
19
+ next unless klass.is_a?(Class) && klass < ActiveRecord::Base
20
+
21
+ captured_models.add(klass)
19
22
  end
20
23
 
21
24
  ActiveSupport::Notifications.subscribed(subscriber, EVENT, monotonic: true, &block)
@@ -27,11 +30,25 @@ module FixtureKit
27
30
  end
28
31
 
29
32
  def mount(data)
30
- statements_by_connection(data).each do |connection, statements|
31
- connection.disable_referential_integrity do
32
- # execute_batch is private in current supported Rails versions.
33
- # This should be revisited when Rails 8.2 makes it public.
34
- connection.__send__(:execute_batch, statements, "FixtureKit Load")
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))
35
52
  end
36
53
  end
37
54
  end
@@ -51,24 +68,30 @@ module FixtureKit
51
68
 
52
69
  def generate_statements(models)
53
70
  models.each_with_object({}) do |model, statements|
54
- columns = model.column_names
71
+ columns = insertable_columns(model)
72
+ column_names = columns.map(&:name)
55
73
 
56
74
  rows = []
57
75
  model.unscoped.order(:id).find_each do |record|
58
- row_values = columns.map do |col|
76
+ row_values = column_names.map do |col|
59
77
  value = record.read_attribute_before_type_cast(col)
60
78
  model.connection.quote(value)
61
79
  end
62
80
  rows << "(#{row_values.join(", ")})"
63
81
  end
64
82
 
65
- sql = rows.empty? ? nil : build_insert_sql(model.table_name, columns, rows, model.connection)
83
+ sql = rows.empty? ? nil : build_insert_sql(model.table_name, column_names, rows, model.connection)
66
84
  statements[model] = sql
67
85
  end
68
86
  end
69
87
 
70
- def build_delete_sql(model)
71
- "DELETE FROM #{model.quoted_table_name}"
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)}"
72
95
  end
73
96
 
74
97
  def build_insert_sql(table_name, columns, rows, connection)
@@ -78,19 +101,38 @@ module FixtureKit
78
101
  "INSERT INTO #{quoted_table} (#{quoted_columns.join(", ")}) VALUES #{rows.join(", ")}"
79
102
  end
80
103
 
81
- def statements_by_connection(records)
82
- deleted_tables = Set.new
104
+ def verify_foreign_keys!(connection)
105
+ return unless ActiveRecord.verify_foreign_keys_for_fixtures
83
106
 
84
- records.each_with_object({}) do |(model, sql), grouped|
85
- connection = model.connection
86
- grouped[connection] ||= []
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
87
116
 
88
- table_key = [connection, model.table_name]
89
- if deleted_tables.add?(table_key)
90
- grouped[connection] << build_delete_sql(model)
91
- end
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])
92
133
 
93
- grouped[connection] << sql if sql
134
+ grouped[pool] ||= []
135
+ grouped[pool] << model
94
136
  end
95
137
  end
96
138
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module FixtureKit
4
- VERSION = "0.15.0"
4
+ VERSION = "0.16.0"
5
5
  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.15.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-05-05 00:00:00.000000000 Z
11
+ date: 2026-05-06 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport