redis-record 0.0.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.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/Gemfile +11 -0
- data/Guardfile +14 -0
- data/LICENSE +22 -0
- data/README.md +29 -0
- data/Rakefile +2 -0
- data/lib/redis-record.rb +1 -0
- data/lib/redis_record.rb +29 -0
- data/lib/redis_record/base.rb +43 -0
- data/lib/redis_record/base/class_methods.rb +61 -0
- data/lib/redis_record/data_types.rb +25 -0
- data/lib/redis_record/filters.rb +33 -0
- data/lib/redis_record/redis_scope.rb +104 -0
- data/lib/redis_record/sorting.rb +30 -0
- data/lib/redis_record/version.rb +3 -0
- data/redis-record.gemspec +21 -0
- data/spec/fixtures/domain.rb +26 -0
- data/spec/lib/domain_spec.rb +40 -0
- data/spec/lib/redis_record/filters_spec.rb +48 -0
- data/spec/lib/redis_record/sorting_spec.rb +20 -0
- data/spec/lib/redis_record_spec.rb +33 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/support/redis.rb +5 -0
- metadata +124 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
source 'https://rubygems.org'
|
2
|
+
|
3
|
+
# Specify your gem's dependencies in redis_record.gemspec
|
4
|
+
gemspec
|
5
|
+
|
6
|
+
gem 'guard'
|
7
|
+
gem 'rb-inotify' if RUBY_PLATFORM.downcase.include?("linux")
|
8
|
+
gem 'rb-fsevent' if RUBY_PLATFORM.downcase.include?("darwin")
|
9
|
+
gem 'guard-bundler'
|
10
|
+
gem 'guard-rspec'
|
11
|
+
gem 'rspec'
|
data/Guardfile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
# A sample Guardfile
|
2
|
+
# More info at https://github.com/guard/guard#readme
|
3
|
+
|
4
|
+
guard 'rspec' do
|
5
|
+
watch(%r{^spec/.+_spec\.rb$})
|
6
|
+
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
|
+
watch('spec/spec_helper.rb') { "spec" }
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
guard 'bundler' do
|
12
|
+
watch('Gemfile')
|
13
|
+
watch(/^.+\.gemspec/)
|
14
|
+
end
|
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Subhash Chandra
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# RedisRecord
|
2
|
+
|
3
|
+
TODO: Write a gem description
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'redis_record'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install redis_record
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
TODO: Write usage instructions here
|
22
|
+
|
23
|
+
## Contributing
|
24
|
+
|
25
|
+
1. Fork it
|
26
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
27
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
28
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
29
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
data/lib/redis-record.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'redis_record'
|
data/lib/redis_record.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'active_attr'
|
2
|
+
require 'active_support'
|
3
|
+
require 'redis'
|
4
|
+
|
5
|
+
class RedisRecord
|
6
|
+
|
7
|
+
Dir[File.expand_path("../redis_record/**/*.rb", __FILE__)].each {|f| require f}
|
8
|
+
|
9
|
+
include ActiveAttr::Model
|
10
|
+
include DataTypes
|
11
|
+
include Base
|
12
|
+
include Sorting
|
13
|
+
include Filters
|
14
|
+
|
15
|
+
@@REDIS = nil
|
16
|
+
|
17
|
+
def self.REDIS
|
18
|
+
@@REDIS
|
19
|
+
end
|
20
|
+
def self.REDIS=(client)
|
21
|
+
@@REDIS = client
|
22
|
+
end
|
23
|
+
|
24
|
+
class_attribute :defined_sorts, :defined_filters
|
25
|
+
self.defined_sorts = {id: nil}
|
26
|
+
self.defined_filters = {}
|
27
|
+
|
28
|
+
ActiveSupport.run_load_hooks :redis_record, self
|
29
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module RedisRecord::Base
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
extend ActiveSupport::Callbacks
|
6
|
+
|
7
|
+
define_callbacks :save
|
8
|
+
define_callbacks :destroy
|
9
|
+
attr_accessor :persisted
|
10
|
+
attr_accessor :original_attributes
|
11
|
+
end
|
12
|
+
|
13
|
+
def save
|
14
|
+
success = nil
|
15
|
+
RedisRecord.REDIS.multi do
|
16
|
+
run_callbacks :save do
|
17
|
+
success = RedisRecord.REDIS.mapped_hmset(key, attributes)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
self.persisted = (success.value == "OK")
|
21
|
+
end
|
22
|
+
alias save! save
|
23
|
+
|
24
|
+
def destroy
|
25
|
+
success = nil
|
26
|
+
RedisRecord.REDIS.multi do
|
27
|
+
run_callbacks :destroy do
|
28
|
+
success = RedisRecord.REDIS.del key
|
29
|
+
end
|
30
|
+
end
|
31
|
+
success.value == 1 ? self : nil
|
32
|
+
end
|
33
|
+
alias destroy! destroy
|
34
|
+
|
35
|
+
def update_attributes(attrs)
|
36
|
+
assign_attributes attrs
|
37
|
+
save
|
38
|
+
end
|
39
|
+
|
40
|
+
def key
|
41
|
+
self.class.key(id)
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'active_support/core_ext/module/delegation'
|
2
|
+
|
3
|
+
module RedisRecord::Base
|
4
|
+
module ClassMethods
|
5
|
+
|
6
|
+
def scoped(*args)
|
7
|
+
RedisScope.new self, *args
|
8
|
+
end
|
9
|
+
|
10
|
+
delegate :filter, :sort, :min, :max, :limit, :offset, :to => :scoped
|
11
|
+
delegate :all, :each, :map, :count, :first, :last, :to => :scoped
|
12
|
+
|
13
|
+
def create(*args)
|
14
|
+
new(*args).save
|
15
|
+
end
|
16
|
+
|
17
|
+
def find(id)
|
18
|
+
find_by_key key id
|
19
|
+
end
|
20
|
+
|
21
|
+
|
22
|
+
def find_or_initialize_by_id(id)
|
23
|
+
find(id) || self.new(:id => id)
|
24
|
+
end
|
25
|
+
|
26
|
+
def create_filter(name, &block)
|
27
|
+
self.defined_filters = self.defined_filters.merge name.to_sym => block
|
28
|
+
end
|
29
|
+
|
30
|
+
def sortable(name, &block)
|
31
|
+
self.defined_sorts = self.defined_sorts.merge name.to_sym => block
|
32
|
+
end
|
33
|
+
|
34
|
+
def values_for_filter(name)
|
35
|
+
RedisRecord.REDIS.zrange filter_key('_Values', name), 0, -1
|
36
|
+
end
|
37
|
+
|
38
|
+
def meta_key(attr)
|
39
|
+
['Meta', model_name, attr].join ':'
|
40
|
+
end
|
41
|
+
|
42
|
+
def filter_key(name, value)
|
43
|
+
meta_key "Filter:#{name}:#{value}"
|
44
|
+
end
|
45
|
+
|
46
|
+
def key(id)
|
47
|
+
[model_name, id].join ':'
|
48
|
+
end
|
49
|
+
|
50
|
+
private
|
51
|
+
def find_by_key(key)
|
52
|
+
attributes = RedisRecord.REDIS.mapped_hmget(key, *attribute_names)
|
53
|
+
attributes['id'] && self.new(attributes).tap { |r|
|
54
|
+
r.persisted = true
|
55
|
+
r.original_attributes = attributes
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module RedisRecord::DataTypes
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
module ClassMethods
|
4
|
+
def create_initializer(type, klass, defaults = {})
|
5
|
+
define_singleton_method(type) do | *list, opts |
|
6
|
+
unless opts.is_a? Hash
|
7
|
+
list << opts
|
8
|
+
opts = {}
|
9
|
+
end
|
10
|
+
opts[:type] ||= klass
|
11
|
+
|
12
|
+
list.each do |attr|
|
13
|
+
attribute attr, defaults.merge(opts)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
included do
|
20
|
+
[ :integer, :string, :date ].each { |klass| create_initializer klass, klass.to_s.classify.constantize }
|
21
|
+
create_initializer(:boolean, ActiveAttr::Typecasting::Boolean) # TODO: Ugly hack
|
22
|
+
create_initializer(:datetime, DateTime)
|
23
|
+
create_initializer(:decimal, BigDecimal)
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module RedisRecord::Filters
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
set_callback :save, :after, :add_to_filter_lists
|
6
|
+
set_callback :save, :before, :remove_from_filter_lists
|
7
|
+
set_callback :destroy, :before, :remove_from_filter_lists
|
8
|
+
end
|
9
|
+
|
10
|
+
protected
|
11
|
+
def filter_key(name, block)
|
12
|
+
value = block ? block.call(self) : self.send(name)
|
13
|
+
RedisRecord.REDIS.zincrby self.class.filter_key('_Values', name), 1, value
|
14
|
+
self.class.filter_key(name, value)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def remove_from_filter_lists
|
19
|
+
return unless original_attributes
|
20
|
+
|
21
|
+
old_dog = self.class.new(original_attributes)
|
22
|
+
defined_filters.each do |name, block|
|
23
|
+
RedisRecord.REDIS.srem old_dog.filter_key(name, block), id
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def add_to_filter_lists
|
28
|
+
defined_filters.each do |name, block|
|
29
|
+
RedisRecord.REDIS.sadd filter_key(name, block), id
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
class RedisScope
|
2
|
+
DEFAULT_OPTIONS = {
|
3
|
+
offset: 0,
|
4
|
+
filters: [],
|
5
|
+
sort: :id,
|
6
|
+
min: '-inf',
|
7
|
+
max: '+inf'
|
8
|
+
}
|
9
|
+
|
10
|
+
def initialize(model, opts = {})
|
11
|
+
@model = model
|
12
|
+
@options = DEFAULT_OPTIONS.merge opts
|
13
|
+
end
|
14
|
+
|
15
|
+
# Modifiers
|
16
|
+
# always returns self
|
17
|
+
|
18
|
+
def filter(name, value=true)
|
19
|
+
raise NameError, ":#{name} isn't in the defined filters" unless @model.defined_filters.include? name
|
20
|
+
new_filters = @options[:filters] + [[name, value]]
|
21
|
+
|
22
|
+
chain_scope filters: new_filters
|
23
|
+
end
|
24
|
+
|
25
|
+
def sort(attr)
|
26
|
+
chain_scope sort: attr
|
27
|
+
end
|
28
|
+
|
29
|
+
def min(value)
|
30
|
+
chain_scope min: value
|
31
|
+
end
|
32
|
+
|
33
|
+
def max(value)
|
34
|
+
chain_scope max: value
|
35
|
+
end
|
36
|
+
|
37
|
+
def limit(n)
|
38
|
+
chain_scope limit: n
|
39
|
+
end
|
40
|
+
|
41
|
+
def offset(n)
|
42
|
+
chain_scope offset: n
|
43
|
+
end
|
44
|
+
|
45
|
+
# Executors
|
46
|
+
def count
|
47
|
+
apply_filters
|
48
|
+
total_records = RedisRecord.REDIS.zcard temp_key
|
49
|
+
|
50
|
+
remaining_records = total_records - @options[:offset]
|
51
|
+
|
52
|
+
if @options[:limit] and @options[:limit] < remaining_records
|
53
|
+
@options[:limit]
|
54
|
+
else
|
55
|
+
remaining_records
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def all
|
60
|
+
ids.map {|id| @model.find id}
|
61
|
+
end
|
62
|
+
delegate :each, :map, to: :all
|
63
|
+
delegate :as_json, to: :all
|
64
|
+
|
65
|
+
def first
|
66
|
+
limit(1).all[0]
|
67
|
+
end
|
68
|
+
|
69
|
+
def last
|
70
|
+
offset(@options[:offset] + count - 1).limit(1).all[0]
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
def chain_scope(opts = {})
|
75
|
+
self.class.new @model, @options.merge(opts)
|
76
|
+
end
|
77
|
+
|
78
|
+
def ids
|
79
|
+
apply_filters
|
80
|
+
RedisRecord.REDIS.zrangebyscore temp_key, @options[:min], @options[:max], limit: [@options[:offset], @options[:limit] || -1]
|
81
|
+
end
|
82
|
+
|
83
|
+
def apply_filters
|
84
|
+
filter_keys = @options[:filters].map do |name, value|
|
85
|
+
if value.is_a? Array
|
86
|
+
values = value
|
87
|
+
union_key = @model.filter_key "_Union:#{name}", values.join('_')
|
88
|
+
value_keys = values.map {|value| @model.filter_key name, value}
|
89
|
+
RedisRecord.REDIS.zunionstore union_key, value_keys
|
90
|
+
union_key
|
91
|
+
else
|
92
|
+
@model.filter_key name, value
|
93
|
+
end
|
94
|
+
end
|
95
|
+
key_sets = [@model.meta_key(@options[:sort])] + filter_keys
|
96
|
+
weights = [1] + [0] * @options[:filters].count
|
97
|
+
RedisRecord.REDIS.zinterstore temp_key, key_sets, weights: weights
|
98
|
+
end
|
99
|
+
|
100
|
+
def temp_key
|
101
|
+
@temp_key ||= @model.meta_key("_Temp:Filtered")
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module RedisRecord::Sorting
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
included do
|
5
|
+
set_callback :destroy, :after, :remove_from_sort_lists
|
6
|
+
set_callback :save, :after, :add_to_sort_lists
|
7
|
+
end
|
8
|
+
|
9
|
+
protected
|
10
|
+
def add_to_sort_lists
|
11
|
+
defined_sorts.each do |name, block|
|
12
|
+
score = 0
|
13
|
+
if block
|
14
|
+
if block.respond_to? :call
|
15
|
+
score = block.call self
|
16
|
+
else
|
17
|
+
score = self.send block
|
18
|
+
end
|
19
|
+
end
|
20
|
+
RedisRecord.REDIS.zadd self.class.meta_key(name), score, id
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def remove_from_sort_lists
|
25
|
+
defined_sorts.each do |name, _|
|
26
|
+
RedisRecord.REDIS.zrem self.class.meta_key(name), id
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/redis_record/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.authors = ["Subhash Chandra"]
|
6
|
+
gem.email = ["TMaYaD@LoonyB.in"]
|
7
|
+
gem.description = %q{Active model interface for redis}
|
8
|
+
gem.summary = %q{Active record like interface for redis without adding bloat}
|
9
|
+
gem.homepage = "http://github.com/loonybin/redis_record"
|
10
|
+
|
11
|
+
gem.files = `git ls-files`.split($\)
|
12
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
13
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
14
|
+
gem.name = "redis-record"
|
15
|
+
gem.require_paths = ["lib"]
|
16
|
+
gem.version = RedisRecord::VERSION
|
17
|
+
|
18
|
+
gem.add_runtime_dependency 'active_attr'
|
19
|
+
gem.add_runtime_dependency 'activesupport'
|
20
|
+
gem.add_runtime_dependency 'redis'
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Domain < RedisRecord
|
2
|
+
attr_accessible :id
|
3
|
+
attr_accessible :hidden, :liked
|
4
|
+
|
5
|
+
string :id # name
|
6
|
+
boolean :hidden, :default => false
|
7
|
+
boolean :liked, :default => false
|
8
|
+
|
9
|
+
create_filter :numbers do |domain|
|
10
|
+
!!domain.id.match(/[0-9]/)
|
11
|
+
end
|
12
|
+
create_filter :hyphenated do |domain|
|
13
|
+
!!domain.id.match(/-/)
|
14
|
+
end
|
15
|
+
create_filter :tld do |domain|
|
16
|
+
domain.id.split('.').last
|
17
|
+
end
|
18
|
+
|
19
|
+
create_filter :hidden
|
20
|
+
create_filter :liked
|
21
|
+
|
22
|
+
sortable :length do |domain|
|
23
|
+
domain.id.length
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fixtures/domain'
|
3
|
+
|
4
|
+
describe Domain do
|
5
|
+
before(:each) do
|
6
|
+
(0..4).each { |i| Domain.create id: "#{i}.com", status: 'Pre-release' }
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should return all the records" do
|
10
|
+
Domain.count.should eq 5
|
11
|
+
Domain.all.map(&:id).should eq %w[0.com 1.com 2.com 3.com 4.com]
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return only 'limit' number of records" do
|
15
|
+
Domain.limit(2).all.map(&:id).should eq %w[0.com 1.com]
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return only records starting from 'offset'" do
|
19
|
+
Domain.offset(3).all.map(&:id).should eq %w[3.com 4.com]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return only 'limit' records starting from 'offset'" do
|
23
|
+
Domain.offset(2).limit(2).all.map(&:id).should eq %w[2.com 3.com]
|
24
|
+
|
25
|
+
# in any order
|
26
|
+
Domain.limit(2).offset(2).all.map(&:id).should eq %w[2.com 3.com]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should not return more records than existing" do
|
30
|
+
Domain.offset(3).limit(3).all.map(&:id).should eq %w[3.com 4.com]
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should not display hidden records" do
|
34
|
+
Domain.first.update_attributes hidden: true
|
35
|
+
|
36
|
+
Domain.filter(:hidden, false).count.should eq 4
|
37
|
+
Domain.filter(:hidden, false).all.map(&:id).should eq %w[1.com 2.com 3.com 4.com]
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fixtures/domain'
|
3
|
+
|
4
|
+
describe Domain do
|
5
|
+
context "with filters" do
|
6
|
+
before(:each) do
|
7
|
+
('a'..'b').each { |i| Domain.create id: "#{i}.com", status: 'Pre-release' }
|
8
|
+
('5'..'6').each { |i| Domain.create id: "#{i}-.net", status: 'Pre-release' }
|
9
|
+
('a'..'b').each { |i| Domain.create id: "#{i}.org", status: 'Pre-release' }
|
10
|
+
end
|
11
|
+
|
12
|
+
it "shouldn't allow undefined filters" do
|
13
|
+
expect{Domain.filter(:blah)}.to raise_error NameError
|
14
|
+
end
|
15
|
+
|
16
|
+
it "should return only records with the given filter applied" do
|
17
|
+
Domain.filter(:numbers).all.map(&:id).should eq %w[5-.net 6-.net]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should return only records matching all the filters" do
|
21
|
+
Domain.filter(:numbers).filter(:hyphenated).all.map(&:id).should eq %w[5-.net 6-.net]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should list out all the available values for a given filter" do
|
25
|
+
Domain.values_for_filter(:tld).should eq %w[com net org]
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should return records with the filter matching a custom value" do
|
29
|
+
Domain.filter(:tld, 'net').map(&:id).should eq %w[5-.net 6-.net]
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should return records with the filter matching any of the custom values" do
|
33
|
+
Domain.filter(:tld, ['net', 'org']).map(&:id).should eq %w[5-.net 6-.net a.org b.org]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should sort and select records even when filters are applied" do
|
37
|
+
(1..4).each {|i| Domain.create id: ('a' * i), status: 'Pre-release'}
|
38
|
+
Domain.filter(:numbers, false).sort(:length).min(2).max(4).map(&:id).should eq %w[aa aaa aaaa]
|
39
|
+
end
|
40
|
+
|
41
|
+
it "should allow defining filters on attributes without block" do
|
42
|
+
Domain.first.update_attributes hidden: true
|
43
|
+
|
44
|
+
Domain.filter(:hidden, false).count.should eq 5
|
45
|
+
Domain.filter(:hidden, false).all.map(&:id).should eq %w[6-.net a.com a.org b.com b.org]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fixtures/domain'
|
3
|
+
|
4
|
+
describe Domain do
|
5
|
+
context 'with sorting' do
|
6
|
+
before(:each) do
|
7
|
+
(1..4).each {|i| Domain.create id: ('a' * i), status: 'Pre-release'}
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should sort by given attribute" do
|
11
|
+
Domain.sort(:length).map(&:id).should eq %w[a aa aaa aaaa]
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should filter for min and max on the sort" do
|
15
|
+
Domain.sort(:length).min(3).map(&:id).should eq %w[aaa aaaa]
|
16
|
+
Domain.sort(:length).max(4).map(&:id).should eq %w[a aa aaa aaaa]
|
17
|
+
Domain.sort(:length).min(2).max(4).map(&:id).should eq %w[aa aaa aaaa]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fixtures/domain'
|
3
|
+
|
4
|
+
describe Domain do
|
5
|
+
before(:each) do
|
6
|
+
(0..4).each { |i| Domain.create id: "#{i}.com" }
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should return all the records" do
|
10
|
+
Domain.count.should eq 5
|
11
|
+
Domain.all.map(&:id).should eq %w[0.com 1.com 2.com 3.com 4.com]
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should return only 'limit' number of records" do
|
15
|
+
Domain.limit(2).all.map(&:id).should eq %w[0.com 1.com]
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should return only records starting from 'offset'" do
|
19
|
+
Domain.offset(3).all.map(&:id).should eq %w[3.com 4.com]
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should return only 'limit' records starting from 'offset'" do
|
23
|
+
Domain.offset(2).limit(2).all.map(&:id).should eq %w[2.com 3.com]
|
24
|
+
|
25
|
+
# in any order
|
26
|
+
Domain.limit(2).offset(2).all.map(&:id).should eq %w[2.com 3.com]
|
27
|
+
end
|
28
|
+
|
29
|
+
it "should not return more records than existing" do
|
30
|
+
Domain.offset(3).limit(3).all.map(&:id).should eq %w[3.com 4.com]
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'redis_record'
|
2
|
+
RedisRecord.REDIS ||= Redis.new db: 2
|
3
|
+
|
4
|
+
Dir[File.expand_path("../support/**/*.rb", __FILE__)].each {|f| require f}
|
5
|
+
|
6
|
+
RSpec.configure do |config|
|
7
|
+
config.treat_symbols_as_metadata_keys_with_true_values = true
|
8
|
+
config.run_all_when_everything_filtered = true
|
9
|
+
config.filter_run :focus
|
10
|
+
|
11
|
+
# Run specs in random order to surface order dependencies. If you find an
|
12
|
+
# order dependency and want to debug it, you can fix the order by providing
|
13
|
+
# the seed, which is printed after each run.
|
14
|
+
# --seed 1234
|
15
|
+
config.order = 'random'
|
16
|
+
end
|
metadata
ADDED
@@ -0,0 +1,124 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redis-record
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Subhash Chandra
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-12-30 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: active_attr
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: activesupport
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: redis
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :runtime
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
description: Active model interface for redis
|
63
|
+
email:
|
64
|
+
- TMaYaD@LoonyB.in
|
65
|
+
executables: []
|
66
|
+
extensions: []
|
67
|
+
extra_rdoc_files: []
|
68
|
+
files:
|
69
|
+
- .gitignore
|
70
|
+
- .rspec
|
71
|
+
- Gemfile
|
72
|
+
- Guardfile
|
73
|
+
- LICENSE
|
74
|
+
- README.md
|
75
|
+
- Rakefile
|
76
|
+
- lib/redis-record.rb
|
77
|
+
- lib/redis_record.rb
|
78
|
+
- lib/redis_record/base.rb
|
79
|
+
- lib/redis_record/base/class_methods.rb
|
80
|
+
- lib/redis_record/data_types.rb
|
81
|
+
- lib/redis_record/filters.rb
|
82
|
+
- lib/redis_record/redis_scope.rb
|
83
|
+
- lib/redis_record/sorting.rb
|
84
|
+
- lib/redis_record/version.rb
|
85
|
+
- redis-record.gemspec
|
86
|
+
- spec/fixtures/domain.rb
|
87
|
+
- spec/lib/domain_spec.rb
|
88
|
+
- spec/lib/redis_record/filters_spec.rb
|
89
|
+
- spec/lib/redis_record/sorting_spec.rb
|
90
|
+
- spec/lib/redis_record_spec.rb
|
91
|
+
- spec/spec_helper.rb
|
92
|
+
- spec/support/redis.rb
|
93
|
+
homepage: http://github.com/loonybin/redis_record
|
94
|
+
licenses: []
|
95
|
+
post_install_message:
|
96
|
+
rdoc_options: []
|
97
|
+
require_paths:
|
98
|
+
- lib
|
99
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
100
|
+
none: false
|
101
|
+
requirements:
|
102
|
+
- - ! '>='
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
none: false
|
107
|
+
requirements:
|
108
|
+
- - ! '>='
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
requirements: []
|
112
|
+
rubyforge_project:
|
113
|
+
rubygems_version: 1.8.23
|
114
|
+
signing_key:
|
115
|
+
specification_version: 3
|
116
|
+
summary: Active record like interface for redis without adding bloat
|
117
|
+
test_files:
|
118
|
+
- spec/fixtures/domain.rb
|
119
|
+
- spec/lib/domain_spec.rb
|
120
|
+
- spec/lib/redis_record/filters_spec.rb
|
121
|
+
- spec/lib/redis_record/sorting_spec.rb
|
122
|
+
- spec/lib/redis_record_spec.rb
|
123
|
+
- spec/spec_helper.rb
|
124
|
+
- spec/support/redis.rb
|