familia 2.0.0.pre16 → 2.0.0.pre18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +2 -2
- data/.github/workflows/{code-smellage.yml → code-smells.yml} +3 -63
- data/.gitignore +2 -0
- data/.rubocop.yml +6 -0
- data/CHANGELOG.rst +82 -0
- data/CLAUDE.md +47 -2
- data/Gemfile.lock +1 -1
- data/README.md +13 -0
- data/bin/irb +1 -1
- data/docs/archive/FAMILIA_TECHNICAL.md +1 -1
- data/docs/guides/core-field-system.md +48 -26
- data/docs/migrating/v2.0.0-pre18.md +58 -0
- data/docs/overview.md +2 -2
- data/docs/qodo-merge-compliance.md +96 -0
- data/docs/reference/api-technical.md +1 -1
- data/examples/encrypted_fields.rb +1 -1
- data/examples/safe_dump.rb +1 -1
- data/lib/familia/base.rb +6 -6
- data/lib/familia/connection/middleware.rb +58 -4
- data/lib/familia/connection.rb +1 -1
- data/lib/familia/data_type/class_methods.rb +63 -0
- data/lib/familia/data_type/connection.rb +83 -0
- data/lib/familia/data_type/{commands.rb → database_commands.rb} +2 -2
- data/lib/familia/data_type/serialization.rb +5 -5
- data/lib/familia/data_type/settings.rb +96 -0
- data/lib/familia/data_type/types/hashkey.rb +2 -1
- data/lib/familia/data_type/types/sorted_set.rb +113 -10
- data/lib/familia/data_type/types/stringkey.rb +0 -4
- data/lib/familia/data_type.rb +8 -195
- data/lib/familia/encryption/encrypted_data.rb +12 -2
- data/lib/familia/encryption/manager.rb +11 -4
- data/lib/familia/features/autoloader.rb +3 -1
- data/lib/familia/features/encrypted_fields/encrypted_field_type.rb +11 -3
- data/lib/familia/features/encrypted_fields.rb +5 -2
- data/lib/familia/features/external_identifier.rb +49 -8
- data/lib/familia/features/object_identifier.rb +84 -12
- data/lib/familia/features/relationships/indexing/multi_index_generators.rb +9 -9
- data/lib/familia/features/relationships/indexing/unique_index_generators.rb +45 -26
- data/lib/familia/features/relationships/indexing.rb +7 -1
- data/lib/familia/features/relationships/participation/participant_methods.rb +6 -2
- data/lib/familia/features/safe_dump.rb +2 -3
- data/lib/familia/features/transient_fields.rb +7 -2
- data/lib/familia/features.rb +6 -1
- data/lib/familia/field_type.rb +0 -18
- data/lib/familia/horreum/{core/connection.rb → connection.rb} +21 -0
- data/lib/familia/horreum/{core/database_commands.rb → database_commands.rb} +1 -1
- data/lib/familia/horreum/{subclass/definition.rb → definition.rb} +102 -56
- data/lib/familia/horreum/{subclass/management.rb → management.rb} +18 -15
- data/lib/familia/horreum/{core/serialization.rb → persistence.rb} +73 -170
- data/lib/familia/horreum/{subclass/related_fields_management.rb → related_fields.rb} +22 -2
- data/lib/familia/horreum/serialization.rb +190 -0
- data/lib/familia/horreum.rb +39 -14
- data/lib/familia/identifier_extractor.rb +60 -0
- data/lib/familia/logging.rb +271 -112
- data/lib/familia/refinements.rb +0 -1
- data/lib/familia/version.rb +1 -1
- data/lib/familia.rb +2 -2
- data/lib/middleware/{database_middleware.rb → database_logger.rb} +47 -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 +1 -1
- 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 +1 -1
- 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/field_groups_try.rb +244 -0
- 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 +16 -1
- 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 +1 -1
- 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 +3 -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 +1 -1
- data/try/{connection → integration/connection}/handler_constraints_try.rb +1 -1
- data/try/{core → integration/connection}/isolated_dbclient_try.rb +3 -3
- data/try/integration/connection/middleware_reconnect_try.rb +87 -0
- data/try/{connection → integration/connection}/operation_mode_guards_try.rb +1 -1
- data/try/{connection → integration/connection}/pipeline_fallback_integration_try.rb +1 -1
- 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 +1 -1
- data/try/integration/cross_component_try.rb +1 -1
- data/try/{core → integration}/database_consistency_try.rb +12 -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 +1 -1
- data/try/{models → integration/models}/customer_try.rb +6 -6
- data/try/{models → integration/models}/datatype_base_try.rb +1 -1
- data/try/{models → integration/models}/familia_object_try.rb +1 -1
- data/try/{core → integration}/persistence_operations_try.rb +1 -1
- data/try/integration/relationships_persistence_round_trip_try.rb +441 -0
- data/try/{configuration → integration}/scenarios_try.rb +2 -2
- 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 +15 -7
- data/try/{memory → support/memory}/memory_docker_ruby_dump.sh +1 -1
- 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 +5 -5
- data/try/{core → unit/core}/errors_try.rb +4 -4
- 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 +2 -2
- 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 +3 -3
- data/try/{core → unit/core}/utils_try.rb +17 -14
- data/try/{data_types → unit/data_types}/boolean_try.rb +1 -1
- 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/unit/data_types/sorted_set_zadd_options_try.rb +625 -0
- data/try/{data_types → unit/data_types}/string_try.rb +1 -1
- data/try/{data_types → unit/data_types}/unsortedset_try.rb +1 -1
- data/try/unit/horreum/auto_indexing_on_save_try.rb +212 -0
- data/try/{horreum → unit/horreum}/base_try.rb +3 -3
- data/try/{horreum → unit/horreum}/class_methods_try.rb +1 -1
- data/try/{horreum → unit/horreum}/commands_try.rb +3 -1
- data/try/unit/horreum/defensive_initialization_try.rb +86 -0
- data/try/{horreum → unit/horreum}/destroy_related_fields_cleanup_try.rb +3 -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 +2 -2
- data/try/unit/horreum/json_type_preservation_try.rb +248 -0
- data/try/{horreum → unit/horreum}/relations_try.rb +1 -1
- data/try/{horreum → unit/horreum}/serialization_persistent_fields_try.rb +24 -18
- data/try/{horreum → unit/horreum}/serialization_try.rb +4 -4
- data/try/{horreum → unit/horreum}/settings_try.rb +3 -1
- 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
- data/try/valkey.conf +26 -0
- metadata +149 -132
- data/lib/familia/distinguisher.rb +0 -85
- data/lib/familia/horreum/core.rb +0 -21
- data/lib/familia/refinements/logger_trace.rb +0 -60
- data/try/refinements/logger_trace_methods_try.rb +0 -44
- /data/lib/familia/horreum/{shared/settings.rb → settings.rb} +0 -0
- /data/lib/familia/horreum/{core/utils.rb → utils.rb} +0 -0
- /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_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
@@ -0,0 +1,244 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# try/features/field_groups_try.rb
|
4
|
+
|
5
|
+
require_relative '../../lib/familia'
|
6
|
+
|
7
|
+
# Define test classes in setup section
|
8
|
+
class BasicUser < Familia::Horreum
|
9
|
+
field_group :personal_info do
|
10
|
+
field :name
|
11
|
+
field :email
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class MultiGroupUser < Familia::Horreum
|
16
|
+
field_group :personal do
|
17
|
+
field :name
|
18
|
+
field :email
|
19
|
+
end
|
20
|
+
|
21
|
+
field_group :metadata do
|
22
|
+
field :created_at
|
23
|
+
field :updated_at
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
class EmptyGroupModel < Familia::Horreum
|
28
|
+
field_group :placeholder
|
29
|
+
end
|
30
|
+
|
31
|
+
class TransientModel < Familia::Horreum
|
32
|
+
feature :transient_fields
|
33
|
+
transient_field :api_key
|
34
|
+
transient_field :session_token
|
35
|
+
end
|
36
|
+
|
37
|
+
class EncryptedModel < Familia::Horreum
|
38
|
+
feature :encrypted_fields
|
39
|
+
encrypted_field :password
|
40
|
+
encrypted_field :credit_card
|
41
|
+
end
|
42
|
+
|
43
|
+
class MixedGroupsModel < Familia::Horreum
|
44
|
+
feature :transient_fields
|
45
|
+
transient_field :temp_data
|
46
|
+
|
47
|
+
field_group :custom do
|
48
|
+
field :custom_field
|
49
|
+
end
|
50
|
+
|
51
|
+
feature :encrypted_fields
|
52
|
+
encrypted_field :secret_key
|
53
|
+
end
|
54
|
+
|
55
|
+
class FieldsOutsideGroups < Familia::Horreum
|
56
|
+
field :standalone_field
|
57
|
+
|
58
|
+
field_group :grouped do
|
59
|
+
field :grouped_field
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
class NoSuchGroup < Familia::Horreum
|
64
|
+
field_group :existing do
|
65
|
+
field :name
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class ParentModel < Familia::Horreum
|
70
|
+
field_group :base_fields do
|
71
|
+
field :id
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
class ChildModel < ParentModel
|
76
|
+
field_group :child_fields do
|
77
|
+
field :name
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
# Create instances for testing
|
82
|
+
@user = MultiGroupUser.new(name: 'Alice', email: 'alice@example.com', created_at: Time.now.to_i)
|
83
|
+
@user2 = BasicUser.new(name: 'Bob', email: 'bob@example.com')
|
84
|
+
|
85
|
+
## Manual field groups - basic access via hash
|
86
|
+
BasicUser.instance_variable_get(:@field_groups)[:personal_info]
|
87
|
+
#=> [:name, :email]
|
88
|
+
|
89
|
+
## Multiple groups - access personal group via hash
|
90
|
+
MultiGroupUser.instance_variable_get(:@field_groups)[:personal]
|
91
|
+
#=> [:name, :email]
|
92
|
+
|
93
|
+
## Multiple groups - access metadata group via hash
|
94
|
+
MultiGroupUser.instance_variable_get(:@field_groups)[:metadata]
|
95
|
+
#=> [:created_at, :updated_at]
|
96
|
+
|
97
|
+
## Multiple groups - list all field groups (returns hash)
|
98
|
+
MultiGroupUser.field_groups.keys.sort
|
99
|
+
#=> [:metadata, :personal]
|
100
|
+
|
101
|
+
## Field groups - fields defined inside groups are tracked
|
102
|
+
user = MultiGroupUser.new(name: 'Alice', email: 'alice@example.com', created_at: Time.now.to_i)
|
103
|
+
|
104
|
+
## Grouped fields - access name field
|
105
|
+
@user.name
|
106
|
+
#=> 'Alice'
|
107
|
+
|
108
|
+
## Grouped fields - access email field
|
109
|
+
@user.email
|
110
|
+
#=> 'alice@example.com'
|
111
|
+
|
112
|
+
## Empty group - access via hash
|
113
|
+
EmptyGroupModel.instance_variable_get(:@field_groups)[:placeholder]
|
114
|
+
#=> []
|
115
|
+
|
116
|
+
## Empty group - list field groups (returns hash)
|
117
|
+
EmptyGroupModel.field_groups
|
118
|
+
#=> {placeholder: []}
|
119
|
+
|
120
|
+
## Empty group - list field group keys
|
121
|
+
EmptyGroupModel.field_groups.keys
|
122
|
+
#=> [:placeholder]
|
123
|
+
|
124
|
+
## Transient feature - access via backward compatible method
|
125
|
+
TransientModel.transient_fields
|
126
|
+
#=> [:api_key, :session_token]
|
127
|
+
|
128
|
+
## Transient feature - access via field_groups hash
|
129
|
+
TransientModel.instance_variable_get(:@field_groups)[:transient_fields]
|
130
|
+
#=> [:api_key, :session_token]
|
131
|
+
|
132
|
+
## Transient feature - field_groups returns hash with content
|
133
|
+
TransientModel.field_groups
|
134
|
+
#=> {transient_fields: [:api_key, :session_token]}
|
135
|
+
|
136
|
+
## Transient feature - list field group keys
|
137
|
+
TransientModel.field_groups.keys
|
138
|
+
#=> [:transient_fields]
|
139
|
+
|
140
|
+
## Encrypted feature - access via backward compatible method
|
141
|
+
EncryptedModel.encrypted_fields
|
142
|
+
#=> [:password, :credit_card]
|
143
|
+
|
144
|
+
## Encrypted feature - access via field_groups hash
|
145
|
+
EncryptedModel.instance_variable_get(:@field_groups)[:encrypted_fields]
|
146
|
+
#=> [:password, :credit_card]
|
147
|
+
|
148
|
+
## Encrypted feature - field_groups returns hash with content
|
149
|
+
EncryptedModel.field_groups
|
150
|
+
#=> {encrypted_fields: [:password, :credit_card]}
|
151
|
+
|
152
|
+
## Encrypted feature - list field group keys
|
153
|
+
EncryptedModel.field_groups.keys
|
154
|
+
#=> [:encrypted_fields]
|
155
|
+
|
156
|
+
## Mixed groups - list all field group keys
|
157
|
+
MixedGroupsModel.field_groups.keys.sort
|
158
|
+
#=> [:custom, :encrypted_fields, :transient_fields]
|
159
|
+
|
160
|
+
## Mixed groups - access custom group via hash
|
161
|
+
MixedGroupsModel.instance_variable_get(:@field_groups)[:custom]
|
162
|
+
#=> [:custom_field]
|
163
|
+
|
164
|
+
## Mixed groups - access transient_fields via backward compatible method
|
165
|
+
MixedGroupsModel.transient_fields
|
166
|
+
#=> [:temp_data]
|
167
|
+
|
168
|
+
## Mixed groups - access encrypted_fields via backward compatible method
|
169
|
+
MixedGroupsModel.encrypted_fields
|
170
|
+
#=> [:secret_key]
|
171
|
+
|
172
|
+
## Error: nested field groups
|
173
|
+
class NestedGroupsModel < Familia::Horreum
|
174
|
+
field_group :outer do
|
175
|
+
field_group :inner do
|
176
|
+
field :bad
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
#=!> Familia::Problem
|
181
|
+
|
182
|
+
## Exception during field_group block resets @current_field_group
|
183
|
+
class ErrorDuringGroup < Familia::Horreum
|
184
|
+
begin
|
185
|
+
field_group :broken do
|
186
|
+
field :first_field
|
187
|
+
raise StandardError, "Simulated error"
|
188
|
+
field :unreachable_field
|
189
|
+
end
|
190
|
+
rescue StandardError
|
191
|
+
# Swallow the error for testing
|
192
|
+
end
|
193
|
+
|
194
|
+
# Field defined after the error should not be in :broken group
|
195
|
+
field :after_error
|
196
|
+
end
|
197
|
+
|
198
|
+
ErrorDuringGroup
|
199
|
+
#=> ErrorDuringGroup
|
200
|
+
|
201
|
+
## Exception handling - broken group has only first_field
|
202
|
+
ErrorDuringGroup.instance_variable_get(:@field_groups)[:broken]
|
203
|
+
#=> [:first_field]
|
204
|
+
|
205
|
+
## Exception handling - after_error field is not in broken group
|
206
|
+
ErrorDuringGroup.instance_variable_get(:@field_groups)[:broken].include?(:after_error)
|
207
|
+
#=> false
|
208
|
+
|
209
|
+
## Exception handling - after_error is in fields list
|
210
|
+
ErrorDuringGroup.fields.include?(:after_error)
|
211
|
+
#=> true
|
212
|
+
|
213
|
+
## Exception handling - current_field_group was reset to nil
|
214
|
+
ErrorDuringGroup.instance_variable_get(:@current_field_group)
|
215
|
+
#=> nil
|
216
|
+
|
217
|
+
|
218
|
+
## Fields outside - access grouped field group via hash
|
219
|
+
FieldsOutsideGroups.instance_variable_get(:@field_groups)[:grouped]
|
220
|
+
#=> [:grouped_field]
|
221
|
+
|
222
|
+
## Fields outside - all fields include both grouped and standalone
|
223
|
+
FieldsOutsideGroups.fields
|
224
|
+
#=> [:standalone_field, :grouped_field]
|
225
|
+
|
226
|
+
## Accessing non-existent field group returns nil
|
227
|
+
NoSuchGroup.instance_variable_get(:@field_groups)[:nonexistent]
|
228
|
+
#=> nil
|
229
|
+
|
230
|
+
## Inheritance - parent class has its own field groups
|
231
|
+
ParentModel.field_groups
|
232
|
+
#=> {base_fields: [:id]}
|
233
|
+
|
234
|
+
## Inheritance - child class has its own field groups
|
235
|
+
ChildModel.field_groups
|
236
|
+
#=> {child_fields: [:name]}
|
237
|
+
|
238
|
+
## Normal field access - get name value
|
239
|
+
@user2.name
|
240
|
+
#=> 'Bob'
|
241
|
+
|
242
|
+
## Normal field access - get email value
|
243
|
+
@user2.email
|
244
|
+
#=> 'bob@example.com'
|
@@ -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
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
|
@@ -152,6 +157,11 @@ found_users.map(&:user_id).sort
|
|
152
157
|
TestUser.find_all_by_email([]).length
|
153
158
|
#=> 0
|
154
159
|
|
160
|
+
## Single value (non-array) is accepted by find_all_by method
|
161
|
+
found_users = TestUser.find_all_by_email('bob@example.com')
|
162
|
+
found_users.map(&:user_id)
|
163
|
+
#=> ["user_002"]
|
164
|
+
|
155
165
|
## Update index entry with old value removal
|
156
166
|
old_email = @user1.email
|
157
167
|
@user1.email = 'alice.new@example.com'
|
@@ -236,6 +246,11 @@ found_emps = @company.find_all_by_badge_number(badges)
|
|
236
246
|
found_emps.map(&:emp_id).sort
|
237
247
|
#=> ["emp_001", "emp_002"]
|
238
248
|
|
249
|
+
## Single value (non-array) accepted for instance-scoped find_all_by
|
250
|
+
found_emps = @company.find_all_by_badge_number('BADGE002')
|
251
|
+
found_emps.map(&:emp_id)
|
252
|
+
#=> ["emp_002"]
|
253
|
+
|
239
254
|
## Update badge index entry
|
240
255
|
old_badge = @emp1.badge_number
|
241
256
|
@emp1.badge_number = 'BADGE001_NEW'
|
@@ -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
|
@@ -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
|
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
# These tryouts test the safe dumping functionality.
|
4
4
|
|
5
|
-
require_relative '../../helpers/test_helpers'
|
5
|
+
require_relative '../../support/helpers/test_helpers'
|
6
6
|
|
7
7
|
## By default Familia::Base has no safe_dump_fields method
|
8
8
|
Familia::Base.respond_to?(:safe_dump_fields)
|
@@ -1,13 +1,15 @@
|
|
1
1
|
# try/features/transient_fields/refresh_reset_try.rb
|
2
2
|
# Test that refresh! properly resets transient fields to nil
|
3
3
|
|
4
|
-
require_relative '../../helpers/test_helpers'
|
4
|
+
require_relative '../../support/helpers/test_helpers'
|
5
5
|
|
6
6
|
Familia.debug = false
|
7
7
|
|
8
8
|
Familia.dbclient.flushdb
|
9
9
|
|
10
10
|
class SecretService < Familia::Horreum
|
11
|
+
feature :transient_fields
|
12
|
+
|
11
13
|
identifier_field :name
|
12
14
|
|
13
15
|
field :name
|