pg_multitenant_schemas 0.1.3 โ 0.2.2
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/.actrc +17 -0
- data/.env.local.example +21 -0
- data/.ruby-version +1 -0
- data/CHANGELOG.md +86 -0
- data/LOCAL_TESTING_SUMMARY.md +141 -0
- data/README.md +269 -16
- data/TESTING_LOCALLY.md +208 -0
- data/docs/README.md +81 -0
- data/docs/configuration.md +340 -0
- data/docs/context.md +292 -0
- data/docs/errors.md +498 -0
- data/docs/github_actions_permissions_fix.md +136 -0
- data/docs/github_actions_setup.md +181 -0
- data/docs/integration_testing.md +454 -0
- data/docs/local_workflow_testing.md +314 -0
- data/docs/migrator.md +291 -0
- data/docs/rails_integration.md +468 -0
- data/docs/schema_switcher.md +182 -0
- data/docs/tenant_resolver.md +394 -0
- data/docs/testing.md +358 -0
- data/examples/context_management.rb +198 -0
- data/examples/migration_workflow.rb +50 -0
- data/examples/rails_integration/controller_examples.rb +368 -0
- data/examples/schema_operations.rb +124 -0
- data/lib/pg_multitenant_schemas/configuration.rb +4 -4
- data/lib/pg_multitenant_schemas/migration_display_reporter.rb +30 -0
- data/lib/pg_multitenant_schemas/migration_executor.rb +81 -0
- data/lib/pg_multitenant_schemas/migration_schema_operations.rb +54 -0
- data/lib/pg_multitenant_schemas/migration_status_reporter.rb +65 -0
- data/lib/pg_multitenant_schemas/migrator.rb +89 -0
- data/lib/pg_multitenant_schemas/schema_switcher.rb +40 -66
- data/lib/pg_multitenant_schemas/tasks/advanced_tasks.rake +21 -0
- data/lib/pg_multitenant_schemas/tasks/basic_tasks.rake +20 -0
- data/lib/pg_multitenant_schemas/tasks/pg_multitenant_schemas.rake +53 -143
- data/lib/pg_multitenant_schemas/tasks/tenant_tasks.rake +65 -0
- data/lib/pg_multitenant_schemas/tenant_task_helpers.rb +102 -0
- data/lib/pg_multitenant_schemas/version.rb +1 -1
- data/lib/pg_multitenant_schemas.rb +10 -5
- data/pg_multitenant_schemas.gemspec +10 -9
- data/pre-push-check.sh +95 -0
- data/rails_integration/app/controllers/application_controller.rb +6 -0
- data/rails_integration/app/models/tenant.rb +6 -0
- data/test-github-setup.sh +85 -0
- data/validate-github-commands.sh +47 -0
- metadata +49 -17
data/docs/testing.md
ADDED
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
# RSpec Testing Guide - PgMultitenantSchemas
|
|
2
|
+
|
|
3
|
+
## ๐ **Overview**
|
|
4
|
+
|
|
5
|
+
This document provides comprehensive information about the RSpec test suite for the PgMultitenantSchemas gem, including unit tests, integration tests, and testing best practices.
|
|
6
|
+
|
|
7
|
+
## ๐๏ธ **Test Architecture**
|
|
8
|
+
|
|
9
|
+
### **Test Categories**
|
|
10
|
+
|
|
11
|
+
The test suite is organized into two main categories:
|
|
12
|
+
|
|
13
|
+
#### **1. Unit Tests** (Fast, Isolated)
|
|
14
|
+
- **Location**: `spec/*_spec.rb`
|
|
15
|
+
- **Execution**: Default `bundle exec rspec`
|
|
16
|
+
- **Purpose**: Test individual components in isolation
|
|
17
|
+
- **Database**: Uses mocked connections where possible
|
|
18
|
+
- **Speed**: Very fast (~0.03-0.16 seconds)
|
|
19
|
+
|
|
20
|
+
#### **2. Integration Tests** (Comprehensive, Database)
|
|
21
|
+
- **Location**: Tagged with `:integration`
|
|
22
|
+
- **Execution**: `bundle exec rspec --tag integration`
|
|
23
|
+
- **Purpose**: Test real PostgreSQL interactions and multi-schema operations
|
|
24
|
+
- **Database**: Requires running PostgreSQL instance
|
|
25
|
+
- **Speed**: Moderate (~0.67-1.17 seconds)
|
|
26
|
+
|
|
27
|
+
## โ๏ธ **Configuration**
|
|
28
|
+
|
|
29
|
+
### **RSpec Configuration Files**
|
|
30
|
+
|
|
31
|
+
#### **`.rspec`**
|
|
32
|
+
```plaintext
|
|
33
|
+
--format documentation
|
|
34
|
+
--color
|
|
35
|
+
--require spec_helper
|
|
36
|
+
--tag ~integration # Exclude integration tests by default
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
#### **`spec/spec_helper.rb`**
|
|
40
|
+
```ruby
|
|
41
|
+
require "rspec"
|
|
42
|
+
require "pg_multitenant_schemas"
|
|
43
|
+
|
|
44
|
+
RSpec.configure do |config|
|
|
45
|
+
config.example_status_persistence_file_path = ".rspec_status"
|
|
46
|
+
config.disable_monkey_patching!
|
|
47
|
+
config.expect_with :rspec do |c|
|
|
48
|
+
c.syntax = :expect
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### **Environment Variables**
|
|
54
|
+
|
|
55
|
+
Integration tests use these environment variables for PostgreSQL connection:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
PG_HOST=localhost # PostgreSQL host
|
|
59
|
+
PG_PORT=5432 # PostgreSQL port
|
|
60
|
+
PG_TEST_DATABASE=pg_multitenant_test # Test database name
|
|
61
|
+
PG_USER=postgres # Database user
|
|
62
|
+
PG_PASSWORD= # Database password (empty by default)
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## ๐งช **Test Suite Structure**
|
|
66
|
+
|
|
67
|
+
### **Unit Tests (65 examples)**
|
|
68
|
+
|
|
69
|
+
| **Test File** | **Component** | **Purpose** |
|
|
70
|
+
|---------------|---------------|-------------|
|
|
71
|
+
| `configuration_spec.rb` | Configuration | Test configuration options and validation |
|
|
72
|
+
| `context_spec.rb` | Context | Test tenant/schema context management |
|
|
73
|
+
| `schema_switcher_spec.rb` | SchemaSwitcher | Test schema operations (mocked) |
|
|
74
|
+
| `tenant_resolver_spec.rb` | TenantResolver | Test subdomain extraction and tenant resolution |
|
|
75
|
+
| `pg_multitenant_schemas_spec.rb` | Main Module | Test gem version and basic functionality |
|
|
76
|
+
| `edge_cases_spec.rb` | Edge Cases | Test error handling and edge cases |
|
|
77
|
+
| `performance_spec.rb` | Performance | Test memory usage and thread safety |
|
|
78
|
+
| `integration_spec.rb` | Integration | Test component interactions (mocked) |
|
|
79
|
+
| `errors_spec.rb` | Error Classes | Test custom error definitions |
|
|
80
|
+
| `rails_integration/tenant_spec.rb` | Rails Integration | Test Rails model and validation integration |
|
|
81
|
+
|
|
82
|
+
### **Integration Tests (21 examples)**
|
|
83
|
+
|
|
84
|
+
| **Test File** | **Component** | **Purpose** |
|
|
85
|
+
|---------------|---------------|-------------|
|
|
86
|
+
| `postgresql_integration_spec.rb` | PostgreSQL | Real database schema operations |
|
|
87
|
+
| `multiple_schemas_integration_spec.rb` | Multi-Schema | Complex schema interactions and isolation |
|
|
88
|
+
| `multiple_schemas_database_spec.rb` | Database Ops | Bulk operations and schema management |
|
|
89
|
+
| `multiple_tenants_context_spec.rb` | Context | Multi-tenant context switching |
|
|
90
|
+
|
|
91
|
+
## ๐ **Running Tests**
|
|
92
|
+
|
|
93
|
+
### **Unit Tests Only** (Default, Fast)
|
|
94
|
+
```bash
|
|
95
|
+
# Run all unit tests (excludes integration)
|
|
96
|
+
bundle exec rspec
|
|
97
|
+
|
|
98
|
+
# Run specific unit test file
|
|
99
|
+
bundle exec rspec spec/configuration_spec.rb
|
|
100
|
+
|
|
101
|
+
# Run with verbose output
|
|
102
|
+
bundle exec rspec --format documentation
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### **Integration Tests Only** (Requires PostgreSQL)
|
|
106
|
+
```bash
|
|
107
|
+
# Run all integration tests
|
|
108
|
+
bundle exec rspec --tag integration
|
|
109
|
+
|
|
110
|
+
# Run with documentation format
|
|
111
|
+
bundle exec rspec --tag integration --format documentation
|
|
112
|
+
|
|
113
|
+
# Run specific integration test
|
|
114
|
+
bundle exec rspec spec/postgresql_integration_spec.rb
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### **All Tests** (Complete Test Suite)
|
|
118
|
+
```bash
|
|
119
|
+
# Run both unit and integration tests
|
|
120
|
+
bundle exec rspec --tag integration spec/ && bundle exec rspec
|
|
121
|
+
|
|
122
|
+
# Alternative: Run all tests including integration
|
|
123
|
+
bundle exec rspec --no-tag
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
## ๐ **Test Categories Deep Dive**
|
|
127
|
+
|
|
128
|
+
### **Unit Tests Details**
|
|
129
|
+
|
|
130
|
+
#### **Configuration Tests**
|
|
131
|
+
```ruby
|
|
132
|
+
# Tests configuration object behavior
|
|
133
|
+
RSpec.describe PgMultitenantSchemas::Configuration do
|
|
134
|
+
describe "#initialize" do
|
|
135
|
+
it "sets default values"
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
describe "#connection_class=" do
|
|
139
|
+
it "allows setting connection class"
|
|
140
|
+
end
|
|
141
|
+
end
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### **Context Management Tests**
|
|
145
|
+
```ruby
|
|
146
|
+
# Tests tenant/schema context switching
|
|
147
|
+
RSpec.describe PgMultitenantSchemas::Context do
|
|
148
|
+
describe ".current_schema" do
|
|
149
|
+
it "defaults to public schema"
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
describe ".current_tenant=" do
|
|
153
|
+
it "sets the current tenant"
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
#### **Edge Cases and Error Handling**
|
|
159
|
+
```ruby
|
|
160
|
+
# Tests robust error handling
|
|
161
|
+
RSpec.describe "Edge Cases and Error Handling" do
|
|
162
|
+
describe "schema name validation" do
|
|
163
|
+
it "handles whitespace-only schema names"
|
|
164
|
+
it "handles special characters in schema names"
|
|
165
|
+
it "handles unicode characters"
|
|
166
|
+
end
|
|
167
|
+
end
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### **Integration Tests Details**
|
|
171
|
+
|
|
172
|
+
#### **PostgreSQL Integration Tests**
|
|
173
|
+
```ruby
|
|
174
|
+
# Real database operations
|
|
175
|
+
RSpec.describe "PostgreSQL Integration Tests", :integration do
|
|
176
|
+
describe "schema creation" do
|
|
177
|
+
it "actually creates a schema in PostgreSQL"
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
describe "schema switching" do
|
|
181
|
+
it "actually switches the search_path"
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
#### **Multiple Schemas Integration**
|
|
187
|
+
```ruby
|
|
188
|
+
# Complex multi-tenant scenarios
|
|
189
|
+
RSpec.describe "Multiple Schemas Integration Tests", :integration do
|
|
190
|
+
describe "multiple tenant schemas" do
|
|
191
|
+
it "creates multiple schemas successfully"
|
|
192
|
+
it "maintains data isolation between schemas"
|
|
193
|
+
it "handles concurrent schema access safely"
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
## ๐ ๏ธ **Database Setup for Integration Tests**
|
|
199
|
+
|
|
200
|
+
### **Prerequisites**
|
|
201
|
+
|
|
202
|
+
1. **PostgreSQL Running**: Ensure PostgreSQL is running locally or accessible
|
|
203
|
+
2. **Test Database**: Create a test database (usually `pg_multitenant_test`)
|
|
204
|
+
3. **Permissions**: Ensure test user has schema creation/deletion permissions
|
|
205
|
+
|
|
206
|
+
### **Setup Commands**
|
|
207
|
+
|
|
208
|
+
```bash
|
|
209
|
+
# Create test database (PostgreSQL)
|
|
210
|
+
createdb pg_multitenant_test
|
|
211
|
+
|
|
212
|
+
# Or using psql
|
|
213
|
+
psql -c "CREATE DATABASE pg_multitenant_test;"
|
|
214
|
+
|
|
215
|
+
# Grant necessary permissions
|
|
216
|
+
psql -d pg_multitenant_test -c "GRANT ALL PRIVILEGES ON DATABASE pg_multitenant_test TO postgres;"
|
|
217
|
+
```
|
|
218
|
+
|
|
219
|
+
### **Connection Configuration**
|
|
220
|
+
|
|
221
|
+
Integration tests automatically handle connection setup:
|
|
222
|
+
|
|
223
|
+
```ruby
|
|
224
|
+
let(:db_config) do
|
|
225
|
+
{
|
|
226
|
+
host: ENV["PG_HOST"] || "localhost",
|
|
227
|
+
port: ENV["PG_PORT"] || 5432,
|
|
228
|
+
dbname: ENV["PG_TEST_DATABASE"] || "pg_multitenant_test",
|
|
229
|
+
user: ENV["PG_USER"] || "postgres",
|
|
230
|
+
password: ENV["PG_PASSWORD"] || ""
|
|
231
|
+
}
|
|
232
|
+
end
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
## ๐งน **Test Cleanup and Isolation**
|
|
236
|
+
|
|
237
|
+
### **Automatic Cleanup**
|
|
238
|
+
|
|
239
|
+
Integration tests include comprehensive cleanup:
|
|
240
|
+
|
|
241
|
+
```ruby
|
|
242
|
+
after do
|
|
243
|
+
# Clean up test schemas
|
|
244
|
+
["tenant_a", "tenant_b", "tenant_c", "public_test"].each do |schema|
|
|
245
|
+
PgMultitenantSchemas::SchemaSwitcher.drop_schema(schema, cascade: true)
|
|
246
|
+
rescue => e
|
|
247
|
+
# Log cleanup errors but don't fail tests
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
# Reset to public schema
|
|
251
|
+
PgMultitenantSchemas::SchemaSwitcher.reset_to_public_schema
|
|
252
|
+
end
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### **Schema Isolation**
|
|
256
|
+
|
|
257
|
+
Each test creates and destroys its own schemas:
|
|
258
|
+
|
|
259
|
+
```ruby
|
|
260
|
+
let(:tenants) { ["tenant_a", "tenant_b", "tenant_c"] }
|
|
261
|
+
|
|
262
|
+
before do
|
|
263
|
+
# Ensure clean state
|
|
264
|
+
tenants.each { |t| PgMultitenantSchemas::SchemaSwitcher.create_schema(t) }
|
|
265
|
+
end
|
|
266
|
+
```
|
|
267
|
+
|
|
268
|
+
## ๐ **Test Coverage and Quality**
|
|
269
|
+
|
|
270
|
+
### **Current Test Metrics**
|
|
271
|
+
|
|
272
|
+
- **Total Examples**: 86 (65 unit + 21 integration)
|
|
273
|
+
- **Failures**: 0
|
|
274
|
+
- **Coverage Areas**:
|
|
275
|
+
- โ
Configuration management
|
|
276
|
+
- โ
Schema operations
|
|
277
|
+
- โ
Tenant resolution
|
|
278
|
+
- โ
Context switching
|
|
279
|
+
- โ
Error handling
|
|
280
|
+
- โ
Performance characteristics
|
|
281
|
+
- โ
Thread safety
|
|
282
|
+
- โ
Rails integration
|
|
283
|
+
- โ
Multi-schema scenarios
|
|
284
|
+
- โ
Concurrent access patterns
|
|
285
|
+
|
|
286
|
+
### **Test Quality Features**
|
|
287
|
+
|
|
288
|
+
- **Fast Unit Tests**: Complete in ~0.03 seconds
|
|
289
|
+
- **Comprehensive Integration**: Real PostgreSQL testing
|
|
290
|
+
- **Thread Safety**: Multi-threaded scenario testing
|
|
291
|
+
- **Memory Leak Detection**: Performance monitoring
|
|
292
|
+
- **Edge Case Coverage**: Unicode, special characters, malformed data
|
|
293
|
+
- **Error Scenario Testing**: Connection failures, invalid schemas
|
|
294
|
+
|
|
295
|
+
## ๐ง **Debugging Tests**
|
|
296
|
+
|
|
297
|
+
### **Common Issues and Solutions**
|
|
298
|
+
|
|
299
|
+
#### **PostgreSQL Connection Issues**
|
|
300
|
+
```bash
|
|
301
|
+
# Check if PostgreSQL is running
|
|
302
|
+
pg_isready
|
|
303
|
+
|
|
304
|
+
# Check connection with custom settings
|
|
305
|
+
PG_HOST=localhost PG_USER=myuser bundle exec rspec --tag integration
|
|
306
|
+
```
|
|
307
|
+
|
|
308
|
+
#### **Schema Cleanup Issues**
|
|
309
|
+
```ruby
|
|
310
|
+
# Manual cleanup if tests leave artifacts
|
|
311
|
+
psql -d pg_multitenant_test -c "DROP SCHEMA IF EXISTS tenant_a CASCADE;"
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
#### **Verbose Test Output**
|
|
315
|
+
```bash
|
|
316
|
+
# Run with detailed output for debugging
|
|
317
|
+
bundle exec rspec --format documentation --color
|
|
318
|
+
|
|
319
|
+
# Run specific failing test
|
|
320
|
+
bundle exec rspec spec/multiple_schemas_integration_spec.rb:90 --format documentation
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
### **Test Development Tips**
|
|
324
|
+
|
|
325
|
+
1. **Unit Test First**: Write fast unit tests before integration tests
|
|
326
|
+
2. **Mock External Dependencies**: Use mocks for database connections in unit tests
|
|
327
|
+
3. **Clean Isolation**: Ensure each test cleans up after itself
|
|
328
|
+
4. **Descriptive Names**: Use clear, descriptive test names
|
|
329
|
+
5. **Edge Cases**: Test boundary conditions and error scenarios
|
|
330
|
+
|
|
331
|
+
## ๐ **Related Documentation**
|
|
332
|
+
|
|
333
|
+
- **[Architecture Overview](README.md)**: Understanding the overall gem structure
|
|
334
|
+
- **[Configuration Guide](configuration.md)**: Test configuration options
|
|
335
|
+
- **[Rails Integration](rails_integration.md)**: Framework-specific testing patterns
|
|
336
|
+
- **[Error Handling](errors.md)**: Error testing strategies
|
|
337
|
+
|
|
338
|
+
## ๐ฏ **Test Development Workflow**
|
|
339
|
+
|
|
340
|
+
### **Adding New Tests**
|
|
341
|
+
|
|
342
|
+
1. **Identify Test Type**: Unit vs Integration
|
|
343
|
+
2. **Create Test File**: Follow naming convention `*_spec.rb`
|
|
344
|
+
3. **Add Appropriate Tags**: Use `:integration` for database tests
|
|
345
|
+
4. **Include Setup/Teardown**: Proper before/after hooks
|
|
346
|
+
5. **Test Edge Cases**: Include error scenarios
|
|
347
|
+
6. **Run Test Suite**: Verify no regressions
|
|
348
|
+
|
|
349
|
+
### **Best Practices**
|
|
350
|
+
|
|
351
|
+
- **Keep Unit Tests Fast**: Avoid database calls in unit tests
|
|
352
|
+
- **Use Descriptive Contexts**: Group related tests logically
|
|
353
|
+
- **Test Public APIs**: Focus on public interface testing
|
|
354
|
+
- **Mock External Services**: Isolate component under test
|
|
355
|
+
- **Include Performance Tests**: Monitor resource usage
|
|
356
|
+
- **Document Complex Scenarios**: Comment non-obvious test logic
|
|
357
|
+
|
|
358
|
+
This comprehensive test suite ensures the PgMultitenantSchemas gem is robust, reliable, and ready for production use across various scenarios and environments.
|
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Context Management Example
|
|
5
|
+
# Demonstrates thread-safe tenant context management
|
|
6
|
+
|
|
7
|
+
require_relative "../lib/pg_multitenant_schemas"
|
|
8
|
+
|
|
9
|
+
puts "๐งต PG Multitenant Schemas - Context Management Example"
|
|
10
|
+
puts "======================================================"
|
|
11
|
+
|
|
12
|
+
# Mock tenant class for demonstration
|
|
13
|
+
class MockTenant
|
|
14
|
+
attr_reader :id, :subdomain, :name
|
|
15
|
+
|
|
16
|
+
def initialize(id, subdomain, name)
|
|
17
|
+
@id = id
|
|
18
|
+
@subdomain = subdomain
|
|
19
|
+
@name = name
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def to_s
|
|
23
|
+
subdomain
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
# Create mock tenants
|
|
28
|
+
tenant_a = MockTenant.new(1, "acme_corp", "ACME Corporation")
|
|
29
|
+
tenant_b = MockTenant.new(2, "beta_inc", "Beta Inc")
|
|
30
|
+
|
|
31
|
+
# Example 1: Basic Context Management
|
|
32
|
+
puts "\n๐ Example 1: Basic Context Management"
|
|
33
|
+
puts "--------------------------------------"
|
|
34
|
+
|
|
35
|
+
# Check initial state
|
|
36
|
+
puts "Initial context:"
|
|
37
|
+
puts " Current tenant: #{PgMultitenantSchemas::Context.current_tenant || "none"}"
|
|
38
|
+
puts " Current schema: #{PgMultitenantSchemas::Context.current_schema}"
|
|
39
|
+
|
|
40
|
+
# Switch to tenant A
|
|
41
|
+
puts "\nSwitching to tenant A (#{tenant_a.subdomain}):"
|
|
42
|
+
PgMultitenantSchemas::Context.switch_to_tenant(tenant_a)
|
|
43
|
+
puts " Current tenant: #{PgMultitenantSchemas::Context.current_tenant}"
|
|
44
|
+
puts " Current schema: #{PgMultitenantSchemas::Context.current_schema}"
|
|
45
|
+
|
|
46
|
+
# Switch to tenant B
|
|
47
|
+
puts "\nSwitching to tenant B (#{tenant_b.subdomain}):"
|
|
48
|
+
PgMultitenantSchemas::Context.switch_to_tenant(tenant_b)
|
|
49
|
+
puts " Current tenant: #{PgMultitenantSchemas::Context.current_tenant}"
|
|
50
|
+
puts " Current schema: #{PgMultitenantSchemas::Context.current_schema}"
|
|
51
|
+
|
|
52
|
+
# Reset context
|
|
53
|
+
puts "\nResetting context:"
|
|
54
|
+
PgMultitenantSchemas::Context.reset!
|
|
55
|
+
puts " Current tenant: #{PgMultitenantSchemas::Context.current_tenant || "none"}"
|
|
56
|
+
puts " Current schema: #{PgMultitenantSchemas::Context.current_schema}"
|
|
57
|
+
|
|
58
|
+
# Example 2: Block-Based Context Management
|
|
59
|
+
puts "\n๐ Example 2: Block-Based Context Management"
|
|
60
|
+
puts "--------------------------------------------"
|
|
61
|
+
|
|
62
|
+
puts "Before block - Current schema: #{PgMultitenantSchemas::Context.current_schema}"
|
|
63
|
+
|
|
64
|
+
PgMultitenantSchemas::Context.with_tenant(tenant_a) do
|
|
65
|
+
puts "Inside block - Current schema: #{PgMultitenantSchemas::Context.current_schema}"
|
|
66
|
+
puts "Inside block - Current tenant: #{PgMultitenantSchemas::Context.current_tenant}"
|
|
67
|
+
|
|
68
|
+
# Simulate some work in tenant context
|
|
69
|
+
puts " ๐ง Performing operations for #{tenant_a.name}..."
|
|
70
|
+
sleep(0.1) # Simulate work
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
puts "After block - Current schema: #{PgMultitenantSchemas::Context.current_schema}"
|
|
74
|
+
puts "After block - Current tenant: #{PgMultitenantSchemas::Context.current_tenant || "none"}"
|
|
75
|
+
|
|
76
|
+
# Example 3: Nested Context Management
|
|
77
|
+
puts "\n๐ช Example 3: Nested Context Management"
|
|
78
|
+
puts "---------------------------------------"
|
|
79
|
+
|
|
80
|
+
puts "Starting nested context example..."
|
|
81
|
+
|
|
82
|
+
PgMultitenantSchemas::Context.with_tenant(tenant_a) do
|
|
83
|
+
puts "Level 1 - In tenant A (#{PgMultitenantSchemas::Context.current_schema})"
|
|
84
|
+
|
|
85
|
+
PgMultitenantSchemas::Context.with_tenant(tenant_b) do
|
|
86
|
+
puts " Level 2 - In tenant B (#{PgMultitenantSchemas::Context.current_schema})"
|
|
87
|
+
|
|
88
|
+
# Even deeper nesting
|
|
89
|
+
PgMultitenantSchemas::Context.with_tenant("custom_schema") do
|
|
90
|
+
puts " Level 3 - In custom schema (#{PgMultitenantSchemas::Context.current_schema})"
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
puts " Level 2 - Back in tenant B (#{PgMultitenantSchemas::Context.current_schema})"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
puts "Level 1 - Back in tenant A (#{PgMultitenantSchemas::Context.current_schema})"
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
puts "Nested context complete - Current schema: #{PgMultitenantSchemas::Context.current_schema}"
|
|
100
|
+
|
|
101
|
+
# Example 4: Error Handling in Context
|
|
102
|
+
puts "\n๐จ Example 4: Error Handling in Context"
|
|
103
|
+
puts "---------------------------------------"
|
|
104
|
+
|
|
105
|
+
puts "Testing error handling with context restoration..."
|
|
106
|
+
|
|
107
|
+
begin
|
|
108
|
+
PgMultitenantSchemas::Context.with_tenant(tenant_a) do
|
|
109
|
+
puts "In tenant A context: #{PgMultitenantSchemas::Context.current_schema}"
|
|
110
|
+
|
|
111
|
+
# Simulate an error
|
|
112
|
+
raise StandardError, "Simulated error!"
|
|
113
|
+
end
|
|
114
|
+
rescue StandardError => e
|
|
115
|
+
puts "Caught error: #{e.message}"
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
puts "After error - Current schema: #{PgMultitenantSchemas::Context.current_schema}"
|
|
119
|
+
puts "โ
Context properly restored after error!"
|
|
120
|
+
|
|
121
|
+
# Example 5: Thread Safety Demonstration
|
|
122
|
+
puts "\n๐งต Example 5: Thread Safety Demonstration"
|
|
123
|
+
puts "-----------------------------------------"
|
|
124
|
+
|
|
125
|
+
threads = []
|
|
126
|
+
results = {}
|
|
127
|
+
|
|
128
|
+
# Create multiple threads with different tenant contexts
|
|
129
|
+
[tenant_a, tenant_b].each_with_index do |tenant, index|
|
|
130
|
+
threads << Thread.new do
|
|
131
|
+
thread_id = "Thread-#{index + 1}"
|
|
132
|
+
results[thread_id] = []
|
|
133
|
+
|
|
134
|
+
PgMultitenantSchemas::Context.with_tenant(tenant) do
|
|
135
|
+
5.times do |i|
|
|
136
|
+
current_schema = PgMultitenantSchemas::Context.current_schema
|
|
137
|
+
current_tenant = PgMultitenantSchemas::Context.current_tenant
|
|
138
|
+
|
|
139
|
+
results[thread_id] << {
|
|
140
|
+
iteration: i + 1,
|
|
141
|
+
schema: current_schema,
|
|
142
|
+
tenant: current_tenant&.subdomain,
|
|
143
|
+
thread: Thread.current.object_id
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
sleep(0.01) # Small delay to allow thread interleaving
|
|
147
|
+
end
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
# Wait for all threads to complete
|
|
153
|
+
threads.each(&:join)
|
|
154
|
+
|
|
155
|
+
# Display results
|
|
156
|
+
puts "Thread safety results:"
|
|
157
|
+
results.each do |thread_id, iterations|
|
|
158
|
+
puts "#{thread_id}:"
|
|
159
|
+
iterations.each do |result|
|
|
160
|
+
puts " Iteration #{result[:iteration]}: #{result[:schema]} (tenant: #{result[:tenant]})"
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
puts "โ
Each thread maintained its own tenant context!"
|
|
165
|
+
|
|
166
|
+
# Example 6: Schema Management Through Context
|
|
167
|
+
puts "\n๐ง Example 6: Schema Management Through Context"
|
|
168
|
+
puts "----------------------------------------------"
|
|
169
|
+
|
|
170
|
+
test_tenant = MockTenant.new(99, "test_tenant", "Test Tenant")
|
|
171
|
+
|
|
172
|
+
begin
|
|
173
|
+
# Create tenant schema
|
|
174
|
+
puts "Creating schema for tenant: #{test_tenant.subdomain}"
|
|
175
|
+
PgMultitenantSchemas::Context.create_tenant_schema(test_tenant)
|
|
176
|
+
puts "โ
Schema created successfully"
|
|
177
|
+
|
|
178
|
+
# Use the tenant context
|
|
179
|
+
PgMultitenantSchemas::Context.with_tenant(test_tenant) do
|
|
180
|
+
puts "Operating in tenant schema: #{PgMultitenantSchemas::Context.current_schema}"
|
|
181
|
+
# Simulate tenant operations
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
# Clean up
|
|
185
|
+
puts "Cleaning up test schema..."
|
|
186
|
+
PgMultitenantSchemas::Context.drop_tenant_schema(test_tenant)
|
|
187
|
+
puts "โ
Schema cleaned up successfully"
|
|
188
|
+
rescue PgMultitenantSchemas::SchemaError => e
|
|
189
|
+
puts "โ Schema operation failed: #{e.message}"
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
puts "\nโจ Context management example completed!"
|
|
193
|
+
puts "\n๐ Key Takeaways:"
|
|
194
|
+
puts " โข Context is automatically restored after blocks"
|
|
195
|
+
puts " โข Each thread maintains independent tenant context"
|
|
196
|
+
puts " โข Nested contexts work correctly with proper restoration"
|
|
197
|
+
puts " โข Error handling doesn't break context restoration"
|
|
198
|
+
puts " โข Context can handle both tenant objects and schema strings"
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
# frozen_string_literal: true
|
|
3
|
+
|
|
4
|
+
# Example script demonstrating the new migration workflow
|
|
5
|
+
# This shows how the simplified migration system works
|
|
6
|
+
|
|
7
|
+
require_relative "../lib/pg_multitenant_schemas"
|
|
8
|
+
|
|
9
|
+
puts "๐ PG Multitenant Schemas - Migration Workflow Example"
|
|
10
|
+
puts "======================================================"
|
|
11
|
+
|
|
12
|
+
# Example 1: Setup new tenant with full migration
|
|
13
|
+
puts "\n๐ Example 1: Setting up a new tenant"
|
|
14
|
+
puts "Command: PgMultitenantSchemas::Migrator.setup_tenant('example_corp')"
|
|
15
|
+
puts "Result: Creates schema + runs all migrations automatically"
|
|
16
|
+
|
|
17
|
+
# Example 2: Migration status check
|
|
18
|
+
puts "\n๐ Example 2: Checking migration status"
|
|
19
|
+
puts "Command: PgMultitenantSchemas::Migrator.migration_status"
|
|
20
|
+
puts "Result: Shows status across all tenant schemas"
|
|
21
|
+
|
|
22
|
+
# Example 3: Bulk migration
|
|
23
|
+
puts "\n๐ Example 3: Migrate all tenants"
|
|
24
|
+
puts "Command: PgMultitenantSchemas::Migrator.migrate_all"
|
|
25
|
+
puts "Result: Runs pending migrations across all tenant schemas"
|
|
26
|
+
|
|
27
|
+
# Example 4: Individual tenant migration
|
|
28
|
+
puts "\n๐ฏ Example 4: Migrate specific tenant"
|
|
29
|
+
puts "Command: PgMultitenantSchemas::Migrator.migrate_tenant('acme_corp')"
|
|
30
|
+
puts "Result: Runs migrations only for acme_corp schema"
|
|
31
|
+
|
|
32
|
+
# Example 5: Create tenant with attributes
|
|
33
|
+
puts "\n๐ข Example 5: Create tenant with attributes"
|
|
34
|
+
puts "Command: PgMultitenantSchemas::Migrator.create_tenant_with_schema({subdomain: 'newco', name: 'New Company'})"
|
|
35
|
+
puts "Result: Creates Tenant record + schema + runs migrations"
|
|
36
|
+
|
|
37
|
+
puts "\nโจ Key Benefits:"
|
|
38
|
+
puts " โข Single command migration across all tenants"
|
|
39
|
+
puts " โข Automatic error handling per tenant"
|
|
40
|
+
puts " โข Progress tracking and status reporting"
|
|
41
|
+
puts " โข Simplified rake task interface"
|
|
42
|
+
puts " โข Programmatic API for custom workflows"
|
|
43
|
+
|
|
44
|
+
puts "\n๐ง Rake Task Examples:"
|
|
45
|
+
puts " rails tenants:migrate # Migrate all tenants"
|
|
46
|
+
puts " rails tenants:create[newco] # Setup new tenant"
|
|
47
|
+
puts " rails tenants:status # Check migration status"
|
|
48
|
+
puts " rails tenants:list # List all tenant schemas"
|
|
49
|
+
|
|
50
|
+
puts "\n๐ See README.md for complete documentation"
|