familia 2.0.0.pre15 → 2.0.0.pre17

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 (288) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -2
  3. data/.github/workflows/code-quality.yml +138 -0
  4. data/.github/workflows/code-smells.yml +85 -0
  5. data/.github/workflows/docs.yml +31 -8
  6. data/.gitignore +3 -1
  7. data/.pre-commit-config.yaml +7 -1
  8. data/.reek.yml +98 -0
  9. data/.rubocop.yml +54 -10
  10. data/.talismanrc +9 -0
  11. data/.yardopts +18 -13
  12. data/CHANGELOG.rst +86 -4
  13. data/CLAUDE.md +39 -1
  14. data/Gemfile +6 -5
  15. data/Gemfile.lock +99 -23
  16. data/LICENSE.txt +1 -1
  17. data/README.md +285 -85
  18. data/changelog.d/README.md +2 -2
  19. data/docs/archive/FAMILIA_RELATIONSHIPS.md +22 -22
  20. data/docs/archive/FAMILIA_TECHNICAL.md +42 -42
  21. data/docs/archive/FAMILIA_UPDATE.md +3 -3
  22. data/docs/archive/README.md +3 -2
  23. data/docs/{guides/API-Reference.md → archive/api-reference.md} +87 -101
  24. data/docs/conf.py +29 -0
  25. data/docs/guides/{Field-System-Guide.md → core-field-system.md} +9 -9
  26. data/docs/guides/feature-encrypted-fields.md +785 -0
  27. data/docs/guides/{Expiration-Feature-Guide.md → feature-expiration.md} +11 -2
  28. data/docs/guides/feature-external-identifiers.md +637 -0
  29. data/docs/guides/feature-object-identifiers.md +435 -0
  30. data/docs/guides/{Quantization-Feature-Guide.md → feature-quantization.md} +94 -29
  31. data/docs/guides/feature-relationships-methods.md +684 -0
  32. data/docs/guides/feature-relationships.md +200 -0
  33. data/docs/guides/{Features-System-Developer-Guide.md → feature-system-devs.md} +4 -4
  34. data/docs/guides/{Feature-System-Guide.md → feature-system.md} +5 -5
  35. data/docs/guides/{Transient-Fields-Guide.md → feature-transient-fields.md} +2 -2
  36. data/docs/guides/{Implementation-Guide.md → implementation.md} +3 -3
  37. data/docs/guides/index.md +176 -0
  38. data/docs/guides/{Security-Model.md → security-model.md} +1 -1
  39. data/docs/migrating/v2.0.0-pre.md +1 -1
  40. data/docs/migrating/v2.0.0-pre11.md +2 -2
  41. data/docs/migrating/v2.0.0-pre12.md +2 -2
  42. data/docs/migrating/v2.0.0-pre5.md +33 -12
  43. data/docs/migrating/v2.0.0-pre6.md +2 -2
  44. data/docs/migrating/v2.0.0-pre7.md +8 -8
  45. data/docs/overview.md +624 -20
  46. data/docs/reference/api-technical.md +1365 -0
  47. data/examples/autoloader/mega_customer/features/deprecated_fields.rb +7 -0
  48. data/examples/autoloader/mega_customer/safe_dump_fields.rb +1 -1
  49. data/examples/autoloader/mega_customer.rb +3 -1
  50. data/examples/encrypted_fields.rb +378 -0
  51. data/examples/json_usage_patterns.rb +144 -0
  52. data/examples/relationships.rb +13 -13
  53. data/examples/safe_dump.rb +7 -7
  54. data/examples/single_connection_transaction_confusions.rb +379 -0
  55. data/lib/familia/base.rb +51 -10
  56. data/lib/familia/connection/handlers.rb +223 -0
  57. data/lib/familia/connection/individual_command_proxy.rb +64 -0
  58. data/lib/familia/connection/middleware.rb +75 -0
  59. data/lib/familia/connection/operation_core.rb +93 -0
  60. data/lib/familia/connection/operations.rb +277 -0
  61. data/lib/familia/connection/pipeline_core.rb +87 -0
  62. data/lib/familia/connection/transaction_core.rb +100 -0
  63. data/lib/familia/connection.rb +60 -186
  64. data/lib/familia/data_type/class_methods.rb +63 -0
  65. data/lib/familia/data_type/commands.rb +53 -51
  66. data/lib/familia/data_type/connection.rb +83 -0
  67. data/lib/familia/data_type/serialization.rb +108 -107
  68. data/lib/familia/data_type/settings.rb +96 -0
  69. data/lib/familia/data_type/types/counter.rb +1 -1
  70. data/lib/familia/data_type/types/hashkey.rb +15 -11
  71. data/lib/familia/data_type/types/{list.rb → listkey.rb} +13 -5
  72. data/lib/familia/data_type/types/lock.rb +3 -2
  73. data/lib/familia/data_type/types/sorted_set.rb +128 -14
  74. data/lib/familia/data_type/types/{string.rb → stringkey.rb} +7 -9
  75. data/lib/familia/data_type/types/unsorted_set.rb +20 -27
  76. data/lib/familia/data_type.rb +12 -171
  77. data/lib/familia/distinguisher.rb +85 -0
  78. data/lib/familia/encryption/encrypted_data.rb +15 -24
  79. data/lib/familia/encryption/manager.rb +6 -4
  80. data/lib/familia/encryption/providers/aes_gcm_provider.rb +1 -1
  81. data/lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb +7 -9
  82. data/lib/familia/encryption/providers/xchacha20_poly1305_provider.rb +4 -5
  83. data/lib/familia/encryption/request_cache.rb +7 -7
  84. data/lib/familia/encryption.rb +2 -3
  85. data/lib/familia/errors.rb +9 -3
  86. data/lib/familia/features/autoloader.rb +30 -12
  87. data/lib/familia/features/encrypted_fields/concealed_string.rb +3 -4
  88. data/lib/familia/features/encrypted_fields/encrypted_field_type.rb +13 -14
  89. data/lib/familia/features/encrypted_fields.rb +71 -66
  90. data/lib/familia/features/expiration/extensions.rb +1 -1
  91. data/lib/familia/features/expiration.rb +31 -26
  92. data/lib/familia/features/external_identifier.rb +57 -19
  93. data/lib/familia/features/object_identifier.rb +134 -25
  94. data/lib/familia/features/quantization.rb +16 -21
  95. data/lib/familia/features/relationships/README.md +97 -0
  96. data/lib/familia/features/relationships/collection_operations.rb +104 -0
  97. data/lib/familia/features/relationships/indexing/multi_index_generators.rb +202 -0
  98. data/lib/familia/features/relationships/indexing/unique_index_generators.rb +306 -0
  99. data/lib/familia/features/relationships/indexing.rb +182 -256
  100. data/lib/familia/features/relationships/indexing_relationship.rb +35 -0
  101. data/lib/familia/features/relationships/participation/participant_methods.rb +164 -0
  102. data/lib/familia/features/relationships/participation/target_methods.rb +225 -0
  103. data/lib/familia/features/relationships/participation.rb +656 -0
  104. data/lib/familia/features/relationships/participation_relationship.rb +31 -0
  105. data/lib/familia/features/relationships/score_encoding.rb +20 -20
  106. data/lib/familia/features/relationships.rb +65 -266
  107. data/lib/familia/features/safe_dump.rb +127 -130
  108. data/lib/familia/features/transient_fields/redacted_string.rb +6 -6
  109. data/lib/familia/features/transient_fields/transient_field_type.rb +5 -5
  110. data/lib/familia/features/transient_fields.rb +10 -7
  111. data/lib/familia/features.rb +10 -14
  112. data/lib/familia/field_type.rb +6 -4
  113. data/lib/familia/horreum/connection.rb +297 -0
  114. data/lib/familia/horreum/{core/database_commands.rb → database_commands.rb} +27 -17
  115. data/lib/familia/horreum/{subclass/definition.rb → definition.rb} +139 -74
  116. data/lib/familia/horreum/{subclass/management.rb → management.rb} +73 -27
  117. data/lib/familia/horreum/{core/serialization.rb → persistence.rb} +108 -185
  118. data/lib/familia/horreum/{subclass/related_fields_management.rb → related_fields.rb} +104 -23
  119. data/lib/familia/horreum/serialization.rb +172 -0
  120. data/lib/familia/horreum/{shared/settings.rb → settings.rb} +2 -1
  121. data/lib/familia/horreum/{core/utils.rb → utils.rb} +2 -1
  122. data/lib/familia/horreum.rb +222 -119
  123. data/lib/familia/json_serializer.rb +0 -1
  124. data/lib/familia/logging.rb +11 -114
  125. data/lib/familia/refinements/dear_json.rb +122 -0
  126. data/lib/familia/refinements/logger_trace.rb +20 -17
  127. data/lib/familia/refinements/stylize_words.rb +65 -0
  128. data/lib/familia/refinements/time_literals.rb +60 -52
  129. data/lib/familia/refinements.rb +2 -1
  130. data/lib/familia/secure_identifier.rb +60 -28
  131. data/lib/familia/settings.rb +83 -7
  132. data/lib/familia/utils.rb +5 -87
  133. data/lib/familia/verifiable_identifier.rb +4 -4
  134. data/lib/familia/version.rb +1 -1
  135. data/lib/familia.rb +72 -14
  136. data/lib/middleware/database_middleware.rb +56 -14
  137. data/lib/{familia/multi_result.rb → multi_result.rb} +23 -16
  138. data/try/configuration/scenarios_try.rb +2 -2
  139. data/try/connection/fiber_context_preservation_try.rb +250 -0
  140. data/try/connection/handler_constraints_try.rb +59 -0
  141. data/try/connection/operation_mode_guards_try.rb +208 -0
  142. data/try/connection/pipeline_fallback_integration_try.rb +128 -0
  143. data/try/connection/responsibility_chain_tracking_try.rb +72 -0
  144. data/try/connection/transaction_fallback_integration_try.rb +288 -0
  145. data/try/connection/transaction_mode_permissive_try.rb +153 -0
  146. data/try/connection/transaction_mode_strict_try.rb +98 -0
  147. data/try/connection/transaction_mode_warn_try.rb +131 -0
  148. data/try/connection/transaction_modes_try.rb +249 -0
  149. data/try/core/autoloader_try.rb +120 -2
  150. data/try/core/connection_try.rb +10 -10
  151. data/try/core/conventional_inheritance_try.rb +130 -0
  152. data/try/core/create_method_try.rb +15 -23
  153. data/try/core/database_consistency_try.rb +11 -10
  154. data/try/core/errors_try.rb +11 -14
  155. data/try/core/familia_extended_try.rb +2 -2
  156. data/try/core/familia_members_methods_try.rb +76 -0
  157. data/try/core/familia_try.rb +1 -1
  158. data/try/core/isolated_dbclient_try.rb +165 -0
  159. data/try/core/middleware_try.rb +16 -16
  160. data/try/core/persistence_operations_try.rb +4 -4
  161. data/try/core/pools_try.rb +42 -26
  162. data/try/core/secure_identifier_try.rb +28 -24
  163. data/try/core/time_utils_try.rb +10 -10
  164. data/try/core/tools_try.rb +3 -3
  165. data/try/core/utils_try.rb +2 -2
  166. data/try/data_types/boolean_try.rb +4 -4
  167. data/try/data_types/datatype_base_try.rb +0 -2
  168. data/try/data_types/list_try.rb +10 -10
  169. data/try/data_types/sorted_set_try.rb +5 -5
  170. data/try/data_types/sorted_set_zadd_options_try.rb +625 -0
  171. data/try/data_types/string_try.rb +12 -12
  172. data/try/data_types/unsortedset_try.rb +33 -0
  173. data/try/debugging/cache_behavior_tracer.rb +7 -7
  174. data/try/debugging/debug_aad_process.rb +1 -1
  175. data/try/debugging/debug_concealed_internal.rb +1 -1
  176. data/try/debugging/debug_cross_context.rb +1 -1
  177. data/try/debugging/debug_fresh_cross_context.rb +1 -1
  178. data/try/debugging/encryption_method_tracer.rb +10 -10
  179. data/try/edge_cases/hash_symbolization_try.rb +1 -1
  180. data/try/edge_cases/ttl_side_effects_try.rb +1 -1
  181. data/try/encryption/config_persistence_try.rb +2 -2
  182. data/try/encryption/encryption_core_try.rb +19 -19
  183. data/try/encryption/instance_variable_scope_try.rb +1 -1
  184. data/try/encryption/module_loading_try.rb +2 -2
  185. data/try/encryption/providers/aes_gcm_provider_try.rb +1 -1
  186. data/try/encryption/providers/xchacha20_poly1305_provider_try.rb +1 -1
  187. data/try/encryption/secure_memory_handling_try.rb +1 -1
  188. data/try/features/encrypted_fields/concealed_string_core_try.rb +11 -7
  189. data/try/features/encrypted_fields/encrypted_fields_core_try.rb +1 -1
  190. data/try/features/encrypted_fields/encrypted_fields_integration_try.rb +3 -3
  191. data/try/features/encrypted_fields/encrypted_fields_no_cache_security_try.rb +10 -10
  192. data/try/features/encrypted_fields/encrypted_fields_security_try.rb +14 -14
  193. data/try/features/encrypted_fields/error_conditions_try.rb +7 -7
  194. data/try/features/encrypted_fields/fresh_key_try.rb +1 -1
  195. data/try/features/encrypted_fields/nonce_uniqueness_try.rb +1 -1
  196. data/try/features/encrypted_fields/secure_by_default_behavior_try.rb +7 -7
  197. data/try/features/encrypted_fields/universal_serialization_safety_try.rb +13 -20
  198. data/try/features/external_identifier/external_identifier_try.rb +1 -1
  199. data/try/features/feature_dependencies_try.rb +3 -3
  200. data/try/features/field_groups_try.rb +244 -0
  201. data/try/features/object_identifier/object_identifier_integration_try.rb +28 -34
  202. data/try/features/object_identifier/object_identifier_try.rb +10 -0
  203. data/try/features/quantization/quantization_try.rb +1 -1
  204. data/try/features/relationships/indexing_commands_verification_try.rb +136 -0
  205. data/try/features/relationships/indexing_try.rb +443 -0
  206. data/try/features/relationships/participation_commands_verification_spec.rb +102 -0
  207. data/try/features/relationships/participation_commands_verification_try.rb +105 -0
  208. data/try/features/relationships/participation_performance_improvements_try.rb +124 -0
  209. data/try/features/relationships/participation_reverse_index_try.rb +196 -0
  210. data/try/features/relationships/relationships_api_changes_try.rb +72 -71
  211. data/try/features/relationships/relationships_edge_cases_try.rb +15 -18
  212. data/try/features/relationships/relationships_performance_minimal_try.rb +2 -2
  213. data/try/features/relationships/relationships_performance_simple_try.rb +8 -8
  214. data/try/features/relationships/relationships_performance_try.rb +20 -20
  215. data/try/features/relationships/relationships_try.rb +27 -38
  216. data/try/features/safe_dump/safe_dump_advanced_try.rb +2 -2
  217. data/try/features/transient_fields/refresh_reset_try.rb +3 -1
  218. data/try/features/transient_fields/simple_refresh_test.rb +1 -1
  219. data/try/helpers/test_cleanup.rb +86 -0
  220. data/try/helpers/test_helpers.rb +6 -7
  221. data/try/horreum/auto_indexing_on_save_try.rb +212 -0
  222. data/try/horreum/base_try.rb +3 -2
  223. data/try/horreum/commands_try.rb +3 -1
  224. data/try/horreum/defensive_initialization_try.rb +86 -0
  225. data/try/horreum/destroy_related_fields_cleanup_try.rb +332 -0
  226. data/try/horreum/initialization_try.rb +11 -7
  227. data/try/horreum/relations_try.rb +21 -13
  228. data/try/horreum/serialization_try.rb +12 -11
  229. data/try/horreum/settings_try.rb +2 -0
  230. data/try/integration/cross_component_try.rb +3 -3
  231. data/try/memory/memory_basic_test.rb +1 -1
  232. data/try/memory/memory_docker_ruby_dump.sh +2 -2
  233. data/try/models/customer_safe_dump_try.rb +1 -1
  234. data/try/models/customer_try.rb +13 -15
  235. data/try/models/datatype_base_try.rb +3 -3
  236. data/try/models/familia_object_try.rb +9 -8
  237. data/try/performance/benchmarks_try.rb +2 -2
  238. data/try/prototypes/atomic_saves_v1_context_proxy.rb +2 -2
  239. data/try/prototypes/atomic_saves_v3_connection_pool.rb +3 -3
  240. data/try/prototypes/atomic_saves_v4.rb +1 -1
  241. data/try/prototypes/lib/atomic_saves_v2_connection_switching_helpers.rb +4 -4
  242. data/try/prototypes/lib/atomic_saves_v3_connection_pool_helpers.rb +4 -4
  243. data/try/prototypes/pooling/lib/atomic_saves_v3_connection_pool_helpers.rb +4 -4
  244. data/try/prototypes/pooling/lib/connection_pool_metrics.rb +5 -5
  245. data/try/prototypes/pooling/lib/connection_pool_stress_test.rb +26 -26
  246. data/try/prototypes/pooling/lib/connection_pool_threading_models.rb +7 -7
  247. data/try/prototypes/pooling/lib/visualize_stress_results.rb +1 -1
  248. data/try/prototypes/pooling/pool_siege.rb +11 -11
  249. data/try/prototypes/pooling/run_stress_tests.rb +7 -7
  250. data/try/refinements/dear_json_array_methods_try.rb +53 -0
  251. data/try/refinements/dear_json_hash_methods_try.rb +54 -0
  252. data/try/refinements/logger_trace_methods_try.rb +44 -0
  253. data/try/refinements/time_literals_numeric_methods_try.rb +141 -0
  254. data/try/refinements/time_literals_string_methods_try.rb +80 -0
  255. data/try/valkey.conf +26 -0
  256. metadata +92 -52
  257. data/.rubocop_todo.yml +0 -208
  258. data/docs/connection_pooling.md +0 -192
  259. data/docs/guides/Connection-Pooling-Guide.md +0 -437
  260. data/docs/guides/Encrypted-Fields-Overview.md +0 -101
  261. data/docs/guides/Feature-System-Autoloading.md +0 -198
  262. data/docs/guides/Home.md +0 -116
  263. data/docs/guides/Relationships-Guide.md +0 -737
  264. data/docs/guides/relationships-methods.md +0 -266
  265. data/docs/reference/auditing_database_commands.rb +0 -228
  266. data/examples/permissions.rb +0 -240
  267. data/lib/familia/features/relationships/cascading.rb +0 -437
  268. data/lib/familia/features/relationships/membership.rb +0 -497
  269. data/lib/familia/features/relationships/permission_management.rb +0 -264
  270. data/lib/familia/features/relationships/querying.rb +0 -615
  271. data/lib/familia/features/relationships/redis_operations.rb +0 -274
  272. data/lib/familia/features/relationships/tracking.rb +0 -418
  273. data/lib/familia/horreum/core/connection.rb +0 -73
  274. data/lib/familia/horreum/core.rb +0 -21
  275. data/lib/familia/refinements/snake_case.rb +0 -40
  276. data/lib/familia/validation/command_recorder.rb +0 -336
  277. data/lib/familia/validation/expectations.rb +0 -519
  278. data/lib/familia/validation/validation_helpers.rb +0 -443
  279. data/lib/familia/validation/validator.rb +0 -412
  280. data/lib/familia/validation.rb +0 -140
  281. data/try/data_types/set_try.rb +0 -33
  282. data/try/features/relationships/categorical_permissions_try.rb +0 -515
  283. data/try/features/safe_dump/module_based_extensions_try.rb +0 -100
  284. data/try/features/safe_dump/safe_dump_autoloading_try.rb +0 -107
  285. data/try/validation/atomic_operations_try.rb.disabled +0 -320
  286. data/try/validation/command_validation_try.rb.disabled +0 -207
  287. data/try/validation/performance_validation_try.rb.disabled +0 -324
  288. data/try/validation/real_world_scenarios_try.rb.disabled +0 -390
@@ -26,7 +26,7 @@ end
26
26
  @test_id_counter = 0
27
27
  def next_test_id
28
28
  @test_id_counter += 1
29
- "test-#{Time.now.to_i}-#{@test_id_counter}"
29
+ "test-#{Familia.now.to_i}-#{@test_id_counter}"
30
30
  end
31
31
 
32
32
  # =============================================
@@ -95,11 +95,11 @@ second_save = @idempotent_obj.save
95
95
 
96
96
  ## Save with partial field data
97
97
  @partial_obj = PersistenceTestModel.new(id: next_test_id)
98
- @partial_obj.name = 'Only Name Set'
98
+ @partial_obj.name = 'Only Name UnsortedSet'
99
99
  # value field is nil/unset
100
100
  result = @partial_obj.save
101
101
  [result, @partial_obj.exists?, @partial_obj.name]
102
- #=> [true, true, 'Only Name Set']
102
+ #=> [true, true, 'Only Name UnsortedSet']
103
103
 
104
104
  # =============================================
105
105
  # 3. save_if_not_exists Method Coverage
@@ -141,7 +141,7 @@ end
141
141
  # 4. create Method Coverage (MISSING from current tests)
142
142
  # =============================================
143
143
 
144
- # NOTE: create method tests disabled due to Redis::Future bug
144
+ # NOTE: create method tests disabled due to Valkey/Redis::Future bug
145
145
  # This would be high-priority coverage but needs the create method bug fixed first
146
146
 
147
147
  ## create method alternative: manual creation simulation
@@ -51,10 +51,28 @@ class PoolTestSession < Familia::Horreum
51
51
 
52
52
  def init
53
53
  @session_id ||= SecureRandom.hex(8)
54
- @created_at ||= Time.now.to_i
54
+ @created_at ||= Familia.now.to_i
55
55
  end
56
56
  end
57
57
 
58
+ class PoolTestAccountDB1 < Familia::Horreum
59
+ logical_database 1
60
+ identifier_field :account_id
61
+ field :account_id
62
+ field :balance, on_conflict: :skip
63
+ field :holder_name
64
+
65
+ def init
66
+ @account_id ||= SecureRandom.hex(6)
67
+ @balance = @balance.to_f if @balance
68
+ end
69
+
70
+ def balance
71
+ @balance&.to_f
72
+ end
73
+ end
74
+
75
+
58
76
  ## Clean up before tests
59
77
  PoolTestAccount.dbclient.flushdb
60
78
  #=> "OK"
@@ -79,23 +97,6 @@ Familia.connection_provider.is_a?(Proc)
79
97
  #=> true
80
98
 
81
99
  ## Test 5: Account in DB 1 via class configuration
82
- class PoolTestAccountDB1 < Familia::Horreum
83
- self.logical_database = 1
84
- identifier_field :account_id
85
- field :account_id
86
- field :balance, on_conflict: :skip
87
- field :holder_name
88
-
89
- def init
90
- @account_id ||= SecureRandom.hex(6)
91
- @balance = @balance.to_f if @balance
92
- end
93
-
94
- def balance
95
- @balance&.to_f
96
- end
97
- end
98
-
99
100
  @account_db1 = PoolTestAccountDB1.new(balance: 750, holder_name: "Charlie")
100
101
  @account_db1.save
101
102
  #=> true
@@ -140,8 +141,8 @@ threads.each(&:join)
140
141
  # Test that transaction connection is available
141
142
  conn.ping
142
143
  end
143
- # Transaction returns array with results
144
- @transfer_result.first
144
+ # Transaction returns MultiResult with success status and results
145
+ @transfer_result.results.first
145
146
  #=> "PONG"
146
147
 
147
148
  ## Test 12: Transaction block executes properly
@@ -149,19 +150,19 @@ end
149
150
  [@account_a.balance, @account_b.balance]
150
151
  #=> [1000.0, 500.0]
151
152
 
152
- ## Test 13: with_connection method
153
- @connection_test_result = Familia.with_connection do |conn|
153
+ ## Test 13: with_dbclient method
154
+ @connection_test_result = Familia.with_dbclient do |conn|
154
155
  conn.set("test_key_#{SecureRandom.hex(4)}", "test_value")
155
156
  end
156
157
  @connection_test_result
157
158
  #=> "OK"
158
159
 
159
160
  ## Test 14: Pipeline operations with connection pool
160
- @pipeline_results = Familia.pipeline do |conn|
161
+ @pipeline_results = Familia.pipelined do |conn|
161
162
  conn.ping
162
163
  end
163
164
  # Pipeline executes successfully
164
- @pipeline_results.first
165
+ @pipeline_results.results.first
165
166
  #=> "PONG"
166
167
 
167
168
  ## Test 15: Multi/EXEC operations with connection pool
@@ -169,7 +170,7 @@ end
169
170
  conn.ping
170
171
  end
171
172
  # Multi/EXEC executes successfully
172
- @multi_results.first
173
+ @multi_results.results.first
173
174
  #=> "PONG"
174
175
 
175
176
  ## Test 16: Error handling in transactions
@@ -208,7 +209,7 @@ timeout_mutex = Mutex.new
208
209
  3.times do |i|
209
210
  timeout_threads << Thread.new do
210
211
  begin
211
- result = Familia.with_connection do |conn|
212
+ result = Familia.with_dbclient do |conn|
212
213
  sleep(0.1) # Brief hold
213
214
  conn.ping
214
215
  end
@@ -270,4 +271,19 @@ Familia.connection_provider = original_provider
270
271
  @captured_uris.any? { |uri| uri.include?('redis://') }
271
272
  #=> true
272
273
 
274
+ ## Check PoolTestAccountDB1 config name
275
+ PoolTestAccountDB1.config_name
276
+ #=> 'pool_test_account_db1'
277
+
278
+
273
279
  puts "Connection pool tests completed successfully!"
280
+
281
+ # Teardown
282
+ Familia.connection_provider = nil
283
+ Fiber[:familia_connection] = nil
284
+ Fiber[:familia_connection_handler_class] = nil
285
+ Fiber[:familia_transaction] = nil
286
+ Fiber[:familia_pipeline] = nil
287
+ Fiber[:familia_key_cache] = nil
288
+ Fiber[:familia_request_cache] = nil
289
+ Fiber[:familia_request_cache_enabled] = nil
@@ -24,6 +24,20 @@ hex_id = Familia.generate_id(16)
24
24
  [hex_id.class, hex_id.length == 64, hex_id.match?(/^[a-f0-9]+$/)]
25
25
  #=> [String, true, true]
26
26
 
27
+ ## Familia.generate_lite_id
28
+ Familia.respond_to?(:generate_lite_id)
29
+ #=> true
30
+
31
+ ## Can generate a default base-36 lite ID
32
+ lite_id = Familia.generate_lite_id
33
+ [lite_id.class, lite_id.length > 10, lite_id.match?(/^[a-z0-9]+$/)]
34
+ #=> [String, true, true]
35
+
36
+ ## Can generate a lite ID with a custom base (hex)
37
+ hex_lite_id = Familia.generate_lite_id(16)
38
+ [hex_lite_id.class, hex_lite_id.length == 32, hex_lite_id.match?(/^[a-f0-9]+$/)]
39
+ #=> [String, true, true]
40
+
27
41
  ## Familia.generate_trace_id
28
42
  Familia.respond_to?(:generate_trace_id)
29
43
  #=> true
@@ -35,39 +49,29 @@ trace_id = Familia.generate_trace_id
35
49
 
36
50
  ## Can generate a trace ID with a custom base (hex)
37
51
  hex_trace_id = Familia.generate_trace_id(16)
38
- [hex_trace_id.class, hex_trace_id.length == 16]
39
- #=> [String, true]
40
-
41
- ## Familia.generate_hex_id
42
- Familia.respond_to?(:generate_hex_id)
43
- #=> true
44
-
45
- ## Can generate a 256-bit hex ID
46
- hex_id = Familia.generate_hex_id
47
- [hex_id.class, hex_id.length == 64, hex_id.match?(/^[a-f0-9]+$/)]
52
+ [hex_trace_id.class, hex_trace_id.length == 16, hex_trace_id.match?(/^[a-f0-9]+$/)]
48
53
  #=> [String, true, true]
49
54
 
50
- ## Familia.generate_hex_trace_id
51
- Familia.respond_to?(:generate_hex_trace_id)
52
- #=> true
55
+ ## Generated lite IDs are unique
56
+ [Familia.generate_lite_id == Familia.generate_lite_id]
57
+ #=> [false]
53
58
 
54
- ## Can generate a 64-bit hex trace ID
55
- hex_trace_id = Familia.generate_hex_trace_id
56
- [hex_trace_id.class, hex_trace_id.length == 16, hex_trace_id.match?(/^[a-f0-9]+$/)]
57
- #=> [String, true, true]
59
+ ## Generated trace IDs are unique
60
+ [Familia.generate_trace_id == Familia.generate_trace_id]
61
+ #=> [false]
58
62
 
59
63
  ## Familia.shorten_to_trace_id
60
64
  Familia.respond_to?(:shorten_to_trace_id)
61
65
  #=> true
62
66
 
63
67
  ## Can shorten hex ID to trace ID (64 bits)
64
- hex_id = Familia.generate_hex_id
68
+ hex_id = Familia.generate_id(16)
65
69
  trace_id = Familia.shorten_to_trace_id(hex_id)
66
70
  [trace_id.class, trace_id.length < hex_id.length]
67
71
  #=> [String, true]
68
72
 
69
73
  ## Can shorten hex ID to trace ID with custom base (hex)
70
- hex_id = Familia.generate_hex_id
74
+ hex_id = Familia.generate_id(16)
71
75
  hex_trace_id = Familia.shorten_to_trace_id(hex_id, base: 16)
72
76
  [hex_trace_id.class, hex_trace_id.length == 16]
73
77
  #=> [String, true]
@@ -77,25 +81,25 @@ Familia.respond_to?(:truncate_hex)
77
81
  #=> true
78
82
 
79
83
  ## Can truncate hex ID to 128 bits by default
80
- hex_id = Familia.generate_hex_id
84
+ hex_id = Familia.generate_id(16)
81
85
  truncated_id = Familia.truncate_hex(hex_id)
82
86
  [truncated_id.class, truncated_id.length < hex_id.length]
83
87
  #=> [String, true]
84
88
 
85
89
  ## Can truncate hex ID to a custom bit length (64 bits)
86
- hex_id = Familia.generate_hex_id
90
+ hex_id = Familia.generate_id(16)
87
91
  truncated_64 = Familia.truncate_hex(hex_id, bits: 64)
88
92
  [truncated_64.class, truncated_64.length < hex_id.length]
89
93
  #=> [String, true]
90
94
 
91
95
  ## Can truncate with a custom base (hex)
92
- hex_id = Familia.generate_hex_id
96
+ hex_id = Familia.generate_id(16)
93
97
  hex_truncated = Familia.truncate_hex(hex_id, bits: 128, base: 16)
94
98
  [hex_truncated.class, hex_truncated.length == 32]
95
99
  #=> [String, true]
96
100
 
97
101
  ## Truncated IDs are deterministic
98
- hex_id = Familia.generate_hex_id
102
+ hex_id = Familia.generate_id(16)
99
103
  id1 = Familia.truncate_hex(hex_id)
100
104
  id2 = Familia.truncate_hex(hex_id)
101
105
  id1 == id2
@@ -118,7 +122,7 @@ end
118
122
  #=> "Input bits (12) cannot be less than desired output bits (64)."
119
123
 
120
124
  ## Shortened IDs are deterministic
121
- hex_id = Familia.generate_hex_id
125
+ hex_id = Familia.generate_id(16)
122
126
  id1 = Familia.shorten_to_trace_id(hex_id)
123
127
  id2 = Familia.shorten_to_trace_id(hex_id)
124
128
  id1 == id2
@@ -52,51 +52,51 @@ result.round(0)
52
52
  #=> 31556952.0
53
53
 
54
54
  ## Numeric#age_in - calculate age in months from timestamp (approximately 1 month ago)
55
- timestamp = Time.now.to_f - Familia::Refinements::TimeLiterals::PER_MONTH
55
+ timestamp = Familia.now - Familia::Refinements::TimeLiterals::PER_MONTH
56
56
  result = RefinedContext.eval_in_refined_context("#{timestamp}.age_in(:months)")
57
57
  (result - 1.0).abs < 0.01
58
58
  #=> true
59
59
 
60
60
  ## Numeric#age_in - calculate age in years from timestamp (approximately 1 year ago)
61
- timestamp = Time.now.to_f - Familia::Refinements::TimeLiterals::PER_YEAR
61
+ timestamp = Familia.now - Familia::Refinements::TimeLiterals::PER_YEAR
62
62
  result = RefinedContext.instance_eval_in_refined_context("#{timestamp}.age_in(:years)")
63
63
  (result - 1.0).abs < 0.01
64
64
  #=> true
65
65
 
66
66
  ## Numeric#months_old - convenience method for age_in(:months)
67
- timestamp = Time.now.to_f - Familia::Refinements::TimeLiterals::PER_MONTH
67
+ timestamp = Familia.now - Familia::Refinements::TimeLiterals::PER_MONTH
68
68
  result = RefinedContext.eval_in_refined_context("#{timestamp}.months_old")
69
69
  (result - 1.0).abs < 0.01
70
70
  #=> true
71
71
 
72
72
  ## Numeric#years_old - convenience method for age_in(:years)
73
- timestamp = Time.now.to_f - Familia::Refinements::TimeLiterals::PER_YEAR
73
+ timestamp = Familia.now - Familia::Refinements::TimeLiterals::PER_YEAR
74
74
  result = RefinedContext.instance_eval_in_refined_context("#{timestamp}.years_old")
75
75
  (result - 1.0).abs < 0.01
76
76
  #=> true
77
77
 
78
78
  ## Numeric#months_old - should NOT return seconds (the original bug)
79
- timestamp = Time.now.to_f - Familia::Refinements::TimeLiterals::PER_MONTH
79
+ timestamp = Familia.now - Familia::Refinements::TimeLiterals::PER_MONTH
80
80
  result = RefinedContext.eval_in_refined_context("#{timestamp}.months_old")
81
81
  result.between?(0.9, 1.1) # Should be ~1 month, not millions of seconds
82
82
  #=> true
83
83
 
84
84
  ## Numeric#years_old - should NOT return seconds (the original bug)
85
- timestamp = Time.now.to_f - Familia::Refinements::TimeLiterals::PER_YEAR
85
+ timestamp = Familia.now - Familia::Refinements::TimeLiterals::PER_YEAR
86
86
  result = RefinedContext.instance_eval_in_refined_context("#{timestamp}.years_old")
87
87
  result.between?(0.9, 1.1) # Should be ~1 year, not millions of seconds
88
88
  #=> true
89
89
 
90
90
  ## age_in with from_time parameter - months
91
- past_time = Time.now - (2 * Familia::Refinements::TimeLiterals::PER_MONTH) # 2 months ago
92
- from_time = Time.now - Familia::Refinements::TimeLiterals::PER_MONTH # 1 month ago
91
+ past_time = Familia.now - (2 * Familia::Refinements::TimeLiterals::PER_MONTH) # 2 months ago
92
+ from_time = Familia.now - Familia::Refinements::TimeLiterals::PER_MONTH # 1 month ago
93
93
  result = RefinedContext.eval_in_refined_context("#{past_time.to_f}.age_in(:months, #{from_time.to_f})")
94
94
  (result - 1.0).abs < 0.01
95
95
  #=> true
96
96
 
97
97
  ## age_in with from_time parameter - years
98
- past_time = Time.now - (2 * Familia::Refinements::TimeLiterals::PER_YEAR) # 2 years ago
99
- from_time = Time.now - Familia::Refinements::TimeLiterals::PER_YEAR # 1 year ago
98
+ past_time = Familia.now - (2 * Familia::Refinements::TimeLiterals::PER_YEAR) # 2 years ago
99
+ from_time = Familia.now - Familia::Refinements::TimeLiterals::PER_YEAR # 1 year ago
100
100
  result = RefinedContext.instance_eval_in_refined_context("#{past_time.to_f}.age_in(:years, #{from_time.to_f})")
101
101
  (result - 1.0).abs < 0.01
102
102
  #=> true
@@ -4,10 +4,10 @@
4
4
 
5
5
  require_relative '../helpers/test_helpers'
6
6
 
7
- ## move_keys across Redis instances (if available)
7
+ ## move_keys across Valkey/Redis instances (if available)
8
8
  begin
9
- source_redis = Redis.new(db: 10)
10
- dest_redis = Redis.new(db: 11)
9
+ source_redis = Redis.new(db: 1, port: 2525)
10
+ dest_redis = Redis.new(db: 2, port: 2525)
11
11
  source_redis.set('test:key1', 'value1')
12
12
  source_redis.set('test:key2', 'value2')
13
13
 
@@ -72,10 +72,10 @@ sym_result = Familia.distinguisher(:symbol)
72
72
  ## distinguisher raises error for high-risk types with strict mode
73
73
  begin
74
74
  Familia.distinguisher(true, strict_values: true)
75
- rescue Familia::HighRiskFactor => e
75
+ rescue Familia::NotDistinguishableError => e
76
76
  e.class
77
77
  end
78
- #=> Familia::HighRiskFactor
78
+ #=> Familia::NotDistinguishableError
79
79
 
80
80
  ## distinguisher allows high-risk types with non-strict mode
81
81
  result = Familia.distinguisher(false, strict_values: false)
@@ -17,10 +17,10 @@ Familia.debug = false
17
17
  ## Trying to store a boolean value to a hash key raises an exception
18
18
  begin
19
19
  @hashkey['test'] = true
20
- rescue Familia::HighRiskFactor => e
20
+ rescue Familia::NotDistinguishableError => e
21
21
  e.message
22
22
  end
23
- #=> "High risk factor for serialization bugs: true<TrueClass>"
23
+ #=> "Cannot represent true<TrueClass> as a string"
24
24
 
25
25
  ## Boolean values are returned as strings
26
26
  @hashkey['test']
@@ -29,10 +29,10 @@ end
29
29
  ## Trying to store a nil value to a hash key raises an exception
30
30
  begin
31
31
  @hashkey['test'] = nil
32
- rescue Familia::HighRiskFactor => e
32
+ rescue Familia::NotDistinguishableError => e
33
33
  e.message
34
34
  end
35
- #=> "High risk factor for serialization bugs: <NilClass>"
35
+ #=> "Cannot represent <NilClass> as a string"
36
36
 
37
37
  ## The exceptions prevented the hash from being updated
38
38
  @hashkey['test']
@@ -30,8 +30,6 @@ RefinedContext.eval_in_refined_context("@limiter1.counter.qstamp(10.minutes, '%H
30
30
 
31
31
  ## Limiter#qstamp as a number
32
32
  @limiter2 = Limiter.new :requests
33
- p [@limiter1.default_expiration, @limiter2.default_expiration]
34
- p [@limiter1.counter.parent.default_expiration, @limiter2.counter.parent.default_expiration]
35
33
  RefinedContext.instance_variable_set(:@limiter2, @limiter2)
36
34
  RefinedContext.eval_in_refined_context("@limiter2.counter.qstamp(10.minutes, pattern: nil, time: 1_302_468_980)")
37
35
  #=> 1302468600
@@ -4,37 +4,37 @@ require_relative '../helpers/test_helpers'
4
4
 
5
5
  @a = Bone.new 'atoken'
6
6
 
7
- ## Familia::List#push
7
+ ## Familia::ListKey#push
8
8
  ret = @a.owners.push :value1
9
9
  ret.class
10
- #=> Familia::List
10
+ #=> Familia::ListKey
11
11
 
12
- ## Familia::List#<<
12
+ ## Familia::ListKey#<<
13
13
  ret = @a.owners << :value2 << :value3 << :value4
14
14
  ret.class
15
- #=> Familia::List
15
+ #=> Familia::ListKey
16
16
 
17
- ## Familia::List#pop
17
+ ## Familia::ListKey#pop
18
18
  @a.owners.pop
19
19
  #=> 'value4'
20
20
 
21
- ## Familia::List#first
21
+ ## Familia::ListKey#first
22
22
  @a.owners.first
23
23
  #=> 'value1'
24
24
 
25
- ## Familia::List#last
25
+ ## Familia::ListKey#last
26
26
  @a.owners.last
27
27
  #=> 'value3'
28
28
 
29
- ## Familia::List#to_a
29
+ ## Familia::ListKey#to_a
30
30
  @a.owners.to_a
31
31
  #=> ['value1','value2','value3']
32
32
 
33
- ## Familia::List#delete
33
+ ## Familia::ListKey#delete
34
34
  @a.owners.remove 'value3'
35
35
  #=> 1
36
36
 
37
- ## Familia::List#size
37
+ ## Familia::ListKey#size
38
38
  @a.owners.size
39
39
  #=> 2
40
40
 
@@ -6,11 +6,11 @@ require_relative '../helpers/test_helpers'
6
6
 
7
7
  ## Familia::SortedSet#add
8
8
  @a = Bone.new 'atoken'
9
- @a.metrics.add 2, :metric2
10
- @a.metrics.add 4, :metric4
11
- @a.metrics.add 0, :metric0
12
- @a.metrics.add 1, :metric1
13
- @a.metrics.add 3, :metric3
9
+ @a.metrics.add :metric2, 2
10
+ @a.metrics.add :metric4, 4
11
+ @a.metrics.add :metric0, 0
12
+ @a.metrics.add :metric1, 1
13
+ @a.metrics.add :metric3, 3
14
14
  #=> true
15
15
 
16
16
  ## Familia::SortedSet#members