modis 1.1.0 → 1.2.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 +4 -4
- data/.gitignore +0 -1
- data/.rubocop.yml +24 -0
- data/.ruby-version +1 -1
- data/.travis.yml +2 -2
- data/Gemfile +1 -0
- data/Gemfile.lock +95 -0
- data/Rakefile +5 -3
- data/lib/modis/attribute.rb +82 -0
- data/lib/modis/errors.rb +2 -0
- data/lib/modis/finder.rb +64 -0
- data/lib/modis/index.rb +92 -0
- data/lib/modis/model.rb +9 -11
- data/lib/modis/persistence.rb +79 -41
- data/lib/modis/version.rb +1 -1
- data/lib/modis.rb +5 -4
- data/lib/tasks/quality.rake +34 -0
- data/spec/attribute_spec.rb +153 -0
- data/spec/errors_spec.rb +1 -1
- data/spec/{finders_spec.rb → finder_spec.rb} +18 -19
- data/spec/index_spec.rb +84 -0
- data/spec/persistence_spec.rb +37 -37
- data/spec/spec_helper.rb +1 -1
- data/spec/support/simplecov_quality_formatter.rb +9 -5
- data/spec/transaction_spec.rb +2 -2
- data/spec/validations_spec.rb +5 -5
- metadata +14 -9
- data/lib/modis/attributes.rb +0 -138
- data/lib/modis/finders.rb +0 -48
- data/lib/tasks/spec.rake +0 -18
- data/spec/attributes_spec.rb +0 -182
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9c1496e1e5c9b430c4aa6257d4ec122d3cb1ee37
|
4
|
+
data.tar.gz: 68c023c5b84245530772181c7a2bf564ebe0712f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f77b3079fd2c210bb678b952710e188dda3eb1ae8d98d00f30b79b511671305df22a3d5863433c48c2a831bf795580afc8a6c1d6973530a0847e7a5f14cabfad
|
7
|
+
data.tar.gz: d22b018df72ac21e0bce75fba13816ecf7067b96602afae6f0d8d09321d2f24c8c194809d30bc221e543bcbc5bd4330157248eed20ac761c1560d0d647b99ddc
|
data/.gitignore
CHANGED
data/.rubocop.yml
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
AllCops:
|
2
|
+
Exclude:
|
3
|
+
- modis.gemspec
|
4
|
+
|
5
|
+
LineLength:
|
6
|
+
Enabled: false
|
7
|
+
|
8
|
+
StringLiterals:
|
9
|
+
Enabled: false
|
10
|
+
|
11
|
+
Documentation:
|
12
|
+
Enabled: false
|
13
|
+
|
14
|
+
MethodLength:
|
15
|
+
Enabled: false
|
16
|
+
|
17
|
+
ClassLength:
|
18
|
+
Enabled: false
|
19
|
+
|
20
|
+
CyclomaticComplexity:
|
21
|
+
Enabled: false
|
22
|
+
|
23
|
+
Style/SignalException:
|
24
|
+
EnforcedStyle: only_raise
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
ruby-2.1.
|
1
|
+
ruby-2.1.2
|
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/Gemfile.lock
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
modis (1.2.0)
|
5
|
+
activemodel (>= 3.0)
|
6
|
+
activesupport (>= 3.0)
|
7
|
+
connection_pool (>= 2)
|
8
|
+
redis (>= 3.0)
|
9
|
+
|
10
|
+
GEM
|
11
|
+
remote: https://rubygems.org/
|
12
|
+
specs:
|
13
|
+
activemodel (4.1.5)
|
14
|
+
activesupport (= 4.1.5)
|
15
|
+
builder (~> 3.1)
|
16
|
+
activesupport (4.1.5)
|
17
|
+
i18n (~> 0.6, >= 0.6.9)
|
18
|
+
json (~> 1.7, >= 1.7.7)
|
19
|
+
minitest (~> 5.1)
|
20
|
+
thread_safe (~> 0.1)
|
21
|
+
tzinfo (~> 1.1)
|
22
|
+
ast (2.0.0)
|
23
|
+
builder (3.2.2)
|
24
|
+
cane (2.6.2)
|
25
|
+
parallel
|
26
|
+
connection_pool (2.0.0)
|
27
|
+
coveralls (0.7.1)
|
28
|
+
multi_json (~> 1.3)
|
29
|
+
rest-client
|
30
|
+
simplecov (>= 0.7)
|
31
|
+
term-ansicolor
|
32
|
+
thor
|
33
|
+
diff-lcs (1.2.5)
|
34
|
+
docile (1.1.5)
|
35
|
+
i18n (0.6.11)
|
36
|
+
json (1.8.1)
|
37
|
+
mime-types (2.3)
|
38
|
+
minitest (5.4.1)
|
39
|
+
multi_json (1.10.1)
|
40
|
+
netrc (0.7.7)
|
41
|
+
parallel (1.3.0)
|
42
|
+
parser (2.2.0.pre.4)
|
43
|
+
ast (>= 1.1, < 3.0)
|
44
|
+
slop (~> 3.4, >= 3.4.5)
|
45
|
+
powerpack (0.0.9)
|
46
|
+
rainbow (2.0.0)
|
47
|
+
rake (10.3.2)
|
48
|
+
redis (3.1.0)
|
49
|
+
rest-client (1.7.2)
|
50
|
+
mime-types (>= 1.16, < 3.0)
|
51
|
+
netrc (~> 0.7)
|
52
|
+
rspec (3.0.0)
|
53
|
+
rspec-core (~> 3.0.0)
|
54
|
+
rspec-expectations (~> 3.0.0)
|
55
|
+
rspec-mocks (~> 3.0.0)
|
56
|
+
rspec-core (3.0.4)
|
57
|
+
rspec-support (~> 3.0.0)
|
58
|
+
rspec-expectations (3.0.4)
|
59
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
60
|
+
rspec-support (~> 3.0.0)
|
61
|
+
rspec-mocks (3.0.4)
|
62
|
+
rspec-support (~> 3.0.0)
|
63
|
+
rspec-support (3.0.4)
|
64
|
+
rubocop (0.25.0)
|
65
|
+
parser (>= 2.2.0.pre.4, < 3.0)
|
66
|
+
powerpack (~> 0.0.6)
|
67
|
+
rainbow (>= 1.99.1, < 3.0)
|
68
|
+
ruby-progressbar (~> 1.4)
|
69
|
+
ruby-progressbar (1.5.1)
|
70
|
+
simplecov (0.9.0)
|
71
|
+
docile (~> 1.1.0)
|
72
|
+
multi_json
|
73
|
+
simplecov-html (~> 0.8.0)
|
74
|
+
simplecov-html (0.8.0)
|
75
|
+
slop (3.6.0)
|
76
|
+
term-ansicolor (1.3.0)
|
77
|
+
tins (~> 1.0)
|
78
|
+
thor (0.19.1)
|
79
|
+
thread_safe (0.3.4)
|
80
|
+
tins (1.3.2)
|
81
|
+
tzinfo (1.2.2)
|
82
|
+
thread_safe (~> 0.1)
|
83
|
+
|
84
|
+
PLATFORMS
|
85
|
+
java
|
86
|
+
ruby
|
87
|
+
|
88
|
+
DEPENDENCIES
|
89
|
+
cane
|
90
|
+
coveralls
|
91
|
+
modis!
|
92
|
+
rake
|
93
|
+
rspec
|
94
|
+
rubocop
|
95
|
+
simplecov
|
data/Rakefile
CHANGED
@@ -8,8 +8,10 @@ RSpec::Core::RakeTask.new(:spec) do |spec|
|
|
8
8
|
spec.rspec_opts = ['--backtrace']
|
9
9
|
end
|
10
10
|
|
11
|
-
if
|
12
|
-
task :
|
11
|
+
if ENV['TRAVIS'] && ENV['QUALITY'] == 'false'
|
12
|
+
task default: 'spec'
|
13
|
+
elsif RUBY_VERSION > '1.9' && defined?(RUBY_ENGINE) && RUBY_ENGINE == 'ruby'
|
14
|
+
task default: 'spec:quality'
|
13
15
|
else
|
14
|
-
task :
|
16
|
+
task default: 'spec'
|
15
17
|
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module Modis
|
2
|
+
module Attribute
|
3
|
+
TYPES = [:string, :integer, :float, :timestamp, :boolean, :array, :hash]
|
4
|
+
|
5
|
+
def self.included(base)
|
6
|
+
base.extend ClassMethods
|
7
|
+
base.instance_eval do
|
8
|
+
bootstrap_attributes
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
def bootstrap_attributes
|
14
|
+
class << self
|
15
|
+
attr_accessor :attributes
|
16
|
+
end
|
17
|
+
|
18
|
+
self.attributes = {}
|
19
|
+
|
20
|
+
attribute :id, :integer
|
21
|
+
end
|
22
|
+
|
23
|
+
def attribute(name, type = :string, options = {})
|
24
|
+
name = name.to_s
|
25
|
+
raise AttributeError, "Attribute with name '#{name}' has already been specified." if attributes.key?(name)
|
26
|
+
raise UnsupportedAttributeType, type unless TYPES.include?(type)
|
27
|
+
|
28
|
+
attributes[name] = options.update(type: type)
|
29
|
+
define_attribute_methods [name]
|
30
|
+
class_eval <<-EOS, __FILE__, __LINE__
|
31
|
+
def #{name}
|
32
|
+
attributes['#{name}']
|
33
|
+
end
|
34
|
+
|
35
|
+
def #{name}=(value)
|
36
|
+
ensure_type('#{name}', value)
|
37
|
+
#{name}_will_change! unless value == attributes['#{name}']
|
38
|
+
attributes['#{name}'] = value
|
39
|
+
end
|
40
|
+
EOS
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def attributes
|
45
|
+
@attributes ||= Hash[self.class.attributes.keys.zip]
|
46
|
+
end
|
47
|
+
|
48
|
+
def assign_attributes(hash)
|
49
|
+
hash.each do |k, v|
|
50
|
+
setter = "#{k}="
|
51
|
+
send(setter, v) if respond_to?(setter)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
def write_attribute(key, value)
|
56
|
+
attributes[key.to_s] = value
|
57
|
+
end
|
58
|
+
|
59
|
+
def read_attribute(key)
|
60
|
+
attributes[key.to_s]
|
61
|
+
end
|
62
|
+
|
63
|
+
protected
|
64
|
+
|
65
|
+
def set_sti_type
|
66
|
+
return unless self.class.sti_child?
|
67
|
+
assign_attributes(type: self.class.name)
|
68
|
+
end
|
69
|
+
|
70
|
+
def reset_changes
|
71
|
+
@changed_attributes.clear if @changed_attributes
|
72
|
+
end
|
73
|
+
|
74
|
+
def apply_defaults
|
75
|
+
defaults = {}
|
76
|
+
self.class.attributes.each do |attribute, options|
|
77
|
+
defaults[attribute] = options[:default] if options[:default]
|
78
|
+
end
|
79
|
+
assign_attributes(defaults)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
data/lib/modis/errors.rb
CHANGED
data/lib/modis/finder.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Modis
|
2
|
+
module Finder
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def find(id)
|
9
|
+
Modis.with_connection do |redis|
|
10
|
+
attributes = attributes_for(redis, id)
|
11
|
+
model_for(attributes)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def all
|
16
|
+
records = []
|
17
|
+
|
18
|
+
Modis.with_connection do |redis|
|
19
|
+
ids = redis.smembers(key_for(:all))
|
20
|
+
records = redis.pipelined do
|
21
|
+
ids.map { |id| record_for(redis, id) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
records.map do |record|
|
26
|
+
attributes = record_to_attributes(record)
|
27
|
+
model_for(attributes)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def attributes_for(redis, id)
|
32
|
+
raise RecordNotFound, "Couldn't find #{name} without an ID" if id.nil?
|
33
|
+
|
34
|
+
attributes = record_to_attributes(record_for(redis, id))
|
35
|
+
|
36
|
+
unless attributes['id'].present?
|
37
|
+
raise RecordNotFound, "Couldn't find #{name} with id=#{id}"
|
38
|
+
end
|
39
|
+
|
40
|
+
attributes
|
41
|
+
end
|
42
|
+
|
43
|
+
private
|
44
|
+
|
45
|
+
def model_for(attributes)
|
46
|
+
model_class(attributes).new(attributes, new_record: false)
|
47
|
+
end
|
48
|
+
|
49
|
+
def record_to_attributes(record)
|
50
|
+
record.each { |k, v| record[k] = coerce_from_persistence(v) }
|
51
|
+
record
|
52
|
+
end
|
53
|
+
|
54
|
+
def record_for(redis, id)
|
55
|
+
redis.hgetall(key_for(id))
|
56
|
+
end
|
57
|
+
|
58
|
+
def model_class(record)
|
59
|
+
return self if record["type"].blank?
|
60
|
+
record["type"].constantize
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
data/lib/modis/index.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
module Modis
|
2
|
+
module Index
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
base.instance_eval do
|
6
|
+
bootstrap_indexes
|
7
|
+
after__internal_create :add_to_index
|
8
|
+
after__internal_update :update_index
|
9
|
+
before__internal_destroy :remove_from_index
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
module ClassMethods
|
14
|
+
def bootstrap_indexes
|
15
|
+
class << self
|
16
|
+
attr_accessor :indexed_attributes
|
17
|
+
end
|
18
|
+
|
19
|
+
self.indexed_attributes = []
|
20
|
+
end
|
21
|
+
|
22
|
+
def index(attribute)
|
23
|
+
attribute = attribute.to_s
|
24
|
+
raise IndexError, "No such attribute '#{attribute}'" unless attributes.key?(attribute)
|
25
|
+
indexed_attributes << attribute
|
26
|
+
end
|
27
|
+
|
28
|
+
def where(query)
|
29
|
+
raise IndexError, 'Queries using multiple indexes is not currently supported.' if query.keys.size > 1
|
30
|
+
attribute, value = query.first
|
31
|
+
index = index_for(attribute, value)
|
32
|
+
index.map { |id| find(id) }
|
33
|
+
end
|
34
|
+
|
35
|
+
def index_for(attribute, value)
|
36
|
+
Modis.with_connection do |redis|
|
37
|
+
key = index_key(attribute, value)
|
38
|
+
redis.smembers(key).map(&:to_i)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def index_key(attribute, value)
|
43
|
+
"#{absolute_namespace}:index:#{attribute}:#{value.inspect}"
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
private
|
48
|
+
|
49
|
+
def indexed_attributes
|
50
|
+
self.class.indexed_attributes
|
51
|
+
end
|
52
|
+
|
53
|
+
def index_key(attribute, value)
|
54
|
+
self.class.index_key(attribute, value)
|
55
|
+
end
|
56
|
+
|
57
|
+
def add_to_index
|
58
|
+
return if indexed_attributes.empty?
|
59
|
+
|
60
|
+
Modis.with_connection do |redis|
|
61
|
+
indexed_attributes.each do |attribute|
|
62
|
+
key = index_key(attribute, read_attribute(attribute))
|
63
|
+
redis.sadd(key, id)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def remove_from_index
|
69
|
+
return if indexed_attributes.empty?
|
70
|
+
|
71
|
+
Modis.with_connection do |redis|
|
72
|
+
indexed_attributes.each do |attribute|
|
73
|
+
key = index_key(attribute, read_attribute(attribute))
|
74
|
+
redis.srem(key, id)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def update_index
|
80
|
+
return if indexed_attributes.empty?
|
81
|
+
|
82
|
+
Modis.with_connection do |redis|
|
83
|
+
(changes.keys & indexed_attributes).each do |attribute|
|
84
|
+
old_value, new_value = changes[attribute]
|
85
|
+
old_key = index_key(attribute, old_value)
|
86
|
+
new_key = index_key(attribute, new_value)
|
87
|
+
redis.smove(old_key, new_key, id)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/modis/model.rb
CHANGED
@@ -9,16 +9,15 @@ module Modis
|
|
9
9
|
extend ActiveModel::Naming
|
10
10
|
extend ActiveModel::Callbacks
|
11
11
|
|
12
|
-
define_model_callbacks :save
|
13
|
-
define_model_callbacks :
|
14
|
-
define_model_callbacks :update
|
15
|
-
define_model_callbacks :destroy
|
12
|
+
define_model_callbacks :save, :create, :update, :destroy
|
13
|
+
define_model_callbacks :_internal_create, :_internal_update, :_internal_destroy
|
16
14
|
|
17
15
|
include Modis::Errors
|
18
16
|
include Modis::Transaction
|
19
17
|
include Modis::Persistence
|
20
|
-
include Modis::
|
21
|
-
include Modis::
|
18
|
+
include Modis::Finder
|
19
|
+
include Modis::Attribute
|
20
|
+
include Modis::Index
|
22
21
|
|
23
22
|
base.extend(ClassMethods)
|
24
23
|
end
|
@@ -31,20 +30,19 @@ module Modis
|
|
31
30
|
end
|
32
31
|
end
|
33
32
|
|
34
|
-
def initialize(record=nil, options={})
|
33
|
+
def initialize(record = nil, options = {})
|
35
34
|
set_sti_type
|
36
35
|
apply_defaults
|
37
36
|
assign_attributes(record.symbolize_keys) if record
|
38
37
|
reset_changes
|
39
38
|
|
40
|
-
|
41
|
-
|
42
|
-
end
|
39
|
+
return unless options.key?(:new_record)
|
40
|
+
instance_variable_set('@new_record', options[:new_record])
|
43
41
|
end
|
44
42
|
|
45
43
|
def ==(other)
|
46
44
|
super || other.instance_of?(self.class) && id.present? && other.id == id
|
47
45
|
end
|
48
|
-
|
46
|
+
alias_method :eql?, :==
|
49
47
|
end
|
50
48
|
end
|
data/lib/modis/persistence.rb
CHANGED
@@ -2,21 +2,25 @@ module Modis
|
|
2
2
|
module Persistence
|
3
3
|
def self.included(base)
|
4
4
|
base.extend ClassMethods
|
5
|
+
base.instance_eval do
|
6
|
+
after__internal_create :track
|
7
|
+
before__internal_destroy :untrack
|
8
|
+
end
|
5
9
|
end
|
6
10
|
|
7
11
|
module ClassMethods
|
8
12
|
# :nodoc:
|
9
13
|
def bootstrap_sti(parent, child)
|
10
14
|
child.instance_eval do
|
11
|
-
|
12
|
-
|
15
|
+
parent.instance_eval do
|
16
|
+
class << self
|
13
17
|
attr_accessor :sti_parent
|
14
18
|
end
|
15
|
-
attribute :type, :string
|
19
|
+
attribute :type, :string unless attributes.key?('type')
|
16
20
|
end
|
17
21
|
|
18
22
|
class << self
|
19
|
-
delegate :attributes, to: :sti_parent
|
23
|
+
delegate :attributes, :indexed_attributes, to: :sti_parent
|
20
24
|
end
|
21
25
|
|
22
26
|
@sti_child = true
|
@@ -35,9 +39,7 @@ module Modis
|
|
35
39
|
@namespace = name.split('::').map(&:underscore).join(':')
|
36
40
|
end
|
37
41
|
|
38
|
-
|
39
|
-
@namespace = value
|
40
|
-
end
|
42
|
+
attr_writer :namespace
|
41
43
|
|
42
44
|
def absolute_namespace
|
43
45
|
parts = [Modis.config.namespace, namespace]
|
@@ -49,9 +51,9 @@ module Modis
|
|
49
51
|
end
|
50
52
|
|
51
53
|
def create(attrs)
|
52
|
-
|
53
|
-
|
54
|
-
|
54
|
+
model = new(attrs)
|
55
|
+
model.save
|
56
|
+
model
|
55
57
|
end
|
56
58
|
|
57
59
|
def create!(attrs)
|
@@ -59,6 +61,10 @@ module Modis
|
|
59
61
|
model.save!
|
60
62
|
model
|
61
63
|
end
|
64
|
+
|
65
|
+
def coerce_from_persistence(value)
|
66
|
+
YAML.load(value)
|
67
|
+
end
|
62
68
|
end
|
63
69
|
|
64
70
|
def persisted?
|
@@ -73,29 +79,28 @@ module Modis
|
|
73
79
|
defined?(@new_record) ? @new_record : true
|
74
80
|
end
|
75
81
|
|
76
|
-
def save(args={})
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
false
|
81
|
-
end
|
82
|
+
def save(args = {})
|
83
|
+
create_or_update(args)
|
84
|
+
rescue Modis::RecordInvalid
|
85
|
+
false
|
82
86
|
end
|
83
87
|
|
84
|
-
def save!(args={})
|
88
|
+
def save!(args = {})
|
85
89
|
create_or_update(args) || (raise RecordNotSaved)
|
86
90
|
end
|
87
91
|
|
88
92
|
def destroy
|
89
93
|
self.class.transaction do |redis|
|
90
94
|
run_callbacks :destroy do
|
91
|
-
|
92
|
-
|
95
|
+
run_callbacks :_internal_destroy do
|
96
|
+
redis.del(key)
|
97
|
+
end
|
93
98
|
end
|
94
99
|
end
|
95
100
|
end
|
96
101
|
|
97
102
|
def reload
|
98
|
-
new_attributes = self.class.attributes_for(id)
|
103
|
+
new_attributes = Modis.with_connection { |redis| self.class.attributes_for(redis, id) }
|
99
104
|
initialize(new_attributes)
|
100
105
|
self
|
101
106
|
end
|
@@ -115,36 +120,69 @@ module Modis
|
|
115
120
|
save!
|
116
121
|
end
|
117
122
|
|
118
|
-
|
123
|
+
private
|
119
124
|
|
120
|
-
def
|
121
|
-
|
122
|
-
|
123
|
-
|
125
|
+
def coerce_for_persistence(attribute, value)
|
126
|
+
ensure_type(attribute, value)
|
127
|
+
YAML.dump(value)
|
128
|
+
end
|
129
|
+
|
130
|
+
def ensure_type(attribute, value)
|
131
|
+
type = self.class.attributes[attribute.to_s][:type]
|
132
|
+
type_classes = classes_for_type(type)
|
133
|
+
|
134
|
+
return unless value && !type_classes.include?(value.class)
|
135
|
+
raise Modis::AttributeCoercionError, "Received value of type '#{value.class}', expected '#{type}' for attribute '#{name}'."
|
136
|
+
end
|
137
|
+
|
138
|
+
def classes_for_type(type)
|
139
|
+
{ string: [String],
|
140
|
+
integer: [Fixnum],
|
141
|
+
float: [Float],
|
142
|
+
timestamp: [Time],
|
143
|
+
hash: [Hash],
|
144
|
+
array: [Array],
|
145
|
+
boolean: [TrueClass, FalseClass] }[type]
|
146
|
+
end
|
147
|
+
|
148
|
+
def create_or_update(args = {})
|
149
|
+
validate(args)
|
150
|
+
future = persist
|
151
|
+
|
152
|
+
if future && future.value == 'OK'
|
153
|
+
reset_changes
|
154
|
+
@new_record = false
|
155
|
+
new_record? ? add_to_index : update_index
|
156
|
+
true
|
157
|
+
else
|
158
|
+
false
|
124
159
|
end
|
160
|
+
end
|
161
|
+
|
162
|
+
def validate(args)
|
163
|
+
skip_validate = args.key?(:validate) && args[:validate] == false
|
164
|
+
return if skip_validate || valid?
|
165
|
+
raise Modis::RecordInvalid, errors.full_messages.join(', ')
|
166
|
+
end
|
125
167
|
|
168
|
+
def persist
|
126
169
|
future = nil
|
127
170
|
set_id if new_record?
|
171
|
+
callback = new_record? ? :create : :update
|
128
172
|
|
129
173
|
self.class.transaction do |redis|
|
130
174
|
run_callbacks :save do
|
131
|
-
callback = new_record? ? :create : :update
|
132
175
|
run_callbacks callback do
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
176
|
+
run_callbacks "_internal_#{callback}" do
|
177
|
+
attrs = []
|
178
|
+
attributes.each { |k, v| attrs << k << coerce_for_persistence(k, v) }
|
179
|
+
future = redis.hmset(self.class.key_for(id), attrs)
|
180
|
+
end
|
137
181
|
end
|
138
182
|
end
|
139
183
|
end
|
140
184
|
|
141
|
-
|
142
|
-
reset_changes
|
143
|
-
@new_record = false
|
144
|
-
true
|
145
|
-
else
|
146
|
-
false
|
147
|
-
end
|
185
|
+
future
|
148
186
|
end
|
149
187
|
|
150
188
|
def set_id
|
@@ -153,12 +191,12 @@ module Modis
|
|
153
191
|
end
|
154
192
|
end
|
155
193
|
|
156
|
-
def track
|
157
|
-
redis.sadd(self.class.key_for(:all), id)
|
194
|
+
def track
|
195
|
+
Modis.with_connection { |redis| redis.sadd(self.class.key_for(:all), id) }
|
158
196
|
end
|
159
197
|
|
160
|
-
def untrack
|
161
|
-
redis.srem(self.class.key_for(:all), id)
|
198
|
+
def untrack
|
199
|
+
Modis.with_connection { |redis| redis.srem(self.class.key_for(:all), id) }
|
162
200
|
end
|
163
201
|
end
|
164
202
|
end
|
data/lib/modis/version.rb
CHANGED