adept_dynamoid 0.5.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (119) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Dynamoid.gemspec +193 -0
  4. data/Gemfile +23 -0
  5. data/Gemfile.lock +86 -0
  6. data/LICENSE.txt +20 -0
  7. data/README.markdown +265 -0
  8. data/Rakefile +62 -0
  9. data/VERSION +1 -0
  10. data/doc/.nojekyll +0 -0
  11. data/doc/Dynamoid.html +312 -0
  12. data/doc/Dynamoid/Adapter.html +1385 -0
  13. data/doc/Dynamoid/Adapter/AwsSdk.html +1585 -0
  14. data/doc/Dynamoid/Adapter/Local.html +1574 -0
  15. data/doc/Dynamoid/Associations.html +131 -0
  16. data/doc/Dynamoid/Associations/Association.html +794 -0
  17. data/doc/Dynamoid/Associations/BelongsTo.html +158 -0
  18. data/doc/Dynamoid/Associations/ClassMethods.html +723 -0
  19. data/doc/Dynamoid/Associations/HasAndBelongsToMany.html +164 -0
  20. data/doc/Dynamoid/Associations/HasMany.html +164 -0
  21. data/doc/Dynamoid/Associations/HasOne.html +158 -0
  22. data/doc/Dynamoid/Associations/ManyAssociation.html +1640 -0
  23. data/doc/Dynamoid/Associations/SingleAssociation.html +598 -0
  24. data/doc/Dynamoid/Components.html +204 -0
  25. data/doc/Dynamoid/Config.html +395 -0
  26. data/doc/Dynamoid/Config/Options.html +609 -0
  27. data/doc/Dynamoid/Criteria.html +131 -0
  28. data/doc/Dynamoid/Criteria/Chain.html +1063 -0
  29. data/doc/Dynamoid/Criteria/ClassMethods.html +98 -0
  30. data/doc/Dynamoid/Document.html +666 -0
  31. data/doc/Dynamoid/Document/ClassMethods.html +937 -0
  32. data/doc/Dynamoid/Errors.html +118 -0
  33. data/doc/Dynamoid/Errors/DocumentNotValid.html +210 -0
  34. data/doc/Dynamoid/Errors/Error.html +130 -0
  35. data/doc/Dynamoid/Errors/InvalidField.html +133 -0
  36. data/doc/Dynamoid/Errors/MissingRangeKey.html +133 -0
  37. data/doc/Dynamoid/Fields.html +669 -0
  38. data/doc/Dynamoid/Fields/ClassMethods.html +309 -0
  39. data/doc/Dynamoid/Finders.html +128 -0
  40. data/doc/Dynamoid/Finders/ClassMethods.html +516 -0
  41. data/doc/Dynamoid/Indexes.html +308 -0
  42. data/doc/Dynamoid/Indexes/ClassMethods.html +353 -0
  43. data/doc/Dynamoid/Indexes/Index.html +1104 -0
  44. data/doc/Dynamoid/Persistence.html +651 -0
  45. data/doc/Dynamoid/Persistence/ClassMethods.html +670 -0
  46. data/doc/Dynamoid/Validations.html +399 -0
  47. data/doc/_index.html +461 -0
  48. data/doc/class_list.html +47 -0
  49. data/doc/css/common.css +1 -0
  50. data/doc/css/full_list.css +55 -0
  51. data/doc/css/style.css +322 -0
  52. data/doc/file.LICENSE.html +66 -0
  53. data/doc/file.README.html +312 -0
  54. data/doc/file_list.html +52 -0
  55. data/doc/frames.html +13 -0
  56. data/doc/index.html +312 -0
  57. data/doc/js/app.js +205 -0
  58. data/doc/js/full_list.js +173 -0
  59. data/doc/js/jquery.js +16 -0
  60. data/doc/method_list.html +1238 -0
  61. data/doc/top-level-namespace.html +105 -0
  62. data/lib/dynamoid.rb +47 -0
  63. data/lib/dynamoid/adapter.rb +177 -0
  64. data/lib/dynamoid/adapter/aws_sdk.rb +223 -0
  65. data/lib/dynamoid/associations.rb +106 -0
  66. data/lib/dynamoid/associations/association.rb +105 -0
  67. data/lib/dynamoid/associations/belongs_to.rb +44 -0
  68. data/lib/dynamoid/associations/has_and_belongs_to_many.rb +40 -0
  69. data/lib/dynamoid/associations/has_many.rb +39 -0
  70. data/lib/dynamoid/associations/has_one.rb +39 -0
  71. data/lib/dynamoid/associations/many_association.rb +191 -0
  72. data/lib/dynamoid/associations/single_association.rb +69 -0
  73. data/lib/dynamoid/components.rb +36 -0
  74. data/lib/dynamoid/config.rb +57 -0
  75. data/lib/dynamoid/config/options.rb +78 -0
  76. data/lib/dynamoid/criteria.rb +29 -0
  77. data/lib/dynamoid/criteria/chain.rb +243 -0
  78. data/lib/dynamoid/dirty.rb +41 -0
  79. data/lib/dynamoid/document.rb +184 -0
  80. data/lib/dynamoid/errors.rb +28 -0
  81. data/lib/dynamoid/fields.rb +130 -0
  82. data/lib/dynamoid/finders.rb +131 -0
  83. data/lib/dynamoid/identity_map.rb +96 -0
  84. data/lib/dynamoid/indexes.rb +69 -0
  85. data/lib/dynamoid/indexes/index.rb +103 -0
  86. data/lib/dynamoid/middleware/identity_map.rb +16 -0
  87. data/lib/dynamoid/persistence.rb +247 -0
  88. data/lib/dynamoid/validations.rb +36 -0
  89. data/spec/app/models/address.rb +10 -0
  90. data/spec/app/models/camel_case.rb +24 -0
  91. data/spec/app/models/magazine.rb +11 -0
  92. data/spec/app/models/message.rb +9 -0
  93. data/spec/app/models/sponsor.rb +8 -0
  94. data/spec/app/models/subscription.rb +12 -0
  95. data/spec/app/models/tweet.rb +12 -0
  96. data/spec/app/models/user.rb +26 -0
  97. data/spec/dynamoid/adapter/aws_sdk_spec.rb +186 -0
  98. data/spec/dynamoid/adapter_spec.rb +117 -0
  99. data/spec/dynamoid/associations/association_spec.rb +194 -0
  100. data/spec/dynamoid/associations/belongs_to_spec.rb +71 -0
  101. data/spec/dynamoid/associations/has_and_belongs_to_many_spec.rb +47 -0
  102. data/spec/dynamoid/associations/has_many_spec.rb +42 -0
  103. data/spec/dynamoid/associations/has_one_spec.rb +45 -0
  104. data/spec/dynamoid/associations_spec.rb +16 -0
  105. data/spec/dynamoid/config_spec.rb +27 -0
  106. data/spec/dynamoid/criteria/chain_spec.rb +140 -0
  107. data/spec/dynamoid/criteria_spec.rb +72 -0
  108. data/spec/dynamoid/dirty_spec.rb +49 -0
  109. data/spec/dynamoid/document_spec.rb +118 -0
  110. data/spec/dynamoid/fields_spec.rb +127 -0
  111. data/spec/dynamoid/finders_spec.rb +135 -0
  112. data/spec/dynamoid/identity_map_spec.rb +45 -0
  113. data/spec/dynamoid/indexes/index_spec.rb +104 -0
  114. data/spec/dynamoid/indexes_spec.rb +25 -0
  115. data/spec/dynamoid/persistence_spec.rb +176 -0
  116. data/spec/dynamoid/validations_spec.rb +36 -0
  117. data/spec/dynamoid_spec.rb +9 -0
  118. data/spec/spec_helper.rb +50 -0
  119. metadata +376 -0
@@ -0,0 +1,96 @@
1
+ module Dynamoid
2
+ module IdentityMap
3
+ extend ActiveSupport::Concern
4
+
5
+ def self.clear
6
+ models.each { |m| m.identity_map.clear }
7
+ end
8
+
9
+ def self.models
10
+ Dynamoid::Config.included_models
11
+ end
12
+
13
+ module ClassMethods
14
+ def identity_map
15
+ @identity_map ||= {}
16
+ end
17
+
18
+ def from_database(attrs = {})
19
+ return super if identity_map_off?
20
+
21
+ key = identity_map_key(attrs)
22
+ document = identity_map[key]
23
+
24
+ if document.nil?
25
+ document = super
26
+ identity_map[key] = document
27
+ else
28
+ document.load(attrs)
29
+ end
30
+
31
+ document
32
+ end
33
+
34
+ def find_by_id(id, options = {})
35
+ return super if identity_map_off?
36
+
37
+ key = id.to_s
38
+
39
+ if range_key = options[:range_key]
40
+ key += "::#{range_key}"
41
+ end
42
+
43
+ if identity_map[key]
44
+ identity_map[key]
45
+ else
46
+ super
47
+ end
48
+ end
49
+
50
+ def identity_map_key(attrs)
51
+ key = attrs[hash_key].to_s
52
+ if range_key
53
+ key += "::#{attrs[range_key]}"
54
+ end
55
+ key
56
+ end
57
+
58
+ def identity_map_on?
59
+ Dynamoid::Config.identity_map
60
+ end
61
+
62
+ def identity_map_off?
63
+ !identity_map_on?
64
+ end
65
+ end
66
+
67
+ def identity_map
68
+ self.class.identity_map
69
+ end
70
+
71
+ def save(*args)
72
+ return super if self.class.identity_map_off?
73
+
74
+ if result = super
75
+ identity_map[identity_map_key] = self
76
+ end
77
+ result
78
+ end
79
+
80
+ def delete
81
+ return super if self.class.identity_map_off?
82
+
83
+ identity_map.delete(identity_map_key)
84
+ super
85
+ end
86
+
87
+
88
+ def identity_map_key
89
+ key = hash_key.to_s
90
+ if self.class.range_key
91
+ key += "::#{range_value}"
92
+ end
93
+ key
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,69 @@
1
+ # encoding: utf-8
2
+ require 'dynamoid/indexes/index'
3
+
4
+ module Dynamoid #:nodoc:
5
+
6
+ # Indexes are quick ways of performing queries by anything other than id in DynamoDB. They are denormalized tables;
7
+ # that is, data is duplicated in the initial table (where the object is saved) and the index table (where
8
+ # we perform indexing).
9
+ module Indexes
10
+ extend ActiveSupport::Concern
11
+
12
+ # Make some helpful attributes to persist indexes.
13
+ included do
14
+ class_attribute :indexes
15
+
16
+ self.indexes = {}
17
+ end
18
+
19
+ module ClassMethods
20
+
21
+ # The call to create an index. Generates a new index with the specified options -- for more information, see Dynamoid::Indexes::Index.
22
+ # This function also attempts to immediately create the indexing table if it does not exist already.
23
+ #
24
+ # @since 0.2.0
25
+ def index(name, options = {})
26
+ index = Dynamoid::Indexes::Index.new(self, name, options)
27
+ self.indexes[index.name] = index
28
+ create_indexes
29
+ end
30
+
31
+ # Helper function to find indexes.
32
+ #
33
+ # @since 0.2.0
34
+ def find_index(index)
35
+ self.indexes[Array(index).collect(&:to_s).sort.collect(&:to_sym)]
36
+ end
37
+
38
+ # Helper function to create indexes (if they don't exist already).
39
+ #
40
+ # @since 0.2.0
41
+ def create_indexes
42
+ self.indexes.each do |name, index|
43
+ opts = {:table_name => index.table_name, :id => :id}
44
+ opts[:range_key] = { :range => :number } if index.range_key?
45
+ self.create_table(opts)
46
+ end
47
+ end
48
+ end
49
+
50
+ # Callback for an object to save itself to each of a class' indexes.
51
+ #
52
+ # @since 0.2.0
53
+ def save_indexes
54
+ self.class.indexes.each do |name, index|
55
+ index.save(self)
56
+ end
57
+ end
58
+
59
+ # Callback for an object to delete itself from each of a class' indexes.
60
+ #
61
+ # @since 0.2.0
62
+ def delete_indexes
63
+ self.class.indexes.each do |name, index|
64
+ index.delete(self)
65
+ end
66
+ end
67
+ end
68
+
69
+ end
@@ -0,0 +1,103 @@
1
+ # encoding: utf-8
2
+ module Dynamoid #:nodoc:
3
+ module Indexes
4
+
5
+ # The class contains all the information an index contains, including its keys and which attributes it covers.
6
+ class Index
7
+ attr_accessor :source, :name, :hash_keys, :range_keys
8
+ alias_method :range_key?, :range_keys
9
+
10
+ # Create a new index. Pass either :range => true or :range => :column_name to create a ranged index on that column.
11
+ #
12
+ # @param [Class] source the source class for the index
13
+ # @param [Symbol] name the name of the index
14
+ #
15
+ # @since 0.2.0
16
+ def initialize(source, name, options = {})
17
+ @source = source
18
+
19
+ if options.delete(:range)
20
+ @range_keys = sort(name)
21
+ elsif options[:range_key]
22
+ @range_keys = sort(options[:range_key])
23
+ end
24
+ @hash_keys = sort(name)
25
+ @name = sort([hash_keys, range_keys])
26
+
27
+ raise Dynamoid::Errors::InvalidField, 'A key specified for an index is not a field' unless keys.all?{|n| source.attributes.include?(n)}
28
+ end
29
+
30
+ # Sort objects into alphabetical strings, used for composing index names correctly (since we always assume they're alphabetical).
31
+ #
32
+ # @example find all users by first and last name
33
+ # sort([:gamma, :alpha, :beta, :omega]) # => [:alpha, :beta, :gamma, :omega]
34
+ #
35
+ # @since 0.2.0
36
+ def sort(objs)
37
+ Array(objs).flatten.compact.uniq.collect(&:to_s).sort.collect(&:to_sym)
38
+ end
39
+
40
+ # Return the array of keys this index uses for its table.
41
+ #
42
+ # @since 0.2.0
43
+ def keys
44
+ [Array(hash_keys) + Array(range_keys)].flatten.uniq
45
+ end
46
+
47
+ # Return the table name for this index.
48
+ #
49
+ # @since 0.2.0
50
+ def table_name
51
+ "#{Dynamoid::Config.namespace}_index_" + source.table_name.sub("#{Dynamoid::Config.namespace}_", '').singularize + "_#{name.collect(&:to_s).collect(&:pluralize).join('_and_')}"
52
+ end
53
+
54
+ # Given either an object or a list of attributes, generate a hash key and a range key for the index. Optionally pass in
55
+ # true to changed_attributes for a list of all the object's dirty attributes in convenient index form (for deleting stale
56
+ # information from the indexes).
57
+ #
58
+ # @param [Object] attrs either an object that responds to :attributes, or a hash of attributes
59
+ #
60
+ # @return [Hash] a hash with the keys :hash_value and :range_value
61
+ #
62
+ # @since 0.2.0
63
+ def values(attrs, changed_attributes = false)
64
+ if changed_attributes
65
+ hash = {}
66
+ attrs.changes.each {|k, v| hash[k.to_sym] = (v.first || v.last)}
67
+ attrs = hash
68
+ end
69
+ attrs = attrs.send(:attributes) if attrs.respond_to?(:attributes)
70
+ {}.tap do |hash|
71
+ hash[:hash_value] = hash_keys.collect{|key| attrs[key]}.join('.')
72
+ hash[:range_value] = range_keys.inject(0.0) {|sum, key| sum + attrs[key].to_f} if self.range_key?
73
+ end
74
+ end
75
+
76
+ # Save an object to this index, merging it with existing ids if there's already something present at this index location.
77
+ # First, though, delete this object from its old indexes (so the object isn't listed in an erroneous index).
78
+ #
79
+ # @since 0.2.0
80
+ def save(obj)
81
+ self.delete(obj, true)
82
+ values = values(obj)
83
+ return true if values[:hash_value].blank? || (!values[:range_value].nil? && values[:range_value].blank?)
84
+ existing = Dynamoid::Adapter.read(self.table_name, values[:hash_value], { :range_key => values[:range_value] })
85
+ ids = ((existing and existing[:ids]) or Set.new)
86
+ Dynamoid::Adapter.write(self.table_name, {:id => values[:hash_value], :ids => ids.merge([obj.id]), :range => values[:range_value]})
87
+ end
88
+
89
+ # Delete an object from this index, preserving existing ids if there are any, and failing gracefully if for some reason the
90
+ # index doesn't already have this object in it.
91
+ #
92
+ # @since 0.2.0
93
+ def delete(obj, changed_attributes = false)
94
+ values = values(obj, changed_attributes)
95
+ return true if values[:hash_value].blank? || (!values[:range_value].nil? && values[:range_value].blank?)
96
+ existing = Dynamoid::Adapter.read(self.table_name, values[:hash_value], { :range_key => values[:range_value]})
97
+ return true unless existing && existing[:ids] && existing[:ids].include?(obj.id)
98
+ Dynamoid::Adapter.write(self.table_name, {:id => values[:hash_value], :ids => (existing[:ids] - Set[obj.id]), :range => values[:range_value]})
99
+ end
100
+
101
+ end
102
+ end
103
+ end
@@ -0,0 +1,16 @@
1
+ module Dynamoid
2
+ module Middleware
3
+ class IdentityMap
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ Dynamoid::IdentityMap.clear
10
+ @app.call(env)
11
+ ensure
12
+ Dynamoid::IdentityMap.clear
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,247 @@
1
+ require 'securerandom'
2
+
3
+ # encoding: utf-8
4
+ module Dynamoid
5
+
6
+ # Persistence is responsible for dumping objects to and marshalling objects from the datastore. It tries to reserialize
7
+ # values to be of the same type as when they were passed in, based on the fields in the class.
8
+ module Persistence
9
+ extend ActiveSupport::Concern
10
+
11
+ attr_accessor :new_record
12
+ alias :new_record? :new_record
13
+
14
+ module ClassMethods
15
+
16
+ # Returns the name of the table the class is for.
17
+ #
18
+ # @since 0.2.0
19
+ def table_name
20
+ "#{Dynamoid::Config.namespace}_#{options[:name] ? options[:name] : self.name.split('::').last.downcase.pluralize}"
21
+ end
22
+
23
+ # Creates a table.
24
+ #
25
+ # @param [Hash] options options to pass for table creation
26
+ # @option options [Symbol] :id the id field for the table
27
+ # @option options [Symbol] :table_name the actual name for the table
28
+ # @option options [Integer] :read_capacity set the read capacity for the table; does not work on existing tables
29
+ # @option options [Integer] :write_capacity set the write capacity for the table; does not work on existing tables
30
+ # @option options [Hash] {range_key => :type} a hash of the name of the range key and a symbol of its type
31
+ #
32
+ # @since 0.4.0
33
+ def create_table(options = {})
34
+ if self.range_key
35
+ range_key_hash = { range_key => dynamo_type(attributes[range_key][:type]) }
36
+ else
37
+ range_key_hash = nil
38
+ end
39
+ options = {
40
+ :id => self.hash_key,
41
+ :table_name => self.table_name,
42
+ :write_capacity => self.write_capacity,
43
+ :read_capacity => self.read_capacity,
44
+ :range_key => range_key_hash
45
+ }.merge(options)
46
+
47
+ return true if table_exists?(options[:table_name])
48
+
49
+ Dynamoid::Adapter.tables << options[:table_name] if Dynamoid::Adapter.create_table(options[:table_name], options[:id], options)
50
+ end
51
+
52
+ # Does a table with this name exist?
53
+ #
54
+ # @since 0.2.0
55
+ def table_exists?(table_name)
56
+ Dynamoid::Adapter.tables ? Dynamoid::Adapter.tables.include?(table_name) : false
57
+ end
58
+
59
+ def from_database(attrs = {})
60
+ new(attrs).tap { |r| r.new_record = false }
61
+ end
62
+
63
+ # Undump an object into a hash, converting each type from a string representation of itself into the type specified by the field.
64
+ #
65
+ # @since 0.2.0
66
+ def undump(incoming = nil)
67
+ incoming = (incoming || {}).symbolize_keys
68
+ Hash.new.tap do |hash|
69
+ self.attributes.each do |attribute, options|
70
+ hash[attribute] = undump_field(incoming[attribute], options)
71
+ end
72
+ incoming.each {|attribute, value| hash[attribute] ||= value }
73
+ end
74
+ end
75
+
76
+ # Undump a value for a given type. Given a string, it'll determine (based on the type provided) whether to turn it into a
77
+ # string, integer, float, set, array, datetime, or serialized return value.
78
+ #
79
+ # @since 0.2.0
80
+ def undump_field(value, options)
81
+ if value.nil? && (default_value = options[:default])
82
+ value = default_value.respond_to?(:call) ? default_value.call : default_value
83
+ else
84
+ return if value.nil? || (value.respond_to?(:empty?) && value.empty?)
85
+ end
86
+
87
+ case options[:type]
88
+ when :string
89
+ value.to_s
90
+ when :integer
91
+ value.to_i
92
+ when :float
93
+ value.to_f
94
+ when :set, :array
95
+ if value.is_a?(Set) || value.is_a?(Array)
96
+ value
97
+ else
98
+ Set[value]
99
+ end
100
+ when :datetime
101
+ if value.is_a?(Date) || value.is_a?(DateTime) || value.is_a?(Time)
102
+ value
103
+ else
104
+ Time.at(value).to_datetime
105
+ end
106
+ when :serialized
107
+ if value.is_a?(String)
108
+ options[:serializer] ? options[:serializer].load(value) : YAML.load(value)
109
+ else
110
+ value
111
+ end
112
+ end
113
+ end
114
+
115
+ def dynamo_type(type)
116
+ case type
117
+ when :integer, :float, :datetime
118
+ :number
119
+ when :string, :serialized
120
+ :string
121
+ else
122
+ raise 'unknown type'
123
+ end
124
+ end
125
+
126
+ end
127
+
128
+ # Set updated_at and any passed in field to current DateTime. Useful for things like last_login_at, etc.
129
+ #
130
+ def touch(name = nil)
131
+ now = DateTime.now
132
+ self.updated_at = now
133
+ attributes[name] = now if name
134
+ save
135
+ end
136
+
137
+ # Is this object persisted in the datastore? Required for some ActiveModel integration stuff.
138
+ #
139
+ # @since 0.2.0
140
+ def persisted?
141
+ !new_record?
142
+ end
143
+
144
+ # Run the callbacks and then persist this object in the datastore.
145
+ #
146
+ # @since 0.2.0
147
+ def save(options = {})
148
+ self.class.create_table
149
+
150
+ if new_record?
151
+ run_callbacks(:create) { persist }
152
+ else
153
+ persist
154
+ end
155
+
156
+ self
157
+ end
158
+
159
+ def update!(conditions = {}, &block)
160
+ options = range_key ? {:range_key => dump_field(self.read_attribute(range_key), self.class.attributes[range_key])} : {}
161
+ new_attrs = Dynamoid::Adapter.update_item(self.class.table_name, self.hash_key, options.merge(:conditions => conditions), &block)
162
+ load(new_attrs)
163
+ end
164
+
165
+ def update(conditions = {}, &block)
166
+ update!(conditions, &block)
167
+ true
168
+ rescue Dynamoid::Errors::ConditionalCheckFailedException
169
+ false
170
+ end
171
+
172
+ # Delete this object, but only after running callbacks for it.
173
+ #
174
+ # @since 0.2.0
175
+ def destroy
176
+ run_callbacks(:destroy) do
177
+ self.delete
178
+ end
179
+ self
180
+ end
181
+
182
+ # Delete this object from the datastore and all indexes.
183
+ #
184
+ # @since 0.2.0
185
+ def delete
186
+ delete_indexes
187
+ options = range_key ? {:range_key => dump_field(self.read_attribute(range_key), self.class.attributes[range_key])} : {}
188
+ Dynamoid::Adapter.delete(self.class.table_name, self.hash_key, options)
189
+ end
190
+
191
+ # Dump this object's attributes into hash form, fit to be persisted into the datastore.
192
+ #
193
+ # @since 0.2.0
194
+ def dump
195
+ Hash.new.tap do |hash|
196
+ self.class.attributes.each do |attribute, options|
197
+ hash[attribute] = dump_field(self.read_attribute(attribute), options)
198
+ end
199
+ end
200
+ end
201
+
202
+ private
203
+
204
+ # Determine how to dump this field. Given a value, it'll determine how to turn it into a value that can be
205
+ # persisted into the datastore.
206
+ #
207
+ # @since 0.2.0
208
+ def dump_field(value, options)
209
+ return if value.nil? || (value.respond_to?(:empty?) && value.empty?)
210
+
211
+ case options[:type]
212
+ when :string
213
+ value.to_s
214
+ when :integer
215
+ value.to_i
216
+ when :float
217
+ value.to_f
218
+ when :set, :array
219
+ if value.is_a?(Set) || value.is_a?(Array)
220
+ value
221
+ else
222
+ Set[value]
223
+ end
224
+ when :datetime
225
+ value.to_time.to_f
226
+ when :serialized
227
+ options[:serializer] ? options[:serializer].dump(value) : value.to_yaml
228
+ end
229
+ end
230
+
231
+ # Persist the object into the datastore. Assign it an id first if it doesn't have one; then afterwards,
232
+ # save its indexes.
233
+ #
234
+ # @since 0.2.0
235
+ def persist
236
+ run_callbacks(:save) do
237
+ self.hash_key = SecureRandom.uuid if self.hash_key.nil? || self.hash_key.blank?
238
+ Dynamoid::Adapter.write(self.class.table_name, self.dump)
239
+ save_indexes
240
+ @new_record = false
241
+ true
242
+ end
243
+ end
244
+
245
+ end
246
+
247
+ end