real_data_tests 0.3.13 → 0.3.15
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/real_data_tests/rspec_helper.rb +113 -59
- data/lib/real_data_tests/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b6d2be28f1fa0fc3982e0d8bb4927ea8f25eb1701d0c77059ec6a4059cb33ee
|
4
|
+
data.tar.gz: 19f5865fbb86760845c079a5b46ba49231533a33a91596e2b7c73438ca3941eb
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d68fbb46440b6950ec57363bbd995ea64503c41c9c66955ad1ad28b9338f51798a7aad945238e0a61c7654651a365b80056b3108e4dff1d2486b5c77cfad91c
|
7
|
+
data.tar.gz: e82c24d4082fb0d5e4e56e6de6cfd0e7130029057f2fa993e4f9bffdc2c5583bde94ee7c224535890f7e74ae01d8dd08ad670e2daef20041d572bf9845955fe8
|
@@ -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,26 +64,10 @@ module RealDataTests
|
|
29
64
|
connection.execute('SET session_replication_role = replica;')
|
30
65
|
|
31
66
|
begin
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
# Split the file into individual statements
|
36
|
-
statements = split_sql_statements(sql_content)
|
37
|
-
|
38
|
-
# Execute each statement
|
39
|
-
statements.each do |statement|
|
40
|
-
next if statement.strip.empty?
|
41
|
-
begin
|
42
|
-
# Clean up any formatting issues that might cause syntax errors
|
43
|
-
cleaned_statement = clean_sql_statement(statement)
|
44
|
-
connection.execute(cleaned_statement)
|
45
|
-
rescue ActiveRecord::StatementInvalid => e
|
46
|
-
# Provide detailed error information
|
47
|
-
raise Error, "Failed to execute SQL statement: #{e.message}\nStatement: #{cleaned_statement}"
|
48
|
-
end
|
67
|
+
blocks.each_with_index do |block, index|
|
68
|
+
execute_block(block, index + 1, blocks.length)
|
49
69
|
end
|
50
70
|
ensure
|
51
|
-
# Re-enable foreign key checks
|
52
71
|
connection.execute('SET session_replication_role = DEFAULT;')
|
53
72
|
end
|
54
73
|
end
|
@@ -71,6 +90,78 @@ module RealDataTests
|
|
71
90
|
options.join(" ")
|
72
91
|
end
|
73
92
|
|
93
|
+
def parse_sql_blocks(content)
|
94
|
+
blocks = []
|
95
|
+
current_block = []
|
96
|
+
in_copy_block = false
|
97
|
+
|
98
|
+
content.each_line do |line|
|
99
|
+
line = line.strip
|
100
|
+
next if line.empty? || line.start_with?('--')
|
101
|
+
|
102
|
+
if line.upcase.start_with?('COPY') && line.upcase.include?('FROM stdin')
|
103
|
+
in_copy_block = true
|
104
|
+
current_block << line
|
105
|
+
elsif line == '\.' && in_copy_block
|
106
|
+
in_copy_block = false
|
107
|
+
current_block << line
|
108
|
+
blocks << SqlBlock.new(current_block.join("\n"))
|
109
|
+
current_block = []
|
110
|
+
elsif in_copy_block
|
111
|
+
current_block << line
|
112
|
+
else
|
113
|
+
# Handle regular SQL statements
|
114
|
+
current_block << line
|
115
|
+
if line.end_with?(';') && !in_copy_block
|
116
|
+
blocks << SqlBlock.new(current_block.join("\n"))
|
117
|
+
current_block = []
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
# Add any remaining block
|
123
|
+
blocks << SqlBlock.new(current_block.join("\n")) unless current_block.empty?
|
124
|
+
blocks
|
125
|
+
end
|
126
|
+
|
127
|
+
def execute_block(block, index, total)
|
128
|
+
case block.type
|
129
|
+
when :insert
|
130
|
+
execute_insert_block(block, index, total)
|
131
|
+
when :copy
|
132
|
+
execute_copy_block(block, index, total)
|
133
|
+
else
|
134
|
+
execute_regular_block(block, index, total)
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def execute_insert_block(block, index, total)
|
139
|
+
puts "Executing INSERT block #{index}/#{total} for table: #{block.table_name}"
|
140
|
+
statement = normalize_insert_statement(block.content)
|
141
|
+
ActiveRecord::Base.connection.execute(statement)
|
142
|
+
end
|
143
|
+
|
144
|
+
def execute_copy_block(block, index, total)
|
145
|
+
puts "Executing COPY block #{index}/#{total}"
|
146
|
+
ActiveRecord::Base.connection.execute(block.content)
|
147
|
+
end
|
148
|
+
|
149
|
+
def execute_regular_block(block, index, total)
|
150
|
+
puts "Executing block #{index}/#{total} of type: #{block.type}"
|
151
|
+
ActiveRecord::Base.connection.execute(block.content)
|
152
|
+
end
|
153
|
+
|
154
|
+
def normalize_insert_statement(statement)
|
155
|
+
# Handle ON CONFLICT clauses properly
|
156
|
+
if statement =~ /(.*?)\s+(ON\s+CONFLICT.*?)\s*;\s*\z/i
|
157
|
+
main_insert = $1
|
158
|
+
conflict_clause = $2
|
159
|
+
"#{main_insert} #{conflict_clause};"
|
160
|
+
else
|
161
|
+
statement
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
74
165
|
def split_sql_statements(sql)
|
75
166
|
statements = []
|
76
167
|
current_statement = ''
|
@@ -95,7 +186,7 @@ module RealDataTests
|
|
95
186
|
# Add the last statement if it exists
|
96
187
|
statements << current_statement.strip unless current_statement.strip.empty?
|
97
188
|
|
98
|
-
#
|
189
|
+
# Normalize `ON CONFLICT` clauses
|
99
190
|
statements = statements.each_with_object([]) do |stmt, result|
|
100
191
|
if stmt.strip.upcase.start_with?('ON CONFLICT')
|
101
192
|
result[-1] = "#{result.last.strip} #{stmt.strip}"
|
@@ -104,10 +195,10 @@ module RealDataTests
|
|
104
195
|
end
|
105
196
|
end
|
106
197
|
|
107
|
-
#
|
198
|
+
# Ensure semicolons and spacing
|
108
199
|
statements.map! do |stmt|
|
109
200
|
stmt = stmt.gsub(/\)\s*ON CONFLICT/, ') ON CONFLICT') # Normalize spacing
|
110
|
-
stmt.strip.end_with?(';') ? stmt.strip : "#{stmt.strip};"
|
201
|
+
stmt.strip.end_with?(';') ? stmt.strip : "#{stmt.strip};"
|
111
202
|
end
|
112
203
|
|
113
204
|
statements
|
@@ -213,41 +304,4 @@ module RealDataTests
|
|
213
304
|
end
|
214
305
|
end
|
215
306
|
end
|
216
|
-
|
217
|
-
def import
|
218
|
-
@logger.info "Starting SQL import..."
|
219
|
-
|
220
|
-
ActiveRecord::Base.transaction do
|
221
|
-
begin
|
222
|
-
# Disable foreign key checks and triggers temporarily
|
223
|
-
ActiveRecord::Base.connection.execute('SET session_replication_role = replica;')
|
224
|
-
|
225
|
-
# Split the SQL content into individual statements
|
226
|
-
statements = split_sql_statements(@sql_content)
|
227
|
-
|
228
|
-
statements.each_with_index do |statement, index|
|
229
|
-
next if statement.strip.empty?
|
230
|
-
|
231
|
-
begin
|
232
|
-
@logger.info "Executing statement #{index + 1} of #{statements.length}"
|
233
|
-
cleaned_statement = clean_sql_statement(statement)
|
234
|
-
ActiveRecord::Base.connection.execute(cleaned_statement)
|
235
|
-
rescue ActiveRecord::StatementInvalid => e
|
236
|
-
@logger.error "Error executing statement #{index + 1}: #{e.message}"
|
237
|
-
@logger.error "Statement: #{cleaned_statement[0..100]}..."
|
238
|
-
raise
|
239
|
-
end
|
240
|
-
end
|
241
|
-
|
242
|
-
@logger.info "Successfully imported all SQL statements"
|
243
|
-
rescue StandardError => e
|
244
|
-
@logger.error "Error during import: #{e.message}"
|
245
|
-
@logger.error e.backtrace.join("\n")
|
246
|
-
raise
|
247
|
-
ensure
|
248
|
-
# Re-enable foreign key checks and triggers
|
249
|
-
ActiveRecord::Base.connection.execute('SET session_replication_role = DEFAULT;')
|
250
|
-
end
|
251
|
-
end
|
252
|
-
end
|
253
307
|
end
|