activerecord-graph-extractor 0.1.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 +7 -0
- data/.rspec +4 -0
- data/CHANGELOG.md +36 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +201 -0
- data/LICENSE +21 -0
- data/README.md +532 -0
- data/Rakefile +36 -0
- data/activerecord-graph-extractor.gemspec +64 -0
- data/docs/dry_run.md +410 -0
- data/docs/examples.md +239 -0
- data/docs/s3_integration.md +381 -0
- data/docs/usage.md +363 -0
- data/examples/dry_run_example.rb +227 -0
- data/examples/s3_example.rb +247 -0
- data/exe/arge +7 -0
- data/lib/activerecord_graph_extractor/cli.rb +627 -0
- data/lib/activerecord_graph_extractor/configuration.rb +98 -0
- data/lib/activerecord_graph_extractor/dependency_resolver.rb +406 -0
- data/lib/activerecord_graph_extractor/dry_run_analyzer.rb +421 -0
- data/lib/activerecord_graph_extractor/errors.rb +33 -0
- data/lib/activerecord_graph_extractor/extractor.rb +182 -0
- data/lib/activerecord_graph_extractor/importer.rb +260 -0
- data/lib/activerecord_graph_extractor/json_serializer.rb +176 -0
- data/lib/activerecord_graph_extractor/primary_key_mapper.rb +57 -0
- data/lib/activerecord_graph_extractor/progress_tracker.rb +202 -0
- data/lib/activerecord_graph_extractor/relationship_analyzer.rb +212 -0
- data/lib/activerecord_graph_extractor/s3_client.rb +170 -0
- data/lib/activerecord_graph_extractor/version.rb +5 -0
- data/lib/activerecord_graph_extractor.rb +34 -0
- data/scripts/verify_installation.rb +192 -0
- metadata +388 -0
@@ -0,0 +1,247 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
# Example: Using ActiveRecord Graph Extractor with S3
|
5
|
+
# This script demonstrates how to extract ActiveRecord data and upload it to S3
|
6
|
+
|
7
|
+
require 'bundler/setup'
|
8
|
+
require 'activerecord_graph_extractor'
|
9
|
+
|
10
|
+
# Configure AWS credentials (in production, use environment variables or IAM roles)
|
11
|
+
# ENV['AWS_ACCESS_KEY_ID'] = 'your_access_key'
|
12
|
+
# ENV['AWS_SECRET_ACCESS_KEY'] = 'your_secret_key'
|
13
|
+
# ENV['AWS_REGION'] = 'us-east-1'
|
14
|
+
|
15
|
+
# Example 1: Basic S3 upload
|
16
|
+
def basic_s3_upload_example
|
17
|
+
puts "=== Basic S3 Upload Example ==="
|
18
|
+
|
19
|
+
# Assuming you have an Order model
|
20
|
+
order = Order.find(123)
|
21
|
+
|
22
|
+
extractor = ActiveRecordGraphExtractor::Extractor.new
|
23
|
+
|
24
|
+
begin
|
25
|
+
result = extractor.extract_and_upload_to_s3(
|
26
|
+
order,
|
27
|
+
bucket_name: 'my-extraction-bucket',
|
28
|
+
s3_key: 'extractions/order_123.json',
|
29
|
+
region: 'us-east-1'
|
30
|
+
)
|
31
|
+
|
32
|
+
puts "ā
Successfully uploaded to S3!"
|
33
|
+
puts " Bucket: #{result['s3_upload'][:bucket]}"
|
34
|
+
puts " Key: #{result['s3_upload'][:key]}"
|
35
|
+
puts " URL: #{result['s3_upload'][:url]}"
|
36
|
+
puts " Size: #{result['s3_upload'][:size]} bytes"
|
37
|
+
puts " Records: #{result['metadata']['total_records']}"
|
38
|
+
|
39
|
+
rescue ActiveRecordGraphExtractor::S3Error => e
|
40
|
+
puts "ā S3 Error: #{e.message}"
|
41
|
+
rescue ActiveRecordGraphExtractor::ExtractionError => e
|
42
|
+
puts "ā Extraction Error: #{e.message}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Example 2: Using S3Client directly
|
47
|
+
def s3_client_example
|
48
|
+
puts "\n=== S3Client Direct Usage Example ==="
|
49
|
+
|
50
|
+
begin
|
51
|
+
# Create S3 client
|
52
|
+
s3_client = ActiveRecordGraphExtractor::S3Client.new(
|
53
|
+
bucket_name: 'my-extraction-bucket',
|
54
|
+
region: 'us-east-1'
|
55
|
+
)
|
56
|
+
|
57
|
+
# Extract to local file first
|
58
|
+
order = Order.find(123)
|
59
|
+
extractor = ActiveRecordGraphExtractor::Extractor.new
|
60
|
+
local_file = 'temp_extraction.json'
|
61
|
+
|
62
|
+
extractor.extract_to_file(order, local_file)
|
63
|
+
|
64
|
+
# Upload to S3
|
65
|
+
upload_result = s3_client.upload_file(
|
66
|
+
local_file,
|
67
|
+
'extractions/manual_upload.json',
|
68
|
+
server_side_encryption: 'AES256',
|
69
|
+
metadata: { 'extracted_by' => 'my_app', 'version' => '1.0' }
|
70
|
+
)
|
71
|
+
|
72
|
+
puts "ā
Manual upload successful!"
|
73
|
+
puts " URL: #{upload_result[:url]}"
|
74
|
+
|
75
|
+
# List files in bucket
|
76
|
+
files = s3_client.list_files(prefix: 'extractions/')
|
77
|
+
puts "\nš Files in bucket:"
|
78
|
+
files.each do |file|
|
79
|
+
puts " #{file[:key]} (#{file[:size]} bytes)"
|
80
|
+
end
|
81
|
+
|
82
|
+
# Clean up local file
|
83
|
+
File.delete(local_file) if File.exist?(local_file)
|
84
|
+
|
85
|
+
rescue ActiveRecordGraphExtractor::S3Error => e
|
86
|
+
puts "ā S3 Error: #{e.message}"
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Example 3: Advanced configuration with custom serializers
|
91
|
+
def advanced_s3_example
|
92
|
+
puts "\n=== Advanced S3 Configuration Example ==="
|
93
|
+
|
94
|
+
# Configure the gem
|
95
|
+
ActiveRecordGraphExtractor.configure do |config|
|
96
|
+
config.max_depth = 3
|
97
|
+
config.handle_circular_references = true
|
98
|
+
|
99
|
+
# Add custom serializer for sensitive data
|
100
|
+
config.add_custom_serializer('User') do |user|
|
101
|
+
{
|
102
|
+
'id' => user.id,
|
103
|
+
'email' => user.email.gsub(/@.*/, '@***'), # Mask email domain
|
104
|
+
'created_at' => user.created_at,
|
105
|
+
'status' => user.status
|
106
|
+
}
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
order = Order.find(123)
|
111
|
+
extractor = ActiveRecordGraphExtractor::Extractor.new
|
112
|
+
|
113
|
+
begin
|
114
|
+
result = extractor.extract_and_upload_to_s3(
|
115
|
+
order,
|
116
|
+
bucket_name: 'secure-extraction-bucket',
|
117
|
+
options: {
|
118
|
+
max_depth: 2,
|
119
|
+
exclude_models: ['PaymentMethod', 'CreditCard'] # Exclude sensitive models
|
120
|
+
}
|
121
|
+
)
|
122
|
+
|
123
|
+
puts "ā
Secure extraction uploaded!"
|
124
|
+
puts " Records: #{result['metadata']['total_records']}"
|
125
|
+
puts " Models: #{result['metadata']['models_extracted'].join(', ')}"
|
126
|
+
|
127
|
+
rescue => e
|
128
|
+
puts "ā Error: #{e.message}"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
# Example 4: Batch processing with error handling
|
133
|
+
def batch_processing_example
|
134
|
+
puts "\n=== Batch Processing Example ==="
|
135
|
+
|
136
|
+
s3_client = ActiveRecordGraphExtractor::S3Client.new(
|
137
|
+
bucket_name: 'batch-extractions',
|
138
|
+
region: 'us-east-1'
|
139
|
+
)
|
140
|
+
|
141
|
+
extractor = ActiveRecordGraphExtractor::Extractor.new
|
142
|
+
|
143
|
+
# Process multiple orders
|
144
|
+
Order.where(status: 'completed').limit(10).find_each do |order|
|
145
|
+
begin
|
146
|
+
result = extractor.extract_to_s3(
|
147
|
+
order,
|
148
|
+
s3_client,
|
149
|
+
"batch/#{Date.current}/order_#{order.id}.json"
|
150
|
+
)
|
151
|
+
|
152
|
+
puts "ā
Processed Order #{order.id} - #{result['metadata']['total_records']} records"
|
153
|
+
|
154
|
+
rescue => e
|
155
|
+
puts "ā Failed to process Order #{order.id}: #{e.message}"
|
156
|
+
# Continue with next order
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Example 5: Download and analyze
|
162
|
+
def download_and_analyze_example
|
163
|
+
puts "\n=== Download and Analyze Example ==="
|
164
|
+
|
165
|
+
s3_client = ActiveRecordGraphExtractor::S3Client.new(
|
166
|
+
bucket_name: 'my-extraction-bucket'
|
167
|
+
)
|
168
|
+
|
169
|
+
begin
|
170
|
+
# List recent extractions
|
171
|
+
files = s3_client.list_files(
|
172
|
+
prefix: 'extractions/',
|
173
|
+
max_keys: 5
|
174
|
+
)
|
175
|
+
|
176
|
+
return if files.empty?
|
177
|
+
|
178
|
+
# Download the most recent file
|
179
|
+
latest_file = files.max_by { |f| f[:last_modified] }
|
180
|
+
local_path = "downloaded_#{File.basename(latest_file[:key])}"
|
181
|
+
|
182
|
+
download_result = s3_client.download_file(latest_file[:key], local_path)
|
183
|
+
puts "ā
Downloaded: #{download_result[:local_path]}"
|
184
|
+
|
185
|
+
# Analyze the file
|
186
|
+
data = JSON.parse(File.read(local_path))
|
187
|
+
metadata = data['metadata']
|
188
|
+
|
189
|
+
puts "\nš Analysis:"
|
190
|
+
puts " Extraction time: #{metadata['extraction_time']}"
|
191
|
+
puts " Total records: #{metadata['total_records']}"
|
192
|
+
puts " Models: #{metadata['models_extracted'].join(', ')}"
|
193
|
+
puts " Duration: #{metadata['duration_seconds']}s"
|
194
|
+
|
195
|
+
# Clean up
|
196
|
+
File.delete(local_path)
|
197
|
+
|
198
|
+
rescue => e
|
199
|
+
puts "ā Error: #{e.message}"
|
200
|
+
end
|
201
|
+
end
|
202
|
+
|
203
|
+
# Example 6: Presigned URLs for sharing
|
204
|
+
def presigned_url_example
|
205
|
+
puts "\n=== Presigned URL Example ==="
|
206
|
+
|
207
|
+
s3_client = ActiveRecordGraphExtractor::S3Client.new(
|
208
|
+
bucket_name: 'my-extraction-bucket'
|
209
|
+
)
|
210
|
+
|
211
|
+
begin
|
212
|
+
# Generate a presigned URL valid for 24 hours
|
213
|
+
url = s3_client.presigned_url(
|
214
|
+
'extractions/order_123.json',
|
215
|
+
expires_in: 24 * 60 * 60 # 24 hours
|
216
|
+
)
|
217
|
+
|
218
|
+
puts "ā
Presigned URL generated:"
|
219
|
+
puts " #{url}"
|
220
|
+
puts " Valid for: 24 hours"
|
221
|
+
puts " Use this URL to download the file without AWS credentials"
|
222
|
+
|
223
|
+
rescue => e
|
224
|
+
puts "ā Error: #{e.message}"
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
# Run examples (uncomment the ones you want to test)
|
229
|
+
if __FILE__ == $0
|
230
|
+
puts "ActiveRecord Graph Extractor S3 Examples"
|
231
|
+
puts "========================================"
|
232
|
+
|
233
|
+
# Make sure to set up your AWS credentials and have valid data before running
|
234
|
+
puts "ā ļø Make sure to configure AWS credentials and update model/ID references"
|
235
|
+
puts "ā ļø These examples assume you have Order model with ID 123"
|
236
|
+
puts
|
237
|
+
|
238
|
+
# Uncomment to run specific examples:
|
239
|
+
# basic_s3_upload_example
|
240
|
+
# s3_client_example
|
241
|
+
# advanced_s3_example
|
242
|
+
# batch_processing_example
|
243
|
+
# download_and_analyze_example
|
244
|
+
# presigned_url_example
|
245
|
+
|
246
|
+
puts "⨠Examples ready to run! Uncomment the ones you want to test."
|
247
|
+
end
|