familia 2.0.0.pre26 → 2.0.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 +4 -4
- data/CHANGELOG.rst +49 -0
- data/Gemfile +1 -0
- data/Gemfile.lock +2 -2
- data/README.md +1 -3
- data/docs/guides/feature-encrypted-fields.md +1 -1
- data/docs/guides/feature-expiration.md +1 -1
- data/docs/guides/feature-quantization.md +1 -1
- data/docs/overview.md +7 -7
- data/docs/reference/api-technical.md +103 -7
- data/familia.gemspec +1 -2
- data/lib/familia/data_type/types/hashkey.rb +238 -0
- data/lib/familia/data_type/types/listkey.rb +110 -4
- data/lib/familia/data_type/types/sorted_set.rb +365 -0
- data/lib/familia/data_type/types/stringkey.rb +139 -0
- data/lib/familia/data_type/types/unsorted_set.rb +122 -2
- data/lib/familia/version.rb +1 -1
- metadata +2 -27
- data/docs/migrating/v2.0.0-pre.md +0 -84
- data/docs/migrating/v2.0.0-pre11.md +0 -253
- data/docs/migrating/v2.0.0-pre12.md +0 -306
- data/docs/migrating/v2.0.0-pre13.md +0 -95
- data/docs/migrating/v2.0.0-pre14.md +0 -37
- data/docs/migrating/v2.0.0-pre18.md +0 -58
- data/docs/migrating/v2.0.0-pre19.md +0 -197
- data/docs/migrating/v2.0.0-pre22.md +0 -241
- data/docs/migrating/v2.0.0-pre5.md +0 -131
- data/docs/migrating/v2.0.0-pre6.md +0 -154
- data/docs/migrating/v2.0.0-pre7.md +0 -222
|
@@ -1,241 +0,0 @@
|
|
|
1
|
-
# Migrating Guide: v2.0.0-pre22
|
|
2
|
-
|
|
3
|
-
This version introduces significant performance optimizations for Redis operations, completes the bidirectional relationships feature, and improves flexibility for external identifiers.
|
|
4
|
-
|
|
5
|
-
## Major Features
|
|
6
|
-
|
|
7
|
-
### Bidirectional Relationship Methods
|
|
8
|
-
|
|
9
|
-
**What's New:**
|
|
10
|
-
|
|
11
|
-
The `participates_in` declarations now generate reverse collection methods with the `_instances` suffix, providing symmetric access to relationships from both directions.
|
|
12
|
-
|
|
13
|
-
**Generated Methods:**
|
|
14
|
-
```ruby
|
|
15
|
-
class User < Familia::Horreum
|
|
16
|
-
participates_in Team, :members
|
|
17
|
-
participates_in Organization, :employees
|
|
18
|
-
end
|
|
19
|
-
|
|
20
|
-
# New reverse collection methods:
|
|
21
|
-
user.team_instances # => [team1, team2]
|
|
22
|
-
user.team_ids # => ["team_123", "team_456"]
|
|
23
|
-
user.team? # => true/false
|
|
24
|
-
user.team_count # => 2
|
|
25
|
-
|
|
26
|
-
user.organization_instances # => [org1]
|
|
27
|
-
user.organization_ids # => ["org_789"]
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
**Custom Names:**
|
|
31
|
-
```ruby
|
|
32
|
-
class User < Familia::Horreum
|
|
33
|
-
participates_in Organization, :contractors, as: :clients
|
|
34
|
-
end
|
|
35
|
-
|
|
36
|
-
user.clients_instances # Instead of organization_instances
|
|
37
|
-
user.clients_ids # Instead of organization_ids
|
|
38
|
-
```
|
|
39
|
-
|
|
40
|
-
**Migration:**
|
|
41
|
-
|
|
42
|
-
No changes required for existing code. The new methods are additive and don't affect existing `participates_in` functionality.
|
|
43
|
-
|
|
44
|
-
### Pipelined Bulk Loading
|
|
45
|
-
|
|
46
|
-
**What's New:**
|
|
47
|
-
|
|
48
|
-
New `load_multi` methods provide up to 2× performance improvement for bulk object loading by using Redis pipelining.
|
|
49
|
-
|
|
50
|
-
**Before (N×2 commands):**
|
|
51
|
-
```ruby
|
|
52
|
-
users = ids.map { |id| User.find_by_id(id) }
|
|
53
|
-
# For 14 objects: 28 Redis commands (14 EXISTS + 14 HGETALL)
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
**After (1 round trip):**
|
|
57
|
-
```ruby
|
|
58
|
-
users = User.load_multi(ids)
|
|
59
|
-
# For 14 objects: 1 pipelined batch with 14 HGETALL commands
|
|
60
|
-
```
|
|
61
|
-
|
|
62
|
-
**Additional Methods:**
|
|
63
|
-
```ruby
|
|
64
|
-
# Load by full dbkeys
|
|
65
|
-
users = User.load_multi_by_keys(['user:123:object', 'user:456:object'])
|
|
66
|
-
|
|
67
|
-
# Filter out nils for missing objects
|
|
68
|
-
existing_only = User.load_multi(ids).compact
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
### Optional EXISTS Check Optimization
|
|
72
|
-
|
|
73
|
-
**What's New:**
|
|
74
|
-
|
|
75
|
-
The `find_by_id` and related methods now support skipping the EXISTS check for 50% reduction in Redis commands.
|
|
76
|
-
|
|
77
|
-
```ruby
|
|
78
|
-
# Default behavior (unchanged, 2 commands)
|
|
79
|
-
user = User.find_by_id(123)
|
|
80
|
-
|
|
81
|
-
# Optimized mode (1 command)
|
|
82
|
-
user = User.find_by_id(123, check_exists: false)
|
|
83
|
-
```
|
|
84
|
-
|
|
85
|
-
**When to Use:**
|
|
86
|
-
- Performance-critical paths
|
|
87
|
-
- Bulk operations with known-to-exist keys
|
|
88
|
-
- High-throughput APIs
|
|
89
|
-
- Loading from sorted set results
|
|
90
|
-
|
|
91
|
-
## Enhanced Features
|
|
92
|
-
|
|
93
|
-
### Flexible External Identifier Format
|
|
94
|
-
|
|
95
|
-
**What's New:**
|
|
96
|
-
|
|
97
|
-
The `external_identifier` feature now supports custom format templates.
|
|
98
|
-
|
|
99
|
-
**Examples:**
|
|
100
|
-
```ruby
|
|
101
|
-
# Default format (unchanged)
|
|
102
|
-
class User < Familia::Horreum
|
|
103
|
-
feature :external_identifier
|
|
104
|
-
end
|
|
105
|
-
user.extid # => "ext_abc123def456"
|
|
106
|
-
|
|
107
|
-
# Custom prefix
|
|
108
|
-
class Customer < Familia::Horreum
|
|
109
|
-
feature :external_identifier, format: 'cust_%{id}'
|
|
110
|
-
end
|
|
111
|
-
customer.extid # => "cust_abc123def456"
|
|
112
|
-
|
|
113
|
-
# Different separator
|
|
114
|
-
class APIKey < Familia::Horreum
|
|
115
|
-
feature :external_identifier, format: 'api-%{id}'
|
|
116
|
-
end
|
|
117
|
-
key.extid # => "api-abc123def456"
|
|
118
|
-
```
|
|
119
|
-
|
|
120
|
-
### Atomic Index Rebuilding
|
|
121
|
-
|
|
122
|
-
**What's New:**
|
|
123
|
-
|
|
124
|
-
Auto-generated rebuild methods for all unique and multi indexes with zero downtime.
|
|
125
|
-
|
|
126
|
-
**Examples:**
|
|
127
|
-
|
|
128
|
-
```ruby
|
|
129
|
-
# Class-level unique index
|
|
130
|
-
User.rebuild_email_lookup
|
|
131
|
-
|
|
132
|
-
# Instance-scoped unique index
|
|
133
|
-
company.rebuild_badge_index
|
|
134
|
-
|
|
135
|
-
# With progress tracking
|
|
136
|
-
User.rebuild_email_lookup(batch_size: 100) do |progress|
|
|
137
|
-
puts "#{progress[:completed]}/#{progress[:total]}"
|
|
138
|
-
end
|
|
139
|
-
```
|
|
140
|
-
|
|
141
|
-
When to Use:
|
|
142
|
-
- After data migrations or bulk imports
|
|
143
|
-
- Recovering from index corruption
|
|
144
|
-
- Adding indexes to existing data
|
|
145
|
-
|
|
146
|
-
Migration:
|
|
147
|
-
|
|
148
|
-
Run rebuild methods once after upgrade to ensure index consistency. No code changes required—methods are auto-generated from existing
|
|
149
|
-
unique_index and multi_index declarations.
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
## Bug Fixes
|
|
153
|
-
|
|
154
|
-
### Symbol/String Target Classes in participates_in
|
|
155
|
-
|
|
156
|
-
**What Was Fixed:**
|
|
157
|
-
|
|
158
|
-
Fixed multiple bugs when using Symbol or String class names in `participates_in`:
|
|
159
|
-
|
|
160
|
-
```ruby
|
|
161
|
-
class Domain < Familia::Horreum
|
|
162
|
-
# All forms now work correctly:
|
|
163
|
-
participates_in Customer, :domains # Class object
|
|
164
|
-
participates_in :Customer, :domains # Symbol (was broken)
|
|
165
|
-
participates_in 'Customer', :domains # String (was broken)
|
|
166
|
-
end
|
|
167
|
-
```
|
|
168
|
-
|
|
169
|
-
**Errors Fixed:**
|
|
170
|
-
- `NoMethodError: private method 'member_by_config_name'`
|
|
171
|
-
- `NoMethodError: undefined method 'familia_name' for Symbol`
|
|
172
|
-
- `NoMethodError: undefined method 'config_name' for Symbol`
|
|
173
|
-
- Confusing nil errors for unloaded classes
|
|
174
|
-
|
|
175
|
-
**New Behavior:**
|
|
176
|
-
|
|
177
|
-
When a target class can't be resolved, you now get a helpful error:
|
|
178
|
-
```
|
|
179
|
-
Target class 'Customer' could not be resolved.
|
|
180
|
-
Possible causes:
|
|
181
|
-
1. The class hasn't been loaded yet (load order issue)
|
|
182
|
-
2. The class name is misspelled
|
|
183
|
-
3. The class doesn't inherit from Familia::Horreum
|
|
184
|
-
|
|
185
|
-
Registered Familia classes: ["User", "Team", "Organization"]
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
## Performance Recommendations
|
|
189
|
-
|
|
190
|
-
### Use Bulk Loading for Collections
|
|
191
|
-
|
|
192
|
-
```ruby
|
|
193
|
-
# ❌ Avoid N+1 queries
|
|
194
|
-
team.members.to_a.map { |id| User.find_by_id(id) }
|
|
195
|
-
|
|
196
|
-
# ✅ Use bulk loading
|
|
197
|
-
User.load_multi(team.members.to_a)
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
### Skip EXISTS Checks When Safe
|
|
201
|
-
|
|
202
|
-
```ruby
|
|
203
|
-
# When loading from sorted sets (keys guaranteed to exist)
|
|
204
|
-
task_ids = project.tasks.range(0, 9)
|
|
205
|
-
tasks = Task.load_multi(task_ids) # Or use check_exists: false
|
|
206
|
-
|
|
207
|
-
# For known-existing keys
|
|
208
|
-
user = User.find_by_id(session[:user_id], check_exists: false)
|
|
209
|
-
```
|
|
210
|
-
|
|
211
|
-
### Leverage Reverse Collection Methods
|
|
212
|
-
|
|
213
|
-
```ruby
|
|
214
|
-
# ❌ Manual parsing of participations
|
|
215
|
-
team_keys = user.participations.members.select { |k| k.start_with?("team:") }
|
|
216
|
-
team_ids = team_keys.map { |k| k.split(':')[1] }
|
|
217
|
-
teams = Team.load_multi(team_ids)
|
|
218
|
-
|
|
219
|
-
# ✅ Use generated methods
|
|
220
|
-
teams = user.team_instances
|
|
221
|
-
```
|
|
222
|
-
|
|
223
|
-
## Backwards Compatibility
|
|
224
|
-
|
|
225
|
-
All changes in this version are backwards compatible:
|
|
226
|
-
|
|
227
|
-
- New methods are additive and don't affect existing APIs
|
|
228
|
-
- Default behaviors remain unchanged
|
|
229
|
-
- Symbol/String fixes don't require code changes
|
|
230
|
-
|
|
231
|
-
## Recommended Actions
|
|
232
|
-
|
|
233
|
-
1. **Adopt bulk loading** for performance-critical paths
|
|
234
|
-
2. **Use reverse collection methods** to simplify relationship queries
|
|
235
|
-
3. **Consider check_exists: false** for guaranteed-existing keys
|
|
236
|
-
4. **Update external_identifier formats** if custom prefixes are needed
|
|
237
|
-
|
|
238
|
-
## See Also
|
|
239
|
-
|
|
240
|
-
- [Relationships Guide](../guides/feature-relationships.md)
|
|
241
|
-
- [Performance Optimization Guide](../guides/optimized-loading.md)
|
|
@@ -1,131 +0,0 @@
|
|
|
1
|
-
# Migrating Guide: Security Features (v2.0.0-pre5)
|
|
2
|
-
|
|
3
|
-
This guide covers adopting the security enhancements introduced in v2.0.0-pre5.
|
|
4
|
-
|
|
5
|
-
## Security Feature Adoption
|
|
6
|
-
|
|
7
|
-
### 1. Configure Encryption Keys
|
|
8
|
-
|
|
9
|
-
Before using encrypted fields, configure encryption keys:
|
|
10
|
-
|
|
11
|
-
```ruby
|
|
12
|
-
Familia.configure do |config|
|
|
13
|
-
config.encryption_keys = {
|
|
14
|
-
v1: 'your-32-byte-base64-encoded-key==',
|
|
15
|
-
v2: 'newer-32-byte-base64-encoded-key=='
|
|
16
|
-
}
|
|
17
|
-
config.current_key_version = :v2
|
|
18
|
-
end
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
**Key Management:**
|
|
22
|
-
- Use secure key storage (environment variables, key management services)
|
|
23
|
-
- Rotate keys regularly by adding new versions
|
|
24
|
-
- Never remove old key versions while data exists
|
|
25
|
-
|
|
26
|
-
### 2. Identify Sensitive Fields
|
|
27
|
-
|
|
28
|
-
Mark fields that contain sensitive data:
|
|
29
|
-
|
|
30
|
-
**For Encryption:**
|
|
31
|
-
```ruby
|
|
32
|
-
class Vault < Familia::Horreum
|
|
33
|
-
feature :encrypted_fields
|
|
34
|
-
|
|
35
|
-
field :name # Plaintext
|
|
36
|
-
encrypted_field :secret_key # Encrypted at rest
|
|
37
|
-
encrypted_field :api_token # Transparent access
|
|
38
|
-
end
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
**For Transient Fields:**
|
|
42
|
-
```ruby
|
|
43
|
-
class User < Familia::Horreum
|
|
44
|
-
feature :transient_fields
|
|
45
|
-
|
|
46
|
-
field :email # Persisted
|
|
47
|
-
transient_field :password # Never persisted
|
|
48
|
-
transient_field :session_token # Runtime only
|
|
49
|
-
end
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
### 3. Update Serialization Code
|
|
53
|
-
|
|
54
|
-
Handle `ConcealedString` in serialization:
|
|
55
|
-
|
|
56
|
-
**Before:**
|
|
57
|
-
```ruby
|
|
58
|
-
def to_json
|
|
59
|
-
{ name: name, password: password }.to_json
|
|
60
|
-
end
|
|
61
|
-
```
|
|
62
|
-
|
|
63
|
-
**After:**
|
|
64
|
-
```ruby
|
|
65
|
-
def to_json
|
|
66
|
-
# ConcealedString automatically excluded from serialization
|
|
67
|
-
{ name: name }.to_json # password field omitted if transient
|
|
68
|
-
end
|
|
69
|
-
```
|
|
70
|
-
|
|
71
|
-
**Manual ConcealedString Handling:**
|
|
72
|
-
```ruby
|
|
73
|
-
# Access original value when needed
|
|
74
|
-
password.reveal # Returns actual string value
|
|
75
|
-
password.cleared? # Returns true if cleared from memory
|
|
76
|
-
```
|
|
77
|
-
|
|
78
|
-
### 4. Implement Key Rotation Procedures
|
|
79
|
-
|
|
80
|
-
**Rotation Process:**
|
|
81
|
-
1. Add new key version to configuration
|
|
82
|
-
2. Update `current_key_version`
|
|
83
|
-
3. Re-encrypt existing data using `re_encrypt_fields!`
|
|
84
|
-
4. Verify migration completion
|
|
85
|
-
5. Remove old keys after migration complete
|
|
86
|
-
|
|
87
|
-
**Example Rotation Script:**
|
|
88
|
-
```ruby
|
|
89
|
-
# Step 1: Add new key version
|
|
90
|
-
Familia.configure do |config|
|
|
91
|
-
config.encryption_keys = {
|
|
92
|
-
v2: ENV['OLD_ENCRYPTION_KEY'],
|
|
93
|
-
v3: ENV['NEW_ENCRYPTION_KEY']
|
|
94
|
-
}
|
|
95
|
-
config.current_key_version = :v3
|
|
96
|
-
end
|
|
97
|
-
|
|
98
|
-
# Step 2: Validate configuration
|
|
99
|
-
Familia::Encryption.validate_configuration!
|
|
100
|
-
|
|
101
|
-
# Step 3: Re-encrypt existing records
|
|
102
|
-
Vault.all.each do |vault|
|
|
103
|
-
vault.re_encrypt_fields! # Re-encrypts with current key
|
|
104
|
-
vault.save
|
|
105
|
-
end
|
|
106
|
-
|
|
107
|
-
# Step 4: Verify migration
|
|
108
|
-
Vault.all.each do |vault|
|
|
109
|
-
status = vault.encrypted_fields_status
|
|
110
|
-
puts "Vault #{vault.identifier}: #{status}"
|
|
111
|
-
end
|
|
112
|
-
|
|
113
|
-
# Step 5: Remove old key (after verification)
|
|
114
|
-
Familia.config.encryption_keys.delete(:v2)
|
|
115
|
-
```
|
|
116
|
-
|
|
117
|
-
## Security Best Practices
|
|
118
|
-
|
|
119
|
-
- **Environment Variables:** Store keys in environment variables, not code
|
|
120
|
-
- **Key Rotation:** Rotate encryption keys regularly (quarterly/annually)
|
|
121
|
-
- **Field Selection:** Only encrypt fields that truly need protection
|
|
122
|
-
- **Memory Clearing:** Use transient fields for temporary sensitive data
|
|
123
|
-
- **Logging:** Verify ConcealedString prevents accidental logging
|
|
124
|
-
- **Configuration Validation:** Use `validate_configuration!` before production
|
|
125
|
-
- **Monitoring:** Use `encrypted_fields_status` to track encryption state
|
|
126
|
-
|
|
127
|
-
## Next Steps
|
|
128
|
-
|
|
129
|
-
After implementing security features:
|
|
130
|
-
1. Review [Architecture Migration](v2.0.0-pre6.md) for persistence improvements
|
|
131
|
-
2. Explore [Relationships Migration](v2.0.0-pre7.md) for the relationship system
|
|
@@ -1,154 +0,0 @@
|
|
|
1
|
-
# Migrating Guide: Architecture Improvements (v2.0.0-pre6)
|
|
2
|
-
|
|
3
|
-
This guide covers the architecture enhancements and new persistence methods in v2.0.0-pre6.
|
|
4
|
-
|
|
5
|
-
## Architecture Improvements
|
|
6
|
-
|
|
7
|
-
### 1. Enhanced Persistence Operations
|
|
8
|
-
|
|
9
|
-
**New `save_if_not_exists` Method:**
|
|
10
|
-
```ruby
|
|
11
|
-
user = User.new(email: 'user@example.com')
|
|
12
|
-
|
|
13
|
-
# Only save if the user doesn't already exist
|
|
14
|
-
if user.save_if_not_exists
|
|
15
|
-
puts "User created successfully"
|
|
16
|
-
else
|
|
17
|
-
puts "User already exists"
|
|
18
|
-
end
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
**Atomic Persistence with Transactions:**
|
|
22
|
-
```ruby
|
|
23
|
-
user.transaction do |conn|
|
|
24
|
-
conn.set(user.key, user.serialize)
|
|
25
|
-
conn.sadd("all_users", user.identifier)
|
|
26
|
-
conn.expire(user.key, user.ttl) if user.ttl
|
|
27
|
-
end
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
### 2. Modular Class Structure
|
|
31
|
-
|
|
32
|
-
The Horreum class structure was reorganized for better maintainability:
|
|
33
|
-
|
|
34
|
-
**Core Modules:**
|
|
35
|
-
- `Familia::Horreum::Core` - Essential functionality
|
|
36
|
-
- `Familia::Horreum::ClassMethods` - Class-level methods
|
|
37
|
-
- `Familia::Horreum::Serialization` - Object serialization
|
|
38
|
-
- `Familia::Horreum::Commands` - Valkey/Redis command wrappers
|
|
39
|
-
|
|
40
|
-
**Feature System Improvements:**
|
|
41
|
-
- Dependency management between features
|
|
42
|
-
- Cleaner feature activation
|
|
43
|
-
- Better error handling for missing dependencies
|
|
44
|
-
|
|
45
|
-
### 3. Enhanced Error Handling
|
|
46
|
-
|
|
47
|
-
**New Exception Types:**
|
|
48
|
-
```ruby
|
|
49
|
-
begin
|
|
50
|
-
user.save!
|
|
51
|
-
rescue Familia::PersistenceError => e
|
|
52
|
-
puts "Failed to save: #{e.message}"
|
|
53
|
-
rescue Familia::ValidationError => e
|
|
54
|
-
puts "Validation failed: #{e.message}"
|
|
55
|
-
end
|
|
56
|
-
```
|
|
57
|
-
|
|
58
|
-
**Improved Data Consistency:**
|
|
59
|
-
- Automatic retry for transient Valkey/Redis connection issues
|
|
60
|
-
- Better handling of concurrent modifications
|
|
61
|
-
- Enhanced validation before persistence operations
|
|
62
|
-
|
|
63
|
-
## Migration Steps
|
|
64
|
-
|
|
65
|
-
### 1. Update Error Handling
|
|
66
|
-
|
|
67
|
-
**Before (v2.0.0-pre5):**
|
|
68
|
-
```ruby
|
|
69
|
-
begin
|
|
70
|
-
user.save
|
|
71
|
-
rescue => e
|
|
72
|
-
puts "Something went wrong: #{e}"
|
|
73
|
-
end
|
|
74
|
-
```
|
|
75
|
-
|
|
76
|
-
**After (v2.0.0-pre6):**
|
|
77
|
-
```ruby
|
|
78
|
-
begin
|
|
79
|
-
user.save
|
|
80
|
-
rescue Familia::PersistenceError => e
|
|
81
|
-
puts "Persistence failed: #{e.message}"
|
|
82
|
-
# Handle specific persistence issues
|
|
83
|
-
rescue Familia::ValidationError => e
|
|
84
|
-
puts "Invalid data: #{e.message}"
|
|
85
|
-
# Handle validation failures
|
|
86
|
-
end
|
|
87
|
-
```
|
|
88
|
-
|
|
89
|
-
### 2. Adopt Conditional Persistence
|
|
90
|
-
|
|
91
|
-
Replace existence checks with atomic operations:
|
|
92
|
-
|
|
93
|
-
**Before:**
|
|
94
|
-
```ruby
|
|
95
|
-
user = User.new(email: email)
|
|
96
|
-
unless User.exists?(email)
|
|
97
|
-
user.save
|
|
98
|
-
end
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
**After:**
|
|
102
|
-
```ruby
|
|
103
|
-
user = User.new(email: email)
|
|
104
|
-
user.save_if_not_exists
|
|
105
|
-
```
|
|
106
|
-
|
|
107
|
-
### 3. Leverage Transaction Support
|
|
108
|
-
|
|
109
|
-
For complex operations, use transactions:
|
|
110
|
-
|
|
111
|
-
```ruby
|
|
112
|
-
# Before - Multiple separate operations
|
|
113
|
-
user.save
|
|
114
|
-
user.tags.add(tag)
|
|
115
|
-
user.scores.add(score, timestamp)
|
|
116
|
-
|
|
117
|
-
# After - Atomic transaction
|
|
118
|
-
user.transaction do |conn|
|
|
119
|
-
conn.set(user.key, user.serialize)
|
|
120
|
-
conn.sadd(user.tags.key, tag)
|
|
121
|
-
conn.zadd(user.scores.key, timestamp, score)
|
|
122
|
-
end
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
## Performance Improvements
|
|
126
|
-
|
|
127
|
-
### Connection Management
|
|
128
|
-
- Improved connection pooling with better resource utilization
|
|
129
|
-
- Reduced connection overhead through intelligent connection reuse
|
|
130
|
-
- Enhanced concurrent operation support
|
|
131
|
-
|
|
132
|
-
### Feature System
|
|
133
|
-
- Lazy feature loading reduces memory footprint
|
|
134
|
-
- Optimized method dispatch for feature methods
|
|
135
|
-
- Better dependency resolution
|
|
136
|
-
|
|
137
|
-
## Breaking Changes
|
|
138
|
-
|
|
139
|
-
### Method Signatures
|
|
140
|
-
- Some internal methods changed signatures for better consistency
|
|
141
|
-
- Error handling improved with specific exception types
|
|
142
|
-
- Transaction block interface standardized
|
|
143
|
-
|
|
144
|
-
### Feature Dependencies
|
|
145
|
-
- Features now explicitly declare dependencies
|
|
146
|
-
- Better error messages for missing feature requirements
|
|
147
|
-
- Automatic dependency resolution where possible
|
|
148
|
-
|
|
149
|
-
## Next Steps
|
|
150
|
-
|
|
151
|
-
After completing architecture migration:
|
|
152
|
-
1. Explore [Relationships Migration](v2.0.0-pre7.md) for the comprehensive relationship system
|
|
153
|
-
2. Review updated documentation for architectural patterns
|
|
154
|
-
3. Consider adopting new persistence patterns in your application
|