familia 1.0.0.pre.rc6 → 1.1.0.pre.rc1

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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/Gemfile.lock +3 -1
  4. data/README.md +5 -5
  5. data/VERSION.yml +2 -2
  6. data/familia.gemspec +1 -2
  7. data/lib/familia/base.rb +11 -11
  8. data/lib/familia/connection.rb +18 -2
  9. data/lib/familia/errors.rb +14 -0
  10. data/lib/familia/features/expiration.rb +13 -2
  11. data/lib/familia/features/quantization.rb +1 -1
  12. data/lib/familia/horreum/class_methods.rb +99 -41
  13. data/lib/familia/horreum/commands.rb +53 -14
  14. data/lib/familia/horreum/relations_management.rb +9 -2
  15. data/lib/familia/horreum/serialization.rb +32 -23
  16. data/lib/familia/horreum.rb +8 -2
  17. data/lib/familia/redistype/commands.rb +5 -2
  18. data/lib/familia/redistype/serialization.rb +17 -16
  19. data/lib/familia/redistype/types/hashkey.rb +166 -0
  20. data/lib/familia/{types → redistype/types}/list.rb +19 -14
  21. data/lib/familia/{types → redistype/types}/sorted_set.rb +23 -19
  22. data/lib/familia/{types → redistype/types}/string.rb +8 -6
  23. data/lib/familia/{types → redistype/types}/unsorted_set.rb +16 -12
  24. data/lib/familia/redistype.rb +19 -9
  25. data/lib/familia.rb +5 -1
  26. data/try/10_familia_try.rb +1 -1
  27. data/try/20_redis_type_try.rb +1 -1
  28. data/try/21_redis_type_zset_try.rb +1 -1
  29. data/try/22_redis_type_set_try.rb +1 -1
  30. data/try/23_redis_type_list_try.rb +2 -2
  31. data/try/24_redis_type_string_try.rb +3 -3
  32. data/try/25_redis_type_hash_try.rb +1 -1
  33. data/try/26_redis_bool_try.rb +2 -2
  34. data/try/27_redis_horreum_try.rb +4 -4
  35. data/try/30_familia_object_try.rb +8 -5
  36. data/try/40_customer_try.rb +6 -6
  37. metadata +15 -15
  38. data/lib/familia/types/hashkey.rb +0 -108
@@ -4,19 +4,21 @@ module Familia
4
4
  class String < RedisType
5
5
  def init; end
6
6
 
7
- def size
7
+ # Returns the number of elements in the list
8
+ # @return [Integer] number of elements
9
+ def char_count
8
10
  to_s.size
9
11
  end
10
- alias length size
12
+ alias size char_count
11
13
 
12
14
  def empty?
13
- size.zero?
15
+ char_count.zero?
14
16
  end
15
17
 
16
18
  def value
17
19
  echo :value, caller(0..0) if Familia.debug
18
20
  redis.setnx rediskey, @opts[:default] if @opts[:default]
19
- from_redis redis.get(rediskey)
21
+ deserialize_value redis.get(rediskey)
20
22
  end
21
23
  alias content value
22
24
  alias get value
@@ -30,7 +32,7 @@ module Familia
30
32
  end
31
33
 
32
34
  def value=(val)
33
- ret = redis.set(rediskey, to_redis(val))
35
+ ret = redis.set(rediskey, serialize_value(val))
34
36
  update_expiration
35
37
  ret
36
38
  end
@@ -38,7 +40,7 @@ module Familia
38
40
  alias set value=
39
41
 
40
42
  def setnx(val)
41
- ret = redis.setnx(rediskey, to_redis(val))
43
+ ret = redis.setnx(rediskey, serialize_value(val))
42
44
  update_expiration
43
45
  ret
44
46
  end
@@ -2,17 +2,20 @@
2
2
 
3
3
  module Familia
4
4
  class Set < RedisType
5
- def size
5
+
6
+ # Returns the number of elements in the unsorted set
7
+ # @return [Integer] number of elements
8
+ def element_count
6
9
  redis.scard rediskey
7
10
  end
8
- alias length size
11
+ alias size element_count
9
12
 
10
13
  def empty?
11
- size.zero?
14
+ element_count.zero?
12
15
  end
13
16
 
14
17
  def add *values
15
- values.flatten.compact.each { |v| redis.sadd? rediskey, to_redis(v) }
18
+ values.flatten.compact.each { |v| redis.sadd? rediskey, serialize_value(v) }
16
19
  update_expiration
17
20
  self
18
21
  end
@@ -24,7 +27,7 @@ module Familia
24
27
  def members
25
28
  echo :members, caller(1..1).first if Familia.debug
26
29
  elements = membersraw
27
- multi_from_redis(*elements)
30
+ deserialize_values(*elements)
28
31
  end
29
32
  alias all members
30
33
  alias to_a members
@@ -66,16 +69,17 @@ module Familia
66
69
  end
67
70
 
68
71
  def member?(val)
69
- redis.sismember rediskey, to_redis(val)
72
+ redis.sismember rediskey, serialize_value(val)
70
73
  end
71
74
  alias include? member?
72
75
 
73
- def delete(val)
74
- redis.srem rediskey, to_redis(val)
76
+ # Removes a member from the set
77
+ # @param value The value to remove from the set
78
+ # @return [Integer] The number of members that were removed (0 or 1)
79
+ def remove_element(value)
80
+ redis.srem rediskey, serialize_value(value)
75
81
  end
76
- alias remove delete
77
- alias rem delete
78
- alias del delete
82
+ alias remove remove_element # deprecated
79
83
 
80
84
  def intersection *setkeys
81
85
  # TODO
@@ -90,7 +94,7 @@ module Familia
90
94
  end
91
95
 
92
96
  def random
93
- from_redis randomraw
97
+ deserialize_value randomraw
94
98
  end
95
99
 
96
100
  def randomraw
@@ -16,17 +16,19 @@ module Familia
16
16
  extend Familia::Features
17
17
 
18
18
  @registered_types = {}
19
- @valid_options = %i[class parent ttl default db key redis]
19
+ @valid_options = %i[class parent ttl default db key redis suffix prefix]
20
20
  @db = nil
21
21
 
22
22
  feature :expiration
23
23
  feature :quantization
24
24
 
25
25
  class << self
26
- attr_reader :registered_types, :valid_options
26
+ attr_reader :registered_types, :valid_options, :has_relations
27
27
  attr_accessor :parent
28
28
  attr_writer :db, :uri
29
+ end
29
30
 
31
+ module ClassMethods
30
32
  # To be called inside every class that inherits RedisType
31
33
  # +methname+ is the term used for the class and instance methods
32
34
  # that are created for the given +klass+ (e.g. set, list, etc)
@@ -58,7 +60,12 @@ module Familia
58
60
  def valid_keys_only(opts)
59
61
  opts.select { |k, _| RedisType.valid_options.include? k }
60
62
  end
63
+
64
+ def has_relations?
65
+ @has_relations ||= false
66
+ end
61
67
  end
68
+ extend ClassMethods
62
69
 
63
70
  attr_reader :keystring, :parent, :opts
64
71
  attr_writer :dump_method, :load_method
@@ -89,8 +96,11 @@ module Familia
89
96
  # :key => a hardcoded key to use instead of the deriving the from
90
97
  # the name and parent (e.g. a derived key: customer:custid:secret_counter).
91
98
  #
92
- # Uses the redis connection of the parent or the value of
93
- # opts[:redis] or Familia.redis (in that order).
99
+ # :suffix => the suffix to use for the key (e.g. 'scores' in customer:custid:scores).
100
+ # :prefix => the prefix to use for the key (e.g. 'customer' in customer:custid:scores).
101
+ #
102
+ # Connection precendence: uses the redis connection of the parent or the
103
+ # value of opts[:redis] or Familia.redis (in that order).
94
104
  def initialize(keystring, opts = {})
95
105
  #Familia.ld " [initializing] #{self.class} #{opts}"
96
106
  @keystring = keystring
@@ -210,9 +220,9 @@ module Familia
210
220
  include Serialization
211
221
  end
212
222
 
213
- require_relative 'types/list'
214
- require_relative 'types/unsorted_set'
215
- require_relative 'types/sorted_set'
216
- require_relative 'types/hashkey'
217
- require_relative 'types/string'
223
+ require_relative 'redistype/types/list'
224
+ require_relative 'redistype/types/unsorted_set'
225
+ require_relative 'redistype/types/sorted_set'
226
+ require_relative 'redistype/types/hashkey'
227
+ require_relative 'redistype/types/string'
218
228
  end
data/lib/familia.rb CHANGED
@@ -35,9 +35,13 @@ module Familia
35
35
  @members = []
36
36
 
37
37
  class << self
38
- attr_accessor :debug
38
+ attr_writer :debug
39
39
  attr_reader :members
40
40
 
41
+ def debug
42
+ @debug ||= ENV['FAMILIA_DEBUG'].to_s.match?(/^(true|1)$/i)
43
+ end
44
+
41
45
  def included(member)
42
46
  raise Problem, "#{member} should subclass Familia::Horreum"
43
47
  end
@@ -21,7 +21,7 @@ Familia::Horreum::ClassMethods.public_method_defined? :list
21
21
  Familia::Horreum::ClassMethods.public_method_defined? :lists
22
22
  #=> true
23
23
 
24
- ## A Familia object knows its redistype relativess
24
+ ## A Familia object knows its redistype relatives
25
25
  Bone.redis_types.is_a?(Hash) && Bone.redis_types.has_key?(:owners)
26
26
  #=> true
27
27
 
@@ -46,7 +46,7 @@ p [@limiter1.counter.parent.ttl, @limiter2.counter.parent.ttl]
46
46
  ##=> "v1:limiter:requests:counter:1302468600"
47
47
 
48
48
  ## Increment counter
49
- @limiter1.counter.clear
49
+ @limiter1.counter.delete!
50
50
  @limiter1.counter.increment
51
51
  #=> 1
52
52
 
@@ -65,4 +65,4 @@ require_relative './test_helpers'
65
65
  @a.metrics.members
66
66
  #=> ['metric2']
67
67
 
68
- @a.metrics.clear
68
+ @a.metrics.delete!
@@ -31,4 +31,4 @@ ret.class
31
31
  #=> 3
32
32
 
33
33
 
34
- @a.tags.clear
34
+ @a.tags.delete!
@@ -31,11 +31,11 @@ ret.class
31
31
  #=> ['value1','value2','value3']
32
32
 
33
33
  ## Familia::List#delete
34
- @a.owners.delete 'value3'
34
+ @a.owners.remove 'value3'
35
35
  #=> 1
36
36
 
37
37
  ## Familia::List#size
38
38
  @a.owners.size
39
39
  #=> 2
40
40
 
41
- @a.owners.clear
41
+ @a.owners.delete!
@@ -22,8 +22,8 @@ require_relative './test_helpers'
22
22
  #=> 'DECENT!'
23
23
 
24
24
  ## Familia::String#destroy!
25
- @a.value.clear
26
- #=> 1
25
+ @a.value.delete!
26
+ #=> true
27
27
 
28
28
  ## Familia::String.new
29
29
  @ret = Familia::String.new 'arbitrary:key'
@@ -63,4 +63,4 @@ require_relative './test_helpers'
63
63
  #=> '1050bytes'
64
64
 
65
65
 
66
- @ret.clear
66
+ @ret.delete!
@@ -50,4 +50,4 @@ require_relative './test_helpers'
50
50
  #=> ['1', '40', '3']
51
51
 
52
52
 
53
- @a.props.clear
53
+ @a.props.delete!
@@ -39,5 +39,5 @@ end
39
39
  #=> "true"
40
40
 
41
41
  ## Clear the hash key
42
- @hashkey.clear
43
- #=> 1
42
+ @hashkey.delete!
43
+ #=> true
@@ -36,8 +36,8 @@ Familia.debug = false
36
36
  #=> @identifier
37
37
 
38
38
  ## Remove the key
39
- @hashkey.clear
40
- #=> 1
39
+ @hashkey.delete!
40
+ #=> true
41
41
 
42
42
  ## Horreum objects can update and save their fields (1 of 2)
43
43
  @customer.name = 'John Doe'
@@ -47,12 +47,12 @@ Familia.debug = false
47
47
  @customer.save
48
48
  #=> true
49
49
 
50
- ## Horreum object fields have a fast writer method (1 of 2)
50
+ ## Horreum object fields have a fast attribute method (1 of 2)
51
51
  Familia.trace :LOAD, @customer.redis, @customer.redisuri, caller if Familia.debug?
52
52
  @customer.name! 'Jane Doe'
53
53
  #=> 0
54
54
 
55
- ## Horreum object fields have a fast writer method (2 of 2)
55
+ ## Horreum object fields have a fast attribute method (2 of 2)
56
56
  @customer.refresh!
57
57
  @customer.name
58
58
  #=> "Jane Doe"
@@ -36,8 +36,8 @@ Bone.suffix
36
36
  Customer.values.all.collect(&:custid)
37
37
  ##=> ['delano']
38
38
 
39
- ## Familia.from_redis
40
- obj = Customer.from_identifier :delano
39
+ ## Can load an object from an identifier
40
+ obj = Customer.find_by_id :delano
41
41
  [obj.class, obj.custid]
42
42
  #=> [Customer, 'delano']
43
43
 
@@ -68,9 +68,8 @@ Customer.customers.size
68
68
  #=> 3
69
69
 
70
70
  ## Familia class clear
71
- Customer.customers.clear
72
- #=> 1
73
-
71
+ Customer.customers.delete!
72
+ #=> true
74
73
 
75
74
  ## Familia class replace 1 of 4
76
75
  Customer.message.value = "msg1"
@@ -87,3 +86,7 @@ Customer.message = "msg2"
87
86
  ## Familia class replace 4 of 4
88
87
  Customer.message.value
89
88
  #=> "msg2"
89
+
90
+
91
+ # Teardown
92
+ Customer.values.delete!
@@ -18,7 +18,7 @@ require_relative './test_helpers'
18
18
  #=> true
19
19
 
20
20
  ## Customer can be retrieved by identifier
21
- retrieved_customer = Customer.from_identifier("test@example.com")
21
+ retrieved_customer = Customer.find_by_id("test@example.com")
22
22
  retrieved_customer.custid
23
23
  #=> "test@example.com"
24
24
 
@@ -35,11 +35,11 @@ retrieved_customer.custid
35
35
  @customer.planid = "premium"
36
36
  @customer.save
37
37
  ident = @customer.identifier
38
- Customer.from_identifier(ident).planid
38
+ Customer.find_by_id(ident).planid
39
39
  #=> "premium"
40
40
 
41
41
  ## Customer can increment secrets_created counter
42
- @customer.secrets_created.clear
42
+ @customer.secrets_created.delete!
43
43
  @customer.secrets_created.increment
44
44
  @customer.secrets_created.value
45
45
  #=> '1'
@@ -74,7 +74,7 @@ Customer.instances.member?(@customer)
74
74
  #=> true
75
75
 
76
76
  ## Customer can be removed from class-level sorted set
77
- Customer.instances.delete(@customer)
77
+ Customer.instances.remove(@customer)
78
78
  Customer.instances.member?(@customer)
79
79
  #=> false
80
80
 
@@ -90,7 +90,7 @@ Customer.instances.member?(@customer)
90
90
 
91
91
  ## Customer can be destroyed
92
92
  ret = @customer.destroy!
93
- cust = Customer.from_identifier("test@example.com")
93
+ cust = Customer.find_by_id("test@example.com")
94
94
  exists = Customer.exists?("test@example.com")
95
95
  [ret, cust.nil?, exists]
96
96
  #=> [true, true, false]
@@ -137,4 +137,4 @@ Customer.instances.uri.to_s
137
137
 
138
138
 
139
139
  # Teardown
140
- Customer.instances.clear
140
+ Customer.instances.delete!
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: familia
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0.pre.rc6
4
+ version: 1.1.0.pre.rc1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Delano Mandelbaum
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-08-26 00:00:00.000000000 Z
11
+ date: 2024-11-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -31,33 +31,33 @@ dependencies:
31
31
  - !ruby/object:Gem::Version
32
32
  version: '6.0'
33
33
  - !ruby/object:Gem::Dependency
34
- name: uri-redis
34
+ name: stringio
35
35
  requirement: !ruby/object:Gem::Requirement
36
36
  requirements:
37
37
  - - "~>"
38
38
  - !ruby/object:Gem::Version
39
- version: '1.3'
39
+ version: 3.1.1
40
40
  type: :runtime
41
41
  prerelease: false
42
42
  version_requirements: !ruby/object:Gem::Requirement
43
43
  requirements:
44
44
  - - "~>"
45
45
  - !ruby/object:Gem::Version
46
- version: '1.3'
46
+ version: 3.1.1
47
47
  - !ruby/object:Gem::Dependency
48
- name: byebug
48
+ name: uri-redis
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: '11.0'
54
- type: :development
53
+ version: '1.3'
54
+ type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
58
  - - "~>"
59
59
  - !ruby/object:Gem::Version
60
- version: '11.0'
60
+ version: '1.3'
61
61
  description: 'Familia: An ORM for Redis in Ruby.. Organize and store ruby objects
62
62
  in Redis'
63
63
  email: gems@solutious.com
@@ -96,14 +96,14 @@ files:
96
96
  - lib/familia/redistype.rb
97
97
  - lib/familia/redistype/commands.rb
98
98
  - lib/familia/redistype/serialization.rb
99
+ - lib/familia/redistype/types/hashkey.rb
100
+ - lib/familia/redistype/types/list.rb
101
+ - lib/familia/redistype/types/sorted_set.rb
102
+ - lib/familia/redistype/types/string.rb
103
+ - lib/familia/redistype/types/unsorted_set.rb
99
104
  - lib/familia/refinements.rb
100
105
  - lib/familia/settings.rb
101
106
  - lib/familia/tools.rb
102
- - lib/familia/types/hashkey.rb
103
- - lib/familia/types/list.rb
104
- - lib/familia/types/sorted_set.rb
105
- - lib/familia/types/string.rb
106
- - lib/familia/types/unsorted_set.rb
107
107
  - lib/familia/utils.rb
108
108
  - lib/familia/version.rb
109
109
  - lib/redis_middleware.rb
@@ -142,7 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
142
142
  - !ruby/object:Gem::Version
143
143
  version: '0'
144
144
  requirements: []
145
- rubygems_version: 3.5.15
145
+ rubygems_version: 3.5.16
146
146
  signing_key:
147
147
  specification_version: 4
148
148
  summary: An ORM for Redis in Ruby.
@@ -1,108 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Familia
4
- class HashKey < RedisType
5
- def size
6
- redis.hlen rediskey
7
- end
8
- alias length size
9
-
10
- def empty?
11
- size.zero?
12
- end
13
-
14
- # +return+ [Integer] Returns 1 if the field is new and added, 0 if the
15
- # field already existed and the value was updated.
16
- def []=(field, val)
17
- ret = redis.hset rediskey, field, to_redis(val)
18
- update_expiration
19
- ret
20
- rescue TypeError => e
21
- Familia.le "[hset]= #{e.message}"
22
- Familia.ld "[hset]= #{rediskey} #{field}=#{val}" if Familia.debug
23
- echo :hset, caller(1..1).first if Familia.debug # logs via echo to redis and back
24
- klass = val.class
25
- msg = "Cannot store #{field} => #{val.inspect} (#{klass}) in #{rediskey}"
26
- raise e.class, msg
27
- end
28
- alias put []=
29
- alias store []=
30
-
31
- def [](field)
32
- from_redis redis.hget(rediskey, field)
33
- end
34
- alias get []
35
-
36
- def fetch(field, default = nil)
37
- ret = self[field]
38
- if ret.nil?
39
- raise IndexError, "No such index for: #{field}" if default.nil?
40
-
41
- default
42
- else
43
- ret
44
- end
45
- end
46
-
47
- def keys
48
- redis.hkeys rediskey
49
- end
50
-
51
- def values
52
- elements = redis.hvals(rediskey)
53
- multi_from_redis(*elements)
54
- end
55
-
56
- def hgetall
57
- # TODO: Use from_redis. Also alias `all` is confusing with
58
- # Onetime::Customer.all which returns all customers.
59
- redis.hgetall rediskey
60
- end
61
- alias all hgetall
62
-
63
- def key?(field)
64
- redis.hexists rediskey, field
65
- end
66
- alias has_key? key?
67
- alias include? key?
68
- alias member? key?
69
-
70
- def delete(field)
71
- redis.hdel rediskey, field
72
- end
73
- alias remove delete
74
- alias rem delete
75
- alias del delete
76
-
77
- def increment(field, by = 1)
78
- redis.hincrby(rediskey, field, by).to_i
79
- end
80
- alias incr increment
81
- alias incrby increment
82
-
83
- def decrement(field, by = 1)
84
- increment field, -by
85
- end
86
- alias decr decrement
87
- alias decrby decrement
88
-
89
- def update(hsh = {})
90
- raise ArgumentError, 'Argument to bulk_set must be a hash' unless hsh.is_a?(Hash)
91
-
92
- data = hsh.inject([]) { |ret, pair| ret << [pair[0], to_redis(pair[1])] }.flatten
93
-
94
- ret = redis.hmset(rediskey, *data)
95
- update_expiration
96
- ret
97
- end
98
- alias merge! update
99
-
100
- def values_at *fields
101
- elements = redis.hmget(rediskey, *fields.flatten.compact)
102
- multi_from_redis(*elements)
103
- end
104
-
105
- Familia::RedisType.register self, :hash # legacy, deprecated
106
- Familia::RedisType.register self, :hashkey
107
- end
108
- end