real_data_tests 0.3.14 → 0.3.16

Sign up to get free protection for your applications and to get access to all the features.
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