familia 2.0.0.pre17 → 2.0.0.pre18

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.
Files changed (220) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.rst +60 -0
  3. data/CLAUDE.md +9 -2
  4. data/Gemfile.lock +1 -1
  5. data/README.md +13 -0
  6. data/bin/irb +1 -1
  7. data/docs/guides/core-field-system.md +48 -26
  8. data/docs/migrating/v2.0.0-pre18.md +58 -0
  9. data/docs/qodo-merge-compliance.md +96 -0
  10. data/lib/familia/base.rb +0 -2
  11. data/lib/familia/connection/middleware.rb +58 -4
  12. data/lib/familia/connection.rb +1 -1
  13. data/lib/familia/data_type/{commands.rb → database_commands.rb} +2 -2
  14. data/lib/familia/data_type/serialization.rb +5 -5
  15. data/lib/familia/data_type.rb +2 -2
  16. data/lib/familia/encryption/encrypted_data.rb +12 -2
  17. data/lib/familia/encryption/manager.rb +11 -4
  18. data/lib/familia/features/autoloader.rb +3 -1
  19. data/lib/familia/features/encrypted_fields/encrypted_field_type.rb +11 -3
  20. data/lib/familia/features/relationships/indexing/multi_index_generators.rb +9 -9
  21. data/lib/familia/features/relationships/indexing/unique_index_generators.rb +41 -27
  22. data/lib/familia/features/safe_dump.rb +2 -3
  23. data/lib/familia/horreum/database_commands.rb +1 -1
  24. data/lib/familia/horreum/definition.rb +6 -37
  25. data/lib/familia/horreum/management.rb +17 -12
  26. data/lib/familia/horreum/persistence.rb +1 -1
  27. data/lib/familia/horreum/serialization.rb +91 -73
  28. data/lib/familia/horreum.rb +10 -6
  29. data/lib/familia/identifier_extractor.rb +60 -0
  30. data/lib/familia/logging.rb +271 -112
  31. data/lib/familia/refinements.rb +0 -1
  32. data/lib/familia/version.rb +1 -1
  33. data/lib/familia.rb +2 -2
  34. data/lib/middleware/{database_middleware.rb → database_logger.rb} +47 -14
  35. data/pr_agent.toml +31 -0
  36. data/pr_compliance_checklist.yaml +45 -0
  37. data/try/edge_cases/empty_identifiers_try.rb +1 -1
  38. data/try/edge_cases/hash_symbolization_try.rb +31 -31
  39. data/try/edge_cases/json_serialization_try.rb +2 -2
  40. data/try/edge_cases/legacy_data_detection/deserialization_edge_cases_try.rb +170 -0
  41. data/try/edge_cases/race_conditions_try.rb +1 -1
  42. data/try/edge_cases/reserved_keywords_try.rb +1 -1
  43. data/try/edge_cases/string_coercion_try.rb +1 -1
  44. data/try/edge_cases/ttl_side_effects_try.rb +1 -1
  45. data/try/features/encrypted_fields/aad_protection_try.rb +1 -1
  46. data/try/features/encrypted_fields/concealed_string_core_try.rb +1 -1
  47. data/try/features/encrypted_fields/context_isolation_try.rb +1 -1
  48. data/try/features/encrypted_fields/encrypted_fields_core_try.rb +1 -1
  49. data/try/features/encrypted_fields/encrypted_fields_integration_try.rb +1 -1
  50. data/try/features/encrypted_fields/encrypted_fields_no_cache_security_try.rb +1 -1
  51. data/try/features/encrypted_fields/encrypted_fields_security_try.rb +1 -1
  52. data/try/features/encrypted_fields/error_conditions_try.rb +1 -1
  53. data/try/features/encrypted_fields/fresh_key_derivation_try.rb +1 -1
  54. data/try/features/encrypted_fields/fresh_key_try.rb +1 -1
  55. data/try/features/encrypted_fields/key_rotation_try.rb +1 -1
  56. data/try/features/encrypted_fields/memory_security_try.rb +1 -1
  57. data/try/features/encrypted_fields/missing_current_key_version_try.rb +1 -1
  58. data/try/features/encrypted_fields/nonce_uniqueness_try.rb +1 -1
  59. data/try/features/encrypted_fields/secure_by_default_behavior_try.rb +1 -1
  60. data/try/features/encrypted_fields/thread_safety_try.rb +1 -1
  61. data/try/features/encrypted_fields/universal_serialization_safety_try.rb +1 -1
  62. data/try/{encryption → features/encryption}/config_persistence_try.rb +1 -1
  63. data/try/{encryption/encryption_core_try.rb → features/encryption/core_try.rb} +2 -2
  64. data/try/{encryption → features/encryption}/instance_variable_scope_try.rb +1 -1
  65. data/try/{encryption → features/encryption}/module_loading_try.rb +1 -1
  66. data/try/{encryption → features/encryption}/providers/aes_gcm_provider_try.rb +1 -1
  67. data/try/{encryption → features/encryption}/providers/xchacha20_poly1305_provider_try.rb +1 -1
  68. data/try/{encryption → features/encryption}/roundtrip_validation_try.rb +1 -1
  69. data/try/{encryption → features/encryption}/secure_memory_handling_try.rb +2 -2
  70. data/try/features/expiration/expiration_try.rb +1 -1
  71. data/try/features/external_identifier/external_identifier_try.rb +1 -1
  72. data/try/features/feature_dependencies_try.rb +1 -1
  73. data/try/features/feature_improvements_try.rb +1 -1
  74. data/try/features/object_identifier/object_identifier_integration_try.rb +1 -1
  75. data/try/features/object_identifier/object_identifier_try.rb +1 -1
  76. data/try/features/quantization/quantization_try.rb +1 -1
  77. data/try/features/real_feature_integration_try.rb +17 -14
  78. data/try/features/relationships/indexing_commands_verification_try.rb +8 -3
  79. data/try/features/relationships/indexing_try.rb +6 -1
  80. data/try/features/relationships/participation_commands_verification_spec.rb +1 -1
  81. data/try/features/relationships/participation_commands_verification_try.rb +4 -4
  82. data/try/features/relationships/participation_performance_improvements_try.rb +1 -1
  83. data/try/features/relationships/participation_reverse_index_try.rb +1 -1
  84. data/try/features/relationships/relationships_api_changes_try.rb +1 -1
  85. data/try/features/relationships/relationships_edge_cases_try.rb +3 -3
  86. data/try/features/relationships/relationships_performance_minimal_try.rb +1 -1
  87. data/try/features/relationships/relationships_performance_simple_try.rb +1 -1
  88. data/try/features/relationships/relationships_performance_try.rb +1 -1
  89. data/try/features/relationships/relationships_performance_working_try.rb +1 -1
  90. data/try/features/relationships/relationships_try.rb +1 -1
  91. data/try/features/safe_dump/safe_dump_advanced_try.rb +1 -1
  92. data/try/features/safe_dump/safe_dump_try.rb +1 -1
  93. data/try/features/transient_fields/redacted_string_try.rb +1 -1
  94. data/try/features/transient_fields/refresh_reset_try.rb +1 -1
  95. data/try/features/transient_fields/single_use_redacted_string_try.rb +1 -1
  96. data/try/features/transient_fields/transient_fields_core_try.rb +1 -1
  97. data/try/features/transient_fields/transient_fields_integration_try.rb +1 -1
  98. data/try/{connection → integration/connection}/fiber_context_preservation_try.rb +1 -1
  99. data/try/{connection → integration/connection}/handler_constraints_try.rb +1 -1
  100. data/try/{core → integration/connection}/isolated_dbclient_try.rb +1 -1
  101. data/try/integration/connection/middleware_reconnect_try.rb +87 -0
  102. data/try/{connection → integration/connection}/operation_mode_guards_try.rb +1 -1
  103. data/try/{connection → integration/connection}/pipeline_fallback_integration_try.rb +1 -1
  104. data/try/{core → integration/connection}/pools_try.rb +1 -1
  105. data/try/{connection → integration/connection}/responsibility_chain_tracking_try.rb +1 -1
  106. data/try/{connection → integration/connection}/transaction_fallback_integration_try.rb +1 -1
  107. data/try/{connection → integration/connection}/transaction_mode_permissive_try.rb +1 -1
  108. data/try/{connection → integration/connection}/transaction_mode_strict_try.rb +1 -1
  109. data/try/{connection → integration/connection}/transaction_mode_warn_try.rb +1 -1
  110. data/try/{connection → integration/connection}/transaction_modes_try.rb +1 -1
  111. data/try/{core → integration}/conventional_inheritance_try.rb +1 -1
  112. data/try/{core → integration}/create_method_try.rb +1 -1
  113. data/try/integration/cross_component_try.rb +1 -1
  114. data/try/{core → integration}/database_consistency_try.rb +11 -8
  115. data/try/{core → integration}/familia_extended_try.rb +1 -1
  116. data/try/{core → integration}/familia_members_methods_try.rb +1 -1
  117. data/try/{models → integration/models}/customer_safe_dump_try.rb +1 -1
  118. data/try/{models → integration/models}/customer_try.rb +1 -1
  119. data/try/{models → integration/models}/datatype_base_try.rb +1 -1
  120. data/try/{models → integration/models}/familia_object_try.rb +1 -1
  121. data/try/{core → integration}/persistence_operations_try.rb +1 -1
  122. data/try/integration/relationships_persistence_round_trip_try.rb +441 -0
  123. data/try/{configuration → integration}/scenarios_try.rb +1 -1
  124. data/try/{core → integration}/secure_identifier_try.rb +1 -1
  125. data/try/{core → integration}/verifiable_identifier_try.rb +1 -1
  126. data/try/performance/benchmarks_try.rb +2 -2
  127. data/try/support/benchmarks/deserialization_benchmark.rb +180 -0
  128. data/try/support/benchmarks/deserialization_correctness_test.rb +237 -0
  129. data/try/{helpers → support/helpers}/test_helpers.rb +12 -3
  130. data/try/{core → unit/core}/autoloader_try.rb +1 -1
  131. data/try/{core → unit/core}/base_enhancements_try.rb +1 -9
  132. data/try/{core → unit/core}/connection_try.rb +1 -1
  133. data/try/{core → unit/core}/errors_try.rb +1 -1
  134. data/try/{core → unit/core}/extensions_try.rb +1 -1
  135. data/try/unit/core/familia_logger_try.rb +110 -0
  136. data/try/{core → unit/core}/familia_try.rb +1 -1
  137. data/try/{core → unit/core}/middleware_try.rb +41 -1
  138. data/try/{core → unit/core}/settings_try.rb +1 -1
  139. data/try/{core → unit/core}/time_utils_try.rb +1 -1
  140. data/try/{core → unit/core}/tools_try.rb +1 -1
  141. data/try/{core → unit/core}/utils_try.rb +17 -14
  142. data/try/{data_types → unit/data_types}/boolean_try.rb +1 -1
  143. data/try/{data_types → unit/data_types}/counter_try.rb +1 -1
  144. data/try/{data_types → unit/data_types}/datatype_base_try.rb +1 -1
  145. data/try/{data_types → unit/data_types}/hash_try.rb +1 -1
  146. data/try/{data_types → unit/data_types}/list_try.rb +1 -1
  147. data/try/{data_types → unit/data_types}/lock_try.rb +1 -1
  148. data/try/{data_types → unit/data_types}/sorted_set_try.rb +1 -1
  149. data/try/{data_types → unit/data_types}/sorted_set_zadd_options_try.rb +1 -1
  150. data/try/{data_types → unit/data_types}/string_try.rb +1 -1
  151. data/try/{data_types → unit/data_types}/unsortedset_try.rb +1 -1
  152. data/try/{horreum → unit/horreum}/auto_indexing_on_save_try.rb +1 -1
  153. data/try/{horreum → unit/horreum}/base_try.rb +3 -3
  154. data/try/{horreum → unit/horreum}/class_methods_try.rb +1 -1
  155. data/try/{horreum → unit/horreum}/commands_try.rb +1 -1
  156. data/try/{horreum → unit/horreum}/defensive_initialization_try.rb +1 -1
  157. data/try/{horreum → unit/horreum}/destroy_related_fields_cleanup_try.rb +1 -1
  158. data/try/{horreum → unit/horreum}/enhanced_conflict_handling_try.rb +1 -1
  159. data/try/{horreum → unit/horreum}/field_categories_try.rb +27 -18
  160. data/try/{horreum → unit/horreum}/field_definition_try.rb +1 -1
  161. data/try/{horreum → unit/horreum}/initialization_try.rb +2 -2
  162. data/try/unit/horreum/json_type_preservation_try.rb +248 -0
  163. data/try/{horreum → unit/horreum}/relations_try.rb +1 -1
  164. data/try/{horreum → unit/horreum}/serialization_persistent_fields_try.rb +24 -18
  165. data/try/{horreum → unit/horreum}/serialization_try.rb +4 -4
  166. data/try/{horreum → unit/horreum}/settings_try.rb +1 -1
  167. data/try/{refinements → unit/refinements}/dear_json_array_methods_try.rb +1 -1
  168. data/try/{refinements → unit/refinements}/dear_json_hash_methods_try.rb +1 -1
  169. data/try/{refinements → unit/refinements}/time_literals_numeric_methods_try.rb +1 -1
  170. data/try/{refinements → unit/refinements}/time_literals_string_methods_try.rb +1 -1
  171. metadata +134 -125
  172. data/lib/familia/distinguisher.rb +0 -85
  173. data/lib/familia/refinements/logger_trace.rb +0 -60
  174. data/try/refinements/logger_trace_methods_try.rb +0 -44
  175. /data/try/{debugging → support/debugging}/README.md +0 -0
  176. /data/try/{debugging → support/debugging}/cache_behavior_tracer.rb +0 -0
  177. /data/try/{debugging → support/debugging}/debug_aad_process.rb +0 -0
  178. /data/try/{debugging → support/debugging}/debug_concealed_internal.rb +0 -0
  179. /data/try/{debugging → support/debugging}/debug_concealed_reveal.rb +0 -0
  180. /data/try/{debugging → support/debugging}/debug_context_aad.rb +0 -0
  181. /data/try/{debugging → support/debugging}/debug_context_simple.rb +0 -0
  182. /data/try/{debugging → support/debugging}/debug_cross_context.rb +0 -0
  183. /data/try/{debugging → support/debugging}/debug_database_load.rb +0 -0
  184. /data/try/{debugging → support/debugging}/debug_encrypted_json_check.rb +0 -0
  185. /data/try/{debugging → support/debugging}/debug_encrypted_json_step_by_step.rb +0 -0
  186. /data/try/{debugging → support/debugging}/debug_exists_lifecycle.rb +0 -0
  187. /data/try/{debugging → support/debugging}/debug_field_decrypt.rb +0 -0
  188. /data/try/{debugging → support/debugging}/debug_fresh_cross_context.rb +0 -0
  189. /data/try/{debugging → support/debugging}/debug_load_path.rb +0 -0
  190. /data/try/{debugging → support/debugging}/debug_method_definition.rb +0 -0
  191. /data/try/{debugging → support/debugging}/debug_method_resolution.rb +0 -0
  192. /data/try/{debugging → support/debugging}/debug_minimal.rb +0 -0
  193. /data/try/{debugging → support/debugging}/debug_provider.rb +0 -0
  194. /data/try/{debugging → support/debugging}/debug_secure_behavior.rb +0 -0
  195. /data/try/{debugging → support/debugging}/debug_string_class.rb +0 -0
  196. /data/try/{debugging → support/debugging}/debug_test.rb +0 -0
  197. /data/try/{debugging → support/debugging}/debug_test_design.rb +0 -0
  198. /data/try/{debugging → support/debugging}/encryption_method_tracer.rb +0 -0
  199. /data/try/{debugging → support/debugging}/provider_diagnostics.rb +0 -0
  200. /data/try/{helpers → support/helpers}/test_cleanup.rb +0 -0
  201. /data/try/{memory → support/memory}/memory_basic_test.rb +0 -0
  202. /data/try/{memory → support/memory}/memory_detailed_test.rb +0 -0
  203. /data/try/{memory → support/memory}/memory_docker_ruby_dump.sh +0 -0
  204. /data/try/{memory → support/memory}/memory_search_for_string.rb +0 -0
  205. /data/try/{memory → support/memory}/test_actual_redactedstring_protection.rb +0 -0
  206. /data/try/{prototypes → support/prototypes}/atomic_saves_v1_context_proxy.rb +0 -0
  207. /data/try/{prototypes → support/prototypes}/atomic_saves_v2_connection_switching.rb +0 -0
  208. /data/try/{prototypes → support/prototypes}/atomic_saves_v3_connection_pool.rb +0 -0
  209. /data/try/{prototypes → support/prototypes}/atomic_saves_v4.rb +0 -0
  210. /data/try/{prototypes → support/prototypes}/lib/atomic_saves_v2_connection_switching_helpers.rb +0 -0
  211. /data/try/{prototypes → support/prototypes}/lib/atomic_saves_v3_connection_pool_helpers.rb +0 -0
  212. /data/try/{prototypes → support/prototypes}/pooling/README.md +0 -0
  213. /data/try/{prototypes → support/prototypes}/pooling/configurable_stress_test.rb +0 -0
  214. /data/try/{prototypes → support/prototypes}/pooling/lib/atomic_saves_v3_connection_pool_helpers.rb +0 -0
  215. /data/try/{prototypes → support/prototypes}/pooling/lib/connection_pool_metrics.rb +0 -0
  216. /data/try/{prototypes → support/prototypes}/pooling/lib/connection_pool_stress_test.rb +0 -0
  217. /data/try/{prototypes → support/prototypes}/pooling/lib/connection_pool_threading_models.rb +0 -0
  218. /data/try/{prototypes → support/prototypes}/pooling/lib/visualize_stress_results.rb +0 -0
  219. /data/try/{prototypes → support/prototypes}/pooling/pool_siege.rb +0 -0
  220. /data/try/{prototypes → support/prototypes}/pooling/run_stress_tests.rb +0 -0
@@ -1,6 +1,6 @@
1
1
  # try/features/real_feature_integration_try.rb
2
2
 
3
- require_relative '../helpers/test_helpers'
3
+ require_relative '../support/helpers/test_helpers'
4
4
 
5
5
  Familia.debug = false
6
6
 
@@ -12,15 +12,17 @@ class ExpirationIntegrationTest < Familia::Horreum
12
12
  feature :expiration
13
13
  end
14
14
 
15
- # Safe dump feature integration with field categories
15
+ # Safe dump feature integration with field types
16
16
  class SafeDumpCategoryTest < Familia::Horreum
17
+ feature :encrypted_fields
18
+ feature :transient_fields
19
+ feature :safe_dump
20
+
17
21
  identifier_field :id
18
22
  field :id
19
- field :public_name, category: :persistent
20
- field :email, category: :encrypted
21
- field :tryouts_cache_data, category: :transient
22
-
23
- feature :safe_dump
23
+ field :public_name
24
+ encrypted_field :email
25
+ transient_field :tryouts_cache_data
24
26
 
25
27
  # Use new SafeDump DSL
26
28
  safe_dump_field :id
@@ -30,14 +32,15 @@ end
30
32
 
31
33
  # Combined features work together
32
34
  class CombinedFeaturesTest < Familia::Horreum
33
- identifier_field :id
34
- field :id
35
- field :name, category: :persistent
36
- field :temp_data, category: :transient
37
-
35
+ feature :transient_fields
38
36
  feature :expiration
39
37
  feature :safe_dump
40
38
 
39
+ identifier_field :id
40
+ field :id
41
+ field :name
42
+ transient_field :temp_data
43
+
41
44
  # Use new SafeDump DSL
42
45
  safe_dump_field :id
43
46
  safe_dump_field :name
@@ -123,11 +126,11 @@ CombinedFeaturesTest.features_enabled.include?(:safe_dump)
123
126
 
124
127
  ## Test that feature() method returns current features when called with no args
125
128
  CombinedFeaturesTest.feature
126
- #=> [:expiration, :safe_dump]
129
+ #=> [:transient_fields, :expiration, :safe_dump]
127
130
 
128
131
  ## Test that features_enabled() method returns the same results as feature() method
129
132
  CombinedFeaturesTest.feature
130
- #=> [:expiration, :safe_dump]
133
+ #=> [:transient_fields, :expiration, :safe_dump]
131
134
 
132
135
  ## Features list is accessible
133
136
  QueryFeaturesTest.feature
@@ -4,7 +4,7 @@
4
4
  # This test ensures the indexing system uses proper DataType methods instead of direct Redis calls
5
5
  #
6
6
 
7
- require_relative '../../helpers/test_helpers'
7
+ require_relative '../../support/helpers/test_helpers'
8
8
 
9
9
  # Enable database command logging for command verification tests
10
10
  Familia.enable_database_logging = true
@@ -44,8 +44,11 @@ end
44
44
 
45
45
  # Test data
46
46
  @user = TestIndexedUser.new(user_id: 'test_user_123', email: 'test@example.com', department: 'engineering')
47
+ @user.save
47
48
  @company = TestIndexedCompany.new(company_id: 'test_company_456', name: 'Test Corp')
49
+ @company.save
48
50
  @employee = TestIndexedEmployee.new(emp_id: 'test_emp_789', email: 'emp@example.com', department: 'sales')
51
+ @employee.save
49
52
 
50
53
  ## Class-level indexing creates proper DataType field
51
54
  TestIndexedUser.respond_to?(:email_index)
@@ -91,6 +94,7 @@ end
91
94
  #=> false
92
95
 
93
96
  ## Instance-level indexing works with parent context
97
+ @employee.save
94
98
  @employee.add_to_test_indexed_company_dept_index(@company)
95
99
  sample = @company.sample_from_department('sales')
96
100
  sample.first&.emp_id == @employee.emp_id
@@ -103,15 +107,16 @@ dept_index.class.name
103
107
 
104
108
  ## Multiple employees in same department
105
109
  @employee2 = TestIndexedEmployee.new(emp_id: 'test_emp_999', email: 'emp2@example.com', department: 'sales')
110
+ @employee2.save
106
111
  @employee2.add_to_test_indexed_company_dept_index(@company)
107
112
  employees_in_sales = @company.find_all_by_department('sales')
108
- employees_in_sales.map(&:emp_id).sort
113
+ employees_in_sales&.map(&:emp_id).sort
109
114
  #=> ["test_emp_789", "test_emp_999"]
110
115
 
111
116
  ## Removing from instance-level index works
112
117
  @employee.remove_from_test_indexed_company_dept_index(@company)
113
118
  remaining_employees = @company.find_all_by_department('sales')
114
- remaining_employees.map(&:emp_id)
119
+ remaining_employees&.map(&:emp_id)
115
120
  #=> ["test_emp_999"]
116
121
 
117
122
  ## Index update methods work correctly
@@ -4,7 +4,7 @@
4
4
  # Tests both multi_index (parent-context) and unique_index (class-level) indexing
5
5
  #
6
6
 
7
- require_relative '../../helpers/test_helpers'
7
+ require_relative '../../support/helpers/test_helpers'
8
8
 
9
9
  # Test classes for indexing functionality
10
10
  class ::TestUser < Familia::Horreum
@@ -55,13 +55,18 @@ end
55
55
 
56
56
  # Setup
57
57
  @user1 = TestUser.new(user_id: 'user_001', email: 'alice@example.com', username: 'alice', department: 'engineering', role: 'developer')
58
+ @user1.save
58
59
  @user2 = TestUser.new(user_id: 'user_002', email: 'bob@example.com', username: 'bob', department: 'marketing', role: 'manager')
60
+ @user2.save
59
61
  @user3 = TestUser.new(user_id: 'user_003', email: 'charlie@example.com', username: 'charlie', department: 'engineering', role: 'lead')
62
+ @user3.save
60
63
 
61
64
  @company_id = "comp_#{rand(10000000)}"
62
65
  @company = TestCompany.create(company_id: @company_id, name: 'Acme Corp')
63
66
  @emp1 = TestEmployee.new(emp_id: 'emp_001', email: 'alice@acme.com', department: 'engineering', manager_id: 'mgr_001', badge_number: 'BADGE001')
67
+ @emp1.save
64
68
  @emp2 = TestEmployee.new(emp_id: 'emp_002', email: 'bob@acme.com', department: 'sales', manager_id: 'mgr_002', badge_number: 'BADGE002')
69
+ @emp2.save
65
70
 
66
71
 
67
72
  ## Context-scoped methods require context parameter
@@ -7,7 +7,7 @@ RSpec.describe 'participation_commands_verification_try' do
7
7
  Timecop.freeze(Time.parse("2024-01-15 10:30:00"))
8
8
  puts Time.now # Always returns 2024-01-15 10:30:00
9
9
  puts Date.today # Always returns 2024-01-15
10
- require_relative '../../../lib/middleware/database_middleware'
10
+ require_relative '../../../lib/middleware/database_logger'
11
11
  require_relative '../../../lib/familia'
12
12
  Familia.enable_database_logging = true
13
13
  Familia.enable_database_counter = true
@@ -17,7 +17,7 @@ puts Date.today # Always returns 2024-01-15
17
17
 
18
18
 
19
19
  # Load middleware first
20
- require_relative '../../../lib/middleware/database_middleware'
20
+ require_relative '../../../lib/middleware/database_logger'
21
21
 
22
22
  # Load Familia
23
23
  require_relative '../../../lib/familia'
@@ -83,7 +83,7 @@ instantiation_commands.empty?
83
83
  database_commands = DatabaseLogger.capture_commands do
84
84
  @customer.save
85
85
  end
86
- database_commands.map { |cmd| cmd[:command] } if database_commands
86
+ database_commands.map { |cmd| cmd.command } if database_commands
87
87
  ##=> [["hmset", "reverse_index_customer:ri_cust_123:object", "customer_id", "ri_cust_123", "name", "Reverse Index Test Customer"], ["zadd", "reverse_index_customer:instances", "1705343400.0", "ri_cust_123"]]
88
88
 
89
89
 
@@ -91,14 +91,14 @@ database_commands.map { |cmd| cmd[:command] } if database_commands
91
91
  database_commands = DatabaseLogger.capture_commands do
92
92
  @domain1.save
93
93
  end
94
- database_commands[0][:command] if database_commands && database_commands[0]
94
+ database_commands[0].command if database_commands && database_commands[0]
95
95
  ##=> ["hmset", "reverse_index_domain:ri_dom_1:object", "domain_id", "ri_dom_1", "display_domain", "example1.com", "created_at", "1705343400.0"]
96
96
 
97
97
  ## Domain2 save functionality
98
98
  database_commands = DatabaseLogger.capture_commands do
99
99
  @domain2.save
100
100
  end
101
- database_commands[0][:command]if database_commands && database_commands[0]
101
+ database_commands[0].command if database_commands && database_commands[0]
102
102
  ##=> ["hmset", "reverse_index_domain:ri_dom_2:object", "domain_id", "ri_dom_2", "display_domain", "example2.com", "created_at", "1705343401.0"]
103
103
 
104
104
 
@@ -3,7 +3,7 @@
3
3
  # Tests for performance improvements in participation functionality
4
4
  # Verifies reverse index functionality and robust type comparison
5
5
 
6
- require_relative '../../helpers/test_helpers'
6
+ require_relative '../../support/helpers/test_helpers'
7
7
 
8
8
  # Test classes for performance improvements
9
9
  class PerfTestCustomer < Familia::Horreum
@@ -3,7 +3,7 @@
3
3
  # Tests for participation reverse index functionality
4
4
  # Verifies performance improvements and correct behavior
5
5
 
6
- require_relative '../../helpers/test_helpers'
6
+ require_relative '../../support/helpers/test_helpers'
7
7
 
8
8
  # Test classes for reverse index functionality
9
9
  class ReverseIndexCustomer < Familia::Horreum
@@ -4,7 +4,7 @@
4
4
  # Testing new class_participates_in and unique_index methods
5
5
  # Testing breaking changes and argument validation
6
6
 
7
- require_relative '../../helpers/test_helpers'
7
+ require_relative '../../support/helpers/test_helpers'
8
8
 
9
9
  # Test classes for new API
10
10
  class ::ApiTestUser < Familia::Horreum
@@ -1,6 +1,6 @@
1
1
  # Simplified edge case testing for Relationships v2 - focusing on core functionality
2
2
 
3
- require_relative '../../helpers/test_helpers'
3
+ require_relative '../../support/helpers/test_helpers'
4
4
 
5
5
  # Test classes for edge case testing
6
6
  class EdgeTestCustomer < Familia::Horreum
@@ -41,14 +41,14 @@ end
41
41
  @domain1 = EdgeTestDomain.new(
42
42
  domain_id: 'edge_dom_1',
43
43
  display_domain: 'edge1.example.com',
44
- created_at: Time.new(2025, 6, 15, 12, 0, 0),
44
+ created_at: Time.new(2025, 6, 15, 12, 0, 0).to_i, # Convert Time to Integer for JSON serialization
45
45
  score_value: 10
46
46
  )
47
47
 
48
48
  @domain2 = EdgeTestDomain.new(
49
49
  domain_id: 'edge_dom_2',
50
50
  display_domain: 'edge2.example.com',
51
- created_at: Time.new(2025, 7, 20, 15, 30, 0),
51
+ created_at: Time.new(2025, 7, 20, 15, 30, 0).to_i, # Convert Time to Integer for JSON serialization
52
52
  score_value: 25
53
53
  )
54
54
 
@@ -1,6 +1,6 @@
1
1
  # Minimal performance testing focusing on core Familia functionality
2
2
 
3
- require_relative '../../helpers/test_helpers'
3
+ require_relative '../../support/helpers/test_helpers'
4
4
  require 'benchmark'
5
5
 
6
6
  # Simple test classes without relationships feature
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # Simplified performance testing for the Relationships feature
4
4
 
5
- require_relative '../../helpers/test_helpers'
5
+ require_relative '../../support/helpers/test_helpers'
6
6
  require 'benchmark'
7
7
 
8
8
  # Test classes for performance testing
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # Performance and integration testing for the Relationships feature
4
4
 
5
- require_relative '../../helpers/test_helpers'
5
+ require_relative '../../support/helpers/test_helpers'
6
6
  require 'benchmark'
7
7
 
8
8
  # Test classes for performance testing
@@ -2,7 +2,7 @@
2
2
  #
3
3
  # Working performance test focusing on basic functionality
4
4
 
5
- require_relative '../../helpers/test_helpers'
5
+ require_relative '../../support/helpers/test_helpers'
6
6
  require 'benchmark'
7
7
 
8
8
  # Simple test class using only basic Familia features
@@ -3,7 +3,7 @@
3
3
  # Simplified Familia v2 relationship functionality tests - focusing on core working features
4
4
  #
5
5
 
6
- require_relative '../../helpers/test_helpers'
6
+ require_relative '../../support/helpers/test_helpers'
7
7
 
8
8
  # Test classes for Familia v2 relationship functionality
9
9
  class TestCustomer < Familia::Horreum
@@ -2,7 +2,7 @@
2
2
 
3
3
  # These tryouts test the safe dumping functionality.
4
4
 
5
- require_relative '../../helpers/test_helpers'
5
+ require_relative '../../support/helpers/test_helpers'
6
6
 
7
7
  ## By default Familia::Base has no safe_dump_fields method
8
8
  Familia::Base.respond_to?(:safe_dump_fields)
@@ -1,6 +1,6 @@
1
1
  # try/features/safe_dump_try.rb
2
2
 
3
- require_relative '../../helpers/test_helpers'
3
+ require_relative '../../support/helpers/test_helpers'
4
4
 
5
5
  Familia.debug = false
6
6
 
@@ -1,6 +1,6 @@
1
1
  # try/features/transient_fields/redacted_string_try.rb
2
2
 
3
- require_relative '../../helpers/test_helpers'
3
+ require_relative '../../support/helpers/test_helpers'
4
4
 
5
5
 
6
6
  # Create sample sensitive values for testing
@@ -1,7 +1,7 @@
1
1
  # try/features/transient_fields/refresh_reset_try.rb
2
2
  # Test that refresh! properly resets transient fields to nil
3
3
 
4
- require_relative '../../helpers/test_helpers'
4
+ require_relative '../../support/helpers/test_helpers'
5
5
 
6
6
  Familia.debug = false
7
7
 
@@ -1,6 +1,6 @@
1
1
  # try/features/transient_fields/single_use_redacted_string_try.rb
2
2
 
3
- require_relative '../../helpers/test_helpers'
3
+ require_relative '../../support/helpers/test_helpers'
4
4
 
5
5
  @otp_code = "123456"
6
6
  @auth_token = "temp-auth-token-xyz"
@@ -1,6 +1,6 @@
1
1
  # try/features/transient_fields_core_try.rb
2
2
 
3
- require_relative '../../helpers/test_helpers'
3
+ require_relative '../../support/helpers/test_helpers'
4
4
 
5
5
  class SecretService < Familia::Horreum
6
6
  feature :transient_fields
@@ -1,6 +1,6 @@
1
1
  # try/features/transient_fields_integration_try.rb
2
2
 
3
- require_relative '../../helpers/test_helpers'
3
+ require_relative '../../support/helpers/test_helpers'
4
4
 
5
5
  class SecretService < Familia::Horreum
6
6
  feature :transient_fields
@@ -12,7 +12,7 @@
12
12
  # - Operation guards prevent unsafe scenarios before fiber issues arise
13
13
  # - Method aliases work correctly
14
14
 
15
- require_relative '../helpers/test_helpers'
15
+ require_relative '../../support/helpers/test_helpers'
16
16
 
17
17
  ## Transaction method works without previous_conn preservation
18
18
  customer = Customer.new(custid: 'tx_test')
@@ -8,7 +8,7 @@
8
8
  # - Fresh connections (provider/create) → safe for all operations
9
9
  # - Transaction connections → safe for reentrant transactions only
10
10
 
11
- require_relative '../helpers/test_helpers'
11
+ require_relative '../../support/helpers/test_helpers'
12
12
 
13
13
  ## FiberTransactionHandler constraints
14
14
  Familia::Connection::FiberTransactionHandler.allows_transaction
@@ -5,7 +5,7 @@
5
5
  # Tests for isolated database connections that don't interfere
6
6
  # with the cached connection pool or existing model connections.
7
7
 
8
- require_relative '../helpers/test_helpers'
8
+ require_relative '../../support/helpers/test_helpers'
9
9
 
10
10
  # Clean up any existing test data in all test databases
11
11
  (0..2).each do |db|
@@ -0,0 +1,87 @@
1
+ # try/integration/connection/middleware_reconnect_try.rb
2
+ #
3
+ # Tests for Familia.reconnect! method that refreshes connection pools
4
+ # with current middleware configuration
5
+
6
+ require_relative '../../support/helpers/test_helpers'
7
+ require 'connection_pool'
8
+
9
+ # Disable logging for cleaner test output
10
+ Familia.enable_database_logging = false
11
+
12
+ # Test model for middleware reconnection testing
13
+ class ReconnectTestUser < Familia::Horreum
14
+ identifier_field :user_id
15
+ field :user_id
16
+ field :name
17
+
18
+ def init
19
+ @user_id ||= SecureRandom.hex(4)
20
+ end
21
+ end
22
+
23
+ ## Test 5: Middleware re-registration flag is reset and re-set
24
+ Familia.enable_database_logging = true
25
+ Familia.instance_variable_set(:@middleware_registered, true)
26
+ Familia.reconnect!
27
+ was_registered = Familia.instance_variable_get(:@middleware_registered)
28
+ was_registered
29
+ #=> true
30
+
31
+ ## Test 6: reconnect! safely handles no middleware enabled
32
+ Familia.enable_database_logging = false
33
+ Familia.enable_database_counter = false
34
+ Familia.reconnect!
35
+ chain_cleared = Familia.instance_variable_get(:@connection_chain).nil?
36
+ chain_cleared
37
+ #=> true
38
+
39
+
40
+
41
+ ## Setup: Clean database
42
+ ReconnectTestUser.dbclient.flushdb
43
+ #=> "OK"
44
+
45
+ ## Test 1: Basic reconnect functionality clears chain and increments version
46
+ Familia.enable_database_logging = true
47
+ initial = Familia.middleware_version
48
+ Familia.reconnect!
49
+ chain_cleared = Familia.instance_variable_get(:@connection_chain).nil?
50
+ version_incremented = Familia.middleware_version > initial
51
+ [chain_cleared, version_incremented]
52
+ #=> [true, true]
53
+
54
+ ## Test 2: Reconnect works with connection providers
55
+
56
+ # Create a simple connection provider
57
+ Familia.connection_provider = ->(uri) { Redis.new(url: uri) }
58
+
59
+ ## Reconnect clears chain even with provider
60
+ Familia.reconnect!
61
+ Familia.instance_variable_get(:@connection_chain)
62
+ #=> nil
63
+
64
+ ## Test 3: Verify new connections work after reconnect
65
+
66
+ # Create user to trigger connection
67
+ @user = ReconnectTestUser.new(name: "Bob")
68
+ @user.save
69
+ #=> true
70
+
71
+ ## User should be retrievable
72
+ @retrieved = ReconnectTestUser.find(@user.identifier)
73
+ @retrieved.name
74
+ #=> "Bob"
75
+
76
+ ## Test 4: Multiple reconnects are safe
77
+ Familia.reconnect!
78
+ Familia.reconnect!
79
+ Familia.reconnect!
80
+
81
+ ## Connection chain should still be cleared (will rebuild on next use)
82
+ Familia.instance_variable_get(:@connection_chain)
83
+ #=> nil
84
+
85
+ ## Cleanup
86
+ Familia.enable_database_logging = false
87
+ Familia.connection_provider = nil
@@ -12,7 +12,7 @@
12
12
  # This prevents bugs where middleware/cached connections return "QUEUED" instead
13
13
  # of actual values, breaking conditional logic and business rules.
14
14
 
15
- require_relative '../helpers/test_helpers'
15
+ require_relative '../../support/helpers/test_helpers'
16
16
 
17
17
  ## FiberConnectionHandler blocks transactions in strict mode
18
18
  begin
@@ -4,7 +4,7 @@
4
4
  # and that the fallback behavior matches transaction fallback patterns.
5
5
  #
6
6
 
7
- require_relative '../helpers/test_helpers'
7
+ require_relative '../../support/helpers/test_helpers'
8
8
 
9
9
  # Store original values
10
10
  $original_pipeline_mode = Familia.pipeline_mode
@@ -5,7 +5,7 @@
5
5
  require 'bundler/setup'
6
6
  require 'securerandom'
7
7
  require 'thread'
8
- require_relative '../helpers/test_helpers'
8
+ require_relative '../../support/helpers/test_helpers'
9
9
 
10
10
  # Configure connection pooling via connection_provider
11
11
  require 'connection_pool'
@@ -10,7 +10,7 @@
10
10
  # - Return the connection from the successful handler
11
11
  # - Return nil if no handler provides a connection
12
12
 
13
- require_relative '../helpers/test_helpers'
13
+ require_relative '../../support/helpers/test_helpers'
14
14
 
15
15
  # Setup - clear any existing fiber state
16
16
  Fiber[:familia_connection_handler_class] = nil
@@ -8,7 +8,7 @@
8
8
  # with Familia's existing features when connection handlers don't support
9
9
  # transactions (e.g., cached connections, middleware connections).
10
10
 
11
- require_relative '../helpers/test_helpers'
11
+ require_relative '../../support/helpers/test_helpers'
12
12
 
13
13
  # Setup - store original values
14
14
  $original_transaction_mode = Familia.transaction_mode
@@ -5,7 +5,7 @@
5
5
  #
6
6
  # Permissive mode: Silently uses IndividualCommandProxy for fallback
7
7
 
8
- require_relative '../helpers/test_helpers'
8
+ require_relative '../../support/helpers/test_helpers'
9
9
 
10
10
  # Test class for permissive mode testing
11
11
  class PermissiveModeTestCustomer < Familia::Horreum
@@ -5,7 +5,7 @@
5
5
  #
6
6
  # Strict mode: Raises OperationModeError when transaction unavailable
7
7
 
8
- require_relative '../helpers/test_helpers'
8
+ require_relative '../../support/helpers/test_helpers'
9
9
 
10
10
  # Test class for strict mode testing
11
11
  class StrictModeTestCustomer < Familia::Horreum
@@ -5,7 +5,7 @@
5
5
  #
6
6
  # Warn mode: Logs warning and uses IndividualCommandProxy for fallback
7
7
 
8
- require_relative '../helpers/test_helpers'
8
+ require_relative '../../support/helpers/test_helpers'
9
9
 
10
10
  # Test class for warn mode testing
11
11
  class WarnModeTestCustomer < Familia::Horreum
@@ -10,7 +10,7 @@
10
10
  # The IndividualCommandProxy executes Redis commands immediately instead of queuing
11
11
  # them in a transaction, maintaining the same MultiResult interface for consistency.
12
12
 
13
- require_relative '../helpers/test_helpers'
13
+ require_relative '../../support/helpers/test_helpers'
14
14
 
15
15
  # Setup - ensure clean state
16
16
  @original_transaction_mode = Familia.transaction_mode
@@ -1,4 +1,4 @@
1
- require_relative '../helpers/test_helpers'
1
+ require_relative '../support/helpers/test_helpers'
2
2
 
3
3
  # Define test classes in global namespace
4
4
  class ::TestVehicle < Familia::Horreum
@@ -3,7 +3,7 @@
3
3
  # Comprehensive test coverage for the create method
4
4
  # Tests the correct exception type and error message handling
5
5
 
6
- require_relative '../helpers/test_helpers'
6
+ require_relative '../support/helpers/test_helpers'
7
7
 
8
8
  # Test class for create method behavior
9
9
  class CreateTestModel < Familia::Horreum
@@ -1,6 +1,6 @@
1
1
  # Test cross-component integration scenarios
2
2
 
3
- require_relative '../helpers/test_helpers'
3
+ require_relative '../support/helpers/test_helpers'
4
4
 
5
5
  class TestUser < Familia::Horreum
6
6
  using Familia::Refinements::StylizeWords
@@ -3,7 +3,7 @@
3
3
  # Database consistency verification and edge case testing
4
4
  # Complements persistence_operations_try.rb with deeper consistency checks
5
5
 
6
- require_relative '../helpers/test_helpers'
6
+ require_relative '../support/helpers/test_helpers'
7
7
 
8
8
  # Test class with different field types for consistency verification
9
9
  class ConsistencyTestModel < Familia::Horreum
@@ -55,15 +55,18 @@ key_parts = dbkey.split(':')
55
55
  # Refresh and verify data integrity
56
56
  @serial_test.refresh!
57
57
  [@serial_test.name, @serial_test.active, @serial_test.metadata]
58
- #=> ['Serialization Test', 'true', {:key=>'value', :array=>[1, 2, 3]}]
58
+ #=> ["Serialization Test", true, {"key"=>"value", "array"=>[1, 2, 3]}]
59
59
 
60
60
  ## Hash field count matches object field count
61
+ @serial_test = ConsistencyTestModel.new(id: next_test_id)
62
+ @serial_test.save
61
63
  expected_fields = @serial_test.class.persistent_fields.length
62
64
  redis_field_count = Familia.dbclient.hlen(@serial_test.dbkey)
63
65
  actual_object_fields = @serial_test.to_h.keys.length
64
- # All should match (redis may have fewer due to nil exclusion)
65
- [expected_fields >= redis_field_count, redis_field_count, actual_object_fields]
66
- #=> [true, 5, 5]
66
+ # The JSON Serializer stores all fields (including nil as "null")
67
+ # Expected fields (5) >= redis count (5) >= to_h count (5, even though email is nil)
68
+ [expected_fields, redis_field_count, actual_object_fields]
69
+ #=> [5, 5, 5]
67
70
 
68
71
  ## Memory vs persistence state consistency after save
69
72
  @consistency_obj = ConsistencyTestModel.new(id: next_test_id, name: 'Memory Test', email: 'test@example.com')
@@ -73,9 +76,9 @@ actual_object_fields = @serial_test.to_h.keys.length
73
76
  memory_name = @consistency_obj.name
74
77
  memory_email = @consistency_obj.email
75
78
 
76
- # Get persistence state
77
- redis_name = Familia.dbclient.hget(@consistency_obj.dbkey, 'name')
78
- redis_email = Familia.dbclient.hget(@consistency_obj.dbkey, 'email')
79
+ # Get persistence state (deserialize from JSON storage)
80
+ redis_name = @consistency_obj.deserialize_value(Familia.dbclient.hget(@consistency_obj.dbkey, 'name'))
81
+ redis_email = @consistency_obj.deserialize_value(Familia.dbclient.hget(@consistency_obj.dbkey, 'email'))
79
82
 
80
83
  [memory_name == redis_name, memory_email == redis_email]
81
84
  #=> [true, true]