real_data_tests 0.3.13 → 0.3.15
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/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
|