familia 2.0.0.pre26 → 2.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 +4 -4
- data/CHANGELOG.rst +94 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +12 -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/guides/writing-migrations.md +345 -0
- data/docs/overview.md +7 -7
- data/docs/reference/api-technical.md +103 -7
- data/examples/migrations/v1_to_v2_serialization_migration.rb +374 -0
- data/examples/schemas/customer.json +33 -0
- data/examples/schemas/session.json +27 -0
- data/familia.gemspec +3 -2
- data/lib/familia/features/schema_validation.rb +139 -0
- data/lib/familia/migration/base.rb +447 -0
- data/lib/familia/migration/errors.rb +31 -0
- data/lib/familia/migration/model.rb +418 -0
- data/lib/familia/migration/pipeline.rb +226 -0
- data/lib/familia/migration/rake_tasks.rake +3 -0
- data/lib/familia/migration/rake_tasks.rb +160 -0
- data/lib/familia/migration/registry.rb +364 -0
- data/lib/familia/migration/runner.rb +311 -0
- data/lib/familia/migration/script.rb +234 -0
- data/lib/familia/migration.rb +43 -0
- data/lib/familia/schema_registry.rb +173 -0
- data/lib/familia/settings.rb +63 -1
- data/lib/familia/version.rb +1 -1
- data/lib/familia.rb +1 -0
- data/try/features/schema_registry_try.rb +193 -0
- data/try/features/schema_validation_feature_try.rb +218 -0
- data/try/migration/base_try.rb +226 -0
- data/try/migration/errors_try.rb +67 -0
- data/try/migration/integration_try.rb +451 -0
- data/try/migration/model_try.rb +431 -0
- data/try/migration/pipeline_try.rb +460 -0
- data/try/migration/rake_tasks_try.rb +61 -0
- data/try/migration/registry_try.rb +199 -0
- data/try/migration/runner_try.rb +311 -0
- data/try/migration/schema_validation_try.rb +201 -0
- data/try/migration/script_try.rb +192 -0
- data/try/migration/v1_to_v2_serialization_try.rb +513 -0
- data/try/performance/benchmarks_try.rb +11 -12
- metadata +45 -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
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# try/migration/base_try.rb
|
|
2
|
+
#
|
|
3
|
+
# frozen_string_literal: true
|
|
4
|
+
|
|
5
|
+
require_relative '../support/helpers/test_helpers'
|
|
6
|
+
require_relative '../../lib/familia/migration'
|
|
7
|
+
|
|
8
|
+
Familia.debug = false
|
|
9
|
+
|
|
10
|
+
# Store initial migration count to detect auto-registration
|
|
11
|
+
@initial_count = Familia::Migration.migrations.size
|
|
12
|
+
|
|
13
|
+
# Define test migrations inline
|
|
14
|
+
class TestBaseMigration < Familia::Migration::Base
|
|
15
|
+
self.migration_id = 'test_20260131_base'
|
|
16
|
+
self.description = 'Test base migration'
|
|
17
|
+
self.dependencies = ['some_other_migration']
|
|
18
|
+
|
|
19
|
+
def migration_needed?
|
|
20
|
+
true
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def migrate
|
|
24
|
+
track_stat(:items_processed, 5)
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
class ReversibleTestMigration < Familia::Migration::Base
|
|
29
|
+
self.migration_id = 'test_20260131_reversible'
|
|
30
|
+
|
|
31
|
+
def migration_needed?
|
|
32
|
+
true
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def migrate
|
|
36
|
+
# do something
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def down
|
|
40
|
+
# undo something
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class CliTestMigration < Familia::Migration::Base
|
|
45
|
+
self.migration_id = 'cli_test_migration'
|
|
46
|
+
|
|
47
|
+
class << self
|
|
48
|
+
attr_accessor :migration_needed_value, :migrate_called
|
|
49
|
+
end
|
|
50
|
+
self.migration_needed_value = true
|
|
51
|
+
self.migrate_called = false
|
|
52
|
+
|
|
53
|
+
def migration_needed?
|
|
54
|
+
self.class.migration_needed_value
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
def migrate
|
|
58
|
+
self.class.migrate_called = true
|
|
59
|
+
true
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
## migration_id class attribute works
|
|
64
|
+
TestBaseMigration.migration_id
|
|
65
|
+
#=> 'test_20260131_base'
|
|
66
|
+
|
|
67
|
+
## description class attribute works
|
|
68
|
+
TestBaseMigration.description
|
|
69
|
+
#=> 'Test base migration'
|
|
70
|
+
|
|
71
|
+
## dependencies class attribute works
|
|
72
|
+
TestBaseMigration.dependencies
|
|
73
|
+
#=> ['some_other_migration']
|
|
74
|
+
|
|
75
|
+
## Subclassing auto-registers migration
|
|
76
|
+
Familia::Migration.migrations.size > @initial_count
|
|
77
|
+
#=> true
|
|
78
|
+
|
|
79
|
+
## Subclass is in migrations list
|
|
80
|
+
Familia::Migration.migrations.include?(TestBaseMigration)
|
|
81
|
+
#=> true
|
|
82
|
+
|
|
83
|
+
## reversible? returns false when down not overridden
|
|
84
|
+
TestBaseMigration.new.reversible?
|
|
85
|
+
#=> false
|
|
86
|
+
|
|
87
|
+
## reversible? returns true when down is overridden
|
|
88
|
+
ReversibleTestMigration.new.reversible?
|
|
89
|
+
#=> true
|
|
90
|
+
|
|
91
|
+
## dry_run? returns true by default (no :run option)
|
|
92
|
+
TestBaseMigration.new.dry_run?
|
|
93
|
+
#=> true
|
|
94
|
+
|
|
95
|
+
## actual_run? returns falsy by default
|
|
96
|
+
TestBaseMigration.new.actual_run? ? true : false
|
|
97
|
+
#=> false
|
|
98
|
+
|
|
99
|
+
## dry_run? returns false when run: true
|
|
100
|
+
TestBaseMigration.new(run: true).dry_run?
|
|
101
|
+
#=> false
|
|
102
|
+
|
|
103
|
+
## actual_run? returns true when run: true
|
|
104
|
+
TestBaseMigration.new(run: true).actual_run?
|
|
105
|
+
#=> true
|
|
106
|
+
|
|
107
|
+
## for_realsies_this_time? yields only in actual run
|
|
108
|
+
results = []
|
|
109
|
+
dry = TestBaseMigration.new(run: false)
|
|
110
|
+
dry.for_realsies_this_time? { results << :dry }
|
|
111
|
+
live = TestBaseMigration.new(run: true)
|
|
112
|
+
live.for_realsies_this_time? { results << :live }
|
|
113
|
+
results
|
|
114
|
+
#=> [:live]
|
|
115
|
+
|
|
116
|
+
## track_stat increments counter
|
|
117
|
+
instance = TestBaseMigration.new
|
|
118
|
+
instance.track_stat(:foo)
|
|
119
|
+
instance.track_stat(:foo)
|
|
120
|
+
instance.track_stat(:bar, 5)
|
|
121
|
+
[instance.stats[:foo], instance.stats[:bar]]
|
|
122
|
+
#=> [2, 5]
|
|
123
|
+
|
|
124
|
+
## stats hash defaults to 0
|
|
125
|
+
instance = TestBaseMigration.new
|
|
126
|
+
instance.stats[:nonexistent]
|
|
127
|
+
#=> 0
|
|
128
|
+
|
|
129
|
+
## redis accessor returns connection (via send for protected method)
|
|
130
|
+
instance = TestBaseMigration.new
|
|
131
|
+
instance.send(:redis).respond_to?(:get)
|
|
132
|
+
#=> true
|
|
133
|
+
|
|
134
|
+
## Base class migration_needed? raises NotImplementedError
|
|
135
|
+
begin
|
|
136
|
+
Familia::Migration::Base.new.migration_needed?
|
|
137
|
+
false
|
|
138
|
+
rescue NotImplementedError
|
|
139
|
+
true
|
|
140
|
+
end
|
|
141
|
+
#=> true
|
|
142
|
+
|
|
143
|
+
## Base class migrate raises NotImplementedError
|
|
144
|
+
begin
|
|
145
|
+
Familia::Migration::Base.new.migrate
|
|
146
|
+
false
|
|
147
|
+
rescue NotImplementedError
|
|
148
|
+
true
|
|
149
|
+
end
|
|
150
|
+
#=> true
|
|
151
|
+
|
|
152
|
+
## prepare can be called without error
|
|
153
|
+
instance = TestBaseMigration.new
|
|
154
|
+
instance.prepare
|
|
155
|
+
true
|
|
156
|
+
#=> true
|
|
157
|
+
|
|
158
|
+
## Logging methods exist
|
|
159
|
+
instance = TestBaseMigration.new
|
|
160
|
+
[:info, :debug, :warn, :error, :header, :progress].all? { |m| instance.respond_to?(m) }
|
|
161
|
+
#=> true
|
|
162
|
+
|
|
163
|
+
## cli_run returns 0 for dry run success
|
|
164
|
+
CliTestMigration.migrate_called = false
|
|
165
|
+
CliTestMigration.migration_needed_value = true
|
|
166
|
+
result = CliTestMigration.cli_run([])
|
|
167
|
+
[result, CliTestMigration.migrate_called]
|
|
168
|
+
#=> [0, true]
|
|
169
|
+
|
|
170
|
+
## cli_run returns 0 for actual run success
|
|
171
|
+
CliTestMigration.migrate_called = false
|
|
172
|
+
CliTestMigration.migration_needed_value = true
|
|
173
|
+
result = CliTestMigration.cli_run(['--run'])
|
|
174
|
+
[result, CliTestMigration.migrate_called]
|
|
175
|
+
#=> [0, true]
|
|
176
|
+
|
|
177
|
+
## cli_run with --check returns 1 when migration needed
|
|
178
|
+
CliTestMigration.migration_needed_value = true
|
|
179
|
+
result = CliTestMigration.cli_run(['--check'])
|
|
180
|
+
result
|
|
181
|
+
#=> 1
|
|
182
|
+
|
|
183
|
+
## cli_run with --check returns 0 when migration not needed
|
|
184
|
+
CliTestMigration.migration_needed_value = false
|
|
185
|
+
result = CliTestMigration.cli_run(['--check'])
|
|
186
|
+
result
|
|
187
|
+
#=> 0
|
|
188
|
+
|
|
189
|
+
## cli_run returns 0 when migration not needed
|
|
190
|
+
CliTestMigration.migration_needed_value = false
|
|
191
|
+
CliTestMigration.migrate_called = false
|
|
192
|
+
result = CliTestMigration.cli_run([])
|
|
193
|
+
[result, CliTestMigration.migrate_called]
|
|
194
|
+
#=> [0, false]
|
|
195
|
+
|
|
196
|
+
## check_only returns 1 when migration needed
|
|
197
|
+
CliTestMigration.migration_needed_value = true
|
|
198
|
+
CliTestMigration.check_only
|
|
199
|
+
#=> 1
|
|
200
|
+
|
|
201
|
+
## check_only returns 0 when migration not needed
|
|
202
|
+
CliTestMigration.migration_needed_value = false
|
|
203
|
+
CliTestMigration.check_only
|
|
204
|
+
#=> 0
|
|
205
|
+
|
|
206
|
+
## dry_run_only? yields only in dry run mode
|
|
207
|
+
results = []
|
|
208
|
+
dry = TestBaseMigration.new(run: false)
|
|
209
|
+
dry.dry_run_only? { results << :dry }
|
|
210
|
+
live = TestBaseMigration.new(run: true)
|
|
211
|
+
live.dry_run_only? { results << :live }
|
|
212
|
+
results
|
|
213
|
+
#=> [:dry]
|
|
214
|
+
|
|
215
|
+
## dry_run_only? returns true in dry run mode
|
|
216
|
+
TestBaseMigration.new(run: false).dry_run_only?
|
|
217
|
+
#=> true
|
|
218
|
+
|
|
219
|
+
## dry_run_only? returns false in actual run mode
|
|
220
|
+
TestBaseMigration.new(run: true).dry_run_only?
|
|
221
|
+
#=> false
|
|
222
|
+
|
|
223
|
+
# Cleanup - remove test migrations from registry
|
|
224
|
+
Familia::Migration.migrations.delete(TestBaseMigration)
|
|
225
|
+
Familia::Migration.migrations.delete(ReversibleTestMigration)
|
|
226
|
+
Familia::Migration.migrations.delete(CliTestMigration)
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
# try/migration/errors_try.rb
|
|
2
|
+
#
|
|
3
|
+
# frozen_string_literal: true
|
|
4
|
+
|
|
5
|
+
require_relative '../support/helpers/test_helpers'
|
|
6
|
+
require_relative '../../lib/familia/migration/errors'
|
|
7
|
+
|
|
8
|
+
## MigrationError inherits from StandardError
|
|
9
|
+
Familia::Migration::Errors::MigrationError.superclass
|
|
10
|
+
#=> StandardError
|
|
11
|
+
|
|
12
|
+
## NotReversible inherits from MigrationError
|
|
13
|
+
Familia::Migration::Errors::NotReversible.superclass
|
|
14
|
+
#=> Familia::Migration::Errors::MigrationError
|
|
15
|
+
|
|
16
|
+
## NotApplied inherits from MigrationError
|
|
17
|
+
Familia::Migration::Errors::NotApplied.superclass
|
|
18
|
+
#=> Familia::Migration::Errors::MigrationError
|
|
19
|
+
|
|
20
|
+
## NotFound inherits from MigrationError
|
|
21
|
+
Familia::Migration::Errors::NotFound.superclass
|
|
22
|
+
#=> Familia::Migration::Errors::MigrationError
|
|
23
|
+
|
|
24
|
+
## DependencyNotMet inherits from MigrationError
|
|
25
|
+
Familia::Migration::Errors::DependencyNotMet.superclass
|
|
26
|
+
#=> Familia::Migration::Errors::MigrationError
|
|
27
|
+
|
|
28
|
+
## HasDependents inherits from MigrationError
|
|
29
|
+
Familia::Migration::Errors::HasDependents.superclass
|
|
30
|
+
#=> Familia::Migration::Errors::MigrationError
|
|
31
|
+
|
|
32
|
+
## CircularDependency inherits from MigrationError
|
|
33
|
+
Familia::Migration::Errors::CircularDependency.superclass
|
|
34
|
+
#=> Familia::Migration::Errors::MigrationError
|
|
35
|
+
|
|
36
|
+
## PreconditionFailed inherits from MigrationError
|
|
37
|
+
Familia::Migration::Errors::PreconditionFailed.superclass
|
|
38
|
+
#=> Familia::Migration::Errors::MigrationError
|
|
39
|
+
|
|
40
|
+
## All error classes are defined as constants
|
|
41
|
+
[
|
|
42
|
+
:MigrationError,
|
|
43
|
+
:NotReversible,
|
|
44
|
+
:NotApplied,
|
|
45
|
+
:NotFound,
|
|
46
|
+
:DependencyNotMet,
|
|
47
|
+
:HasDependents,
|
|
48
|
+
:CircularDependency,
|
|
49
|
+
:PreconditionFailed
|
|
50
|
+
].all? { |name| Familia::Migration::Errors.const_defined?(name) }
|
|
51
|
+
#=> true
|
|
52
|
+
|
|
53
|
+
## Errors can be raised with custom messages
|
|
54
|
+
begin
|
|
55
|
+
raise Familia::Migration::Errors::NotFound, "Migration xyz not found"
|
|
56
|
+
rescue Familia::Migration::Errors::MigrationError => e
|
|
57
|
+
e.message
|
|
58
|
+
end
|
|
59
|
+
#=> "Migration xyz not found"
|
|
60
|
+
|
|
61
|
+
## Errors can be rescued by parent class
|
|
62
|
+
begin
|
|
63
|
+
raise Familia::Migration::Errors::CircularDependency, "A depends on B depends on A"
|
|
64
|
+
rescue Familia::Migration::Errors::MigrationError => e
|
|
65
|
+
e.class.name.split('::').last
|
|
66
|
+
end
|
|
67
|
+
#=> "CircularDependency"
|