redis_object 1.4.9 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b9ccf1c938d105fd4c5de98d24c25a6009d56939
4
- data.tar.gz: 3b51f8681e54015ab02aba99fdc998402adb592d
3
+ metadata.gz: 24c6d1f461aa94f27fe6c79750dc3e1b1fcb8120
4
+ data.tar.gz: b6739ea7fde6bff76edbed5377882cfe196c46ff
5
5
  SHA512:
6
- metadata.gz: 07e05812157992cb885463dc32ee8e7567c6557dbf899938d5830938e8d5a9af2413cdeb7aa982bdfcb3cd198b4e9269bd27c195aaa3f8303f940d57d85e2a16
7
- data.tar.gz: d64f93d5c17ac8373576ab43b01fc5d2f240a645dff175e8d52e594e69a97970f207bf7aa10547e69e8dcbf80821e33153650e630b03d25c4ad8b0fc5bdfbc18
6
+ metadata.gz: b4cada8b2e40e5391667c19ae39ce4f7e1131a0e59951bb6d0c665212b78781493d878cb034c60ced5751da3c4d6e7b5bce0c4b86bf7e73dc11f425e9208ba1c
7
+ data.tar.gz: 995c5f452bc853e98e59f5791b345830d0af7b38d8a09266a83ee9234b12afe53d739744a5c307358232277b523e1a31c6c89151bedbf98f1221b2e56eacb716
data/.travis.yml CHANGED
@@ -1,9 +1,8 @@
1
1
  language: ruby
2
+ services:
3
+ - redis-server
2
4
  rvm:
3
5
  - 1.9.3
4
6
  - 2.0.0
5
7
  env:
6
- - "TEST_DB=14"
7
- addons:
8
- code_climate:
9
- repo_token: "8b629930bc603ff8abbbe21d72914c991d265959abdd284a638e9d8366e9ade5"
8
+ - "TEST_DB=14"
data/Gemfile CHANGED
@@ -3,9 +3,8 @@ source "http://rubygems.org"
3
3
  group :test do
4
4
  gem 'rake'
5
5
  gem 'rspec'
6
- gem 'coveralls', require: false
7
6
  gem 'fuubar'
8
- gem "codeclimate-test-reporter", require: nil
7
+ gem 'simplecov'
9
8
  end
10
9
 
11
10
  group :development, :test do
data/README.markdown CHANGED
@@ -3,9 +3,6 @@ RedisObject is a fast and simple-to-use object persistence layer for Ruby.
3
3
 
4
4
  [![Gem Version](https://badge.fury.io/rb/redis_object.png)](https://rubygems.org/gems/redis_object)
5
5
  [![Build Status](https://travis-ci.org/remotezygote/RedisObject.png?branch=master)](https://travis-ci.org/remotezygote/RedisObject)
6
- [![Coverage Status](https://coveralls.io/repos/remotezygote/RedisObject/badge.png?branch=master)](https://coveralls.io/r/remotezygote/RedisObject?branch=master)
7
- [![Code Climate](https://codeclimate.com/github/remotezygote/RedisObject.png)](https://codeclimate.com/github/remotezygote/RedisObject)
8
- [![Dependency Status](https://gemnasium.com/remotezygote/RedisObject.png)](https://gemnasium.com/remotezygote/RedisObject)
9
6
 
10
7
  ## Prerequisites
11
8
  You'll need [Redis](http://redis.io). Other storage adapters are in the works. Maybe.
data/lib/redis_object.rb CHANGED
@@ -8,6 +8,7 @@ require "redis_object/ext/list_enumerator"
8
8
 
9
9
  require "redis_object/ext/script_cache"
10
10
  require "redis_object/base"
11
+ require "redis_object/matchers"
11
12
  require "redis_object/inheritance_tracking"
12
13
  require "redis_object/storage"
13
14
  require "redis_object/keys"
@@ -28,6 +29,7 @@ module Seabright
28
29
 
29
30
  include Seabright::Filters
30
31
  include Seabright::ObjectBase
32
+ include Seabright::Matchers
31
33
  include Seabright::InheritanceTracking
32
34
  include Seabright::CachedScripts
33
35
  include Seabright::Storage
@@ -278,231 +278,6 @@ module Seabright
278
278
  end
279
279
  end
280
280
 
281
- NilPattern = 'nilpattern:'
282
-
283
- RedisObject::ScriptSources::Matcher = "local itms = redis.call('SMEMBERS',KEYS[1])
284
- local out = {}
285
- local val
286
- local pattern
287
- for i, v in ipairs(itms) do
288
- val = redis.call('HGET',v..'_h',ARGV[1])
289
- if val then
290
- if ARGV[2]:find('^pattern:') then
291
- pattern = ARGV[2]:gsub('^pattern:','')
292
- if val:match(pattern) then
293
- table.insert(out,itms[i])
294
- end
295
- elseif ARGV[2]:find('^ipattern:') then
296
- pattern = ARGV[2]:gsub('^ipattern:',''):lower()
297
- if val:lower():match(pattern) then
298
- table.insert(out,itms[i])
299
- end
300
- else
301
- if val == ARGV[2] then
302
- table.insert(out,itms[i])
303
- end
304
- end
305
- else
306
- if ARGV[2] == '#{NilPattern}' then
307
- table.insert(out,itms[i])
308
- end
309
- end
310
- end
311
- return out".gsub(/\t/,'').freeze
312
-
313
- RedisObject::ScriptSources::MultiMatcher = "local itms = redis.call('SMEMBERS',KEYS[1])
314
- local out = {}
315
- local matchers = {}
316
- local matcher = {}
317
- local mod
318
- for i=1,#ARGV do
319
- mod = i % 2
320
- if mod == 1 then
321
- matcher[1] = ARGV[i]
322
- else
323
- matcher[2] = ARGV[i]
324
- table.insert(matchers,matcher)
325
- matcher = {}
326
- end
327
- end
328
- local val
329
- local good
330
- local pattern
331
- for i, v in ipairs(itms) do
332
- good = true
333
- for n=1,#matchers do
334
- val = redis.call('HGET',v..'_h',matchers[n][1])
335
- if val then
336
- if matchers[n][2]:find('^pattern:') then
337
- pattern = matchers[n][2]:gsub('^pattern:','')
338
- if val:match(pattern) then
339
- good = good
340
- else
341
- good = false
342
- break
343
- end
344
- elseif matchers[n][2]:find('^ipattern:') then
345
- pattern = matchers[n][2]:gsub('^ipattern:',''):lower()
346
- if val:lower():match(pattern) then
347
- good = good
348
- else
349
- good = false
350
- break
351
- end
352
- else
353
- if val ~= matchers[n][2] then
354
- good = false
355
- break
356
- end
357
- end
358
- else
359
- if matchers[n][2] == '#{NilPattern}' then
360
- good = good
361
- else
362
- good = false
363
- break
364
- end
365
- end
366
- end
367
- if good == true then
368
- table.insert(out,itms[i])
369
- end
370
- end
371
- return out".gsub(/\t/,'').freeze
372
-
373
- RedisObject::ScriptSources::OrMatcher = "local itms = redis.call('SMEMBERS',KEYS[1])
374
- local out = {}
375
- local matchers = {}
376
- local matcher = {}
377
- local mod
378
- for i=1,#ARGV do
379
- mod = i % 2
380
- if mod == 1 then
381
- matcher[1] = ARGV[i]
382
- else
383
- matcher[2] = ARGV[i]
384
- table.insert(matchers,matcher)
385
- matcher = {}
386
- end
387
- end
388
-
389
- local val
390
- local good
391
- local pattern
392
- for i, v in ipairs(itms) do
393
- good = false
394
- for n=1,#matchers do
395
- val = redis.call('HGET',v..'_h',matchers[n][1])
396
- if val then
397
- if matchers[n][2]:find('^pattern:') then
398
- pattern = matchers[n][2]:gsub('^pattern:','')
399
- if val:match(pattern) then
400
- good = true
401
- break
402
- else
403
- good = good
404
- end
405
- elseif matchers[n][2]:find('^ipattern:') then
406
- pattern = matchers[n][2]:gsub('^ipattern:',''):lower()
407
- if val:lower():match(pattern) then
408
- good = true
409
- break
410
- else
411
- good = good
412
- end
413
- else
414
- if val == matchers[n][2] then
415
- good = true
416
- break
417
- end
418
- end
419
- else
420
- if matchers[n][2] == '#{NilPattern}' then
421
- good = good
422
- break
423
- else
424
- good = false
425
- end
426
- end
427
- end
428
- if good == true then
429
- table.insert(out,itms[i])
430
- end
431
- end
432
- return out".gsub(/\t/,'').freeze
433
-
434
- def match(pkt, use_or=false)
435
- if use_or
436
- mtchr = :OrMatcher
437
- else
438
- mtchr = pkt.keys.count > 1 ? :MultiMatcher : :Matcher
439
- end
440
- pkt = pkt.flatten.reduce([]) do |i,v|
441
- x = case v
442
- when Regexp
443
- convert_regex_to_lua(v)
444
- when Array
445
- raise ArgumentError.new("An array can only be used with the find_or method") unless use_or
446
- inject_key(i.last, v)
447
- when NilClass
448
- NilPattern
449
- else
450
- v.to_s
451
- end
452
- i << x
453
- i
454
- end
455
- kys = run_script(mtchr,[plname],pkt.flatten)
456
- ListEnumerator.new(kys) do |y|
457
- kys.each do |k|
458
- y << find(k)
459
- end
460
- end
461
- end
462
-
463
- def inject_key(key,list)
464
- out = []
465
- list.each do |i|
466
- if i == list.first
467
- out << i
468
- else
469
- out << key
470
- out << i
471
- end
472
- end
473
- out
474
- end
475
-
476
- def convert_regex_to_lua(reg)
477
- "#{reg.casefold? ? "i" : ""}pattern:#{reg.source.gsub("\\","")}"
478
- end
479
-
480
- def grab(ident)
481
- case ident
482
- when String, Symbol
483
- return store.exists(self.hkey(ident.to_s)) ? self.new(ident.to_s) : nil
484
- when Hash
485
- return match(ident)
486
- end
487
- nil
488
- end
489
-
490
- def or_grab(ident)
491
- case ident
492
- when Hash
493
- return match(ident, true)
494
- end
495
- nil
496
- end
497
-
498
- def find(ident)
499
- grab(ident)
500
- end
501
-
502
- def or_find(ident)
503
- or_grab(ident)
504
- end
505
-
506
281
  def exists?(k)
507
282
  store.exists(self.hkey(k)) || store.exists(self.reserve_key(k))
508
283
  end
@@ -513,14 +288,6 @@ module Seabright
513
288
  obj
514
289
  end
515
290
 
516
- # def dump
517
- # out = []
518
- # each do |obj|
519
- # out << obj.dump
520
- # end
521
- # out.join("\n")
522
- # end
523
-
524
291
  def use_dbnum(db=0)
525
292
  @dbnum = db
526
293
  end
@@ -242,7 +242,7 @@ module Seabright
242
242
  RedisObject::ScriptSources::RevScript = "redis.call('ZINTERSTORE', KEYS[1], 2, KEYS[2], KEYS[3], 'WEIGHTS', 1, 0)\nlocal keys = redis.call('ZREVRANGE', KEYS[1], 0, KEYS[4])\nredis.call('DEL', KEYS[1])\nreturn keys".freeze
243
243
 
244
244
  def keys_by_index(idx,num=-1,reverse=false)
245
- keys = run_script(reverse ? :RevScript : :FwdScript, [temp_key, index_key(idx), key, num])
245
+ keys = run_script(reverse ? :RevScript : :FwdScript, [temp_key, sort_index_key(idx), key, num])
246
246
  ListEnumerator.new(keys) do |y|
247
247
  keys.each do |member|
248
248
  y << member
@@ -250,8 +250,8 @@ module Seabright
250
250
  end
251
251
  end
252
252
 
253
- def index_key(idx)
254
- class_const.index_key(idx)
253
+ def sort_index_key(idx)
254
+ class_const.sort_index_key(idx)
255
255
  end
256
256
 
257
257
  def item_key(k)
@@ -1,4 +1,15 @@
1
1
  module Seabright
2
+
3
+ class RedisObject
4
+
5
+ def self.reindex_everything!
6
+ RedisObject.child_classes.each do |cls|
7
+ cls.reindex_all_indices!
8
+ end
9
+ end
10
+
11
+ end
12
+
2
13
  module Indices
3
14
 
4
15
  def index_key(idx)
@@ -13,13 +24,27 @@ module Seabright
13
24
 
14
25
  def indexed_set_method(meth,k,v)
15
26
  ret = send("unindexed_#{meth}".to_sym,k,v)
27
+ if self.class.has_index?(k)
28
+ set_index k, v, hkey
29
+ end
16
30
  if self.class.has_sort_index?(k)
17
- store.zrem(index_key(k), hkey)
18
- store.zadd(index_key(k), score_format(k,v), hkey)
31
+ set_sort_index k, v, hkey
19
32
  end
20
33
  ret
21
34
  end
22
35
 
36
+ def set_index(k,v,hkey)
37
+ if cur = get(k)
38
+ store.srem(self.class.index_key(k,cur), hkey)
39
+ end
40
+ store.sadd(self.class.index_key(k,v), hkey)
41
+ end
42
+
43
+ def set_sort_index(k,v,hkey)
44
+ store.zrem(self.class.sort_index_key(k), hkey)
45
+ store.zadd(self.class.sort_index_key(k), score_format(k,v), hkey)
46
+ end
47
+
23
48
  alias_method :unindexed_set, :set unless method_defined?(:unindexed_set)
24
49
  def set(k,v)
25
50
  indexed_set_method(:set,k,v)
@@ -32,12 +57,13 @@ module Seabright
32
57
 
33
58
  alias_method :unindexed_mset, :mset unless method_defined?(:unindexed_mset)
34
59
  def mset(dat)
35
- ret = unindexed_mset(dat)
60
+ dat.select {|k,v| self.class.has_index?(k) }.each do |k,v|
61
+ set_index k, v, hkey
62
+ end
36
63
  dat.select {|k,v| self.class.has_sort_index?(k) }.each do |k,v|
37
- store.zrem(index_key(k), hkey)
38
- store.zadd(index_key(k), score_format(k,v), hkey)
64
+ set_sort_index k, v, hkey
39
65
  end
40
- ret
66
+ unindexed_mset(dat)
41
67
  end
42
68
 
43
69
  end
@@ -45,7 +71,7 @@ module Seabright
45
71
  end
46
72
 
47
73
  def indexed(idx,num=-1,reverse=false)
48
- kys = store.send(reverse ? :zrevrange : :zrange, index_key(idx), 0, num-1)
74
+ kys = store.send(reverse ? :zrevrange : :zrange, sort_index_key(idx), 0, num-1)
49
75
  out = ListEnumerator.new(kys) do |yielder|
50
76
  kys.each do |member|
51
77
  if a = self.find_by_key(member)
@@ -62,12 +88,25 @@ module Seabright
62
88
  end
63
89
  end
64
90
 
65
- def index_key(idx)
91
+ def index_key(k,v)
92
+ "#{self.plname}::field_index::#{k}::#{v}"
93
+ end
94
+
95
+ def sort_index_key(idx)
66
96
  "#{self.plname}::#{idx}"
67
97
  end
68
98
 
99
+ def indices
100
+ @@indices ||= Set.new
101
+ end
102
+
69
103
  def sort_indices
70
- @@sort_indices ||= []
104
+ @@sort_indices ||= Set.new
105
+ end
106
+
107
+ def index(k)
108
+ indices << k.to_sym
109
+ intercept_sets_for_indices!
71
110
  end
72
111
 
73
112
  def sort_by(k)
@@ -76,12 +115,26 @@ module Seabright
76
115
  end
77
116
 
78
117
  def reindex(k)
79
- store.del index_key(k)
118
+ store.keys(index_key(k,"*")).each do |ik|
119
+ store.del ik
120
+ end
80
121
  all.each do |obj|
81
- obj.set(k,obj.get(k))
122
+ if v = obj.get(k)
123
+ obj.set_index(k, v, obj.hkey)
124
+ end
125
+ end
126
+ end
127
+
128
+ def reindex_all_indices!
129
+ indices.each do |k|
130
+ reindex(k)
82
131
  end
83
132
  end
84
133
 
134
+ def has_index?(k)
135
+ k and indices.include?(k.to_sym)
136
+ end
137
+
85
138
  def has_sort_index?(k)
86
139
  k and sort_indices.include?(k.to_sym)
87
140
  end
@@ -0,0 +1,496 @@
1
+ module Seabright
2
+ module Matchers
3
+
4
+ module ClassMethods
5
+
6
+ NilPattern = 'nilpattern:'
7
+
8
+ GetKeyList = "local itms
9
+ if KEYS[2] then
10
+ itms = {}
11
+ for n=2,#KEYS do
12
+ local kys = redis.call('SMEMBERS',KEYS[n])
13
+ for k=1,#kys do
14
+ local rk
15
+ if kys[k]:match('.*_h') then
16
+ rk = kys[k]
17
+ else
18
+ rk = kys[k]..'_h'
19
+ end
20
+ table.insert(itms, rk)
21
+ end
22
+ end
23
+ else
24
+ itms = {}
25
+ local kys = redis.call('SMEMBERS',KEYS[1])
26
+ for k=1,#kys do
27
+ local rk
28
+ if kys[k]:match('.*_h') then
29
+ rk = kys[k]
30
+ else
31
+ rk = kys[k]..'_h'
32
+ end
33
+ table.insert(itms, rk)
34
+ end
35
+ end".gsub(/\t/,'').freeze
36
+
37
+ RedisObject::ScriptSources::KeyListFor = GetKeyList + "
38
+ return itms
39
+ ".gsub(/\t/,'').freeze
40
+
41
+ RedisObject::ScriptSources::Matcher = GetKeyList + "
42
+ local out = {}
43
+ local val
44
+ local pattern
45
+ for i, v in ipairs(itms) do
46
+ val = redis.call('HGET',v,ARGV[1])
47
+ if val then
48
+ if ARGV[2]:find('^pattern:') then
49
+ pattern = ARGV[2]:gsub('^pattern:','')
50
+ if val:match(pattern) then
51
+ table.insert(out,itms[i])
52
+ end
53
+ elseif ARGV[2]:find('^ipattern:') then
54
+ pattern = ARGV[2]:gsub('^ipattern:',''):lower()
55
+ if val:lower():match(pattern) then
56
+ table.insert(out,itms[i])
57
+ end
58
+ else
59
+ if val == ARGV[2] then
60
+ table.insert(out,itms[i])
61
+ end
62
+ end
63
+ else
64
+ if ARGV[2] == '#{NilPattern}' then
65
+ table.insert(out,itms[i])
66
+ end
67
+ end
68
+ end
69
+ return out".gsub(/\t/,'').freeze
70
+
71
+ RedisObject::ScriptSources::MultiMatcher = GetKeyList + "
72
+ local out = {}
73
+ local matchers = {}
74
+ local matcher = {}
75
+ local mod
76
+ for i=1,#ARGV do
77
+ mod = i % 2
78
+ if mod == 1 then
79
+ matcher[1] = ARGV[i]
80
+ else
81
+ matcher[2] = ARGV[i]
82
+ table.insert(matchers,matcher)
83
+ matcher = {}
84
+ end
85
+ end
86
+ local val
87
+ local good
88
+ local pattern
89
+ for i, v in ipairs(itms) do
90
+ good = true
91
+ for n=1,#matchers do
92
+ val = redis.call('HGET',v,matchers[n][1])
93
+ if val then
94
+ if matchers[n][2]:find('^pattern:') then
95
+ pattern = matchers[n][2]:gsub('^pattern:','')
96
+ if val:match(pattern) then
97
+ good = good
98
+ else
99
+ good = false
100
+ break
101
+ end
102
+ elseif matchers[n][2]:find('^ipattern:') then
103
+ pattern = matchers[n][2]:gsub('^ipattern:',''):lower()
104
+ if val:lower():match(pattern) then
105
+ good = good
106
+ else
107
+ good = false
108
+ break
109
+ end
110
+ else
111
+ if val ~= matchers[n][2] then
112
+ good = false
113
+ break
114
+ end
115
+ end
116
+ else
117
+ if matchers[n][2] == '#{NilPattern}' then
118
+ good = good
119
+ else
120
+ good = false
121
+ break
122
+ end
123
+ end
124
+ end
125
+ if good == true then
126
+ table.insert(out,itms[i])
127
+ end
128
+ end
129
+ return out".gsub(/\t/,'').freeze
130
+
131
+ RedisObject::ScriptSources::OrMatcher = GetKeyList + "
132
+ local out = {}
133
+ local matchers = {}
134
+ local matcher = {}
135
+ local mod
136
+ for i=1,#ARGV do
137
+ mod = i % 2
138
+ if mod == 1 then
139
+ matcher[1] = ARGV[i]
140
+ else
141
+ matcher[2] = ARGV[i]
142
+ table.insert(matchers,matcher)
143
+ matcher = {}
144
+ end
145
+ end
146
+
147
+ local val
148
+ local good
149
+ local pattern
150
+ for i, v in ipairs(itms) do
151
+ good = false
152
+ for n=1,#matchers do
153
+ val = redis.call('HGET',v,matchers[n][1])
154
+ if val then
155
+ if matchers[n][2]:find('^pattern:') then
156
+ pattern = matchers[n][2]:gsub('^pattern:','')
157
+ if val:match(pattern) then
158
+ good = true
159
+ break
160
+ else
161
+ good = good
162
+ end
163
+ elseif matchers[n][2]:find('^ipattern:') then
164
+ pattern = matchers[n][2]:gsub('^ipattern:',''):lower()
165
+ if val:lower():match(pattern) then
166
+ good = true
167
+ break
168
+ else
169
+ good = good
170
+ end
171
+ else
172
+ if val == matchers[n][2] then
173
+ good = true
174
+ break
175
+ end
176
+ end
177
+ else
178
+ if matchers[n][2] == '#{NilPattern}' then
179
+ good = good
180
+ break
181
+ else
182
+ good = false
183
+ end
184
+ end
185
+ end
186
+ if good == true then
187
+ table.insert(out,itms[i])
188
+ end
189
+ end
190
+ return out".gsub(/\t/,'').freeze
191
+
192
+ def match(pkt, use_or=false)
193
+ if use_or
194
+ mtchr = :OrMatcher
195
+ else
196
+ mtchr = pkt.keys.count > 1 ? :MultiMatcher : :Matcher
197
+ end
198
+ if (ids = pkt[id_sym] || pkt[id_sym.to_s]) and !ids.is_a?(Regexp)
199
+ return match_by_id(ids, pkt, use_or)
200
+ end
201
+ indcs = [plname] + extract_usable_indices(pkt)
202
+ pkt = pkt.flatten.reduce([]) do |i,v|
203
+ x = case v
204
+ when Regexp
205
+ convert_regex_to_lua(v)
206
+ when Array
207
+ raise ArgumentError.new("An array can only be used with the find_or method") unless use_or
208
+ inject_key(i.last, v)
209
+ when NilClass
210
+ NilPattern
211
+ else
212
+ v.to_s
213
+ end
214
+ i << x
215
+ i
216
+ end
217
+ kys = run_script(mtchr, indcs, pkt.flatten)
218
+ ListEnumerator.new(kys) do |y|
219
+ kys.each do |k|
220
+ y << find(k)
221
+ end
222
+ end
223
+ end
224
+
225
+ RedisObject::ScriptSources::FirstMatcher = GetKeyList + "
226
+ local val
227
+ local pattern
228
+ for i, v in ipairs(itms) do
229
+ val = redis.call('HGET',v,ARGV[1])
230
+ if val then
231
+ if ARGV[2]:find('^pattern:') then
232
+ pattern = ARGV[2]:gsub('^pattern:','')
233
+ if val:match(pattern) then
234
+ return itms[i]
235
+ end
236
+ elseif ARGV[2]:find('^ipattern:') then
237
+ pattern = ARGV[2]:gsub('^ipattern:',''):lower()
238
+ if val:lower():match(pattern) then
239
+ return itms[i]
240
+ end
241
+ else
242
+ if val == ARGV[2] then
243
+ return itms[i]
244
+ end
245
+ end
246
+ else
247
+ if ARGV[2] == '#{NilPattern}' then
248
+ return itms[i]
249
+ end
250
+ end
251
+ end
252
+ return ''".gsub(/\t/,'').freeze
253
+
254
+ RedisObject::ScriptSources::FirstMultiMatcher = GetKeyList + "
255
+ local matchers = {}
256
+ local matcher = {}
257
+ local mod
258
+ for i=1,#ARGV do
259
+ mod = i % 2
260
+ if mod == 1 then
261
+ matcher[1] = ARGV[i]
262
+ else
263
+ matcher[2] = ARGV[i]
264
+ table.insert(matchers,matcher)
265
+ matcher = {}
266
+ end
267
+ end
268
+ local val
269
+ local good
270
+ local pattern
271
+ for i, v in ipairs(itms) do
272
+ good = true
273
+ for n=1,#matchers do
274
+ val = redis.call('HGET',v,matchers[n][1])
275
+ if val then
276
+ if matchers[n][2]:find('^pattern:') then
277
+ pattern = matchers[n][2]:gsub('^pattern:','')
278
+ if val:match(pattern) then
279
+ good = good
280
+ else
281
+ good = false
282
+ break
283
+ end
284
+ elseif matchers[n][2]:find('^ipattern:') then
285
+ pattern = matchers[n][2]:gsub('^ipattern:',''):lower()
286
+ if val:lower():match(pattern) then
287
+ good = good
288
+ else
289
+ good = false
290
+ break
291
+ end
292
+ else
293
+ if val ~= matchers[n][2] then
294
+ good = false
295
+ break
296
+ end
297
+ end
298
+ else
299
+ if matchers[n][2] == '#{NilPattern}' then
300
+ good = good
301
+ else
302
+ good = false
303
+ break
304
+ end
305
+ end
306
+ end
307
+ if good == true then
308
+ return itms[i]
309
+ end
310
+ end
311
+ return ''".gsub(/\t/,'').freeze
312
+
313
+ RedisObject::ScriptSources::FirstOrMatcher = GetKeyList + "
314
+ local matchers = {}
315
+ local matcher = {}
316
+ local mod
317
+ for i=1,#ARGV do
318
+ mod = i % 2
319
+ if mod == 1 then
320
+ matcher[1] = ARGV[i]
321
+ else
322
+ matcher[2] = ARGV[i]
323
+ table.insert(matchers,matcher)
324
+ matcher = {}
325
+ end
326
+ end
327
+
328
+ local val
329
+ local good
330
+ local pattern
331
+ for i, v in ipairs(itms) do
332
+ good = false
333
+ for n=1,#matchers do
334
+ val = redis.call('HGET',v,matchers[n][1])
335
+ if val then
336
+ if matchers[n][2]:find('^pattern:') then
337
+ pattern = matchers[n][2]:gsub('^pattern:','')
338
+ if val:match(pattern) then
339
+ good = true
340
+ break
341
+ else
342
+ good = good
343
+ end
344
+ elseif matchers[n][2]:find('^ipattern:') then
345
+ pattern = matchers[n][2]:gsub('^ipattern:',''):lower()
346
+ if val:lower():match(pattern) then
347
+ good = true
348
+ break
349
+ else
350
+ good = good
351
+ end
352
+ else
353
+ if val == matchers[n][2] then
354
+ good = true
355
+ break
356
+ end
357
+ end
358
+ else
359
+ if matchers[n][2] == '#{NilPattern}' then
360
+ good = good
361
+ break
362
+ else
363
+ good = false
364
+ end
365
+ end
366
+ end
367
+ if good == true then
368
+ return itms[i]
369
+ end
370
+ end
371
+ return ''".gsub(/\t/,'').freeze
372
+
373
+ def extract_usable_indices(pkt)
374
+ pkt.inject([]) do |acc,(k,v)|
375
+ if self.has_index?(k)
376
+ acc << index_key(k,v)
377
+ end
378
+ acc
379
+ end
380
+ end
381
+
382
+ def match_by_id(ids, pkt, use_or = false)
383
+ case ids
384
+ when Array
385
+ raise ArgumentError.new("An array can only be used with the or_find_first method") unless use_or
386
+ ids.map do |i|
387
+ match_by_id(i, pkt, use_or)
388
+ end.flatten
389
+ when String, Symbol
390
+ if obj = find(ids)
391
+ pkt.each do |k,v|
392
+ case v
393
+ when Regexp
394
+ return nil unless v.match(obj.get(k))
395
+ when Array
396
+ raise ArgumentError.new("An array can only be used with the or_find_first method") unless use_or
397
+ return nil unless v.any? { |val| obj.get(k) == v }
398
+ when String, Symbol
399
+ return nil unless obj.get(k) == v
400
+ when NilClass
401
+ return nil unless obj.get(k) == nil
402
+ end
403
+ end
404
+ end
405
+ [obj]
406
+ end
407
+ end
408
+
409
+ def match_first(pkt, use_or=false)
410
+ if use_or
411
+ mtchr = :FirstOrMatcher
412
+ else
413
+ mtchr = pkt.keys.count > 1 ? :FirstMultiMatcher : :FirstMatcher
414
+ end
415
+ if (ids = pkt[id_sym] || pkt[id_sym.to_s]) and !ids.is_a?(Regexp)
416
+ return match_by_id(ids, pkt, use_or).first
417
+ end
418
+ indcs = [plname] + extract_usable_indices(pkt)
419
+ pkt = pkt.flatten.reduce([]) do |i,v|
420
+ x = case v
421
+ when Regexp
422
+ convert_regex_to_lua(v)
423
+ when Array
424
+ raise ArgumentError.new("An array can only be used with the or_find_first method") unless use_or
425
+ inject_key(i.last, v)
426
+ when NilClass
427
+ NilPattern
428
+ else
429
+ v.to_s
430
+ end
431
+ i << x
432
+ i
433
+ end
434
+ find_by_key(run_script(mtchr,indcs, pkt.flatten))
435
+ end
436
+
437
+ def inject_key(key,list)
438
+ out = []
439
+ list.each do |i|
440
+ if i == list.first
441
+ out << i
442
+ else
443
+ out << key
444
+ out << i
445
+ end
446
+ end
447
+ out
448
+ end
449
+
450
+ def convert_regex_to_lua(reg)
451
+ "#{reg.casefold? ? "i" : ""}pattern:#{reg.source.gsub("\\","")}"
452
+ end
453
+
454
+ def grab(ident)
455
+ case ident
456
+ when String, Symbol
457
+ return store.exists(self.hkey(ident.to_s)) ? self.new(ident.to_s) : nil
458
+ when Hash
459
+ return match(ident)
460
+ end
461
+ nil
462
+ end
463
+
464
+ def or_grab(ident)
465
+ case ident
466
+ when Hash
467
+ return match(ident, true)
468
+ end
469
+ nil
470
+ end
471
+
472
+ def find(ident)
473
+ grab(ident)
474
+ end
475
+
476
+ def find_first(ident)
477
+ match_first(ident)
478
+ end
479
+
480
+ def or_find(ident)
481
+ or_grab(ident)
482
+ end
483
+
484
+ def or_find_first(ident)
485
+ match_first(ident)
486
+ end
487
+
488
+ end
489
+
490
+ def self.included(base)
491
+ base.extend(ClassMethods)
492
+ end
493
+
494
+ end
495
+ end
496
+
@@ -1,5 +1,5 @@
1
1
  module Seabright
2
2
  class RedisObject
3
- VERSION = "1.4.9"
3
+ VERSION = "1.5.0"
4
4
  end
5
5
  end
@@ -22,7 +22,6 @@ module BenchmarkSpec
22
22
  end
23
23
 
24
24
  def aggregate
25
- sleep 0.1
26
25
  42.7
27
26
  end
28
27
  benchmark :aggregate
data/spec/indices_spec.rb CHANGED
@@ -15,8 +15,7 @@ module IndexSpec
15
15
 
16
16
  TestData = TestValues.inject({}){|acc,(k,v)| acc["a_#{k}".to_sym] = v; acc }
17
17
 
18
- # Delicious pizza!
19
- class IndexedObject < RedisObject
18
+ class SortedObject < RedisObject
20
19
 
21
20
  TestValues.keys.each do |type|
22
21
  send(type.to_sym,"a_#{type}".to_sym)
@@ -27,23 +26,60 @@ module IndexSpec
27
26
 
28
27
  end
29
28
 
29
+ class IndexedObject < RedisObject
30
+
31
+ index :some_text
32
+
33
+ end
34
+
30
35
  describe Seabright::Indices do
36
+
31
37
  before do
32
38
  RedisObject.store.flushdb
33
39
  end
34
40
 
35
- it "indexes on integer field" do
41
+ it "sorts on integer field" do
36
42
 
37
43
  5.times do
38
- obj = IndexedObject.create(a_number: Random.rand(100), a_bool: true)
44
+ obj = SortedObject.create(a_number: Random.rand(100), a_bool: true)
39
45
  end
40
46
 
41
- IndexedObject.indexed(:a_number,3,true).count.should eq(3)
42
- IndexedObject.indexed(:a_number,3,true) do |o|
43
- o.should be_a(IndexedObject)
47
+ SortedObject.indexed(:a_number,3,true).count.should eq(3)
48
+ SortedObject.indexed(:a_number,3,true) do |o|
49
+ o.should be_a(SortedObject)
44
50
  end
45
51
 
46
52
  end
47
53
 
54
+ it "indexes on string field" do
55
+
56
+ cnt = 0
57
+ 5.times do
58
+ obj = IndexedObject.create(some_text: "a" + cnt.to_s)
59
+ cnt += 1
60
+ end
61
+
62
+ IndexedObject.find_first(some_text: "a0").should be_a(IndexedObject)
63
+ IndexedObject.find_first(some_text: "a4").should be_a(IndexedObject)
64
+ IndexedObject.find_first(some_text: "a5").should eq(nil)
65
+
66
+ IndexedObject.reindex_all_indices!
67
+
68
+ IndexedObject.find_first(some_text: "a0").should be_a(IndexedObject)
69
+ IndexedObject.find_first(some_text: "a4").should be_a(IndexedObject)
70
+ IndexedObject.find_first(some_text: "a5").should eq(nil)
71
+
72
+ RedisObject.reindex_everything!
73
+
74
+ IndexedObject.find_first(some_text: "a0").should be_a(IndexedObject)
75
+ IndexedObject.find_first(some_text: "a4").should be_a(IndexedObject)
76
+ IndexedObject.find_first(some_text: "a5").should eq(nil)
77
+
78
+ # IndexedObject.indexed(:a_number,3,true) do |o|
79
+ # o.should be_a(IndexedObject)
80
+ # end
81
+
82
+ end
83
+
48
84
  end
49
85
  end
data/spec/spec_helper.rb CHANGED
@@ -6,15 +6,9 @@ require 'test/unit'
6
6
  require 'rspec'
7
7
 
8
8
  require 'simplecov'
9
- require 'coveralls'
10
9
 
11
- require "codeclimate-test-reporter"
12
- CodeClimate::TestReporter.start
10
+ SimpleCov.formatter = SimpleCov::Formatter::HTMLFormatter
13
11
 
14
- SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
15
- SimpleCov::Formatter::HTMLFormatter,
16
- Coveralls::SimpleCov::Formatter
17
- ]
18
12
  SimpleCov.start do
19
13
  add_filter "_spec.rb"
20
14
  # add_filter "/experimental/"
@@ -13,7 +13,6 @@ module TriggerSpec
13
13
 
14
14
  (1..5).each do |n|
15
15
  TimestampedObject.create(n.to_s)
16
- sleep Random.rand(1.0)
17
16
  end
18
17
 
19
18
  TimestampedObject.recently_created.first.id.should eq("5")
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: redis_object
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.4.9
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Bragg
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-11-14 00:00:00.000000000 Z
11
+ date: 2013-11-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: utf8_utils
@@ -116,6 +116,7 @@ files:
116
116
  - lib/redis_object/inheritance_tracking.rb
117
117
  - lib/redis_object/keys.rb
118
118
  - lib/redis_object/logger.rb
119
+ - lib/redis_object/matchers.rb
119
120
  - lib/redis_object/storage.rb
120
121
  - lib/redis_object/storage/adapter.rb
121
122
  - lib/redis_object/storage/aws.rb
@@ -149,7 +150,7 @@ files:
149
150
  - spec/timestamp_spec.rb
150
151
  - spec/trigger_spec.rb
151
152
  - spec/types_spec.rb
152
- - spec/view_caching_spec.rb
153
+ - spec/view_caching_spec_disabled.rb
153
154
  - spec/views_spec.rb
154
155
  homepage: ''
155
156
  licenses: []
@@ -192,6 +193,6 @@ test_files:
192
193
  - spec/timestamp_spec.rb
193
194
  - spec/trigger_spec.rb
194
195
  - spec/types_spec.rb
195
- - spec/view_caching_spec.rb
196
+ - spec/view_caching_spec_disabled.rb
196
197
  - spec/views_spec.rb
197
198
  has_rdoc: