redcord 0.0.1.alpha → 0.1.1
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/lib/redcord.rb +30 -2
- data/lib/redcord.rbi +0 -16
- data/lib/redcord/actions.rb +171 -40
- data/lib/redcord/attribute.rb +126 -21
- data/lib/redcord/base.rb +15 -0
- data/lib/redcord/configurations.rb +4 -0
- data/lib/redcord/logger.rb +1 -1
- data/lib/redcord/lua_script_reader.rb +16 -5
- data/lib/redcord/migration.rb +2 -0
- data/lib/redcord/migration/index.rb +57 -0
- data/lib/redcord/migration/migrator.rb +1 -1
- data/lib/redcord/migration/ttl.rb +9 -4
- data/lib/redcord/migration/version.rb +3 -0
- data/lib/redcord/railtie.rb +18 -0
- data/lib/redcord/redis.rb +200 -0
- data/lib/redcord/redis_connection.rb +38 -29
- data/lib/redcord/relation.rb +214 -38
- data/lib/redcord/serializer.rb +147 -49
- data/lib/redcord/server_scripts/create_hash.erb.lua +81 -0
- data/lib/redcord/server_scripts/delete_hash.erb.lua +17 -8
- data/lib/redcord/server_scripts/find_by_attr.erb.lua +50 -16
- data/lib/redcord/server_scripts/find_by_attr_count.erb.lua +45 -14
- data/lib/redcord/server_scripts/shared/index_helper_methods.erb.lua +45 -16
- data/lib/redcord/server_scripts/shared/lua_helper_methods.erb.lua +20 -4
- data/lib/redcord/server_scripts/shared/query_helper_methods.erb.lua +86 -14
- data/lib/redcord/server_scripts/update_hash.erb.lua +40 -26
- data/lib/redcord/tasks/redis.rake +15 -0
- data/lib/redcord/tracer.rb +48 -0
- data/lib/redcord/vacuum_helper.rb +90 -0
- metadata +13 -11
- data/lib/redcord/prepared_redis.rb +0 -18
- data/lib/redcord/server_scripts.rb +0 -78
- data/lib/redcord/server_scripts/create_hash_returning_id.erb.lua +0 -68
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 525c939f4cee5b8adbb11b0530a2b2f44f6a26a8bb1a55e4dc837d725b3f71fb
|
4
|
+
data.tar.gz: f7e1747cc025310b20ab5e8d675fefe6d951ec60c5c09056454e11c8c366008e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6e2ff5ff1008d0a9e59e02438010e78324ec86c3ce03c470f28175498c7b29fbd277f97509f59dead80e258609ed033c9d686119726553b206996c064d4c7827
|
7
|
+
data.tar.gz: bba7b07d1e6b222614667a271b25973f5d1693d2090cb533dcbbfaf092f6200cce75ce5a7cf76356277bc1d51ae5011405465caae64ad295b85faa63d016c191
|
data/lib/redcord.rb
CHANGED
@@ -1,11 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# typed: strict
|
2
|
-
module Redcord
|
3
|
-
end
|
4
4
|
|
5
5
|
require 'sorbet-runtime'
|
6
6
|
|
7
|
+
module Redcord
|
8
|
+
extend T::Sig
|
9
|
+
|
10
|
+
@@configuration_blks = T.let(
|
11
|
+
[],
|
12
|
+
T::Array[T.proc.params(arg0: T.untyped).void],
|
13
|
+
)
|
14
|
+
|
15
|
+
sig {
|
16
|
+
params(
|
17
|
+
blk: T.proc.params(arg0: T.untyped).void,
|
18
|
+
).void
|
19
|
+
}
|
20
|
+
def self.configure(&blk)
|
21
|
+
@@configuration_blks << blk
|
22
|
+
end
|
23
|
+
|
24
|
+
sig { void }
|
25
|
+
def self._after_initialize!
|
26
|
+
@@configuration_blks.each do |blk|
|
27
|
+
blk.call(Redcord::Base)
|
28
|
+
end
|
29
|
+
|
30
|
+
@@configuration_blks.clear
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
7
34
|
require 'redcord/base'
|
8
35
|
require 'redcord/migration'
|
9
36
|
require 'redcord/migration/migrator'
|
10
37
|
require 'redcord/migration/version'
|
11
38
|
require 'redcord/railtie'
|
39
|
+
require 'redcord/vacuum_helper'
|
data/lib/redcord.rbi
CHANGED
@@ -45,22 +45,6 @@ module Redcord::TTL::ClassMethods
|
|
45
45
|
include Redcord::Serializer::ClassMethods
|
46
46
|
end
|
47
47
|
|
48
|
-
module Redcord::ServerScripts
|
49
|
-
include Kernel
|
50
|
-
|
51
|
-
sig do
|
52
|
-
params(
|
53
|
-
sha: String,
|
54
|
-
keys: T::Array[T.untyped],
|
55
|
-
argv: T::Array[T.untyped],
|
56
|
-
).returns(T.untyped)
|
57
|
-
end
|
58
|
-
def evalsha(sha, keys: [], argv:[]); end
|
59
|
-
|
60
|
-
sig { returns(T::Hash[Symbol, String]) }
|
61
|
-
def redcord_server_script_shas; end
|
62
|
-
end
|
63
|
-
|
64
48
|
module Redcord::Actions::ClassMethods
|
65
49
|
include Kernel
|
66
50
|
include Redcord::RedisConnection::ClassMethods
|
data/lib/redcord/actions.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# typed: strict
|
4
|
+
|
2
5
|
require 'sorbet-coerce'
|
3
6
|
|
4
7
|
require 'redcord/relation'
|
@@ -6,9 +9,7 @@ require 'redcord/relation'
|
|
6
9
|
module Redcord
|
7
10
|
# Raised by Model.find
|
8
11
|
class RecordNotFound < StandardError; end
|
9
|
-
|
10
|
-
class AttributeNotIndexed < StandardError; end
|
11
|
-
class WrongAttributeType < TypeError; end
|
12
|
+
class InvalidAction < StandardError; end
|
12
13
|
end
|
13
14
|
|
14
15
|
module Redcord::Actions
|
@@ -24,25 +25,65 @@ module Redcord::Actions
|
|
24
25
|
module ClassMethods
|
25
26
|
extend T::Sig
|
26
27
|
|
28
|
+
sig { returns(Integer) }
|
29
|
+
def count
|
30
|
+
Redcord::Base.trace(
|
31
|
+
'redcord_actions_class_methods_count',
|
32
|
+
model_name: name,
|
33
|
+
) do
|
34
|
+
res = 0
|
35
|
+
redis.scan_each_shard("#{model_key}:id:*") { res += 1 }
|
36
|
+
res
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
27
40
|
sig { params(args: T::Hash[Symbol, T.untyped]).returns(T.untyped) }
|
28
41
|
def create!(args)
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
42
|
+
Redcord::Base.trace(
|
43
|
+
'redcord_actions_class_methods_create!',
|
44
|
+
model_name: name,
|
45
|
+
) do
|
46
|
+
self.props.keys.each { |attr_key| args[attr_key] = nil unless args.key?(attr_key) }
|
47
|
+
args[:created_at] = args[:updated_at] = Time.zone.now
|
48
|
+
instance = TypeCoerce[self].new.from(args)
|
49
|
+
id = redis.create_hash_returning_id(
|
50
|
+
model_key,
|
51
|
+
to_redis_hash(args),
|
52
|
+
ttl: _script_arg_ttl,
|
53
|
+
index_attrs: _script_arg_index_attrs,
|
54
|
+
range_index_attrs: _script_arg_range_index_attrs,
|
55
|
+
custom_index_attrs: _script_arg_custom_index_attrs,
|
56
|
+
hash_tag: instance.hash_tag,
|
57
|
+
)
|
58
|
+
instance.send(:id=, id)
|
59
|
+
instance
|
60
|
+
end
|
34
61
|
end
|
35
62
|
|
36
63
|
sig { params(id: T.untyped).returns(T.untyped) }
|
37
64
|
def find(id)
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
)
|
65
|
+
Redcord::Base.trace(
|
66
|
+
'redcord_actions_class_methods_find',
|
67
|
+
model_name: name,
|
68
|
+
) do
|
69
|
+
instance_key = "#{model_key}:id:#{id}"
|
70
|
+
args = redis.hgetall(instance_key)
|
71
|
+
if args.empty?
|
72
|
+
raise Redcord::RecordNotFound, "Couldn't find #{name} with 'id'=#{id}"
|
73
|
+
end
|
74
|
+
|
75
|
+
coerce_and_set_id(args, id)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
sig { params(args: T::Hash[Symbol, T.untyped]).returns(T.untyped) }
|
80
|
+
def find_by(args)
|
81
|
+
Redcord::Base.trace(
|
82
|
+
'redcord_actions_class_methods_find_by_args',
|
83
|
+
model_name: name,
|
84
|
+
) do
|
85
|
+
where(args).to_a.first
|
44
86
|
end
|
45
|
-
coerce_and_set_id(args, id)
|
46
87
|
end
|
47
88
|
|
48
89
|
sig { params(args: T::Hash[Symbol, T.untyped]).returns(Redcord::Relation) }
|
@@ -52,7 +93,18 @@ module Redcord::Actions
|
|
52
93
|
|
53
94
|
sig { params(id: T.untyped).returns(T::Boolean) }
|
54
95
|
def destroy(id)
|
55
|
-
|
96
|
+
Redcord::Base.trace(
|
97
|
+
'redcord_actions_class_methods_destroy',
|
98
|
+
model_name: name,
|
99
|
+
) do
|
100
|
+
redis.delete_hash(
|
101
|
+
model_key,
|
102
|
+
id,
|
103
|
+
index_attrs: _script_arg_index_attrs,
|
104
|
+
range_index_attrs: _script_arg_range_index_attrs,
|
105
|
+
custom_index_attrs: _script_arg_custom_index_attrs,
|
106
|
+
) == 1
|
107
|
+
end
|
56
108
|
end
|
57
109
|
end
|
58
110
|
|
@@ -65,45 +117,124 @@ module Redcord::Actions
|
|
65
117
|
sig { abstract.returns(T.nilable(ActiveSupport::TimeWithZone)) }
|
66
118
|
def created_at; end
|
67
119
|
|
68
|
-
sig {
|
120
|
+
sig {
|
121
|
+
abstract.params(
|
122
|
+
time: ActiveSupport::TimeWithZone,
|
123
|
+
).returns(T.nilable(ActiveSupport::TimeWithZone))
|
124
|
+
}
|
69
125
|
def created_at=(time); end
|
70
126
|
|
71
127
|
sig { abstract.returns(T.nilable(ActiveSupport::TimeWithZone)) }
|
72
128
|
def updated_at; end
|
73
129
|
|
74
|
-
sig {
|
130
|
+
sig {
|
131
|
+
abstract.params(
|
132
|
+
time: ActiveSupport::TimeWithZone,
|
133
|
+
).returns(T.nilable(ActiveSupport::TimeWithZone))
|
134
|
+
}
|
75
135
|
def updated_at=(time); end
|
76
136
|
|
77
137
|
sig { void }
|
78
138
|
def save!
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
139
|
+
Redcord::Base.trace(
|
140
|
+
'redcord_actions_instance_methods_save!',
|
141
|
+
model_name: self.class.name,
|
142
|
+
) do
|
143
|
+
self.updated_at = Time.zone.now
|
144
|
+
_id = id
|
145
|
+
if _id.nil?
|
146
|
+
serialized_instance = serialize
|
147
|
+
self.class.props.keys.each do |attr_key|
|
148
|
+
serialized_instance[attr_key.to_s] = nil unless serialized_instance.key?(attr_key.to_s)
|
149
|
+
end
|
150
|
+
self.created_at = T.must(self.updated_at)
|
151
|
+
_id = redis.create_hash_returning_id(
|
152
|
+
self.class.model_key,
|
153
|
+
self.class.to_redis_hash(serialized_instance),
|
154
|
+
ttl: self.class._script_arg_ttl,
|
155
|
+
index_attrs: self.class._script_arg_index_attrs,
|
156
|
+
range_index_attrs: self.class._script_arg_range_index_attrs,
|
157
|
+
custom_index_attrs: self.class._script_arg_custom_index_attrs,
|
158
|
+
hash_tag: hash_tag,
|
159
|
+
)
|
160
|
+
send(:id=, _id)
|
161
|
+
else
|
162
|
+
redis.update_hash(
|
163
|
+
self.class.model_key,
|
164
|
+
_id,
|
165
|
+
self.class.to_redis_hash(serialize),
|
166
|
+
ttl: self.class._script_arg_ttl,
|
167
|
+
index_attrs: self.class._script_arg_index_attrs,
|
168
|
+
range_index_attrs: self.class._script_arg_range_index_attrs,
|
169
|
+
custom_index_attrs: self.class._script_arg_custom_index_attrs,
|
170
|
+
hash_tag: hash_tag,
|
171
|
+
)
|
172
|
+
end
|
87
173
|
end
|
88
174
|
end
|
89
175
|
|
176
|
+
sig { returns(T::Boolean) }
|
177
|
+
def save
|
178
|
+
save!
|
179
|
+
|
180
|
+
true
|
181
|
+
rescue Redis::CommandError
|
182
|
+
# TODO: break down Redis::CommandError by parsing the error message
|
183
|
+
false
|
184
|
+
end
|
185
|
+
|
90
186
|
sig { params(args: T::Hash[Symbol, T.untyped]).void }
|
91
|
-
def update!(args
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
args
|
98
|
-
|
99
|
-
|
187
|
+
def update!(args)
|
188
|
+
Redcord::Base.trace(
|
189
|
+
'redcord_actions_instance_methods_update!',
|
190
|
+
model_name: self.class.name,
|
191
|
+
) do
|
192
|
+
shard_by_attr = self.class.shard_by_attribute
|
193
|
+
if args.keys.include?(shard_by_attr)
|
194
|
+
raise Redcord::InvalidAction, "Cannot update shard_by attribute #{shard_by_attr}"
|
195
|
+
end
|
196
|
+
|
197
|
+
_id = id
|
198
|
+
if _id.nil?
|
199
|
+
_set_args!(args)
|
200
|
+
save!
|
201
|
+
else
|
202
|
+
args[:updated_at] = Time.zone.now
|
203
|
+
_set_args!(args)
|
204
|
+
redis.update_hash(
|
205
|
+
self.class.model_key,
|
206
|
+
_id,
|
207
|
+
self.class.to_redis_hash(args),
|
208
|
+
ttl: self.class._script_arg_ttl,
|
209
|
+
index_attrs: self.class._script_arg_index_attrs,
|
210
|
+
range_index_attrs: self.class._script_arg_range_index_attrs,
|
211
|
+
custom_index_attrs: self.class._script_arg_custom_index_attrs,
|
212
|
+
hash_tag: hash_tag,
|
213
|
+
)
|
214
|
+
end
|
100
215
|
end
|
101
216
|
end
|
102
217
|
|
218
|
+
sig { params(args: T::Hash[Symbol, T.untyped]).returns(T::Boolean) }
|
219
|
+
def update(args)
|
220
|
+
update!(args)
|
221
|
+
|
222
|
+
true
|
223
|
+
rescue Redis::CommandError
|
224
|
+
# TODO: break down Redis::CommandError by parsing the error message
|
225
|
+
false
|
226
|
+
end
|
227
|
+
|
103
228
|
sig { returns(T::Boolean) }
|
104
229
|
def destroy
|
105
|
-
|
106
|
-
|
230
|
+
Redcord::Base.trace(
|
231
|
+
'redcord_actions_instance_methods_destroy',
|
232
|
+
model_name: self.class.name,
|
233
|
+
) do
|
234
|
+
return false if id.nil?
|
235
|
+
|
236
|
+
self.class.destroy(T.must(id))
|
237
|
+
end
|
107
238
|
end
|
108
239
|
|
109
240
|
sig { returns(String) }
|
@@ -118,14 +249,14 @@ module Redcord::Actions
|
|
118
249
|
end
|
119
250
|
end
|
120
251
|
|
121
|
-
sig { returns(T.nilable(
|
252
|
+
sig { returns(T.nilable(String)) }
|
122
253
|
def id
|
123
254
|
instance_variable_get(:@_id)
|
124
255
|
end
|
125
256
|
|
126
|
-
|
257
|
+
private
|
127
258
|
|
128
|
-
sig { params(id:
|
259
|
+
sig { params(id: String).returns(String) }
|
129
260
|
def id=(id)
|
130
261
|
instance_variable_set(:@_id, id)
|
131
262
|
end
|
data/lib/redcord/attribute.rb
CHANGED
@@ -1,19 +1,45 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# typed: strict
|
4
|
+
module Redcord
|
5
|
+
class InvalidAttribute < StandardError; end
|
6
|
+
end
|
7
|
+
|
2
8
|
module Redcord::Attribute
|
3
9
|
extend T::Sig
|
4
10
|
extend T::Helpers
|
5
11
|
|
6
|
-
# We implicitly determine what should be a range index on Redis based on Ruby
|
12
|
+
# We implicitly determine what should be a range index on Redis based on Ruby
|
13
|
+
# type.
|
7
14
|
RangeIndexType = T.type_alias {
|
8
|
-
T.any(
|
15
|
+
T.any(
|
16
|
+
Float,
|
17
|
+
Integer,
|
18
|
+
NilClass,
|
19
|
+
Numeric,
|
20
|
+
Time,
|
21
|
+
)
|
9
22
|
}
|
10
23
|
|
24
|
+
# Implicitly determine what data type can be a used in custom index on Redis based on Ruby type.
|
25
|
+
# Custom index currently supports positive integers with up to 19 characters in decimal notation,
|
26
|
+
# will raise error in Lua if bigger numbers are used.
|
27
|
+
CustomIndexType = T.type_alias {
|
28
|
+
T.any(
|
29
|
+
Integer,
|
30
|
+
Time,
|
31
|
+
)
|
32
|
+
}
|
33
|
+
|
11
34
|
sig { params(klass: T.class_of(T::Struct)).void }
|
12
35
|
def self.included(klass)
|
13
36
|
klass.extend(ClassMethods)
|
37
|
+
klass.include(InstanceMethods)
|
14
38
|
klass.class_variable_set(:@@index_attributes, Set.new)
|
15
39
|
klass.class_variable_set(:@@range_index_attributes, Set.new)
|
40
|
+
klass.class_variable_set(:@@custom_index_attributes, Hash.new { |h, k| h[k] = [] })
|
16
41
|
klass.class_variable_set(:@@ttl, nil)
|
42
|
+
klass.class_variable_set(:@@shard_by_attribute, nil)
|
17
43
|
end
|
18
44
|
|
19
45
|
module ClassMethods
|
@@ -26,48 +52,127 @@ module Redcord::Attribute
|
|
26
52
|
options: T::Hash[Symbol, T.untyped],
|
27
53
|
).void
|
28
54
|
end
|
29
|
-
def attribute(name, type, options={})
|
55
|
+
def attribute(name, type, options = {})
|
30
56
|
# TODO: support uniq options
|
57
|
+
# TODO: validate types
|
31
58
|
prop(name, type)
|
32
|
-
|
33
|
-
|
34
|
-
end
|
59
|
+
|
60
|
+
index_attribute(name, type) if options[:index]
|
35
61
|
end
|
36
|
-
|
37
62
|
|
38
|
-
sig { params(attr: Symbol, type: T.any(Class,T::Types::Base)).void }
|
63
|
+
sig { params(attr: Symbol, type: T.any(Class, T::Types::Base)).void }
|
39
64
|
def index_attribute(attr, type)
|
40
65
|
if should_range_index?(type)
|
41
66
|
class_variable_get(:@@range_index_attributes) << attr
|
42
|
-
sadd_proc_on_redis_connection("range_index_attrs", attr.to_s)
|
43
67
|
else
|
44
68
|
class_variable_get(:@@index_attributes) << attr
|
45
|
-
sadd_proc_on_redis_connection("index_attrs", attr.to_s)
|
46
69
|
end
|
47
70
|
end
|
71
|
+
|
72
|
+
sig { params(index_name: Symbol, attrs: T::Array[Symbol]).void }
|
73
|
+
def custom_index(index_name, attrs)
|
74
|
+
attrs.each do |attr|
|
75
|
+
type = props[attr][:type]
|
76
|
+
if !can_custom_index?(type)
|
77
|
+
raise(Redcord::WrongAttributeType, "Custom index doesn't support '#{type}' attributes.")
|
78
|
+
end
|
79
|
+
end
|
80
|
+
shard_by_attr = class_variable_get(:@@shard_by_attribute)
|
81
|
+
if shard_by_attr and shard_by_attr != attrs.first
|
82
|
+
raise(
|
83
|
+
Redcord::CustomIndexInvalidDesign,
|
84
|
+
"shard_by attribute '#{shard_by_attr}' must be placed first in '#{index_name}' index"
|
85
|
+
)
|
86
|
+
end
|
87
|
+
class_variable_get(:@@custom_index_attributes)[index_name] = attrs
|
88
|
+
end
|
48
89
|
|
49
90
|
sig { params(duration: T.nilable(ActiveSupport::Duration)).void }
|
50
91
|
def ttl(duration)
|
51
92
|
class_variable_set(:@@ttl, duration)
|
52
93
|
end
|
53
94
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
#
|
58
|
-
|
59
|
-
|
60
|
-
|
95
|
+
def shard_by_attribute(attr=nil)
|
96
|
+
return class_variable_get(:@@shard_by_attribute) if attr.nil?
|
97
|
+
|
98
|
+
# attr must be an non-index attribute (index: false)
|
99
|
+
if class_variable_get(:@@index_attributes).include?(attr) ||
|
100
|
+
class_variable_get(:@@range_index_attributes).include?(attr)
|
101
|
+
raise Redcord::InvalidAttribute, "Cannot shard by an index attribute '#{attr}'"
|
102
|
+
end
|
103
|
+
|
104
|
+
class_variable_get(:@@custom_index_attributes).each do |index_name, attrs|
|
105
|
+
if attr != attrs.first
|
106
|
+
raise(
|
107
|
+
Redcord::CustomIndexInvalidDesign,
|
108
|
+
"shard_by attribute '#{attr}' must be placed first in '#{index_name}' index"
|
109
|
+
)
|
110
|
+
end
|
111
|
+
|
112
|
+
# Delete the shard_by_attribute since it would be a constant in the
|
113
|
+
# custom index set
|
114
|
+
attrs.shift
|
61
115
|
end
|
116
|
+
|
117
|
+
class_variable_set(:@@shard_by_attribute, attr)
|
118
|
+
end
|
119
|
+
|
120
|
+
sig { returns(Integer) }
|
121
|
+
def _script_arg_ttl
|
122
|
+
class_variable_get(:@@ttl)&.to_i || -1
|
123
|
+
end
|
124
|
+
|
125
|
+
sig { returns(T::Array[Symbol]) }
|
126
|
+
def _script_arg_index_attrs
|
127
|
+
class_variable_get(:@@index_attributes).to_a
|
128
|
+
end
|
129
|
+
|
130
|
+
sig { returns(T::Array[Symbol]) }
|
131
|
+
def _script_arg_range_index_attrs
|
132
|
+
class_variable_get(:@@range_index_attributes).to_a
|
133
|
+
end
|
134
|
+
|
135
|
+
sig { returns(T::Hash[Symbol, T::Array]) }
|
136
|
+
def _script_arg_custom_index_attrs
|
137
|
+
class_variable_get(:@@custom_index_attributes)
|
62
138
|
end
|
63
139
|
|
64
|
-
|
140
|
+
private
|
141
|
+
|
142
|
+
sig { params(type: T.any(Class, T::Types::Base)).returns(T::Boolean) }
|
65
143
|
def should_range_index?(type)
|
66
144
|
# Change Ruby raw type to Sorbet type in order to call subtype_of?
|
67
|
-
if type.is_a?(Class)
|
68
|
-
|
145
|
+
type = T::Types::Simple.new(type) if type.is_a?(Class)
|
146
|
+
|
147
|
+
type.subtype_of?(RangeIndexType)
|
148
|
+
end
|
149
|
+
|
150
|
+
sig { params(type: T.any(Class, T::Types::Base)).returns(T::Boolean) }
|
151
|
+
def can_custom_index?(type)
|
152
|
+
# Change Ruby raw type to Sorbet type in order to call subtype_of?
|
153
|
+
type = T::Types::Simple.new(type) if type.is_a?(Class)
|
154
|
+
type.subtype_of?(CustomIndexType)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
module InstanceMethods
|
159
|
+
extend T::Sig
|
160
|
+
|
161
|
+
sig { returns(T.nilable(String)) }
|
162
|
+
def hash_tag
|
163
|
+
attr = self.class.class_variable_get(:@@shard_by_attribute)
|
164
|
+
|
165
|
+
return nil if attr.nil?
|
166
|
+
|
167
|
+
# A blank hash tag would cause MOVED error in cluster mode
|
168
|
+
tag = send(attr)
|
169
|
+
default_tag = '__redcord_hash_tag_null__'
|
170
|
+
|
171
|
+
if tag == default_tag
|
172
|
+
raise Redcord::InvalidAttribute, "#{attr}=#{default_tag} conflicts with default hash_tag value"
|
69
173
|
end
|
70
|
-
|
174
|
+
|
175
|
+
"{#{tag || default_tag}}"
|
71
176
|
end
|
72
177
|
end
|
73
178
|
|