familia 2.0.0.pre19 → 2.0.0.pre21
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/claude-code-review.yml +4 -9
- data/.github/workflows/code-smells.yml +64 -3
- data/.pre-commit-config.yaml +8 -6
- data/.reek.yml +10 -9
- data/.rubocop.yml +4 -0
- data/CHANGELOG.rst +177 -112
- data/CLAUDE.md +28 -1
- data/Gemfile +1 -1
- data/Gemfile.lock +20 -17
- data/bin/try +16 -0
- data/bin/tryouts +16 -0
- data/changelog.d/20251105_flexible_external_identifier_format.rst +66 -0
- data/changelog.d/20251107_112554_delano_179_participation_asymmetry.rst +44 -0
- data/changelog.d/20251107_213121_delano_fix_thread_safety_races_011CUumCP492Twxm4NLt2FvL.rst +20 -0
- data/changelog.d/20251107_fix_participates_in_symbol_resolution.rst +91 -0
- data/changelog.d/20251107_optimized_redis_exists_checks.rst +94 -0
- data/changelog.d/20251108_frozen_string_literal_pragma.rst +44 -0
- data/docs/1106-participates_in-bidirectional-solution.md +129 -0
- data/docs/guides/encryption.md +486 -0
- data/docs/guides/feature-encrypted-fields.md +123 -7
- data/docs/guides/feature-expiration.md +161 -117
- data/docs/guides/feature-external-identifiers.md +415 -443
- data/docs/guides/feature-object-identifiers.md +400 -269
- data/docs/guides/feature-quantization.md +120 -6
- data/docs/guides/feature-relationships-indexing.md +318 -0
- data/docs/guides/feature-relationships-methods.md +146 -604
- data/docs/guides/feature-relationships-participation.md +263 -0
- data/docs/guides/feature-relationships.md +118 -136
- data/docs/guides/feature-system-devs.md +176 -693
- data/docs/guides/feature-system.md +119 -6
- data/docs/guides/feature-transient-fields.md +81 -0
- data/docs/guides/field-system.md +778 -0
- data/docs/guides/index.md +32 -15
- data/docs/guides/logging.md +187 -0
- data/docs/guides/optimized-loading.md +674 -0
- data/docs/guides/thread-safety-monitoring.md +61 -0
- data/docs/guides/{time-utilities.md → time-literals.md} +12 -12
- data/docs/migrating/v2.0.0-pre22.md +241 -0
- data/docs/overview.md +7 -9
- data/docs/reference/api-technical.md +267 -320
- data/examples/autoloader/mega_customer/features/deprecated_fields.rb +2 -0
- data/examples/autoloader/mega_customer/safe_dump_fields.rb +2 -0
- data/examples/autoloader/mega_customer.rb +2 -0
- data/examples/datatype_standalone.rb +4 -3
- data/examples/encrypted_fields.rb +2 -1
- data/examples/json_usage_patterns.rb +2 -0
- data/examples/relationships.rb +3 -0
- data/examples/safe_dump.rb +2 -1
- data/examples/sampling_demo.rb +53 -0
- data/examples/single_connection_transaction_confusions.rb +2 -1
- data/familia.gemspec +2 -1
- data/lib/familia/base.rb +2 -0
- data/lib/familia/connection/behavior.rb +2 -0
- data/lib/familia/connection/handlers.rb +2 -0
- data/lib/familia/connection/individual_command_proxy.rb +2 -0
- data/lib/familia/connection/middleware.rb +34 -24
- data/lib/familia/connection/operation_core.rb +2 -0
- data/lib/familia/connection/operations.rb +2 -0
- data/lib/familia/connection/pipelined_core.rb +2 -0
- data/lib/familia/connection/transaction_core.rb +68 -0
- data/lib/familia/connection.rb +18 -3
- data/lib/familia/data_type/class_methods.rb +3 -1
- data/lib/familia/data_type/connection.rb +2 -0
- data/lib/familia/data_type/database_commands.rb +2 -0
- data/lib/familia/data_type/serialization.rb +6 -4
- data/lib/familia/data_type/settings.rb +2 -0
- data/lib/familia/data_type/types/counter.rb +2 -0
- data/lib/familia/data_type/types/hashkey.rb +7 -5
- data/lib/familia/data_type/types/listkey.rb +2 -0
- data/lib/familia/data_type/types/lock.rb +2 -0
- data/lib/familia/data_type/types/sorted_set.rb +2 -0
- data/lib/familia/data_type/types/stringkey.rb +2 -0
- data/lib/familia/data_type/types/unsorted_set.rb +2 -0
- data/lib/familia/data_type.rb +2 -0
- data/lib/familia/encryption/encrypted_data.rb +4 -2
- data/lib/familia/encryption/manager.rb +2 -0
- data/lib/familia/encryption/provider.rb +2 -0
- data/lib/familia/encryption/providers/aes_gcm_provider.rb +2 -0
- data/lib/familia/encryption/providers/secure_xchacha20_poly1305_provider.rb +2 -0
- data/lib/familia/encryption/providers/xchacha20_poly1305_provider.rb +2 -0
- data/lib/familia/encryption/registry.rb +2 -0
- data/lib/familia/encryption/request_cache.rb +2 -0
- data/lib/familia/encryption.rb +9 -2
- data/lib/familia/errors.rb +2 -0
- data/lib/familia/features/autoloader.rb +2 -0
- data/lib/familia/features/encrypted_fields/concealed_string.rb +2 -0
- data/lib/familia/features/encrypted_fields/encrypted_field_type.rb +4 -0
- data/lib/familia/features/encrypted_fields.rb +2 -2
- data/lib/familia/features/expiration/extensions.rb +3 -1
- data/lib/familia/features/expiration.rb +12 -4
- data/lib/familia/features/external_identifier.rb +33 -7
- data/lib/familia/features/object_identifier.rb +2 -0
- data/lib/familia/features/quantization.rb +3 -1
- data/lib/familia/features/relationships/README.md +3 -1
- data/lib/familia/features/relationships/collection_operations.rb +2 -0
- data/lib/familia/features/relationships/indexing/multi_index_generators.rb +138 -9
- data/lib/familia/features/relationships/indexing/rebuild_strategies.rb +479 -0
- data/lib/familia/features/relationships/indexing/unique_index_generators.rb +89 -21
- data/lib/familia/features/relationships/indexing.rb +3 -0
- data/lib/familia/features/relationships/indexing_relationship.rb +3 -1
- data/lib/familia/features/relationships/participation/participant_methods.rb +131 -14
- data/lib/familia/features/relationships/participation/rebuild_strategies.md +41 -0
- data/lib/familia/features/relationships/participation/target_methods.rb +6 -6
- data/lib/familia/features/relationships/participation.rb +155 -69
- data/lib/familia/features/relationships/participation_membership.rb +69 -0
- data/lib/familia/features/relationships/participation_relationship.rb +34 -6
- data/lib/familia/features/relationships/score_encoding.rb +2 -0
- data/lib/familia/features/relationships.rb +5 -3
- data/lib/familia/features/safe_dump.rb +2 -0
- data/lib/familia/features/transient_fields/redacted_string.rb +2 -0
- data/lib/familia/features/transient_fields/single_use_redacted_string.rb +2 -0
- data/lib/familia/features/transient_fields/transient_field_type.rb +5 -3
- data/lib/familia/features/transient_fields.rb +2 -0
- data/lib/familia/features.rb +2 -0
- data/lib/familia/field_type.rb +3 -1
- data/lib/familia/horreum/connection.rb +17 -1
- data/lib/familia/horreum/database_commands.rb +2 -0
- data/lib/familia/horreum/definition.rb +16 -6
- data/lib/familia/horreum/management.rb +212 -42
- data/lib/familia/horreum/persistence.rb +176 -108
- data/lib/familia/horreum/related_fields.rb +2 -0
- data/lib/familia/horreum/serialization.rb +23 -4
- data/lib/familia/horreum/settings.rb +2 -0
- data/lib/familia/horreum/utils.rb +2 -0
- data/lib/familia/horreum.rb +15 -1
- data/lib/familia/identifier_extractor.rb +2 -0
- data/lib/familia/instrumentation.rb +156 -0
- data/lib/familia/json_serializer.rb +2 -0
- data/lib/familia/logging.rb +92 -32
- data/lib/familia/refinements/dear_json.rb +2 -0
- data/lib/familia/refinements/stylize_words.rb +2 -14
- data/lib/familia/refinements/time_literals.rb +2 -0
- data/lib/familia/refinements.rb +2 -0
- data/lib/familia/secure_identifier.rb +10 -2
- data/lib/familia/settings.rb +2 -0
- data/lib/familia/thread_safety/instrumented_mutex.rb +166 -0
- data/lib/familia/thread_safety/monitor.rb +328 -0
- data/lib/familia/utils.rb +13 -0
- data/lib/familia/verifiable_identifier.rb +3 -1
- data/lib/familia/version.rb +3 -1
- data/lib/familia.rb +31 -4
- data/lib/middleware/database_command_counter.rb +152 -0
- data/lib/middleware/database_logger.rb +295 -170
- data/lib/multi_result.rb +2 -0
- data/try/edge_cases/empty_identifiers_try.rb +2 -0
- data/try/edge_cases/hash_symbolization_try.rb +2 -0
- data/try/edge_cases/json_serialization_try.rb +2 -0
- data/try/edge_cases/legacy_data_detection/deserialization_edge_cases_try.rb +4 -0
- data/try/edge_cases/race_conditions_try.rb +4 -0
- data/try/edge_cases/reserved_keywords_try.rb +4 -0
- data/try/edge_cases/string_coercion_try.rb +2 -0
- data/try/edge_cases/ttl_side_effects_try.rb +4 -0
- data/try/features/encrypted_fields/aad_protection_try.rb +4 -0
- data/try/features/encrypted_fields/concealed_string_core_try.rb +4 -0
- data/try/features/encrypted_fields/context_isolation_try.rb +4 -0
- data/try/features/encrypted_fields/encrypted_fields_core_try.rb +33 -0
- data/try/features/encrypted_fields/encrypted_fields_integration_try.rb +4 -0
- data/try/features/encrypted_fields/encrypted_fields_no_cache_security_try.rb +4 -0
- data/try/features/encrypted_fields/encrypted_fields_security_try.rb +4 -0
- data/try/features/encrypted_fields/error_conditions_try.rb +4 -0
- data/try/features/encrypted_fields/fresh_key_derivation_try.rb +4 -0
- data/try/features/encrypted_fields/fresh_key_try.rb +4 -0
- data/try/features/encrypted_fields/key_rotation_try.rb +4 -0
- data/try/features/encrypted_fields/memory_security_try.rb +4 -0
- data/try/features/encrypted_fields/missing_current_key_version_try.rb +4 -0
- data/try/features/encrypted_fields/nonce_uniqueness_try.rb +4 -0
- data/try/features/encrypted_fields/secure_by_default_behavior_try.rb +4 -0
- data/try/features/encrypted_fields/thread_safety_try.rb +4 -0
- data/try/features/encrypted_fields/universal_serialization_safety_try.rb +4 -0
- data/try/features/encryption/config_persistence_try.rb +4 -0
- data/try/features/encryption/core_try.rb +4 -0
- data/try/features/encryption/instance_variable_scope_try.rb +4 -0
- data/try/features/encryption/module_loading_try.rb +4 -0
- data/try/features/encryption/providers/aes_gcm_provider_try.rb +4 -0
- data/try/features/encryption/providers/xchacha20_poly1305_provider_try.rb +4 -0
- data/try/features/encryption/roundtrip_validation_try.rb +4 -0
- data/try/features/encryption/secure_memory_handling_try.rb +4 -0
- data/try/features/expiration/expiration_try.rb +4 -0
- data/try/features/external_identifier/external_identifier_try.rb +171 -8
- data/try/features/feature_dependencies_try.rb +2 -0
- data/try/features/feature_improvements_try.rb +2 -0
- data/try/features/field_groups_try.rb +2 -0
- data/try/features/object_identifier/object_identifier_integration_try.rb +12 -9
- data/try/features/object_identifier/object_identifier_try.rb +2 -0
- data/try/features/quantization/quantization_try.rb +4 -0
- data/try/features/real_feature_integration_try.rb +2 -0
- data/try/features/relationships/indexing_commands_verification_try.rb +2 -0
- data/try/features/relationships/indexing_rebuild_try.rb +600 -0
- data/try/features/relationships/indexing_try.rb +2 -0
- data/try/features/relationships/participation_bidirectional_try.rb +242 -0
- data/try/features/relationships/participation_commands_verification_spec.rb +4 -0
- data/try/features/relationships/participation_commands_verification_try.rb +2 -0
- data/try/features/relationships/participation_performance_improvements_try.rb +11 -9
- data/try/features/relationships/participation_reverse_index_try.rb +15 -13
- data/try/features/relationships/participation_target_class_resolution_try.rb +209 -0
- data/try/features/relationships/participation_unresolved_target_try.rb +109 -0
- data/try/features/relationships/relationships_api_changes_try.rb +2 -0
- data/try/features/relationships/relationships_edge_cases_try.rb +4 -0
- data/try/features/relationships/relationships_performance_minimal_try.rb +4 -0
- data/try/features/relationships/relationships_performance_simple_try.rb +4 -0
- data/try/features/relationships/relationships_performance_try.rb +4 -0
- data/try/features/relationships/relationships_performance_working_try.rb +4 -0
- data/try/features/relationships/relationships_try.rb +6 -4
- data/try/features/safe_dump/safe_dump_advanced_try.rb +4 -0
- data/try/features/safe_dump/safe_dump_try.rb +4 -0
- data/try/features/transient_fields/redacted_string_try.rb +2 -0
- data/try/features/transient_fields/refresh_reset_try.rb +3 -0
- data/try/features/transient_fields/simple_refresh_test.rb +3 -0
- data/try/features/transient_fields/single_use_redacted_string_try.rb +2 -0
- data/try/features/transient_fields/transient_fields_core_try.rb +4 -0
- data/try/features/transient_fields/transient_fields_integration_try.rb +4 -0
- data/try/integration/connection/fiber_context_preservation_try.rb +4 -0
- data/try/integration/connection/handler_constraints_try.rb +4 -0
- data/try/integration/connection/isolated_dbclient_try.rb +4 -0
- data/try/integration/connection/middleware_reconnect_try.rb +2 -0
- data/try/integration/connection/operation_mode_guards_try.rb +4 -0
- data/try/integration/connection/pipeline_fallback_integration_try.rb +3 -0
- data/try/integration/connection/pools_try.rb +4 -0
- data/try/integration/connection/responsibility_chain_tracking_try.rb +4 -0
- data/try/integration/connection/transaction_fallback_integration_try.rb +4 -0
- data/try/integration/connection/transaction_mode_permissive_try.rb +4 -0
- data/try/integration/connection/transaction_mode_strict_try.rb +4 -0
- data/try/integration/connection/transaction_mode_warn_try.rb +4 -0
- data/try/integration/connection/transaction_modes_try.rb +4 -0
- data/try/integration/conventional_inheritance_try.rb +4 -0
- data/try/integration/create_method_try.rb +4 -0
- data/try/integration/cross_component_try.rb +4 -0
- data/try/integration/data_types/datatype_pipelines_try.rb +4 -0
- data/try/integration/data_types/datatype_transactions_try.rb +4 -0
- data/try/integration/database_consistency_try.rb +4 -0
- data/try/integration/familia_extended_try.rb +4 -0
- data/try/integration/familia_members_methods_try.rb +4 -0
- data/try/integration/models/customer_safe_dump_try.rb +4 -0
- data/try/integration/models/customer_try.rb +4 -0
- data/try/integration/models/datatype_base_try.rb +4 -0
- data/try/integration/models/familia_object_try.rb +4 -0
- data/try/integration/persistence_operations_try.rb +4 -0
- data/try/integration/relationships_persistence_round_trip_try.rb +17 -14
- data/try/integration/save_methods_consistency_try.rb +241 -0
- data/try/integration/scenarios_try.rb +4 -0
- data/try/integration/secure_identifier_try.rb +4 -0
- data/try/integration/transaction_safety_core_try.rb +176 -0
- data/try/integration/transaction_safety_workflow_try.rb +291 -0
- data/try/integration/verifiable_identifier_try.rb +4 -0
- data/try/investigation/pipeline_routing/README.md +228 -0
- data/try/performance/benchmarks_try.rb +4 -0
- data/try/performance/transaction_safety_benchmark_try.rb +238 -0
- data/try/support/benchmarks/deserialization_benchmark.rb +3 -1
- data/try/support/benchmarks/deserialization_correctness_test.rb +3 -1
- data/try/support/debugging/cache_behavior_tracer.rb +4 -0
- data/try/support/debugging/debug_aad_process.rb +3 -0
- data/try/support/debugging/debug_concealed_internal.rb +3 -0
- data/try/support/debugging/debug_concealed_reveal.rb +3 -0
- data/try/support/debugging/debug_context_aad.rb +3 -0
- data/try/support/debugging/debug_context_simple.rb +3 -0
- data/try/support/debugging/debug_cross_context.rb +3 -0
- data/try/support/debugging/debug_database_load.rb +3 -0
- data/try/support/debugging/debug_encrypted_json_check.rb +3 -0
- data/try/support/debugging/debug_encrypted_json_step_by_step.rb +3 -0
- data/try/support/debugging/debug_exists_lifecycle.rb +3 -0
- data/try/support/debugging/debug_field_decrypt.rb +3 -0
- data/try/support/debugging/debug_fresh_cross_context.rb +3 -0
- data/try/support/debugging/debug_load_path.rb +3 -0
- data/try/support/debugging/debug_method_definition.rb +3 -0
- data/try/support/debugging/debug_method_resolution.rb +3 -0
- data/try/support/debugging/debug_minimal.rb +3 -0
- data/try/support/debugging/debug_provider.rb +3 -0
- data/try/support/debugging/debug_secure_behavior.rb +3 -0
- data/try/support/debugging/debug_string_class.rb +3 -0
- data/try/support/debugging/debug_test.rb +3 -0
- data/try/support/debugging/debug_test_design.rb +3 -0
- data/try/support/debugging/encryption_method_tracer.rb +4 -0
- data/try/support/debugging/provider_diagnostics.rb +4 -0
- data/try/support/helpers/test_cleanup.rb +4 -0
- data/try/support/helpers/test_helpers.rb +5 -0
- data/try/support/memory/memory_basic_test.rb +4 -0
- data/try/support/memory/memory_detailed_test.rb +4 -0
- data/try/support/memory/memory_search_for_string.rb +4 -0
- data/try/support/memory/test_actual_redactedstring_protection.rb +4 -0
- data/try/support/prototypes/atomic_saves_v1_context_proxy.rb +4 -0
- data/try/support/prototypes/atomic_saves_v2_connection_switching.rb +4 -0
- data/try/support/prototypes/atomic_saves_v3_connection_pool.rb +4 -0
- data/try/support/prototypes/atomic_saves_v4.rb +4 -0
- data/try/support/prototypes/lib/atomic_saves_v2_connection_switching_helpers.rb +4 -0
- data/try/support/prototypes/lib/atomic_saves_v3_connection_pool_helpers.rb +4 -0
- data/try/support/prototypes/pooling/configurable_stress_test.rb +4 -0
- data/try/support/prototypes/pooling/lib/atomic_saves_v3_connection_pool_helpers.rb +4 -0
- data/try/support/prototypes/pooling/lib/connection_pool_metrics.rb +4 -0
- data/try/support/prototypes/pooling/lib/connection_pool_stress_test.rb +4 -0
- data/try/support/prototypes/pooling/lib/connection_pool_threading_models.rb +4 -0
- data/try/support/prototypes/pooling/lib/visualize_stress_results.rb +4 -2
- data/try/support/prototypes/pooling/pool_siege.rb +4 -2
- data/try/support/prototypes/pooling/run_stress_tests.rb +4 -2
- data/try/thread_safety/README.md +496 -0
- data/try/thread_safety/class_connection_chain_race_try.rb +265 -0
- data/try/thread_safety/connection_chain_race_try.rb +148 -0
- data/try/thread_safety/encryption_manager_cache_race_try.rb +166 -0
- data/try/thread_safety/feature_registry_race_try.rb +226 -0
- data/try/thread_safety/fiber_pipeline_isolation_try.rb +235 -0
- data/try/thread_safety/fiber_transaction_isolation_try.rb +208 -0
- data/try/thread_safety/field_registration_race_try.rb +222 -0
- data/try/thread_safety/logger_initialization_race_try.rb +170 -0
- data/try/thread_safety/middleware_registration_race_try.rb +154 -0
- data/try/thread_safety/module_config_race_try.rb +175 -0
- data/try/thread_safety/secure_identifier_cache_race_try.rb +226 -0
- data/try/unit/core/autoloader_try.rb +4 -0
- data/try/unit/core/base_enhancements_try.rb +4 -0
- data/try/unit/core/connection_try.rb +4 -0
- data/try/unit/core/errors_try.rb +4 -0
- data/try/unit/core/extensions_try.rb +4 -0
- data/try/unit/core/familia_logger_try.rb +2 -0
- data/try/unit/core/familia_try.rb +4 -0
- data/try/unit/core/middleware_sampling_try.rb +335 -0
- data/try/unit/core/middleware_test_helpers_bug_try.rb +58 -0
- data/try/unit/core/middleware_thread_safety_try.rb +245 -0
- data/try/unit/core/middleware_try.rb +4 -0
- data/try/unit/core/settings_try.rb +4 -0
- data/try/unit/core/time_utils_try.rb +4 -0
- data/try/unit/core/tools_try.rb +4 -0
- data/try/unit/core/utils_try.rb +37 -0
- data/try/unit/data_types/boolean_try.rb +4 -0
- data/try/unit/data_types/counter_try.rb +4 -0
- data/try/unit/data_types/datatype_base_try.rb +4 -0
- data/try/unit/data_types/hash_try.rb +4 -0
- data/try/unit/data_types/list_try.rb +4 -0
- data/try/unit/data_types/lock_try.rb +4 -0
- data/try/unit/data_types/sorted_set_try.rb +4 -0
- data/try/unit/data_types/sorted_set_zadd_options_try.rb +4 -0
- data/try/unit/data_types/string_try.rb +4 -0
- data/try/unit/data_types/unsortedset_try.rb +4 -0
- data/try/unit/familia_resolve_class_try.rb +116 -0
- data/try/unit/horreum/auto_indexing_on_save_try.rb +5 -1
- data/try/unit/horreum/automatic_index_validation_try.rb +2 -0
- data/try/unit/horreum/base_try.rb +4 -0
- data/try/unit/horreum/class_methods_try.rb +4 -0
- data/try/unit/horreum/commands_try.rb +4 -0
- data/try/unit/horreum/defensive_initialization_try.rb +4 -0
- data/try/unit/horreum/destroy_related_fields_cleanup_try.rb +4 -0
- data/try/unit/horreum/enhanced_conflict_handling_try.rb +4 -0
- data/try/unit/horreum/field_categories_try.rb +4 -0
- data/try/unit/horreum/field_definition_try.rb +4 -0
- data/try/unit/horreum/initialization_try.rb +4 -0
- data/try/unit/horreum/json_type_preservation_try.rb +2 -0
- data/try/unit/horreum/optimized_loading_try.rb +156 -0
- data/try/unit/horreum/relations_try.rb +4 -0
- data/try/unit/horreum/serialization_persistent_fields_try.rb +4 -0
- data/try/unit/horreum/serialization_try.rb +4 -0
- data/try/unit/horreum/settings_try.rb +4 -0
- data/try/unit/horreum/unique_index_edge_cases_try.rb +4 -0
- data/try/unit/horreum/unique_index_guard_validation_try.rb +2 -0
- data/try/unit/middleware/database_command_counter_methods_try.rb +139 -0
- data/try/unit/middleware/database_logger_methods_try.rb +251 -0
- data/try/unit/refinements/dear_json_array_methods_try.rb +4 -0
- data/try/unit/refinements/dear_json_hash_methods_try.rb +4 -0
- data/try/unit/refinements/time_literals_numeric_methods_try.rb +4 -0
- data/try/unit/refinements/time_literals_string_methods_try.rb +4 -0
- data/try/unit/thread_safety_monitor_try.rb +149 -0
- metadata +72 -17
- data/.github/workflows/code-quality.yml +0 -138
- data/changelog.d/20251011_012003_delano_159_datatype_transaction_pipeline_support.rst +0 -91
- data/changelog.d/20251011_203905_delano_next.rst +0 -30
- data/changelog.d/20251011_212633_delano_next.rst +0 -13
- data/changelog.d/20251011_221253_delano_next.rst +0 -26
- data/docs/archive/FAMILIA_RELATIONSHIPS.md +0 -210
- data/docs/archive/FAMILIA_TECHNICAL.md +0 -823
- data/docs/archive/FAMILIA_UPDATE.md +0 -226
- data/docs/archive/README.md +0 -64
- data/docs/archive/api-reference.md +0 -333
- data/docs/guides/core-field-system.md +0 -806
- data/docs/guides/implementation.md +0 -276
- data/docs/guides/security-model.md +0 -183
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# lib/familia/features/relationships/participation_membership.rb
|
|
2
|
+
#
|
|
3
|
+
# frozen_string_literal: true
|
|
4
|
+
|
|
5
|
+
module Familia
|
|
6
|
+
module Features
|
|
7
|
+
module Relationships
|
|
8
|
+
#
|
|
9
|
+
# ParticipationMembership
|
|
10
|
+
#
|
|
11
|
+
# Represents runtime snapshot of a participant's membership in a target collection.
|
|
12
|
+
# Returned by current_participations to provide a type-safe, structured view
|
|
13
|
+
# of actual participation state.
|
|
14
|
+
#
|
|
15
|
+
# @note This represents what currently exists in Redis, not just configuration.
|
|
16
|
+
# See ParticipationRelationship for static configuration metadata.
|
|
17
|
+
#
|
|
18
|
+
# @example
|
|
19
|
+
# membership = user.current_participations.first
|
|
20
|
+
# membership.target_class # => "Team"
|
|
21
|
+
# membership.target_id # => "team123"
|
|
22
|
+
# membership.collection_name # => :members
|
|
23
|
+
# membership.type # => :sorted_set
|
|
24
|
+
# membership.score # => 1762554020.05
|
|
25
|
+
#
|
|
26
|
+
ParticipationMembership = Data.define(
|
|
27
|
+
:target_class, # String - class name (e.g., "Customer")
|
|
28
|
+
:target_id, # String - target instance identifier
|
|
29
|
+
:collection_name, # Symbol - collection name (e.g., :domains)
|
|
30
|
+
:type, # Symbol - collection type (:sorted_set, :set, :list)
|
|
31
|
+
:score, # Float - optional, for sorted_set only
|
|
32
|
+
:decoded_score, # Hash - optional, decoded score data
|
|
33
|
+
:position # Integer - optional, for list only
|
|
34
|
+
) do
|
|
35
|
+
# Check if this membership is a sorted set
|
|
36
|
+
# @return [Boolean]
|
|
37
|
+
def sorted_set?
|
|
38
|
+
type == :sorted_set
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# Check if this membership is a set
|
|
42
|
+
# @return [Boolean]
|
|
43
|
+
def set?
|
|
44
|
+
type == :set
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Check if this membership is a list
|
|
48
|
+
# @return [Boolean]
|
|
49
|
+
def list?
|
|
50
|
+
type == :list
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Get the target instance (requires loading from database)
|
|
54
|
+
# @return [Familia::Horreum, nil] the loaded target instance
|
|
55
|
+
def target_instance
|
|
56
|
+
return nil unless target_class
|
|
57
|
+
|
|
58
|
+
# Resolve class from string name
|
|
59
|
+
# Only rescue NameError (class doesn't exist), not all exceptions
|
|
60
|
+
klass = Object.const_get(target_class)
|
|
61
|
+
klass.find_by_id(target_id)
|
|
62
|
+
rescue NameError
|
|
63
|
+
# Target class doesn't exist or isn't loaded
|
|
64
|
+
nil
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# lib/familia/features/relationships/participation_relationship.rb
|
|
2
|
+
#
|
|
3
|
+
# frozen_string_literal: true
|
|
2
4
|
|
|
3
5
|
module Familia
|
|
4
6
|
module Features
|
|
@@ -10,20 +12,46 @@ module Familia
|
|
|
10
12
|
# Used to configure code generation and runtime behavior for participates_in
|
|
11
13
|
# and class_participates_in declarations.
|
|
12
14
|
#
|
|
15
|
+
# @note target_class is resolved once at definition time for performance.
|
|
16
|
+
# Use _original_target for debugging/introspection to see what was passed.
|
|
17
|
+
#
|
|
13
18
|
ParticipationRelationship = Data.define(
|
|
14
|
-
:
|
|
19
|
+
:_original_target, # Original Symbol/String/Class as passed to participates_in
|
|
20
|
+
:target_class, # Resolved Class object (e.g., User class, not :User symbol)
|
|
15
21
|
:collection_name, # Symbol name of the collection (e.g., :members, :domains)
|
|
16
22
|
:score, # Proc/Symbol/nil - score calculator for sorted sets
|
|
17
23
|
:type, # Symbol - collection type (:sorted_set, :set, :list)
|
|
18
|
-
:bidirectional,
|
|
24
|
+
:bidirectional, # Boolean/Symbol - whether to generate reverse methods
|
|
19
25
|
) do
|
|
26
|
+
# Get a unique key for this participation relationship
|
|
27
|
+
# Useful for comparisons and hash keys
|
|
20
28
|
#
|
|
21
|
-
#
|
|
29
|
+
# @return [String] unique identifier in format "TargetClass:collection_name"
|
|
30
|
+
def unique_key
|
|
31
|
+
Familia.join(target_class_base, collection_name)
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
# Get the base class name without namespace
|
|
35
|
+
# Handles anonymous class wrappers like "#<Class:0x123>::SymbolResolutionCustomer"
|
|
22
36
|
#
|
|
23
|
-
# @return [String]
|
|
37
|
+
# @return [String] base class name (e.g., "Customer")
|
|
38
|
+
def target_class_base
|
|
39
|
+
target_class.name.split('::').last
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Check if this relationship matches the given target and collection
|
|
43
|
+
# Handles namespace-agnostic class comparison
|
|
24
44
|
#
|
|
25
|
-
|
|
26
|
-
|
|
45
|
+
# @param comparison_target [Class, String, Symbol] target to compare against
|
|
46
|
+
# @param comparison_collection [Symbol, String] collection name to compare
|
|
47
|
+
# @return [Boolean] true if both target and collection match
|
|
48
|
+
def matches?(comparison_target, comparison_collection)
|
|
49
|
+
# Normalize comparison target to base class name
|
|
50
|
+
comparison_target = comparison_target.name if comparison_target.is_a?(Class)
|
|
51
|
+
comparison_target_base = comparison_target.to_s.split('::').last
|
|
52
|
+
|
|
53
|
+
target_class_base == comparison_target_base &&
|
|
54
|
+
collection_name == comparison_collection.to_sym
|
|
27
55
|
end
|
|
28
56
|
end
|
|
29
57
|
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# lib/familia/features/relationships.rb
|
|
2
|
+
#
|
|
3
|
+
# frozen_string_literal: true
|
|
2
4
|
|
|
3
5
|
require 'securerandom'
|
|
4
6
|
require_relative 'relationships/score_encoding'
|
|
@@ -84,7 +86,7 @@ module Familia
|
|
|
84
86
|
|
|
85
87
|
# Feature initialization
|
|
86
88
|
def self.included(base)
|
|
87
|
-
Familia.
|
|
89
|
+
Familia.debug "[#{base}] Relationships included"
|
|
88
90
|
base.extend ModelClassMethods
|
|
89
91
|
base.include ModelInstanceMethods
|
|
90
92
|
|
|
@@ -157,7 +159,7 @@ module Familia
|
|
|
157
159
|
def create_temp_key(base_name, ttl = 300)
|
|
158
160
|
timestamp = Familia.now.to_i
|
|
159
161
|
random_suffix = SecureRandom.hex(3)
|
|
160
|
-
temp_key =
|
|
162
|
+
temp_key = Familia.join('temp', base_name, timestamp, random_suffix)
|
|
161
163
|
|
|
162
164
|
# UnsortedSet immediate expiry to ensure cleanup even if operation fails
|
|
163
165
|
if respond_to?(:dbclient)
|
|
@@ -256,7 +258,7 @@ module Familia
|
|
|
256
258
|
def create_temp_key(base_name, ttl = 300)
|
|
257
259
|
timestamp = Familia.now.to_i
|
|
258
260
|
random_suffix = SecureRandom.hex(3)
|
|
259
|
-
temp_key =
|
|
261
|
+
temp_key = Familia.join('temp', base_name, timestamp, random_suffix)
|
|
260
262
|
|
|
261
263
|
# UnsortedSet immediate expiry to ensure cleanup even if operation fails
|
|
262
264
|
dbclient.expire(temp_key, ttl)
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# lib/familia/features/transient_fields/transient_field_type.rb
|
|
2
|
+
#
|
|
3
|
+
# frozen_string_literal: true
|
|
2
4
|
|
|
3
5
|
require 'familia/field_type'
|
|
4
6
|
|
|
@@ -80,7 +82,7 @@ module Familia
|
|
|
80
82
|
#
|
|
81
83
|
def define_fast_writer(_klass)
|
|
82
84
|
# No fast writer for transient fields since they're not persisted
|
|
83
|
-
Familia.
|
|
85
|
+
Familia.debug "[TransientFieldType] Skipping fast writer for transient field: #{@name}"
|
|
84
86
|
nil
|
|
85
87
|
end
|
|
86
88
|
|
|
@@ -117,7 +119,7 @@ module Familia
|
|
|
117
119
|
#
|
|
118
120
|
def serialize(_value, _record = nil)
|
|
119
121
|
# Transient fields should never be serialized
|
|
120
|
-
Familia.
|
|
122
|
+
Familia.debug "[TransientFieldType] WARNING: serialize called on transient field #{@name}"
|
|
121
123
|
nil
|
|
122
124
|
end
|
|
123
125
|
|
|
@@ -132,7 +134,7 @@ module Familia
|
|
|
132
134
|
#
|
|
133
135
|
def deserialize(_value, _record = nil)
|
|
134
136
|
# Transient fields should never be deserialized
|
|
135
|
-
Familia.
|
|
137
|
+
Familia.debug "[TransientFieldType] WARNING: deserialize called on transient field #{@name}"
|
|
136
138
|
nil
|
|
137
139
|
end
|
|
138
140
|
end
|
data/lib/familia/features.rb
CHANGED
data/lib/familia/field_type.rb
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# lib/familia/field_type.rb
|
|
2
|
+
#
|
|
3
|
+
# frozen_string_literal: true
|
|
2
4
|
|
|
3
5
|
module Familia
|
|
4
6
|
# Base class for all field types in Familia
|
|
@@ -152,7 +154,7 @@ module Familia
|
|
|
152
154
|
|
|
153
155
|
# Convert value for database storage
|
|
154
156
|
prepared = serialize_value(val)
|
|
155
|
-
Familia.
|
|
157
|
+
Familia.debug "[FieldType#define_fast_writer] #{fast_method_name} val: #{val.class} prepared: #{prepared.class}"
|
|
156
158
|
|
|
157
159
|
# Use the setter method to update instance variable
|
|
158
160
|
send(:"#{method_name}=", val) if method_name
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# lib/familia/horreum/connection.rb
|
|
2
|
+
#
|
|
3
|
+
# frozen_string_literal: true
|
|
2
4
|
|
|
3
5
|
module Familia
|
|
4
6
|
class Horreum
|
|
@@ -24,10 +26,19 @@ module Familia
|
|
|
24
26
|
# 2. DefaultConnectionHandler - Horreum model class-level @dbclient
|
|
25
27
|
# 3. GlobalFallbackHandler - Familia.dbclient(uri || logical_database) (global fallback)
|
|
26
28
|
#
|
|
29
|
+
# Thread-safe lazy initialization using double-checked locking to ensure
|
|
30
|
+
# only a single connection chain is built even under high concurrent load.
|
|
31
|
+
#
|
|
27
32
|
# @return [Redis] the Database connection instance.
|
|
28
33
|
#
|
|
29
34
|
def dbclient(uri = nil)
|
|
30
|
-
|
|
35
|
+
# Fast path: return existing chain if already initialized
|
|
36
|
+
return @class_connection_chain.handle(uri) if @class_connection_chain
|
|
37
|
+
|
|
38
|
+
# Slow path: thread-safe initialization
|
|
39
|
+
@class_connection_chain_mutex.synchronize do
|
|
40
|
+
@class_connection_chain ||= build_connection_chain
|
|
41
|
+
end
|
|
31
42
|
@class_connection_chain.handle(uri)
|
|
32
43
|
end
|
|
33
44
|
|
|
@@ -268,6 +279,11 @@ module Familia
|
|
|
268
279
|
.add_handler(@cached_connection_handler)
|
|
269
280
|
.add_handler(@create_connection_handler)
|
|
270
281
|
end
|
|
282
|
+
|
|
283
|
+
# Thread-safe mutex initialization when module is extended
|
|
284
|
+
def self.extended(base)
|
|
285
|
+
base.instance_variable_set(:@class_connection_chain_mutex, Mutex.new)
|
|
286
|
+
end
|
|
271
287
|
end
|
|
272
288
|
end
|
|
273
289
|
end
|
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
# lib/familia/horreum/definition.rb
|
|
2
|
+
#
|
|
3
|
+
# frozen_string_literal: true
|
|
2
4
|
|
|
3
5
|
require_relative 'settings'
|
|
4
6
|
|
|
@@ -98,7 +100,7 @@ module Familia
|
|
|
98
100
|
@current_field_group = nil
|
|
99
101
|
end
|
|
100
102
|
else
|
|
101
|
-
Familia.
|
|
103
|
+
Familia.debug "[field_group] Created field group :#{name} but no block given"
|
|
102
104
|
end
|
|
103
105
|
|
|
104
106
|
field_groups[name.to_sym]
|
|
@@ -124,7 +126,10 @@ module Familia
|
|
|
124
126
|
# ]
|
|
125
127
|
#
|
|
126
128
|
def field_groups
|
|
127
|
-
@
|
|
129
|
+
@field_groups_mutex ||= Familia::ThreadSafety::InstrumentedMutex.new('field_groups')
|
|
130
|
+
@field_groups || @field_groups_mutex.synchronize do
|
|
131
|
+
@field_groups ||= {}
|
|
132
|
+
end
|
|
128
133
|
end
|
|
129
134
|
|
|
130
135
|
# Sets or retrieves the unique identifier field for the class.
|
|
@@ -215,8 +220,10 @@ module Familia
|
|
|
215
220
|
# Returns the list of field names defined for the class in the order
|
|
216
221
|
# that they were defined. i.e. `field :a; field :b; fields => [:a, :b]`.
|
|
217
222
|
def fields
|
|
218
|
-
@
|
|
219
|
-
@fields
|
|
223
|
+
@fields_mutex ||= Familia::ThreadSafety::InstrumentedMutex.new('fields')
|
|
224
|
+
@fields || @fields_mutex.synchronize do
|
|
225
|
+
@fields ||= []
|
|
226
|
+
end
|
|
220
227
|
end
|
|
221
228
|
|
|
222
229
|
def class_related_fields
|
|
@@ -235,7 +242,10 @@ module Familia
|
|
|
235
242
|
|
|
236
243
|
# Storage for field type instances
|
|
237
244
|
def field_types
|
|
238
|
-
@
|
|
245
|
+
@field_types_mutex ||= Familia::ThreadSafety::InstrumentedMutex.new('field_types')
|
|
246
|
+
@field_types || @field_types_mutex.synchronize do
|
|
247
|
+
@field_types ||= {}
|
|
248
|
+
end
|
|
239
249
|
end
|
|
240
250
|
|
|
241
251
|
# Returns a hash mapping field names to method names for backward compatibility
|
|
@@ -476,7 +486,7 @@ module Familia
|
|
|
476
486
|
|
|
477
487
|
# Convert the provided value to a format suitable for Database storage.
|
|
478
488
|
prepared = serialize_value(val)
|
|
479
|
-
Familia.
|
|
489
|
+
Familia.debug "[define_fast_writer_method] #{fast_method_name} val: #{val.class} prepared: #{prepared.class}"
|
|
480
490
|
|
|
481
491
|
# Use the existing accessor method to set the attribute value.
|
|
482
492
|
send :"#{method_name}=", val
|