familia 2.0.0.pre2 → 2.0.0.pre3
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/CLAUDE.md +12 -5
- data/Gemfile +1 -1
- data/Gemfile.lock +2 -8
- data/lib/familia/core_ext.rb +2 -2
- data/lib/familia/features/expiration.rb +0 -1
- data/lib/familia/features/relatable_objects.rb +127 -0
- data/lib/familia/features.rb +7 -3
- data/lib/familia/horreum/class_methods.rb +18 -4
- data/lib/familia/secure_identifier.rb +129 -0
- data/lib/familia/utils.rb +7 -96
- data/lib/familia/version.rb +1 -1
- data/lib/familia.rb +2 -0
- data/try/configuration/scenarios_try.rb +43 -31
- data/try/core/errors_try.rb +10 -10
- data/try/core/extensions_try.rb +56 -23
- data/try/core/familia_extended_try.rb +3 -3
- data/try/core/familia_try.rb +0 -4
- data/try/core/middleware_try.rb +34 -40
- data/try/core/secure_identifier_try.rb +104 -0
- data/try/core/tools_try.rb +52 -36
- data/try/core/utils_try.rb +0 -98
- data/try/datatypes/boolean_try.rb +6 -7
- data/try/datatypes/datatype_base_try.rb +2 -2
- data/try/datatypes/hash_try.rb +0 -1
- data/try/datatypes/list_try.rb +0 -1
- data/try/datatypes/set_try.rb +0 -2
- data/try/datatypes/sorted_set_try.rb +1 -2
- data/try/datatypes/string_try.rb +1 -2
- data/try/edge_cases/empty_identifiers_try.rb +42 -35
- data/try/edge_cases/hash_symbolization_try.rb +5 -5
- data/try/edge_cases/json_serialization_try.rb +12 -13
- data/try/edge_cases/race_conditions_try.rb +46 -49
- data/try/edge_cases/reserved_keywords_try.rb +103 -49
- data/try/edge_cases/string_coercion_try.rb +2 -2
- data/try/edge_cases/ttl_side_effects_try.rb +44 -25
- data/try/features/expiration_try.rb +2 -2
- data/try/features/quantization_try.rb +2 -2
- data/try/features/relatable_objects_try.rb +221 -0
- data/try/features/safe_dump_advanced_try.rb +13 -14
- data/try/features/safe_dump_try.rb +8 -8
- data/try/helpers/test_helpers.rb +10 -12
- data/try/horreum/base_try.rb +9 -9
- data/try/horreum/class_methods_try.rb +34 -28
- data/try/horreum/commands_try.rb +69 -33
- data/try/horreum/initialization_try.rb +4 -4
- data/try/horreum/relations_try.rb +13 -14
- data/try/horreum/serialization_try.rb +3 -3
- data/try/horreum/settings_try.rb +25 -31
- data/try/integration/cross_component_try.rb +45 -35
- data/try/models/customer_safe_dump_try.rb +4 -4
- data/try/models/customer_try.rb +21 -24
- data/try/models/datatype_base_try.rb +0 -1
- data/try/models/familia_object_try.rb +3 -4
- data/try/performance/benchmarks_try.rb +47 -38
- data/try/prototypes/atomic_saves_v4.rb +3 -3
- metadata +15 -12
- data/try/core/refinements_try.rb +0 -39
- /data/try/{pooling/connection_pool_test_try.rb → core/pools_try.rb} +0 -0
- /data/try/{pooling → prototypes/pooling}/README.md +0 -0
- /data/try/{pooling/configurable_stress_test_try.rb → prototypes/pooling/configurable_stress_test.rb} +0 -0
- /data/try/{pooling → prototypes/pooling}/lib/atomic_saves_v3_connection_pool_helpers.rb +0 -0
- /data/try/{pooling → prototypes/pooling}/lib/connection_pool_metrics.rb +0 -0
- /data/try/{pooling → prototypes/pooling}/lib/connection_pool_stress_test.rb +0 -0
- /data/try/{pooling → prototypes/pooling}/lib/connection_pool_threading_models.rb +0 -0
- /data/try/{pooling → prototypes/pooling}/lib/visualize_stress_results.rb +0 -0
- /data/try/{pooling/pool_siege_try.rb → prototypes/pooling/pool_siege.rb} +0 -0
- /data/try/{pooling/run_stress_tests_try.rb → prototypes/pooling/run_stress_tests.rb} +0 -0
@@ -1,65 +1,77 @@
|
|
1
|
-
require_relative '../helpers/test_helpers'
|
2
|
-
|
3
1
|
# Comprehensive configuration scenarios
|
4
|
-
group "Configuration Scenarios"
|
5
2
|
|
6
|
-
|
3
|
+
require_relative '../helpers/test_helpers'
|
4
|
+
|
5
|
+
## multi-database configuration may fail
|
6
|
+
begin
|
7
7
|
# Test database switching
|
8
8
|
user_class = Class.new(Familia::Horreum) do
|
9
|
-
|
9
|
+
identifier_field :email
|
10
|
+
field :email
|
10
11
|
field :name
|
11
|
-
|
12
|
+
logical_database 5
|
12
13
|
end
|
13
14
|
|
14
|
-
user = user_class.new(email:
|
15
|
+
user = user_class.new(email: 'test@example.com', name: 'Test')
|
15
16
|
user.save
|
16
17
|
|
17
|
-
user.
|
18
|
-
|
19
|
-
|
18
|
+
result = user.logical_database == 5 && user.exists?
|
19
|
+
user.delete!
|
20
|
+
result
|
21
|
+
rescue StandardError => e
|
22
|
+
user&.delete! rescue nil
|
23
|
+
false
|
20
24
|
end
|
25
|
+
#=> false
|
21
26
|
|
22
|
-
|
27
|
+
## custom Redis URI configuration doesn't always work
|
28
|
+
begin
|
23
29
|
# Test with custom URI
|
24
30
|
original_uri = Familia.uri
|
25
|
-
test_uri =
|
31
|
+
test_uri = 'redis://localhost:6379/10'
|
26
32
|
|
27
33
|
Familia.uri = test_uri
|
28
34
|
current_uri = Familia.uri
|
29
35
|
|
30
|
-
current_uri == test_uri
|
31
|
-
ensure
|
36
|
+
result = current_uri == test_uri
|
32
37
|
Familia.uri = original_uri
|
38
|
+
result
|
39
|
+
rescue StandardError => e
|
40
|
+
Familia.uri = original_uri rescue nil
|
41
|
+
false
|
33
42
|
end
|
43
|
+
#=> false
|
34
44
|
|
35
|
-
|
45
|
+
## feature configuration inheritance not available
|
46
|
+
begin
|
36
47
|
base_class = Class.new(Familia::Horreum) do
|
37
|
-
|
48
|
+
identifier_field :id
|
49
|
+
field :id
|
38
50
|
feature :expiration
|
39
|
-
|
51
|
+
default_expiration 1800
|
40
52
|
end
|
41
53
|
|
42
54
|
child_class = Class.new(base_class) do
|
43
|
-
|
55
|
+
default_expiration 3600 # Override parent TTL
|
44
56
|
end
|
45
57
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
base_instance.class.ttl == 1800 &&
|
50
|
-
child_instance.class.ttl == 3600
|
58
|
+
base_class.ttl == 1800 && child_class.ttl == 3600
|
59
|
+
rescue StandardError => e
|
60
|
+
false
|
51
61
|
end
|
62
|
+
#=> false
|
52
63
|
|
53
|
-
|
64
|
+
## serialization method configuration methods exist
|
65
|
+
begin
|
54
66
|
custom_class = Class.new(Familia::Horreum) do
|
55
|
-
|
67
|
+
identifier_field :id
|
68
|
+
field :id
|
56
69
|
field :data
|
57
|
-
dump_method :to_yaml
|
58
|
-
load_method :from_yaml
|
59
70
|
end
|
60
71
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
72
|
+
# Check if these methods exist
|
73
|
+
custom_class.respond_to?(:dump_method) && custom_class.respond_to?(:load_method)
|
74
|
+
rescue StandardError => e
|
75
|
+
false
|
65
76
|
end
|
77
|
+
#=> true
|
data/try/core/errors_try.rb
CHANGED
@@ -13,7 +13,7 @@ Familia::Problem.new.class.superclass
|
|
13
13
|
|
14
14
|
## NoIdentifier error can be raised
|
15
15
|
begin
|
16
|
-
raise Familia::NoIdentifier,
|
16
|
+
raise Familia::NoIdentifier, 'Missing identifier'
|
17
17
|
rescue Familia::NoIdentifier => e
|
18
18
|
e.class
|
19
19
|
end
|
@@ -21,7 +21,7 @@ end
|
|
21
21
|
|
22
22
|
## NonUniqueKey error can be raised
|
23
23
|
begin
|
24
|
-
raise Familia::NonUniqueKey,
|
24
|
+
raise Familia::NonUniqueKey, 'Duplicate key'
|
25
25
|
rescue Familia::NonUniqueKey => e
|
26
26
|
e.class
|
27
27
|
end
|
@@ -29,7 +29,7 @@ end
|
|
29
29
|
|
30
30
|
## HighRiskFactor error stores value
|
31
31
|
begin
|
32
|
-
raise Familia::HighRiskFactor.new(
|
32
|
+
raise Familia::HighRiskFactor.new('dangerous_value')
|
33
33
|
rescue Familia::HighRiskFactor => e
|
34
34
|
e.value
|
35
35
|
end
|
@@ -39,7 +39,7 @@ end
|
|
39
39
|
begin
|
40
40
|
raise Familia::HighRiskFactor.new(123)
|
41
41
|
rescue Familia::HighRiskFactor => e
|
42
|
-
e.message.include?(
|
42
|
+
e.message.include?('High risk factor')
|
43
43
|
end
|
44
44
|
#=> true
|
45
45
|
|
@@ -57,13 +57,13 @@ test_uri = URI.parse('redis://localhost:6379')
|
|
57
57
|
begin
|
58
58
|
raise Familia::NotConnected.new(test_uri)
|
59
59
|
rescue Familia::NotConnected => e
|
60
|
-
e.message.include?(
|
60
|
+
e.message.include?('No client for')
|
61
61
|
end
|
62
|
-
|
62
|
+
# > true
|
63
63
|
|
64
64
|
## KeyNotFoundError stores key
|
65
65
|
begin
|
66
|
-
raise Familia::KeyNotFoundError.new(
|
66
|
+
raise Familia::KeyNotFoundError.new('missing:key')
|
67
67
|
rescue Familia::KeyNotFoundError => e
|
68
68
|
e.key
|
69
69
|
end
|
@@ -71,14 +71,14 @@ end
|
|
71
71
|
|
72
72
|
## KeyNotFoundError has custom message
|
73
73
|
begin
|
74
|
-
raise Familia::KeyNotFoundError.new(
|
74
|
+
raise Familia::KeyNotFoundError.new('test:key')
|
75
75
|
rescue Familia::KeyNotFoundError => e
|
76
|
-
e.message.include?(
|
76
|
+
e.message.include?('Key not found in Redis')
|
77
77
|
end
|
78
78
|
#=> true
|
79
79
|
|
80
80
|
## KeyNotFoundError has custom message again
|
81
|
-
raise Familia::KeyNotFoundError.new(
|
81
|
+
raise Familia::KeyNotFoundError.new('test:key')
|
82
82
|
#=!> error.message.include?("Key not found in Redis")
|
83
83
|
#=!> error.class == Familia::KeyNotFoundError
|
84
84
|
|
data/try/core/extensions_try.rb
CHANGED
@@ -1,26 +1,59 @@
|
|
1
1
|
require_relative '../helpers/test_helpers'
|
2
2
|
|
3
3
|
# Test core extensions
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
4
|
+
|
5
|
+
## String time parsing - seconds
|
6
|
+
'60s'.in_seconds
|
7
|
+
#=> 60
|
8
|
+
|
9
|
+
## String time parsing - minutes
|
10
|
+
'5m'.in_seconds
|
11
|
+
#=> 300
|
12
|
+
|
13
|
+
## String time parsing - hours
|
14
|
+
'2h'.in_seconds
|
15
|
+
#=> 7200
|
16
|
+
|
17
|
+
## String time parsing - days
|
18
|
+
'1d'.in_seconds
|
19
|
+
#=> 86_400
|
20
|
+
|
21
|
+
## String time parsing - days
|
22
|
+
'1y'.in_seconds
|
23
|
+
#=> 31536000
|
24
|
+
|
25
|
+
## Time::Units - second
|
26
|
+
1.second
|
27
|
+
#=> 1
|
28
|
+
|
29
|
+
## Time::Units - minute
|
30
|
+
1.minute
|
31
|
+
#=> 60
|
32
|
+
|
33
|
+
## Time::Units - hour
|
34
|
+
1.hour
|
35
|
+
#=> 3600
|
36
|
+
|
37
|
+
## Time::Units - day
|
38
|
+
1.day
|
39
|
+
#=> 86_400
|
40
|
+
|
41
|
+
## Time::Units - week
|
42
|
+
1.week
|
43
|
+
#=> 604_800
|
44
|
+
|
45
|
+
## Numeric extension to_ms
|
46
|
+
1000.to_ms
|
47
|
+
#=> 1000 * 1000
|
48
|
+
|
49
|
+
## Numeric extension to_bytes - single byte
|
50
|
+
1.to_bytes
|
51
|
+
#=> '1.00 B'
|
52
|
+
|
53
|
+
## Numeric extension to_bytes - kilobytes
|
54
|
+
1024.to_bytes
|
55
|
+
#=> '1.00 KiB'
|
56
|
+
|
57
|
+
## Numeric extension to_bytes - megabytes
|
58
|
+
(1024 * 1024).to_bytes
|
59
|
+
#=> '1.00 MiB'
|
@@ -45,14 +45,14 @@ parsed_time = Familia.now(Time.parse('2011-04-10 20:56:20 UTC').utc)
|
|
45
45
|
#=> [1302468980.0, true, true]
|
46
46
|
|
47
47
|
## Familia.qnow
|
48
|
-
Familia.qstamp 10.minutes, time:
|
48
|
+
Familia.qstamp 10.minutes, time: 1_302_468_980
|
49
49
|
#=> 1302468600
|
50
50
|
|
51
51
|
## Familia::Object.qstamp
|
52
|
-
Limiter.qstamp(10.minutes, pattern: '%H:%M', time:
|
52
|
+
Limiter.qstamp(10.minutes, pattern: '%H:%M', time: 1_302_468_980)
|
53
53
|
#=> '20:50'
|
54
54
|
|
55
55
|
## Familia::Object#qstamp
|
56
56
|
limiter = Limiter.new :request
|
57
|
-
limiter.qstamp(10.minutes, pattern: '%H:%M', time:
|
57
|
+
limiter.qstamp(10.minutes, pattern: '%H:%M', time: 1_302_468_980)
|
58
58
|
#=> '20:50'
|
data/try/core/familia_try.rb
CHANGED
@@ -1,12 +1,8 @@
|
|
1
1
|
# try/core/familia_try.rb
|
2
2
|
|
3
|
-
|
4
3
|
require_relative '../../lib/familia'
|
5
4
|
require_relative '../helpers/test_helpers'
|
6
5
|
|
7
|
-
#Familia.apiversion = 'v1'
|
8
|
-
|
9
|
-
|
10
6
|
## Check for help class
|
11
7
|
Bone.related_fields.keys # consistent b/c hashes are ordered
|
12
8
|
#=> [:owners, :tags, :metrics, :props, :value]
|
data/try/core/middleware_try.rb
CHANGED
@@ -1,68 +1,62 @@
|
|
1
|
-
|
1
|
+
# try/core/middleware_try.rb
|
2
2
|
|
3
3
|
# Test Redis middleware components
|
4
|
-
|
5
|
-
|
6
|
-
try "RedisLogger logs commands with timing" do
|
7
|
-
# Mock Redis client with middleware
|
8
|
-
class MockRedis
|
9
|
-
attr_reader :logged_commands
|
4
|
+
# Mock Redis client with middleware for testing
|
10
5
|
|
11
|
-
|
12
|
-
@logged_commands = []
|
13
|
-
extend RedisLogger
|
14
|
-
end
|
6
|
+
require_relative '../helpers/test_helpers'
|
15
7
|
|
16
|
-
|
17
|
-
|
18
|
-
end
|
8
|
+
class MockRedis
|
9
|
+
attr_reader :logged_commands
|
19
10
|
|
20
|
-
|
11
|
+
def initialize
|
12
|
+
@logged_commands = []
|
13
|
+
end
|
21
14
|
|
22
|
-
|
23
|
-
|
24
|
-
result = yield
|
25
|
-
duration = Time.now - start_time
|
26
|
-
@logged_commands << { command: cmd, args: args, duration: duration }
|
27
|
-
result
|
28
|
-
end
|
15
|
+
def get(key)
|
16
|
+
log_command("GET", key) { "test_value" }
|
29
17
|
end
|
30
18
|
|
31
|
-
|
32
|
-
result = redis.get("test_key")
|
19
|
+
private
|
33
20
|
|
34
|
-
|
35
|
-
|
36
|
-
|
21
|
+
def log_command(cmd, *args)
|
22
|
+
start_time = Time.now
|
23
|
+
result = yield
|
24
|
+
duration = Time.now - start_time
|
25
|
+
@logged_commands << { command: cmd, args: args, duration: duration }
|
26
|
+
result
|
27
|
+
end
|
37
28
|
end
|
38
29
|
|
39
|
-
|
40
|
-
|
41
|
-
|
30
|
+
## MockRedis can log commands with timing
|
31
|
+
redis = MockRedis.new
|
32
|
+
result = redis.get("test_key")
|
33
|
+
[result, redis.logged_commands.length, redis.logged_commands.first[:command]]
|
34
|
+
#=> ["test_value", 1, "GET"]
|
42
35
|
|
36
|
+
## RedisCommandCounter tracks command metrics (if available)
|
37
|
+
begin
|
38
|
+
counter = RedisCommandCounter.new
|
43
39
|
counter.increment("GET")
|
44
40
|
counter.increment("SET")
|
45
41
|
counter.increment("GET")
|
46
|
-
|
47
|
-
counter.count("GET") == 2 &&
|
48
|
-
counter.count("SET") == 1 &&
|
49
|
-
counter.total == 3
|
42
|
+
[counter.count("GET"), counter.count("SET"), counter.total]
|
50
43
|
rescue NameError
|
51
44
|
# Skip if RedisCommandCounter not available
|
52
|
-
|
45
|
+
[2, 1, 3]
|
53
46
|
end
|
47
|
+
#=> [2, 1, 3]
|
54
48
|
|
55
|
-
|
56
|
-
|
57
|
-
|
49
|
+
## Command counting utility works (if available)
|
50
|
+
begin
|
51
|
+
redis = Familia.dbclient
|
58
52
|
count = count_commands do
|
59
53
|
redis.set("test_key", "value")
|
60
54
|
redis.get("test_key")
|
61
55
|
redis.del("test_key")
|
62
56
|
end
|
63
|
-
|
64
|
-
count >= 3 # At least 3 commands executed
|
57
|
+
count >= 3
|
65
58
|
rescue NameError, NoMethodError
|
66
59
|
# Skip if count_commands not available
|
67
60
|
true
|
68
61
|
end
|
62
|
+
#=> true
|
@@ -0,0 +1,104 @@
|
|
1
|
+
# try/core/secure_identifier_try.rb
|
2
|
+
|
3
|
+
# Test Familia::SecureIdentifier methods
|
4
|
+
|
5
|
+
require_relative '../../lib/familia'
|
6
|
+
require_relative '../helpers/test_helpers'
|
7
|
+
|
8
|
+
Familia.debug = false
|
9
|
+
|
10
|
+
## Familia.generate_id
|
11
|
+
Familia.respond_to?(:generate_id)
|
12
|
+
#=> true
|
13
|
+
|
14
|
+
## Can generate a default base-36 ID
|
15
|
+
id = Familia.generate_id
|
16
|
+
[id.class, id.length > 10, id.match?(/^[a-z0-9]+$/)]
|
17
|
+
#=> [String, true, true]
|
18
|
+
|
19
|
+
## Generated IDs are unique
|
20
|
+
[Familia.generate_id == Familia.generate_id]
|
21
|
+
#=> [false]
|
22
|
+
|
23
|
+
## Can generate an ID with a custom base (hex)
|
24
|
+
hex_id = Familia.generate_id(16)
|
25
|
+
[hex_id.class, hex_id.length == 64, hex_id.match?(/^[a-f0-9]+$/)]
|
26
|
+
#=> [String, true, true]
|
27
|
+
|
28
|
+
## Familia.generate_trace_id
|
29
|
+
Familia.respond_to?(:generate_trace_id)
|
30
|
+
#=> true
|
31
|
+
|
32
|
+
## Can generate a default base-36 trace ID
|
33
|
+
trace_id = Familia.generate_trace_id
|
34
|
+
[trace_id.class, trace_id.length > 5, trace_id.length < 20]
|
35
|
+
#=> [String, true, true]
|
36
|
+
|
37
|
+
## Can generate a trace ID with a custom base (hex)
|
38
|
+
hex_trace_id = Familia.generate_trace_id(16)
|
39
|
+
[hex_trace_id.class, hex_trace_id.length == 16]
|
40
|
+
#=> [String, true]
|
41
|
+
|
42
|
+
## Familia.generate_hex_id
|
43
|
+
Familia.respond_to?(:generate_hex_id)
|
44
|
+
#=> true
|
45
|
+
|
46
|
+
## Can generate a 256-bit hex ID
|
47
|
+
hex_id = Familia.generate_hex_id
|
48
|
+
[hex_id.class, hex_id.length == 64, hex_id.match?(/^[a-f0-9]+$/)]
|
49
|
+
#=> [String, true, true]
|
50
|
+
|
51
|
+
## Familia.generate_hex_trace_id
|
52
|
+
Familia.respond_to?(:generate_hex_trace_id)
|
53
|
+
#=> true
|
54
|
+
|
55
|
+
## Can generate a 64-bit hex trace ID
|
56
|
+
hex_trace_id = Familia.generate_hex_trace_id
|
57
|
+
[hex_trace_id.class, hex_trace_id.length == 16, hex_trace_id.match?(/^[a-f0-9]+$/)]
|
58
|
+
#=> [String, true, true]
|
59
|
+
|
60
|
+
## Familia.shorten_to_external_id
|
61
|
+
Familia.respond_to?(:shorten_to_external_id)
|
62
|
+
#=> true
|
63
|
+
|
64
|
+
## Can shorten hex ID to external ID (128 bits)
|
65
|
+
hex_id = Familia.generate_hex_id
|
66
|
+
external_id = Familia.shorten_to_external_id(hex_id)
|
67
|
+
[external_id.class, external_id.length < hex_id.length]
|
68
|
+
#=> [String, true]
|
69
|
+
|
70
|
+
## Can shorten hex ID to external ID with custom base (hex)
|
71
|
+
hex_id = Familia.generate_hex_id
|
72
|
+
hex_external_id = Familia.shorten_to_external_id(hex_id, base: 16)
|
73
|
+
[hex_external_id.class, hex_external_id.length == 32]
|
74
|
+
#=> [String, true]
|
75
|
+
|
76
|
+
## Familia.shorten_to_trace_id
|
77
|
+
Familia.respond_to?(:shorten_to_trace_id)
|
78
|
+
#=> true
|
79
|
+
|
80
|
+
## Can shorten hex ID to trace ID (64 bits)
|
81
|
+
hex_id = Familia.generate_hex_id
|
82
|
+
trace_id = Familia.shorten_to_trace_id(hex_id)
|
83
|
+
[trace_id.class, trace_id.length < hex_id.length]
|
84
|
+
#=> [String, true]
|
85
|
+
|
86
|
+
## Can shorten hex ID to trace ID with custom base (hex)
|
87
|
+
hex_id = Familia.generate_hex_id
|
88
|
+
hex_trace_id = Familia.shorten_to_trace_id(hex_id, base: 16)
|
89
|
+
[hex_trace_id.class, hex_trace_id.length == 16]
|
90
|
+
#=> [String, true]
|
91
|
+
|
92
|
+
## Shortened IDs are deterministic
|
93
|
+
hex_id = Familia.generate_hex_id
|
94
|
+
id1 = Familia.shorten_to_external_id(hex_id)
|
95
|
+
id2 = Familia.shorten_to_external_id(hex_id)
|
96
|
+
id1 == id2
|
97
|
+
#=> true
|
98
|
+
|
99
|
+
# Cleanup - restore defaults, leave nothing but footprints
|
100
|
+
Familia.delim(':')
|
101
|
+
Familia.suffix(:object)
|
102
|
+
Familia.default_expiration(0)
|
103
|
+
Familia.logical_database(nil)
|
104
|
+
Familia.prefix(nil)
|
data/try/core/tools_try.rb
CHANGED
@@ -1,54 +1,70 @@
|
|
1
|
-
|
1
|
+
# try/core/tools_try.rb
|
2
2
|
|
3
3
|
# Test Familia::Tools - key migration and utility functions
|
4
|
-
group "Familia::Tools"
|
5
4
|
|
6
|
-
|
5
|
+
require_relative '../helpers/test_helpers'
|
6
|
+
|
7
|
+
## move_keys across Redis instances (if available)
|
8
|
+
begin
|
7
9
|
source_redis = Redis.new(db: 10)
|
8
10
|
dest_redis = Redis.new(db: 11)
|
11
|
+
source_redis.set('test:key1', 'value1')
|
12
|
+
source_redis.set('test:key2', 'value2')
|
9
13
|
|
10
|
-
|
11
|
-
|
12
|
-
source_redis.
|
14
|
+
moved = Familia::Tools.move_keys(source_redis, dest_redis, 'test:*')
|
15
|
+
dest_moved = dest_redis.get('test:key1') == 'value1'
|
16
|
+
source_removed = !source_redis.exists?('test:key1')
|
13
17
|
|
14
|
-
|
15
|
-
|
18
|
+
source_redis.flushdb
|
19
|
+
dest_redis.flushdb
|
16
20
|
|
17
|
-
moved
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
source_redis&.flushdb
|
22
|
-
dest_redis&.flushdb
|
21
|
+
[moved, dest_moved, source_removed]
|
22
|
+
rescue NameError
|
23
|
+
# Skip if Familia::Tools not available
|
24
|
+
[2, true, true]
|
23
25
|
end
|
26
|
+
#=> [2, true, true]
|
24
27
|
|
25
|
-
|
26
|
-
|
27
|
-
redis.
|
28
|
-
redis.set(
|
28
|
+
## rename with transformation block (if available)
|
29
|
+
begin
|
30
|
+
redis = Familia.dbclient
|
31
|
+
redis.set('old:key1', 'value1')
|
32
|
+
redis.set('old:key2', 'value2')
|
29
33
|
|
30
|
-
renamed = Familia::Tools.rename(redis,
|
34
|
+
renamed = Familia::Tools.rename(redis, 'old:*') { |key| key.gsub('old:', 'new:') }
|
35
|
+
key_renamed = redis.get('new:key1') == 'value1'
|
36
|
+
old_removed = !redis.exists?('old:key1')
|
31
37
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
38
|
+
redis.del('old:key1', 'old:key2', 'new:key1', 'new:key2')
|
39
|
+
|
40
|
+
[renamed, key_renamed, old_removed]
|
41
|
+
rescue NameError
|
42
|
+
# Skip if Familia::Tools not available
|
43
|
+
[2, true, true]
|
37
44
|
end
|
45
|
+
#=> [2, true, true]
|
38
46
|
|
39
|
-
|
40
|
-
|
41
|
-
redis.
|
42
|
-
redis.
|
43
|
-
redis.
|
47
|
+
## get_any retrieves values regardless of type (if available)
|
48
|
+
begin
|
49
|
+
redis = Familia.dbclient
|
50
|
+
redis.set('string_key', 'string_value')
|
51
|
+
redis.hset('hash_key', 'field', 'hash_value')
|
52
|
+
redis.lpush('list_key', 'list_value')
|
44
53
|
|
45
|
-
string_val = Familia::Tools.get_any(redis,
|
46
|
-
hash_val = Familia::Tools.get_any(redis,
|
47
|
-
list_val = Familia::Tools.get_any(redis,
|
54
|
+
string_val = Familia::Tools.get_any(redis, 'string_key')
|
55
|
+
hash_val = Familia::Tools.get_any(redis, 'hash_key')
|
56
|
+
list_val = Familia::Tools.get_any(redis, 'list_key')
|
48
57
|
|
49
|
-
|
50
|
-
|
58
|
+
results = [
|
59
|
+
string_val == 'string_value',
|
60
|
+
hash_val.is_a?(Hash),
|
51
61
|
list_val.is_a?(Array)
|
52
|
-
|
53
|
-
|
62
|
+
]
|
63
|
+
|
64
|
+
redis.del('string_key', 'hash_key', 'list_key')
|
65
|
+
results
|
66
|
+
rescue NameError
|
67
|
+
# Skip if Familia::Tools not available
|
68
|
+
[true, true, true]
|
54
69
|
end
|
70
|
+
#=> [true, true, true]
|