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.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +2 -2
- data/.github/workflows/code-quality.yml +138 -0
- data/.github/workflows/code-smells.yml +85 -0
- data/.github/workflows/docs.yml +31 -8
- data/.gitignore +3 -1
- data/.pre-commit-config.yaml +7 -1
- data/.reek.yml +98 -0
- data/.rubocop.yml +54 -10
- data/.talismanrc +9 -0
- data/.yardopts +18 -13
- data/CHANGELOG.rst +86 -4
- data/CLAUDE.md +39 -1
- data/Gemfile +6 -5
- data/Gemfile.lock +99 -23
- data/LICENSE.txt +1 -1
- data/README.md +285 -85
- data/changelog.d/README.md +2 -2
- data/docs/archive/FAMILIA_RELATIONSHIPS.md +22 -22
- data/docs/archive/FAMILIA_TECHNICAL.md +42 -42
- data/docs/archive/FAMILIA_UPDATE.md +3 -3
- data/docs/archive/README.md +3 -2
- data/docs/{guides/API-Reference.md → archive/api-reference.md} +87 -101
- data/docs/conf.py +29 -0
- data/docs/guides/{Field-System-Guide.md → core-field-system.md} +9 -9
- data/docs/guides/feature-encrypted-fields.md +785 -0
- data/docs/guides/{Expiration-Feature-Guide.md → feature-expiration.md} +11 -2
- data/docs/guides/feature-external-identifiers.md +637 -0
- data/docs/guides/feature-object-identifiers.md +435 -0
- data/docs/guides/{Quantization-Feature-Guide.md → feature-quantization.md} +94 -29
- data/docs/guides/feature-relationships-methods.md +684 -0
- data/docs/guides/feature-relationships.md +200 -0
- data/docs/guides/{Features-System-Developer-Guide.md → feature-system-devs.md} +4 -4
- data/docs/guides/{Feature-System-Guide.md → feature-system.md} +5 -5
- data/docs/guides/{Transient-Fields-Guide.md → feature-transient-fields.md} +2 -2
- data/docs/guides/{Implementation-Guide.md → implementation.md} +3 -3
- data/docs/guides/index.md +176 -0
- data/docs/guides/{Security-Model.md → security-model.md} +1 -1
- data/docs/migrating/v2.0.0-pre.md +1 -1
- data/docs/migrating/v2.0.0-pre11.md +2 -2
- data/docs/migrating/v2.0.0-pre12.md +2 -2
- data/docs/migrating/v2.0.0-pre5.md +33 -12
- data/docs/migrating/v2.0.0-pre6.md +2 -2
- data/docs/migrating/v2.0.0-pre7.md +8 -8
- data/docs/overview.md +624 -20
- data/docs/reference/api-technical.md +1365 -0
- data/examples/autoloader/mega_customer/features/deprecated_fields.rb +7 -0
- data/examples/autoloader/mega_customer/safe_dump_fields.rb +1 -1
- data/examples/autoloader/mega_customer.rb +3 -1
- data/examples/encrypted_fields.rb +378 -0
- data/examples/json_usage_patterns.rb +144 -0
- data/examples/relationships.rb +13 -13
- data/examples/safe_dump.rb +7 -7
- data/examples/single_connection_transaction_confusions.rb +379 -0
- data/lib/familia/base.rb +51 -10
- data/lib/familia/connection/handlers.rb +223 -0
- data/lib/familia/connection/individual_command_proxy.rb +64 -0
- data/lib/familia/connection/middleware.rb +75 -0
- data/lib/familia/connection/operation_core.rb +93 -0
- data/lib/familia/connection/operations.rb +277 -0
- data/lib/familia/connection/pipeline_core.rb +87 -0
- data/lib/familia/connection/transaction_core.rb +100 -0
- data/lib/familia/connection.rb +60 -186
- data/lib/familia/data_type/class_methods.rb +63 -0
- data/lib/familia/data_type/commands.rb +53 -51
- data/lib/familia/data_type/connection.rb +83 -0
- data/lib/familia/data_type/serialization.rb +108 -107
- data/lib/familia/data_type/settings.rb +96 -0
- data/lib/familia/data_type/types/counter.rb +1 -1
- data/lib/familia/data_type/types/hashkey.rb +15 -11
- data/lib/familia/data_type/types/{list.rb → listkey.rb} +13 -5
- data/lib/familia/data_type/types/lock.rb +3 -2
- data/lib/familia/data_type/types/sorted_set.rb +128 -14
- data/lib/familia/data_type/types/{string.rb → stringkey.rb} +7 -9
- data/lib/familia/data_type/types/unsorted_set.rb +20 -27
- data/lib/familia/data_type.rb +12 -171
- data/lib/familia/distinguisher.rb +85 -0
- data/lib/familia/encryption/encrypted_data.rb +15 -24
- data/lib/familia/encryption/manager.rb +6 -4
- data/lib/familia/encryption/providers/aes_gcm_provider.rb +1 -1
- data/lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb +7 -9
- data/lib/familia/encryption/providers/xchacha20_poly1305_provider.rb +4 -5
- data/lib/familia/encryption/request_cache.rb +7 -7
- data/lib/familia/encryption.rb +2 -3
- data/lib/familia/errors.rb +9 -3
- data/lib/familia/features/autoloader.rb +30 -12
- data/lib/familia/features/encrypted_fields/concealed_string.rb +3 -4
- data/lib/familia/features/encrypted_fields/encrypted_field_type.rb +13 -14
- data/lib/familia/features/encrypted_fields.rb +71 -66
- data/lib/familia/features/expiration/extensions.rb +1 -1
- data/lib/familia/features/expiration.rb +31 -26
- data/lib/familia/features/external_identifier.rb +57 -19
- data/lib/familia/features/object_identifier.rb +134 -25
- data/lib/familia/features/quantization.rb +16 -21
- data/lib/familia/features/relationships/README.md +97 -0
- data/lib/familia/features/relationships/collection_operations.rb +104 -0
- data/lib/familia/features/relationships/indexing/multi_index_generators.rb +202 -0
- data/lib/familia/features/relationships/indexing/unique_index_generators.rb +306 -0
- data/lib/familia/features/relationships/indexing.rb +182 -256
- data/lib/familia/features/relationships/indexing_relationship.rb +35 -0
- data/lib/familia/features/relationships/participation/participant_methods.rb +164 -0
- data/lib/familia/features/relationships/participation/target_methods.rb +225 -0
- data/lib/familia/features/relationships/participation.rb +656 -0
- data/lib/familia/features/relationships/participation_relationship.rb +31 -0
- data/lib/familia/features/relationships/score_encoding.rb +20 -20
- data/lib/familia/features/relationships.rb +65 -266
- data/lib/familia/features/safe_dump.rb +127 -130
- data/lib/familia/features/transient_fields/redacted_string.rb +6 -6
- data/lib/familia/features/transient_fields/transient_field_type.rb +5 -5
- data/lib/familia/features/transient_fields.rb +10 -7
- data/lib/familia/features.rb +10 -14
- data/lib/familia/field_type.rb +6 -4
- data/lib/familia/horreum/connection.rb +297 -0
- data/lib/familia/horreum/{core/database_commands.rb → database_commands.rb} +27 -17
- data/lib/familia/horreum/{subclass/definition.rb → definition.rb} +139 -74
- data/lib/familia/horreum/{subclass/management.rb → management.rb} +73 -27
- data/lib/familia/horreum/{core/serialization.rb → persistence.rb} +108 -185
- data/lib/familia/horreum/{subclass/related_fields_management.rb → related_fields.rb} +104 -23
- data/lib/familia/horreum/serialization.rb +172 -0
- data/lib/familia/horreum/{shared/settings.rb → settings.rb} +2 -1
- data/lib/familia/horreum/{core/utils.rb → utils.rb} +2 -1
- data/lib/familia/horreum.rb +222 -119
- data/lib/familia/json_serializer.rb +0 -1
- data/lib/familia/logging.rb +11 -114
- data/lib/familia/refinements/dear_json.rb +122 -0
- data/lib/familia/refinements/logger_trace.rb +20 -17
- data/lib/familia/refinements/stylize_words.rb +65 -0
- data/lib/familia/refinements/time_literals.rb +60 -52
- data/lib/familia/refinements.rb +2 -1
- data/lib/familia/secure_identifier.rb +60 -28
- data/lib/familia/settings.rb +83 -7
- data/lib/familia/utils.rb +5 -87
- data/lib/familia/verifiable_identifier.rb +4 -4
- data/lib/familia/version.rb +1 -1
- data/lib/familia.rb +72 -14
- data/lib/middleware/database_middleware.rb +56 -14
- data/lib/{familia/multi_result.rb → multi_result.rb} +23 -16
- data/try/configuration/scenarios_try.rb +2 -2
- data/try/connection/fiber_context_preservation_try.rb +250 -0
- data/try/connection/handler_constraints_try.rb +59 -0
- data/try/connection/operation_mode_guards_try.rb +208 -0
- data/try/connection/pipeline_fallback_integration_try.rb +128 -0
- data/try/connection/responsibility_chain_tracking_try.rb +72 -0
- data/try/connection/transaction_fallback_integration_try.rb +288 -0
- data/try/connection/transaction_mode_permissive_try.rb +153 -0
- data/try/connection/transaction_mode_strict_try.rb +98 -0
- data/try/connection/transaction_mode_warn_try.rb +131 -0
- data/try/connection/transaction_modes_try.rb +249 -0
- data/try/core/autoloader_try.rb +120 -2
- data/try/core/connection_try.rb +10 -10
- data/try/core/conventional_inheritance_try.rb +130 -0
- data/try/core/create_method_try.rb +15 -23
- data/try/core/database_consistency_try.rb +11 -10
- data/try/core/errors_try.rb +11 -14
- data/try/core/familia_extended_try.rb +2 -2
- data/try/core/familia_members_methods_try.rb +76 -0
- data/try/core/familia_try.rb +1 -1
- data/try/core/isolated_dbclient_try.rb +165 -0
- data/try/core/middleware_try.rb +16 -16
- data/try/core/persistence_operations_try.rb +4 -4
- data/try/core/pools_try.rb +42 -26
- data/try/core/secure_identifier_try.rb +28 -24
- data/try/core/time_utils_try.rb +10 -10
- data/try/core/tools_try.rb +3 -3
- data/try/core/utils_try.rb +2 -2
- data/try/data_types/boolean_try.rb +4 -4
- data/try/data_types/datatype_base_try.rb +0 -2
- data/try/data_types/list_try.rb +10 -10
- data/try/data_types/sorted_set_try.rb +5 -5
- data/try/data_types/sorted_set_zadd_options_try.rb +625 -0
- data/try/data_types/string_try.rb +12 -12
- data/try/data_types/unsortedset_try.rb +33 -0
- data/try/debugging/cache_behavior_tracer.rb +7 -7
- data/try/debugging/debug_aad_process.rb +1 -1
- data/try/debugging/debug_concealed_internal.rb +1 -1
- data/try/debugging/debug_cross_context.rb +1 -1
- data/try/debugging/debug_fresh_cross_context.rb +1 -1
- data/try/debugging/encryption_method_tracer.rb +10 -10
- data/try/edge_cases/hash_symbolization_try.rb +1 -1
- data/try/edge_cases/ttl_side_effects_try.rb +1 -1
- data/try/encryption/config_persistence_try.rb +2 -2
- data/try/encryption/encryption_core_try.rb +19 -19
- data/try/encryption/instance_variable_scope_try.rb +1 -1
- data/try/encryption/module_loading_try.rb +2 -2
- data/try/encryption/providers/aes_gcm_provider_try.rb +1 -1
- data/try/encryption/providers/xchacha20_poly1305_provider_try.rb +1 -1
- data/try/encryption/secure_memory_handling_try.rb +1 -1
- data/try/features/encrypted_fields/concealed_string_core_try.rb +11 -7
- data/try/features/encrypted_fields/encrypted_fields_core_try.rb +1 -1
- data/try/features/encrypted_fields/encrypted_fields_integration_try.rb +3 -3
- data/try/features/encrypted_fields/encrypted_fields_no_cache_security_try.rb +10 -10
- data/try/features/encrypted_fields/encrypted_fields_security_try.rb +14 -14
- data/try/features/encrypted_fields/error_conditions_try.rb +7 -7
- data/try/features/encrypted_fields/fresh_key_try.rb +1 -1
- data/try/features/encrypted_fields/nonce_uniqueness_try.rb +1 -1
- data/try/features/encrypted_fields/secure_by_default_behavior_try.rb +7 -7
- data/try/features/encrypted_fields/universal_serialization_safety_try.rb +13 -20
- data/try/features/external_identifier/external_identifier_try.rb +1 -1
- data/try/features/feature_dependencies_try.rb +3 -3
- data/try/features/field_groups_try.rb +244 -0
- data/try/features/object_identifier/object_identifier_integration_try.rb +28 -34
- data/try/features/object_identifier/object_identifier_try.rb +10 -0
- data/try/features/quantization/quantization_try.rb +1 -1
- data/try/features/relationships/indexing_commands_verification_try.rb +136 -0
- data/try/features/relationships/indexing_try.rb +443 -0
- data/try/features/relationships/participation_commands_verification_spec.rb +102 -0
- data/try/features/relationships/participation_commands_verification_try.rb +105 -0
- data/try/features/relationships/participation_performance_improvements_try.rb +124 -0
- data/try/features/relationships/participation_reverse_index_try.rb +196 -0
- data/try/features/relationships/relationships_api_changes_try.rb +72 -71
- data/try/features/relationships/relationships_edge_cases_try.rb +15 -18
- data/try/features/relationships/relationships_performance_minimal_try.rb +2 -2
- data/try/features/relationships/relationships_performance_simple_try.rb +8 -8
- data/try/features/relationships/relationships_performance_try.rb +20 -20
- data/try/features/relationships/relationships_try.rb +27 -38
- data/try/features/safe_dump/safe_dump_advanced_try.rb +2 -2
- data/try/features/transient_fields/refresh_reset_try.rb +3 -1
- data/try/features/transient_fields/simple_refresh_test.rb +1 -1
- data/try/helpers/test_cleanup.rb +86 -0
- data/try/helpers/test_helpers.rb +6 -7
- data/try/horreum/auto_indexing_on_save_try.rb +212 -0
- data/try/horreum/base_try.rb +3 -2
- data/try/horreum/commands_try.rb +3 -1
- data/try/horreum/defensive_initialization_try.rb +86 -0
- data/try/horreum/destroy_related_fields_cleanup_try.rb +332 -0
- data/try/horreum/initialization_try.rb +11 -7
- data/try/horreum/relations_try.rb +21 -13
- data/try/horreum/serialization_try.rb +12 -11
- data/try/horreum/settings_try.rb +2 -0
- data/try/integration/cross_component_try.rb +3 -3
- data/try/memory/memory_basic_test.rb +1 -1
- data/try/memory/memory_docker_ruby_dump.sh +2 -2
- data/try/models/customer_safe_dump_try.rb +1 -1
- data/try/models/customer_try.rb +13 -15
- data/try/models/datatype_base_try.rb +3 -3
- data/try/models/familia_object_try.rb +9 -8
- data/try/performance/benchmarks_try.rb +2 -2
- data/try/prototypes/atomic_saves_v1_context_proxy.rb +2 -2
- data/try/prototypes/atomic_saves_v3_connection_pool.rb +3 -3
- data/try/prototypes/atomic_saves_v4.rb +1 -1
- data/try/prototypes/lib/atomic_saves_v2_connection_switching_helpers.rb +4 -4
- data/try/prototypes/lib/atomic_saves_v3_connection_pool_helpers.rb +4 -4
- data/try/prototypes/pooling/lib/atomic_saves_v3_connection_pool_helpers.rb +4 -4
- data/try/prototypes/pooling/lib/connection_pool_metrics.rb +5 -5
- data/try/prototypes/pooling/lib/connection_pool_stress_test.rb +26 -26
- data/try/prototypes/pooling/lib/connection_pool_threading_models.rb +7 -7
- data/try/prototypes/pooling/lib/visualize_stress_results.rb +1 -1
- data/try/prototypes/pooling/pool_siege.rb +11 -11
- data/try/prototypes/pooling/run_stress_tests.rb +7 -7
- data/try/refinements/dear_json_array_methods_try.rb +53 -0
- data/try/refinements/dear_json_hash_methods_try.rb +54 -0
- data/try/refinements/logger_trace_methods_try.rb +44 -0
- data/try/refinements/time_literals_numeric_methods_try.rb +141 -0
- data/try/refinements/time_literals_string_methods_try.rb +80 -0
- data/try/valkey.conf +26 -0
- metadata +92 -52
- data/.rubocop_todo.yml +0 -208
- data/docs/connection_pooling.md +0 -192
- data/docs/guides/Connection-Pooling-Guide.md +0 -437
- data/docs/guides/Encrypted-Fields-Overview.md +0 -101
- data/docs/guides/Feature-System-Autoloading.md +0 -198
- data/docs/guides/Home.md +0 -116
- data/docs/guides/Relationships-Guide.md +0 -737
- data/docs/guides/relationships-methods.md +0 -266
- data/docs/reference/auditing_database_commands.rb +0 -228
- data/examples/permissions.rb +0 -240
- data/lib/familia/features/relationships/cascading.rb +0 -437
- data/lib/familia/features/relationships/membership.rb +0 -497
- data/lib/familia/features/relationships/permission_management.rb +0 -264
- data/lib/familia/features/relationships/querying.rb +0 -615
- data/lib/familia/features/relationships/redis_operations.rb +0 -274
- data/lib/familia/features/relationships/tracking.rb +0 -418
- data/lib/familia/horreum/core/connection.rb +0 -73
- data/lib/familia/horreum/core.rb +0 -21
- data/lib/familia/refinements/snake_case.rb +0 -40
- data/lib/familia/validation/command_recorder.rb +0 -336
- data/lib/familia/validation/expectations.rb +0 -519
- data/lib/familia/validation/validation_helpers.rb +0 -443
- data/lib/familia/validation/validator.rb +0 -412
- data/lib/familia/validation.rb +0 -140
- data/try/data_types/set_try.rb +0 -33
- data/try/features/relationships/categorical_permissions_try.rb +0 -515
- data/try/features/safe_dump/module_based_extensions_try.rb +0 -100
- data/try/features/safe_dump/safe_dump_autoloading_try.rb +0 -107
- data/try/validation/atomic_operations_try.rb.disabled +0 -320
- data/try/validation/command_validation_try.rb.disabled +0 -207
- data/try/validation/performance_validation_try.rb.disabled +0 -324
- 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-#{
|
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
|
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
|
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
|
data/try/core/pools_try.rb
CHANGED
@@ -51,10 +51,28 @@ class PoolTestSession < Familia::Horreum
|
|
51
51
|
|
52
52
|
def init
|
53
53
|
@session_id ||= SecureRandom.hex(8)
|
54
|
-
@created_at ||=
|
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
|
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:
|
153
|
-
@connection_test_result = Familia.
|
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.
|
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.
|
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
|
-
##
|
51
|
-
Familia.
|
52
|
-
#=>
|
55
|
+
## Generated lite IDs are unique
|
56
|
+
[Familia.generate_lite_id == Familia.generate_lite_id]
|
57
|
+
#=> [false]
|
53
58
|
|
54
|
-
##
|
55
|
-
|
56
|
-
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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.
|
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
|
data/try/core/time_utils_try.rb
CHANGED
@@ -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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
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 =
|
92
|
-
from_time =
|
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 =
|
99
|
-
from_time =
|
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
|
data/try/core/tools_try.rb
CHANGED
@@ -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
|
-
dest_redis = Redis.new(db:
|
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
|
|
data/try/core/utils_try.rb
CHANGED
@@ -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::
|
75
|
+
rescue Familia::NotDistinguishableError => e
|
76
76
|
e.class
|
77
77
|
end
|
78
|
-
#=> Familia::
|
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::
|
20
|
+
rescue Familia::NotDistinguishableError => e
|
21
21
|
e.message
|
22
22
|
end
|
23
|
-
#=> "
|
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::
|
32
|
+
rescue Familia::NotDistinguishableError => e
|
33
33
|
e.message
|
34
34
|
end
|
35
|
-
#=> "
|
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
|
data/try/data_types/list_try.rb
CHANGED
@@ -4,37 +4,37 @@ require_relative '../helpers/test_helpers'
|
|
4
4
|
|
5
5
|
@a = Bone.new 'atoken'
|
6
6
|
|
7
|
-
## Familia::
|
7
|
+
## Familia::ListKey#push
|
8
8
|
ret = @a.owners.push :value1
|
9
9
|
ret.class
|
10
|
-
#=> Familia::
|
10
|
+
#=> Familia::ListKey
|
11
11
|
|
12
|
-
## Familia::
|
12
|
+
## Familia::ListKey#<<
|
13
13
|
ret = @a.owners << :value2 << :value3 << :value4
|
14
14
|
ret.class
|
15
|
-
#=> Familia::
|
15
|
+
#=> Familia::ListKey
|
16
16
|
|
17
|
-
## Familia::
|
17
|
+
## Familia::ListKey#pop
|
18
18
|
@a.owners.pop
|
19
19
|
#=> 'value4'
|
20
20
|
|
21
|
-
## Familia::
|
21
|
+
## Familia::ListKey#first
|
22
22
|
@a.owners.first
|
23
23
|
#=> 'value1'
|
24
24
|
|
25
|
-
## Familia::
|
25
|
+
## Familia::ListKey#last
|
26
26
|
@a.owners.last
|
27
27
|
#=> 'value3'
|
28
28
|
|
29
|
-
## Familia::
|
29
|
+
## Familia::ListKey#to_a
|
30
30
|
@a.owners.to_a
|
31
31
|
#=> ['value1','value2','value3']
|
32
32
|
|
33
|
-
## Familia::
|
33
|
+
## Familia::ListKey#delete
|
34
34
|
@a.owners.remove 'value3'
|
35
35
|
#=> 1
|
36
36
|
|
37
|
-
## Familia::
|
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
|
10
|
-
@a.metrics.add
|
11
|
-
@a.metrics.add
|
12
|
-
@a.metrics.add
|
13
|
-
@a.metrics.add
|
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
|