familia 0.10.2 → 1.0.0.pre.rc2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.pre-commit-config.yaml +1 -1
  4. data/.rubocop.yml +75 -0
  5. data/.rubocop_todo.yml +63 -0
  6. data/Gemfile +6 -1
  7. data/Gemfile.lock +47 -15
  8. data/README.md +65 -13
  9. data/VERSION.yml +4 -3
  10. data/familia.gemspec +18 -13
  11. data/lib/familia/base.rb +33 -0
  12. data/lib/familia/connection.rb +87 -0
  13. data/lib/familia/core_ext.rb +119 -124
  14. data/lib/familia/errors.rb +33 -0
  15. data/lib/familia/features/api_version.rb +19 -0
  16. data/lib/familia/features/atomic_saves.rb +8 -0
  17. data/lib/familia/features/quantizer.rb +35 -0
  18. data/lib/familia/features/safe_dump.rb +194 -0
  19. data/lib/familia/features.rb +51 -0
  20. data/lib/familia/horreum/class_methods.rb +292 -0
  21. data/lib/familia/horreum/commands.rb +106 -0
  22. data/lib/familia/horreum/relations_management.rb +141 -0
  23. data/lib/familia/horreum/serialization.rb +193 -0
  24. data/lib/familia/horreum/settings.rb +63 -0
  25. data/lib/familia/horreum/utils.rb +44 -0
  26. data/lib/familia/horreum.rb +248 -0
  27. data/lib/familia/logging.rb +232 -0
  28. data/lib/familia/redistype/commands.rb +56 -0
  29. data/lib/familia/redistype/serialization.rb +110 -0
  30. data/lib/familia/redistype.rb +185 -0
  31. data/lib/familia/refinements.rb +88 -0
  32. data/lib/familia/settings.rb +38 -0
  33. data/lib/familia/types/hashkey.rb +107 -0
  34. data/lib/familia/types/list.rb +155 -0
  35. data/lib/familia/types/sorted_set.rb +234 -0
  36. data/lib/familia/types/string.rb +115 -0
  37. data/lib/familia/types/unsorted_set.rb +123 -0
  38. data/lib/familia/utils.rb +125 -0
  39. data/lib/familia/version.rb +25 -0
  40. data/lib/familia.rb +57 -161
  41. data/lib/redis_middleware.rb +109 -0
  42. data/try/00_familia_try.rb +5 -4
  43. data/try/10_familia_try.rb +21 -17
  44. data/try/20_redis_type_try.rb +67 -0
  45. data/try/{21_redis_object_zset_try.rb → 21_redis_type_zset_try.rb} +2 -2
  46. data/try/{22_redis_object_set_try.rb → 22_redis_type_set_try.rb} +2 -2
  47. data/try/{23_redis_object_list_try.rb → 23_redis_type_list_try.rb} +2 -2
  48. data/try/{24_redis_object_string_try.rb → 24_redis_type_string_try.rb} +6 -6
  49. data/try/{25_redis_object_hash_try.rb → 25_redis_type_hash_try.rb} +3 -3
  50. data/try/26_redis_bool_try.rb +10 -6
  51. data/try/27_redis_horreum_try.rb +93 -0
  52. data/try/30_familia_object_try.rb +21 -20
  53. data/try/35_feature_safedump_try.rb +83 -0
  54. data/try/40_customer_try.rb +140 -0
  55. data/try/41_customer_safedump_try.rb +86 -0
  56. data/try/test_helpers.rb +194 -0
  57. metadata +51 -47
  58. data/lib/familia/helpers.rb +0 -70
  59. data/lib/familia/object.rb +0 -533
  60. data/lib/familia/redisobject.rb +0 -1017
  61. data/lib/familia/test_helpers.rb +0 -40
  62. data/lib/familia/tools.rb +0 -67
  63. data/try/20_redis_object_try.rb +0 -44
@@ -0,0 +1,194 @@
1
+ # rubocop:disable all
2
+
3
+ require 'digest'
4
+ require_relative '../lib/familia'
5
+
6
+ # ENV['FAMILIA_TRACE'] = '1'
7
+ #Familia.debug = true
8
+ Familia.enable_redis_logging = true
9
+ Familia.enable_redis_counter = true
10
+
11
+ class Bone < Familia::Horreum
12
+ identifier [:token, :name]
13
+ field :token
14
+ field :name
15
+ list :owners
16
+ set :tags
17
+ zset :metrics
18
+ hashkey :props
19
+ string :value, :default => "GREAT!"
20
+ end
21
+
22
+ class Blone < Familia::Horreum
23
+ feature :safe_dump
24
+ list :owners
25
+ set :tags
26
+ zset :metrics
27
+ hashkey :props
28
+ string :value, :default => "GREAT!"
29
+ end
30
+
31
+ class Customer < Familia::Horreum
32
+ db 15 # don't use Onetime's default DB
33
+ ttl 5.years
34
+
35
+ feature :safe_dump
36
+ #feature :api_version
37
+
38
+ # NOTE: The SafeDump mixin caches the safe_dump_field_map so updating this list
39
+ # with hot reloading in dev mode will not work. You will need to restart the
40
+ # server to see the changes.
41
+ @safe_dump_fields = [
42
+ :custid,
43
+ :role,
44
+ :verified,
45
+ :updated,
46
+ :created,
47
+
48
+ # NOTE: The secrets_created incrementer is null until the first secret
49
+ # is created. See CreateSecret for where the incrementer is called.
50
+ #
51
+ {secrets_created: ->(cust) { cust.secrets_created.value || 0 } },
52
+
53
+ # We use the hash syntax here since `:active?` is not a valid symbol.
54
+ {active: ->(cust) { cust.active? } }
55
+ ]
56
+
57
+ class_sorted_set :values, key: 'onetime:customer'
58
+ class_hashkey :domains
59
+
60
+ hashkey :stripe_customer
61
+ sorted_set :timeline
62
+ sorted_set :custom_domains
63
+
64
+ counter :secrets_created
65
+
66
+ identifier :custid
67
+
68
+ field :custid
69
+ field :sessid
70
+ field :email
71
+ field :role
72
+ field :key
73
+ field :name
74
+ field :passphrase_encryption
75
+ field :passphrase
76
+ field :verified
77
+ field :apitoken
78
+ field :planid
79
+ field :created
80
+ field :updated
81
+ field :reset_requested #=> Boolean
82
+
83
+ hashkey :password_reset #=> Familia::HashKey
84
+ list :sessions #=> Familia::List
85
+
86
+ class_list :customers, suffix: []
87
+ class_string :message
88
+
89
+ class_zset :instances, class: self, reference: true
90
+
91
+ def active?
92
+ verified && !reset_requested
93
+ end
94
+ end
95
+ @c = Customer.new
96
+ @c.custid = "d@example.com"
97
+
98
+ class Session < Familia::Horreum
99
+ db 14 # don't use Onetime's default DB
100
+ ttl 180.minutes
101
+
102
+ identifier :generate_id
103
+
104
+ field :sessid
105
+ field :shrimp
106
+ field :custid
107
+ field :useragent
108
+ field :key
109
+ field :authenticated
110
+ field :ipaddress
111
+ field :created
112
+ field :updated
113
+
114
+ def generate_id
115
+ @sessid ||= Familia.generate_id
116
+ @sessid
117
+ end
118
+
119
+ # The external identifier is used by the rate limiter to estimate a unique
120
+ # client. We can't use the session ID b/c the request agent can choose to
121
+ # not send cookies, or the user can clear their cookies (in both cases the
122
+ # session ID would change which would circumvent the rate limiter). The
123
+ # external identifier is a hash of the IP address and the customer ID
124
+ # which means that anonymous users from the same IP address are treated
125
+ # as the same client (as far as the limiter is concerned). Not ideal.
126
+ #
127
+ # To put it another way, the risk of colliding external identifiers is
128
+ # acceptable for the rate limiter, but not for the session data. Acceptable
129
+ # b/c the rate limiter is a temporary measure to prevent abuse, and the
130
+ # worse case scenario is that a user is rate limited when they shouldn't be.
131
+ # The session data is permanent and must be kept separate to avoid leaking
132
+ # data between users.
133
+ def external_identifier
134
+ elements = []
135
+ elements << ipaddress || 'UNKNOWNIP'
136
+ elements << custid || 'anon'
137
+ @external_identifier ||= Familia.generate_sha_hash(elements)
138
+ Familia.ld "[Session.external_identifier] sess identifier input: #{elements.inspect} (result: #{@external_identifier})"
139
+ @external_identifier
140
+ end
141
+
142
+ end
143
+ @s = Session.new
144
+
145
+ class CustomDomain < Familia::Horreum
146
+
147
+ class_sorted_set :values, key: 'onetime:customdomain:values'
148
+
149
+ identifier :derive_id
150
+
151
+ field :display_domain
152
+ field :custid
153
+ field :base_domain
154
+ field :subdomain
155
+ field :trd
156
+ field :tld
157
+ field :sld
158
+ # No :key field (so we can test hte behaviour in Horreum#initialize)
159
+ field :txt_validation_host
160
+ field :txt_validation_value
161
+ field :status
162
+ field :vhost
163
+ field :verified
164
+ field :created
165
+ field :updated
166
+ field :_original_value
167
+
168
+ # Derive a unique identifier for the object based on the display domain and
169
+ # the customer ID. This is used to ensure that the same domain can't be
170
+ # added twice by the same customer while avoiding collisions between customers.
171
+ def derive_id
172
+ elements = [
173
+ display_domain,
174
+ custid
175
+ ]
176
+ Familia.generate_sha_hash(*elements).slice(0, 8)
177
+ end
178
+ end
179
+ @d = CustomDomain.new
180
+ @d.display_domain = "example.com"
181
+ @d.custid = @c.custid
182
+
183
+ class Limiter < Familia::Horreum
184
+
185
+ identifier :name
186
+ field :name
187
+ # No :key field (so we can test hte behaviour in Horreum#initialize)
188
+
189
+ string :counter, :ttl => 1.hour, :quantize => [10.minutes, '%H:%M', 1302468980]
190
+
191
+ def identifier
192
+ @name
193
+ end
194
+ end
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: 0.10.2
4
+ version: 1.0.0.pre.rc2
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-06-23 00:00:00.000000000 Z
11
+ date: 2024-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -45,47 +45,19 @@ dependencies:
45
45
  - !ruby/object:Gem::Version
46
46
  version: '1.3'
47
47
  - !ruby/object:Gem::Dependency
48
- name: gibbler
48
+ name: byebug
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
51
  - - "~>"
52
52
  - !ruby/object:Gem::Version
53
- version: 1.0.0
54
- type: :runtime
55
- prerelease: false
56
- version_requirements: !ruby/object:Gem::Requirement
57
- requirements:
58
- - - "~>"
59
- - !ruby/object:Gem::Version
60
- version: 1.0.0
61
- - !ruby/object:Gem::Dependency
62
- name: storable
63
- requirement: !ruby/object:Gem::Requirement
64
- requirements:
65
- - - "~>"
66
- - !ruby/object:Gem::Version
67
- version: 0.10.0
68
- type: :runtime
69
- prerelease: false
70
- version_requirements: !ruby/object:Gem::Requirement
71
- requirements:
72
- - - "~>"
73
- - !ruby/object:Gem::Version
74
- version: 0.10.0
75
- - !ruby/object:Gem::Dependency
76
- name: multi_json
77
- requirement: !ruby/object:Gem::Requirement
78
- requirements:
79
- - - "~>"
80
- - !ruby/object:Gem::Version
81
- version: '1.15'
82
- type: :runtime
53
+ version: '11.0'
54
+ type: :development
83
55
  prerelease: false
84
56
  version_requirements: !ruby/object:Gem::Requirement
85
57
  requirements:
86
58
  - - "~>"
87
59
  - !ruby/object:Gem::Version
88
- version: '1.15'
60
+ version: '11.0'
89
61
  description: 'Familia: An ORM for Redis in Ruby.. Organize and store ruby objects
90
62
  in Redis'
91
63
  email: gems@solutious.com
@@ -96,6 +68,8 @@ files:
96
68
  - ".github/workflows/ruby.yml"
97
69
  - ".gitignore"
98
70
  - ".pre-commit-config.yaml"
71
+ - ".rubocop.yml"
72
+ - ".rubocop_todo.yml"
99
73
  - Gemfile
100
74
  - Gemfile.lock
101
75
  - LICENSE.txt
@@ -103,26 +77,56 @@ files:
103
77
  - VERSION.yml
104
78
  - familia.gemspec
105
79
  - lib/familia.rb
80
+ - lib/familia/base.rb
81
+ - lib/familia/connection.rb
106
82
  - lib/familia/core_ext.rb
107
- - lib/familia/helpers.rb
108
- - lib/familia/object.rb
109
- - lib/familia/redisobject.rb
110
- - lib/familia/test_helpers.rb
111
- - lib/familia/tools.rb
83
+ - lib/familia/errors.rb
84
+ - lib/familia/features.rb
85
+ - lib/familia/features/api_version.rb
86
+ - lib/familia/features/atomic_saves.rb
87
+ - lib/familia/features/quantizer.rb
88
+ - lib/familia/features/safe_dump.rb
89
+ - lib/familia/horreum.rb
90
+ - lib/familia/horreum/class_methods.rb
91
+ - lib/familia/horreum/commands.rb
92
+ - lib/familia/horreum/relations_management.rb
93
+ - lib/familia/horreum/serialization.rb
94
+ - lib/familia/horreum/settings.rb
95
+ - lib/familia/horreum/utils.rb
96
+ - lib/familia/logging.rb
97
+ - lib/familia/redistype.rb
98
+ - lib/familia/redistype/commands.rb
99
+ - lib/familia/redistype/serialization.rb
100
+ - lib/familia/refinements.rb
101
+ - lib/familia/settings.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
+ - lib/familia/utils.rb
108
+ - lib/familia/version.rb
109
+ - lib/redis_middleware.rb
112
110
  - try/00_familia_try.rb
113
111
  - try/10_familia_try.rb
114
- - try/20_redis_object_try.rb
115
- - try/21_redis_object_zset_try.rb
116
- - try/22_redis_object_set_try.rb
117
- - try/23_redis_object_list_try.rb
118
- - try/24_redis_object_string_try.rb
119
- - try/25_redis_object_hash_try.rb
112
+ - try/20_redis_type_try.rb
113
+ - try/21_redis_type_zset_try.rb
114
+ - try/22_redis_type_set_try.rb
115
+ - try/23_redis_type_list_try.rb
116
+ - try/24_redis_type_string_try.rb
117
+ - try/25_redis_type_hash_try.rb
120
118
  - try/26_redis_bool_try.rb
119
+ - try/27_redis_horreum_try.rb
121
120
  - try/30_familia_object_try.rb
121
+ - try/35_feature_safedump_try.rb
122
+ - try/40_customer_try.rb
123
+ - try/41_customer_safedump_try.rb
124
+ - try/test_helpers.rb
122
125
  homepage: https://github.com/delano/familia
123
126
  licenses:
124
127
  - MIT
125
- metadata: {}
128
+ metadata:
129
+ rubygems_mfa_required: 'true'
126
130
  post_install_message:
127
131
  rdoc_options: []
128
132
  require_paths:
@@ -138,7 +142,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
138
142
  - !ruby/object:Gem::Version
139
143
  version: '0'
140
144
  requirements: []
141
- rubygems_version: 3.5.9
145
+ rubygems_version: 3.5.15
142
146
  signing_key:
143
147
  specification_version: 4
144
148
  summary: An ORM for Redis in Ruby.
@@ -1,70 +0,0 @@
1
-
2
- module Familia
3
- #
4
- # class Example
5
- # include Familia
6
- # field :name
7
- # include Familia::Stamps
8
- # end
9
- #
10
- module Stamps
11
- def self.included(obj)
12
- obj.module_eval do
13
- field :created => Integer
14
- field :updated => Integer
15
- def init_stamps
16
- now = Time.now.utc.to_i
17
- @created ||= now
18
- @updated ||= now
19
- end
20
- def created
21
- @created ||= Time.now.utc.to_i
22
- end
23
- def updated
24
- @updated ||= Time.now.utc.to_i
25
- end
26
- def created_age
27
- Time.now.utc.to_i-created
28
- end
29
- def updated_age
30
- Time.now.utc.to_i-updated
31
- end
32
- def update_time
33
- @updated = Time.now.utc.to_i
34
- end
35
- def update_time!
36
- update_time
37
- save if respond_to? :save
38
- @updated
39
- end
40
- end
41
- end
42
- end
43
- module Status
44
- def self.included(obj)
45
- obj.module_eval do
46
- field :status
47
- field :message
48
- def failure?() status? 'failure' end
49
- def success?() status? 'success' end
50
- def pending?() status? 'pending' end
51
- def expired?() status? 'expired' end
52
- def disabled?() status? 'disabled' end
53
- def failure!(msg=nil) status! 'failure', msg end
54
- def success!(msg=nil) status! 'success', msg end
55
- def pending!(msg=nil) status! 'pending', msg end
56
- def expired!(msg=nil) status! 'expired', msg end
57
- def disabled!(msg=nil) status! 'disabled', msg end
58
- private
59
- def status?(s)
60
- status.to_s == s.to_s
61
- end
62
- def status!(s, msg=nil)
63
- @updated = Time.now.utc.to_f
64
- @status, @message = s, msg
65
- save if respond_to? :save
66
- end
67
- end
68
- end
69
- end
70
- end