redis_object 1.4.9 → 1.5.0

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 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: