familia 2.0.0.pre17 → 2.0.0.pre19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.rst +118 -6
- data/CLAUDE.md +43 -11
- data/Gemfile +2 -2
- data/Gemfile.lock +9 -47
- data/README.md +52 -0
- data/bin/irb +1 -1
- data/changelog.d/20251011_012003_delano_159_datatype_transaction_pipeline_support.rst +91 -0
- data/changelog.d/20251011_203905_delano_next.rst +30 -0
- data/changelog.d/20251011_212633_delano_next.rst +13 -0
- data/changelog.d/20251011_221253_delano_next.rst +26 -0
- data/docs/guides/core-field-system.md +48 -26
- data/docs/guides/feature-expiration.md +18 -18
- data/docs/migrating/v2.0.0-pre18.md +58 -0
- data/docs/migrating/v2.0.0-pre19.md +197 -0
- data/docs/qodo-merge-compliance.md +96 -0
- data/examples/datatype_standalone.rb +281 -0
- data/lib/familia/base.rb +0 -2
- data/lib/familia/connection/behavior.rb +252 -0
- data/lib/familia/connection/handlers.rb +95 -0
- data/lib/familia/connection/middleware.rb +58 -4
- data/lib/familia/connection/operation_core.rb +1 -1
- data/lib/familia/connection/{pipeline_core.rb → pipelined_core.rb} +2 -2
- data/lib/familia/connection/transaction_core.rb +7 -9
- data/lib/familia/connection.rb +2 -1
- data/lib/familia/data_type/connection.rb +151 -7
- data/lib/familia/data_type/{commands.rb → database_commands.rb} +9 -6
- data/lib/familia/data_type/serialization.rb +9 -5
- data/lib/familia/data_type/types/hashkey.rb +1 -1
- data/lib/familia/data_type.rb +2 -2
- data/lib/familia/encryption/encrypted_data.rb +12 -2
- data/lib/familia/encryption/manager.rb +11 -4
- data/lib/familia/errors.rb +51 -14
- data/lib/familia/features/autoloader.rb +3 -1
- data/lib/familia/features/encrypted_fields/encrypted_field_type.rb +11 -3
- data/lib/familia/features/expiration/extensions.rb +8 -10
- data/lib/familia/features/expiration.rb +19 -19
- data/lib/familia/features/relationships/indexing/multi_index_generators.rb +45 -44
- data/lib/familia/features/relationships/indexing/unique_index_generators.rb +151 -65
- data/lib/familia/features/relationships/indexing.rb +37 -42
- data/lib/familia/features/relationships/indexing_relationship.rb +14 -4
- data/lib/familia/features/safe_dump.rb +2 -3
- data/lib/familia/field_type.rb +2 -1
- data/lib/familia/horreum/connection.rb +11 -35
- data/lib/familia/horreum/database_commands.rb +130 -11
- data/lib/familia/horreum/definition.rb +8 -38
- data/lib/familia/horreum/management.rb +38 -27
- data/lib/familia/horreum/persistence.rb +191 -67
- data/lib/familia/horreum/serialization.rb +94 -73
- data/lib/familia/horreum/utils.rb +0 -8
- data/lib/familia/horreum.rb +41 -18
- data/lib/familia/identifier_extractor.rb +60 -0
- data/lib/familia/logging.rb +268 -112
- data/lib/familia/refinements.rb +0 -1
- data/lib/familia/settings.rb +7 -7
- data/lib/familia/version.rb +1 -1
- data/lib/familia.rb +2 -2
- data/lib/middleware/{database_middleware.rb → database_logger.rb} +118 -14
- data/pr_agent.toml +31 -0
- data/pr_compliance_checklist.yaml +45 -0
- data/try/edge_cases/empty_identifiers_try.rb +1 -1
- data/try/edge_cases/hash_symbolization_try.rb +31 -31
- data/try/edge_cases/json_serialization_try.rb +2 -2
- data/try/edge_cases/legacy_data_detection/deserialization_edge_cases_try.rb +170 -0
- data/try/edge_cases/race_conditions_try.rb +1 -1
- data/try/edge_cases/reserved_keywords_try.rb +1 -1
- data/try/edge_cases/string_coercion_try.rb +5 -5
- data/try/edge_cases/ttl_side_effects_try.rb +1 -1
- data/try/features/encrypted_fields/aad_protection_try.rb +1 -1
- data/try/features/encrypted_fields/concealed_string_core_try.rb +1 -1
- data/try/features/encrypted_fields/context_isolation_try.rb +1 -1
- data/try/features/encrypted_fields/encrypted_fields_core_try.rb +1 -1
- data/try/features/encrypted_fields/encrypted_fields_integration_try.rb +1 -1
- data/try/features/encrypted_fields/encrypted_fields_no_cache_security_try.rb +1 -1
- data/try/features/encrypted_fields/encrypted_fields_security_try.rb +1 -1
- data/try/features/encrypted_fields/error_conditions_try.rb +1 -1
- data/try/features/encrypted_fields/fresh_key_derivation_try.rb +1 -1
- data/try/features/encrypted_fields/fresh_key_try.rb +1 -1
- data/try/features/encrypted_fields/key_rotation_try.rb +1 -1
- data/try/features/encrypted_fields/memory_security_try.rb +1 -1
- data/try/features/encrypted_fields/missing_current_key_version_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 +1 -1
- data/try/features/encrypted_fields/thread_safety_try.rb +1 -1
- data/try/features/encrypted_fields/universal_serialization_safety_try.rb +1 -1
- data/try/{encryption → features/encryption}/config_persistence_try.rb +1 -1
- data/try/{encryption/encryption_core_try.rb → features/encryption/core_try.rb} +2 -2
- data/try/{encryption → features/encryption}/instance_variable_scope_try.rb +1 -1
- data/try/{encryption → features/encryption}/module_loading_try.rb +1 -1
- data/try/{encryption → features/encryption}/providers/aes_gcm_provider_try.rb +1 -1
- data/try/{encryption → features/encryption}/providers/xchacha20_poly1305_provider_try.rb +1 -1
- data/try/{encryption → features/encryption}/roundtrip_validation_try.rb +1 -1
- data/try/{encryption → features/encryption}/secure_memory_handling_try.rb +2 -2
- data/try/features/expiration/expiration_try.rb +2 -2
- data/try/features/external_identifier/external_identifier_try.rb +1 -1
- data/try/features/feature_dependencies_try.rb +1 -1
- data/try/features/feature_improvements_try.rb +1 -1
- data/try/features/object_identifier/object_identifier_integration_try.rb +1 -1
- data/try/features/object_identifier/object_identifier_try.rb +1 -1
- data/try/features/quantization/quantization_try.rb +1 -1
- data/try/features/real_feature_integration_try.rb +17 -14
- data/try/features/relationships/indexing_commands_verification_try.rb +8 -3
- data/try/features/relationships/indexing_try.rb +34 -5
- data/try/features/relationships/participation_commands_verification_spec.rb +1 -1
- data/try/features/relationships/participation_commands_verification_try.rb +4 -4
- data/try/features/relationships/participation_performance_improvements_try.rb +1 -1
- data/try/features/relationships/participation_reverse_index_try.rb +1 -1
- data/try/features/relationships/relationships_api_changes_try.rb +5 -5
- data/try/features/relationships/relationships_edge_cases_try.rb +3 -3
- data/try/features/relationships/relationships_performance_minimal_try.rb +1 -1
- data/try/features/relationships/relationships_performance_simple_try.rb +1 -1
- data/try/features/relationships/relationships_performance_try.rb +1 -1
- data/try/features/relationships/relationships_performance_working_try.rb +1 -1
- data/try/features/relationships/relationships_try.rb +1 -1
- data/try/features/safe_dump/safe_dump_advanced_try.rb +1 -1
- data/try/features/safe_dump/safe_dump_try.rb +1 -1
- data/try/features/transient_fields/redacted_string_try.rb +1 -1
- data/try/features/transient_fields/refresh_reset_try.rb +1 -1
- data/try/features/transient_fields/single_use_redacted_string_try.rb +1 -1
- data/try/features/transient_fields/transient_fields_core_try.rb +1 -1
- data/try/features/transient_fields/transient_fields_integration_try.rb +1 -1
- data/try/{connection → integration/connection}/fiber_context_preservation_try.rb +4 -4
- data/try/{connection → integration/connection}/handler_constraints_try.rb +1 -1
- data/try/{core → integration/connection}/isolated_dbclient_try.rb +1 -1
- data/try/integration/connection/middleware_reconnect_try.rb +87 -0
- data/try/{connection → integration/connection}/operation_mode_guards_try.rb +2 -2
- data/try/{connection → integration/connection}/pipeline_fallback_integration_try.rb +13 -13
- data/try/{core → integration/connection}/pools_try.rb +1 -1
- data/try/{connection → integration/connection}/responsibility_chain_tracking_try.rb +1 -1
- data/try/{connection → integration/connection}/transaction_fallback_integration_try.rb +1 -1
- data/try/{connection → integration/connection}/transaction_mode_permissive_try.rb +1 -1
- data/try/{connection → integration/connection}/transaction_mode_strict_try.rb +1 -1
- data/try/{connection → integration/connection}/transaction_mode_warn_try.rb +1 -1
- data/try/{connection → integration/connection}/transaction_modes_try.rb +1 -1
- data/try/{core → integration}/conventional_inheritance_try.rb +1 -1
- data/try/{core → integration}/create_method_try.rb +23 -23
- data/try/integration/cross_component_try.rb +1 -1
- data/try/integration/data_types/datatype_pipelines_try.rb +104 -0
- data/try/integration/data_types/datatype_transactions_try.rb +247 -0
- data/try/{core → integration}/database_consistency_try.rb +11 -8
- data/try/{core → integration}/familia_extended_try.rb +1 -1
- data/try/{core → integration}/familia_members_methods_try.rb +1 -1
- data/try/{models → integration/models}/customer_safe_dump_try.rb +6 -2
- data/try/{models → integration/models}/customer_try.rb +1 -1
- data/try/{models → integration/models}/datatype_base_try.rb +1 -1
- data/try/{models → integration/models}/familia_object_try.rb +2 -2
- data/try/{core → integration}/persistence_operations_try.rb +163 -11
- data/try/integration/relationships_persistence_round_trip_try.rb +441 -0
- data/try/{configuration → integration}/scenarios_try.rb +1 -1
- data/try/{core → integration}/secure_identifier_try.rb +1 -1
- data/try/{core → integration}/verifiable_identifier_try.rb +1 -1
- data/try/performance/benchmarks_try.rb +2 -2
- data/try/support/benchmarks/deserialization_benchmark.rb +180 -0
- data/try/support/benchmarks/deserialization_correctness_test.rb +237 -0
- data/try/{helpers → support/helpers}/test_helpers.rb +12 -3
- data/try/{core → unit/core}/autoloader_try.rb +1 -1
- data/try/{core → unit/core}/base_enhancements_try.rb +1 -9
- data/try/{core → unit/core}/connection_try.rb +1 -1
- data/try/{core → unit/core}/errors_try.rb +1 -1
- data/try/{core → unit/core}/extensions_try.rb +1 -1
- data/try/unit/core/familia_logger_try.rb +110 -0
- data/try/{core → unit/core}/familia_try.rb +1 -1
- data/try/{core → unit/core}/middleware_try.rb +41 -1
- data/try/{core → unit/core}/settings_try.rb +1 -1
- data/try/{core → unit/core}/time_utils_try.rb +1 -1
- data/try/{core → unit/core}/tools_try.rb +1 -1
- data/try/{core → unit/core}/utils_try.rb +17 -14
- data/try/{data_types → unit/data_types}/boolean_try.rb +2 -2
- data/try/{data_types → unit/data_types}/counter_try.rb +1 -1
- data/try/{data_types → unit/data_types}/datatype_base_try.rb +1 -1
- data/try/{data_types → unit/data_types}/hash_try.rb +1 -1
- data/try/{data_types → unit/data_types}/list_try.rb +1 -1
- data/try/{data_types → unit/data_types}/lock_try.rb +1 -1
- data/try/{data_types → unit/data_types}/sorted_set_try.rb +1 -1
- data/try/{data_types → unit/data_types}/sorted_set_zadd_options_try.rb +1 -1
- data/try/{data_types → unit/data_types}/string_try.rb +2 -2
- data/try/{data_types → unit/data_types}/unsortedset_try.rb +1 -1
- data/try/{horreum → unit/horreum}/auto_indexing_on_save_try.rb +33 -17
- data/try/unit/horreum/automatic_index_validation_try.rb +253 -0
- data/try/{horreum → unit/horreum}/base_try.rb +4 -4
- data/try/{horreum → unit/horreum}/class_methods_try.rb +3 -3
- data/try/{horreum → unit/horreum}/commands_try.rb +1 -1
- data/try/{horreum → unit/horreum}/defensive_initialization_try.rb +1 -1
- data/try/{horreum → unit/horreum}/destroy_related_fields_cleanup_try.rb +1 -1
- data/try/{horreum → unit/horreum}/enhanced_conflict_handling_try.rb +1 -1
- data/try/{horreum → unit/horreum}/field_categories_try.rb +27 -18
- data/try/{horreum → unit/horreum}/field_definition_try.rb +1 -1
- data/try/{horreum → unit/horreum}/initialization_try.rb +3 -3
- data/try/unit/horreum/json_type_preservation_try.rb +248 -0
- data/try/{horreum → unit/horreum}/relations_try.rb +5 -5
- data/try/{horreum → unit/horreum}/serialization_persistent_fields_try.rb +24 -18
- data/try/{horreum → unit/horreum}/serialization_try.rb +6 -6
- data/try/{horreum → unit/horreum}/settings_try.rb +1 -1
- data/try/unit/horreum/unique_index_edge_cases_try.rb +376 -0
- data/try/unit/horreum/unique_index_guard_validation_try.rb +281 -0
- data/try/{refinements → unit/refinements}/dear_json_array_methods_try.rb +1 -1
- data/try/{refinements → unit/refinements}/dear_json_hash_methods_try.rb +1 -1
- data/try/{refinements → unit/refinements}/time_literals_numeric_methods_try.rb +1 -1
- data/try/{refinements → unit/refinements}/time_literals_string_methods_try.rb +1 -1
- metadata +147 -126
- data/lib/familia/distinguisher.rb +0 -85
- data/lib/familia/refinements/logger_trace.rb +0 -60
- data/try/refinements/logger_trace_methods_try.rb +0 -44
- /data/try/{debugging → support/debugging}/README.md +0 -0
- /data/try/{debugging → support/debugging}/cache_behavior_tracer.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_aad_process.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_concealed_internal.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_concealed_reveal.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_context_aad.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_context_simple.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_cross_context.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_database_load.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_encrypted_json_check.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_encrypted_json_step_by_step.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_exists_lifecycle.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_field_decrypt.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_fresh_cross_context.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_load_path.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_method_definition.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_method_resolution.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_minimal.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_provider.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_secure_behavior.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_string_class.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_test.rb +0 -0
- /data/try/{debugging → support/debugging}/debug_test_design.rb +0 -0
- /data/try/{debugging → support/debugging}/encryption_method_tracer.rb +0 -0
- /data/try/{debugging → support/debugging}/provider_diagnostics.rb +0 -0
- /data/try/{helpers → support/helpers}/test_cleanup.rb +0 -0
- /data/try/{memory → support/memory}/memory_basic_test.rb +0 -0
- /data/try/{memory → support/memory}/memory_detailed_test.rb +0 -0
- /data/try/{memory → support/memory}/memory_docker_ruby_dump.sh +0 -0
- /data/try/{memory → support/memory}/memory_search_for_string.rb +0 -0
- /data/try/{memory → support/memory}/test_actual_redactedstring_protection.rb +0 -0
- /data/try/{prototypes → support/prototypes}/atomic_saves_v1_context_proxy.rb +0 -0
- /data/try/{prototypes → support/prototypes}/atomic_saves_v2_connection_switching.rb +0 -0
- /data/try/{prototypes → support/prototypes}/atomic_saves_v3_connection_pool.rb +0 -0
- /data/try/{prototypes → support/prototypes}/atomic_saves_v4.rb +0 -0
- /data/try/{prototypes → support/prototypes}/lib/atomic_saves_v2_connection_switching_helpers.rb +0 -0
- /data/try/{prototypes → support/prototypes}/lib/atomic_saves_v3_connection_pool_helpers.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/README.md +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/configurable_stress_test.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/lib/atomic_saves_v3_connection_pool_helpers.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/lib/connection_pool_metrics.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/lib/connection_pool_stress_test.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/lib/connection_pool_threading_models.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/lib/visualize_stress_results.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/pool_siege.rb +0 -0
- /data/try/{prototypes → support/prototypes}/pooling/run_stress_tests.rb +0 -0
@@ -3,7 +3,7 @@
|
|
3
3
|
# Security tests for the no-cache encryption strategy
|
4
4
|
# These tests verify that we maintain security properties by NOT caching derived keys
|
5
5
|
|
6
|
-
require_relative '../../helpers/test_helpers'
|
6
|
+
require_relative '../../support/helpers/test_helpers'
|
7
7
|
|
8
8
|
test_keys = {
|
9
9
|
v1: Base64.strict_encode64('a' * 32),
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
require 'base64'
|
4
4
|
|
5
|
-
require_relative '../../helpers/test_helpers'
|
5
|
+
require_relative '../../support/helpers/test_helpers'
|
6
6
|
|
7
7
|
# This tryouts file is based on the premise that there is no current key
|
8
8
|
# version set. This is a global setting so if other tryouts rely on
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# try/encryption/encryption_core_try.rb
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
3
|
+
require_relative '../../support/helpers/test_helpers'
|
4
|
+
require_relative '../../../lib/familia/encryption'
|
5
5
|
require 'base64'
|
6
6
|
|
7
7
|
# Test constants will be redefined in each test since variables don't persist
|
@@ -1,7 +1,7 @@
|
|
1
1
|
# try/encryption/secure_memory_handling_try.rb
|
2
2
|
|
3
|
-
require_relative '
|
4
|
-
require_relative '
|
3
|
+
require_relative '../../support/helpers/test_helpers'
|
4
|
+
require_relative '../../../lib/familia/encryption/providers/secure_xchacha20_poly1305_provider'
|
5
5
|
require 'base64'
|
6
6
|
|
7
7
|
# SETUP
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# try/features/expiration_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
|
|
@@ -58,7 +58,7 @@ ExpiringTest.default_expiration
|
|
58
58
|
#=> true
|
59
59
|
|
60
60
|
## Can call update_expiration method
|
61
|
-
result = @test_obj.update_expiration(
|
61
|
+
result = @test_obj.update_expiration(expiration: 180)
|
62
62
|
[result.class, result]
|
63
63
|
#=> [FalseClass, false]
|
64
64
|
|
@@ -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
|
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
|
20
|
-
|
21
|
-
|
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
|
-
|
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
|
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
|
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
|
-
@company = TestCompany.create(company_id: @company_id, name: 'Acme Corp')
|
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
|
@@ -81,7 +86,7 @@ sample = @company.sample_from_department(@emp2.department)
|
|
81
86
|
|
82
87
|
## First indexing relationship has correct configuration
|
83
88
|
config = @user1.class.indexing_relationships.first
|
84
|
-
[config.field, config.index_name, config.
|
89
|
+
[config.field, config.index_name, config.scope_class == TestUser, config.query]
|
85
90
|
#=> [:email, :email_lookup, true, true]
|
86
91
|
|
87
92
|
## Second indexing relationship has query disabled
|
@@ -184,7 +189,7 @@ TestUser.respond_to?(:find_by_username)
|
|
184
189
|
|
185
190
|
## Instance-scoped unique index has correct configuration
|
186
191
|
config = @emp1.class.indexing_relationships.find { |r| r.field == :badge_number }
|
187
|
-
[config.index_name, config.
|
192
|
+
[config.index_name, config.scope_class, config.cardinality]
|
188
193
|
#=> [:badge_index, TestCompany, :unique]
|
189
194
|
|
190
195
|
## Target class gets finder method for unique index
|
@@ -246,6 +251,16 @@ found_emps = @company.find_all_by_badge_number('BADGE002')
|
|
246
251
|
found_emps.map(&:emp_id)
|
247
252
|
#=> ["emp_002"]
|
248
253
|
|
254
|
+
## Instance-scoped bulk query filters nil inputs
|
255
|
+
badges_with_nil = [nil, 'BADGE001', nil]
|
256
|
+
found_emps = @company.find_all_by_badge_number(badges_with_nil)
|
257
|
+
found_emps.map(&:emp_id)
|
258
|
+
#=> ["emp_001"]
|
259
|
+
|
260
|
+
## Instance-scoped bulk query with only nil returns empty
|
261
|
+
@company.find_all_by_badge_number([nil, nil]).length
|
262
|
+
#=> 0
|
263
|
+
|
249
264
|
## Update badge index entry
|
250
265
|
old_badge = @emp1.badge_number
|
251
266
|
@emp1.badge_number = 'BADGE001_NEW'
|
@@ -272,7 +287,7 @@ old_badge = @emp1.badge_number
|
|
272
287
|
|
273
288
|
## Context-scoped multi_index relationship has correct configuration
|
274
289
|
config = @emp1.class.indexing_relationships.find { |r| r.field == :department }
|
275
|
-
[config.field, config.index_name, config.
|
290
|
+
[config.field, config.index_name, config.scope_class]
|
276
291
|
#=> [:department, :dept_index, TestCompany]
|
277
292
|
|
278
293
|
## Context-scoped methods are generated with collision-free naming
|
@@ -415,6 +430,20 @@ found = TestUser.find_all_by_email(emails)
|
|
415
430
|
found.map(&:user_id)
|
416
431
|
#=> ["user_002"]
|
417
432
|
|
433
|
+
## Bulk query filters nil inputs before querying
|
434
|
+
emails_with_nil = [nil, 'bob@example.com', nil]
|
435
|
+
found = TestUser.find_all_by_email(emails_with_nil)
|
436
|
+
found.map(&:user_id)
|
437
|
+
#=> ["user_002"]
|
438
|
+
|
439
|
+
## Bulk query with only nil inputs returns empty array
|
440
|
+
TestUser.find_all_by_email([nil, nil]).length
|
441
|
+
#=> 0
|
442
|
+
|
443
|
+
## Bulk query with nil as single value returns empty array
|
444
|
+
TestUser.find_all_by_email(nil).length
|
445
|
+
#=> 0
|
446
|
+
|
418
447
|
## Adding to index with nil field value does nothing
|
419
448
|
@user_nil = TestUser.new(user_id: 'user_nil', email: nil)
|
420
449
|
@user_nil.add_to_class_email_lookup
|
@@ -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/
|
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/
|
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
|
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]
|
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]
|
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
|
@@ -264,17 +264,17 @@ participation_meta.target_class.familia_name
|
|
264
264
|
|
265
265
|
## unique_index stores correct target_class
|
266
266
|
indexing_meta = ApiTestUser.indexing_relationships.find { |r| r.index_name == :email_lookup }
|
267
|
-
indexing_meta.
|
267
|
+
indexing_meta.scope_class
|
268
268
|
#=> ApiTestUser
|
269
269
|
|
270
|
-
## unique_index stores correct
|
270
|
+
## unique_index stores correct scope_class via familia_name
|
271
271
|
indexing_meta = ApiTestUser.indexing_relationships.find { |r| r.index_name == :email_lookup }
|
272
|
-
indexing_meta.
|
272
|
+
indexing_meta.scope_class.familia_name
|
273
273
|
#=> 'ApiTestUser'
|
274
274
|
|
275
275
|
## multi_index with within: stores correct metadata
|
276
276
|
membership_meta = ApiTestMembership.indexing_relationships.find { |r| r.index_name == :user_memberships }
|
277
|
-
membership_meta.
|
277
|
+
membership_meta.scope_class
|
278
278
|
#=> ApiTestUser
|
279
279
|
|
280
280
|
# =============================================
|
@@ -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
|
|
@@ -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
|