adept_dynamoid 0.5.0.6

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