real_data_tests 0.3.14 → 0.3.16

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: e7e142b478391e00c15f51378e09dd2b7e1429f8c7d1bdd2bb5d059ae8a968fb
4
- data.tar.gz: a4464de621782aebfa90bac25e90458e4feca5c1007898d3537d44866a937c7b
3
+ metadata.gz: fbf98b8c1c4b72e614a490731c40ff4f56c36eb14b4b13cf19fc13b7c3022fe3
4
+ data.tar.gz: '029a17e72f0a42f34eae153cbf4a212e185100027e438b8a9e48efb112b7e349'
5
5
  SHA512:
6
- metadata.gz: '078fcfb22739b26714d756e10afc54ce10a15b947706f1f8eccee31f65384695b770ea546e69a889c033378fff79d314b1b66c4d86b29b3eab2dbb62e6b93231'
7
- data.tar.gz: c02a03e895d13a78e75adcf5c8ff5c6d9ea920d91dbaf463dad5e344bbe890e5877cb42385a65aa1f2df5c57b94cb595c96b78279cb9f1f66616e44e9a50a927
6
+ metadata.gz: 854233f093058fe510b0c37409a6a4c3445a2c65a70dc9c862d3a8eaec12a535ba435b354a5348b8e4f41bf15291caacabcb1d9b4274b506f02d1baeec97e2b0
7
+ data.tar.gz: ce700cb666714010f2622307da5321fac568eb32afbaf6795121d855e6e47409047192a0c38d3b0ed1f3b8e82d109988135c7c8b6a6cfb63c6e8e274c79a686e
@@ -1,5 +1,38 @@
1
1
  module RealDataTests
2
2
  module RSpecHelper
3
+ class SqlBlock
4
+ attr_reader :type, :content, :table_name
5
+
6
+ def initialize(content)
7
+ @content = content.strip
8
+ @type = determine_block_type
9
+ @table_name = extract_table_name if @type == :insert
10
+ end
11
+
12
+ private
13
+
14
+ def determine_block_type
15
+ case @content
16
+ when /\AINSERT INTO/i
17
+ :insert
18
+ when /\ACOPY.*FROM stdin/i
19
+ :copy
20
+ when /\AALTER TABLE/i
21
+ :alter
22
+ when /\ASET/i
23
+ :set
24
+ else
25
+ :other
26
+ end
27
+ end
28
+
29
+ def extract_table_name
30
+ if @content =~ /INSERT INTO\s+"?([^\s"(]+)"?\s/i
31
+ $1
32
+ end
33
+ end
34
+ end
35
+
3
36
  def load_real_test_data(name)
4
37
  dump_path = File.join(RealDataTests.configuration.dump_path, "#{name}.sql")
5
38
  raise Error, "Test data file not found: #{dump_path}" unless File.exist?(dump_path)
@@ -17,11 +50,13 @@ module RealDataTests
17
50
  end
18
51
  end
19
52
 
20
- # Native Ruby implementation
21
53
  def load_real_test_data_native(name)
22
54
  dump_path = File.join(RealDataTests.configuration.dump_path, "#{name}.sql")
23
55
  raise Error, "Test data file not found: #{dump_path}" unless File.exist?(dump_path)
24
56
 
57
+ sql_content = File.read(dump_path)
58
+ blocks = parse_sql_blocks(sql_content)
59
+
25
60
  ActiveRecord::Base.transaction do
26
61
  connection = ActiveRecord::Base.connection
27
62
 
@@ -29,17 +64,8 @@ module RealDataTests
29
64
  connection.execute('SET session_replication_role = replica;')
30
65
 
31
66
  begin
32
- sql_content = File.read(dump_path)
33
- statements = split_sql_statements(sql_content)
34
-
35
- statements.each_with_index do |statement, index|
36
- begin
37
- cleaned_statement = clean_sql_statement(statement)
38
- puts "Executing Statement ##{index + 1}: #{cleaned_statement}" # Debug log
39
- connection.execute(cleaned_statement)
40
- rescue ActiveRecord::StatementInvalid => e
41
- raise Error, "Error executing statement ##{index + 1}: #{e.message}\nSQL: #{cleaned_statement}"
42
- end
67
+ blocks.each_with_index do |block, index|
68
+ execute_block(block, index + 1, blocks.length)
43
69
  end
44
70
  ensure
45
71
  connection.execute('SET session_replication_role = DEFAULT;')
@@ -64,6 +90,147 @@ module RealDataTests
64
90
  options.join(" ")
65
91
  end
66
92
 
93
+ class SqlBlock
94
+ attr_reader :type, :content, :table_name
95
+
96
+ def initialize(content)
97
+ @content = content.strip
98
+ @type = determine_block_type
99
+ @table_name = extract_table_name if @type == :insert
100
+ end
101
+
102
+ private
103
+
104
+ def determine_block_type
105
+ if @content.match?(/\AINSERT INTO/i)
106
+ :insert
107
+ elsif @content.match?(/\ACOPY.*FROM stdin/i)
108
+ :copy
109
+ elsif @content.match?(/\AALTER TABLE/i)
110
+ :alter
111
+ elsif @content.match?(/\ASET/i)
112
+ :set
113
+ else
114
+ :other
115
+ end
116
+ end
117
+
118
+ def extract_table_name
119
+ if @content =~ /INSERT INTO\s+"?([^\s"(]+)"?\s/i
120
+ $1
121
+ end
122
+ end
123
+ end
124
+
125
+ def parse_sql_blocks(content)
126
+ blocks = []
127
+ current_block = []
128
+ in_copy_block = false
129
+
130
+ content.each_line do |line|
131
+ line = line.chomp
132
+
133
+ # Skip empty lines and comments unless in COPY block
134
+ next if !in_copy_block && (line.empty? || line.start_with?('--'))
135
+
136
+ # Handle start of COPY block
137
+ if !in_copy_block && line.upcase.match?(/\ACOPY.*FROM stdin/i)
138
+ current_block = [line]
139
+ in_copy_block = true
140
+ next
141
+ end
142
+
143
+ # Handle end of COPY block
144
+ if in_copy_block && line == '\\.'
145
+ current_block << line
146
+ blocks << SqlBlock.new(current_block.join("\n"))
147
+ current_block = []
148
+ in_copy_block = false
149
+ next
150
+ end
151
+
152
+ # Accumulate lines in COPY block
153
+ if in_copy_block
154
+ current_block << line
155
+ next
156
+ end
157
+
158
+ # Handle regular SQL statements
159
+ current_block << line
160
+ if line.end_with?(';')
161
+ blocks << SqlBlock.new(current_block.join("\n"))
162
+ current_block = []
163
+ end
164
+ end
165
+
166
+ # Handle any remaining block
167
+ blocks << SqlBlock.new(current_block.join("\n")) unless current_block.empty?
168
+ blocks
169
+ end
170
+
171
+ def execute_block(block, index, total)
172
+ case block.type
173
+ when :insert
174
+ execute_insert_block(block, index, total)
175
+ when :copy
176
+ execute_copy_block(block, index, total)
177
+ else
178
+ execute_regular_block(block, index, total)
179
+ end
180
+ end
181
+
182
+ def execute_insert_block(block, index, total)
183
+ puts "Executing INSERT block #{index}/#{total} for table: #{block.table_name}"
184
+ # Don't modify statements that already end with semicolon
185
+ statement = if block.content.strip.end_with?(';')
186
+ block.content
187
+ else
188
+ "#{block.content};"
189
+ end
190
+
191
+ begin
192
+ ActiveRecord::Base.connection.execute(statement)
193
+ rescue ActiveRecord::StatementInvalid => e
194
+ if e.message.include?('syntax error at or near "ON"')
195
+ # Try alternative formatting for ON CONFLICT
196
+ modified_statement = statement.gsub(/\)\s+ON\s+CONFLICT/, ') ON CONFLICT')
197
+ ActiveRecord::Base.connection.execute(modified_statement)
198
+ else
199
+ raise
200
+ end
201
+ end
202
+ end
203
+
204
+ def execute_copy_block(block, index, total)
205
+ puts "Executing COPY block #{index}/#{total}"
206
+ ActiveRecord::Base.connection.execute(block.content)
207
+ end
208
+
209
+ def execute_regular_block(block, index, total)
210
+ puts "Executing block #{index}/#{total} of type: #{block.type}"
211
+ ActiveRecord::Base.connection.execute(block.content)
212
+ end
213
+
214
+ def normalize_insert_statement(statement)
215
+ # First clean up any excess whitespace around parentheses
216
+ statement = statement.gsub(/\(\s+/, '(')
217
+ .gsub(/\s+\)/, ')')
218
+ .gsub(/\)\s+ON\s+CONFLICT/, ') ON CONFLICT')
219
+
220
+ # Ensure proper spacing around ON CONFLICT
221
+ if statement =~ /(.*?)\s*ON\s+CONFLICT\s+(.*?)\s*(?:DO\s+.*?)?\s*;\s*\z/i
222
+ base = $1.strip
223
+ conflict_part = $2.strip
224
+ action_part = $3&.strip || 'DO NOTHING'
225
+
226
+ # Rebuild the statement with consistent formatting
227
+ "#{base} ON CONFLICT #{conflict_part} #{action_part};"
228
+ else
229
+ # If no ON CONFLICT clause, just clean up the spacing
230
+ statement.strip.sub(/;?\s*$/, ';')
231
+ end
232
+ end
233
+
67
234
  def split_sql_statements(sql)
68
235
  statements = []
69
236
  current_statement = ''
@@ -206,41 +373,4 @@ module RealDataTests
206
373
  end
207
374
  end
208
375
  end
209
-
210
- def import
211
- @logger.info "Starting SQL import..."
212
-
213
- ActiveRecord::Base.transaction do
214
- begin
215
- # Disable foreign key checks and triggers temporarily
216
- ActiveRecord::Base.connection.execute('SET session_replication_role = replica;')
217
-
218
- # Split the SQL content into individual statements
219
- statements = split_sql_statements(@sql_content)
220
-
221
- statements.each_with_index do |statement, index|
222
- next if statement.strip.empty?
223
-
224
- begin
225
- @logger.info "Executing statement #{index + 1} of #{statements.length}"
226
- cleaned_statement = clean_sql_statement(statement)
227
- ActiveRecord::Base.connection.execute(cleaned_statement)
228
- rescue ActiveRecord::StatementInvalid => e
229
- @logger.error "Error executing statement #{index + 1}: #{e.message}"
230
- @logger.error "Statement: #{cleaned_statement[0..100]}..."
231
- raise
232
- end
233
- end
234
-
235
- @logger.info "Successfully imported all SQL statements"
236
- rescue StandardError => e
237
- @logger.error "Error during import: #{e.message}"
238
- @logger.error e.backtrace.join("\n")
239
- raise
240
- ensure
241
- # Re-enable foreign key checks and triggers
242
- ActiveRecord::Base.connection.execute('SET session_replication_role = DEFAULT;')
243
- end
244
- end
245
- end
246
376
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RealDataTests
4
- VERSION = "0.3.14"
4
+ VERSION = "0.3.16"
5
5
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: real_data_tests
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.14
4
+ version: 0.3.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Kevin Dias