Module: Dynamoid::Persistence
- Extended by:
- ActiveSupport::Concern
- Included in:
- Components
- Defined in:
- lib/dynamoid/persistence.rb,
lib/dynamoid/persistence/save.rb,
lib/dynamoid/persistence/import.rb,
lib/dynamoid/persistence/upsert.rb,
lib/dynamoid/persistence/update_fields.rb,
lib/dynamoid/persistence/update_validations.rb
Overview
Persistence is responsible for dumping objects to and marshalling objects from the data store. It tries to reserialize values to be of the same type as when they were passed in, based on the fields in the class.
Defined Under Namespace
Modules: ClassMethods, UpdateValidations Classes: Import, Save, UpdateFields, Upsert
Constant Summary collapse
- UNIX_EPOCH_DATE =
Date.new(1970, 1, 1).freeze
Instance Attribute Summary collapse
-
#new_record ⇒ Object
(also: #new_record?)
Returns the value of attribute new_record.
Instance Method Summary collapse
-
#decrement(attribute, by = 1) ⇒ Dynamoid::Document
Change numeric attribute value.
-
#decrement!(attribute, by = 1) ⇒ true|false
Change numeric attribute value and save a model.
-
#delete ⇒ Dynamoid::Document
Delete a model.
-
#destroy ⇒ Dynamoid::Document|false
Delete a model.
-
#destroy! ⇒ Object
Delete a model.
-
#increment(attribute, by = 1) ⇒ Dynamoid::Document
Change numeric attribute value.
-
#increment!(attribute, by = 1) ⇒ true|false
Change numeric attribute value and save a model.
-
#persisted? ⇒ true|false
Is this object persisted in DynamoDB?.
-
#save(options = {}) ⇒ true|false
Create new model or persist changes.
-
#touch(name = nil) ⇒ Dynamoid::Document
Update document timestamps.
-
#update(conditions = {}, &block) ⇒ true|false
Update a model.
-
#update!(conditions = {}) ⇒ Dynamoid::Document
Update a model.
-
#update_attribute(attribute, value) ⇒ Dynamoid::Document
Update a single attribute, saving the object afterwards.
-
#update_attributes(attributes) ⇒ true|false
Update multiple attributes at once, saving the object once the updates are complete.
-
#update_attributes!(attributes) ⇒ Object
Update multiple attributes at once, saving the object once the updates are complete.
Instance Attribute Details
#new_record ⇒ Object Also known as: new_record?
Returns the value of attribute new_record.
20 21 22 |
# File 'lib/dynamoid/persistence.rb', line 20 def new_record @new_record end |
Instance Method Details
#decrement(attribute, by = 1) ⇒ Dynamoid::Document
Change numeric attribute value.
Initializes attribute to zero if nil
and subtracts the specified value (by default is 1). Only makes sense for number-based attributes.
user.decrement(:followers_count)
user.decrement(:followers_count, 2)
760 761 762 763 764 |
# File 'lib/dynamoid/persistence.rb', line 760 def decrement(attribute, by = 1) self[attribute] ||= 0 self[attribute] -= by self end |
#decrement!(attribute, by = 1) ⇒ true|false
Change numeric attribute value and save a model.
Initializes attribute to zero if nil
and subtracts the specified value (by default is 1). Only makes sense for number-based attributes.
user.decrement!(:followers_count)
user.decrement!(:followers_count, 2)
Returns true
if a model was saved and false
otherwise.
779 780 781 782 |
# File 'lib/dynamoid/persistence.rb', line 779 def decrement!(attribute, by = 1) decrement(attribute, by) save end |
#delete ⇒ Dynamoid::Document
Delete a model.
Supports optimistic locking with the lock_version
attribute and doesn’t delete a model if it’s already changed.
Raises Dynamoid::Errors::StaleObjectError
exception if cannot delete a model.
828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 |
# File 'lib/dynamoid/persistence.rb', line 828 def delete = range_key ? { range_key: Dumping.dump_field(read_attribute(range_key), self.class.attributes[range_key]) } : {} # Add an optimistic locking check if the lock_version column exists if self.class.attributes[:lock_version] conditions = { if: {} } conditions[:if][:lock_version] = if changes[:lock_version].nil? lock_version else changes[:lock_version][0] end [:conditions] = conditions end @destroyed = true Dynamoid.adapter.delete(self.class.table_name, hash_key, ) self.class.associations.each do |name, | send(name).disassociate_source end self rescue Dynamoid::Errors::ConditionalCheckFailedException raise Dynamoid::Errors::StaleObjectError.new(self, 'delete') end |
#destroy ⇒ Dynamoid::Document|false
Delete a model.
Runs callbacks.
Supports optimistic locking with the lock_version
attribute and doesn’t delete a model if it’s already changed.
Returns self
if deleted successfully and false
otherwise.
795 796 797 798 799 800 801 802 803 |
# File 'lib/dynamoid/persistence.rb', line 795 def destroy ret = run_callbacks(:destroy) do delete end @destroyed = true ret == false ? false : self end |
#destroy! ⇒ Object
Delete a model.
Runs callbacks.
Supports optimistic locking with the lock_version
attribute and doesn’t delete a model if it’s already changed.
Raises Dynamoid::Errors::RecordNotDestroyed
exception if model deleting failed.
814 815 816 |
# File 'lib/dynamoid/persistence.rb', line 814 def destroy! destroy || (raise Dynamoid::Errors::RecordNotDestroyed, self) end |
#increment(attribute, by = 1) ⇒ Dynamoid::Document
Change numeric attribute value.
Initializes attribute to zero if nil
and adds the specified value (by default is 1). Only makes sense for number-based attributes.
user.increment(:followers_count)
user.increment(:followers_count, 2)
725 726 727 728 729 |
# File 'lib/dynamoid/persistence.rb', line 725 def increment(attribute, by = 1) self[attribute] ||= 0 self[attribute] += by self end |
#increment!(attribute, by = 1) ⇒ true|false
Change numeric attribute value and save a model.
Initializes attribute to zero if nil
and adds the specified value (by default is 1). Only makes sense for number-based attributes.
user.increment!(:followers_count)
user.increment!(:followers_count, 2)
Returns true
if a model was saved and false
otherwise.
744 745 746 747 |
# File 'lib/dynamoid/persistence.rb', line 744 def increment!(attribute, by = 1) increment(attribute, by) save end |
#persisted? ⇒ true|false
Is this object persisted in DynamoDB?
user = User.new
user.persisted? # => false
user.save
user.persisted? # => true
437 438 439 |
# File 'lib/dynamoid/persistence.rb', line 437 def persisted? !(new_record? || @destroyed) end |
#save(options = {}) ⇒ true|false
Create new model or persist changes.
Run the validation and callbacks. Returns true
if saving is successful and false
otherwise.
user = User.new
user.save # => true
user.age = 26
user.save # => true
Validation can be skipped with validate: false option:
user = User.new(age: -1)
user.save(validate: false) # => true
save
by default sets timestamps attributes - created_at
and updated_at
when creates new model and updates updated_at
attribute when update already existing one.
Changing updated_at
attribute at updating a model can be skipped with touch: false option:
user.save(touch: false)
If a model is new and hash key (id
by default) is not assigned yet it was assigned implicitly with random UUID value.
If lock_version
attribute is declared it will be incremented. If it’s blank then it will be initialized with 1.
save
method call raises Dynamoid::Errors::RecordNotUnique
exception if primary key (hash key + optional range key) already exists in a table.
save
method call raises Dynamoid::Errors::StaleObjectError
exception if there is lock_version
attribute and the document in a table was already changed concurrently and lock_version
was consequently increased.
When a table is not created yet the first save
method call will create a table. It’s useful in test environment to avoid explicit table creation.
489 490 491 492 493 494 495 496 497 498 499 500 501 |
# File 'lib/dynamoid/persistence.rb', line 489 def save( = {}) self.class.create_table(sync: true) @_touch_record = [:touch] create_or_update = new_record? ? :create : :update run_callbacks(create_or_update) do run_callbacks(:save) do Save.call(self) end end end |
#touch(name = nil) ⇒ Dynamoid::Document
Update document timestamps.
Set updated_at
attribute to current DateTime.
post.touch
Can update another field in addition with the same timestamp if it’s name passed as argument.
user.touch(:last_login_at)
419 420 421 422 423 424 425 |
# File 'lib/dynamoid/persistence.rb', line 419 def touch(name = nil) now = DateTime.now self.updated_at = now attributes[name] = now if name save self end |
#update(conditions = {}, &block) ⇒ true|false
Update a model.
Runs validation and callbacks. Reloads all attribute values.
Accepts mandatory block in order to specify operations which will modify attributes. Supports following operations: add
, delete
and set
.
Operation add
just adds a value for numeric attributes and join collections if attribute is a collection (one of array
, set
or map
).
user.update do |t|
t.add(age: 1, followers_count: 5)
t.add(hobbies: ['skying', 'climbing'])
end
Operation delete
is applied to collection attribute types and substructs one collection from another.
user.update do |t|
t.delete(hobbies: ['skying'])
end
If it’s applied to a scalar attribute then the item’s attribute is removed at all:
user.update do |t|
t.delete(age: nil)
end
or even without useless value at all:
user.update do |t|
t.delete(:age)
end
Operation set
just changes an attribute value:
user.update do |t|
t.set(age: 21)
end
All the operations works like ADD
, DELETE
and PUT
actions supported by AttributeUpdates
parameter of UpdateItem
operation.
Can update a model conditionaly:
user.update(if: { age: 20 }) do |t|
t.add(age: 1)
end
If a document doesn’t meet conditions it just returns false
. Otherwise it returns true
.
It will increment the lock_version
attribute if a table has the column, but will not check it. Thus, a concurrent save
call will never cause an update!
to fail, but an update!
may cause a concurrent save
to fail.
707 708 709 710 711 712 |
# File 'lib/dynamoid/persistence.rb', line 707 def update(conditions = {}, &block) update!(conditions, &block) true rescue Dynamoid::Errors::StaleObjectError false end |
#update!(conditions = {}) ⇒ Dynamoid::Document
Update a model.
Runs validation and callbacks. Reloads all attribute values.
Accepts mandatory block in order to specify operations which will modify attributes. Supports following operations: add
, delete
and set
.
Operation add
just adds a value for numeric attributes and join collections if attribute is a collection (one of array
, set
or map
).
user.update! do |t|
t.add(age: 1, followers_count: 5)
t.add(hobbies: ['skying', 'climbing'])
end
Operation delete
is applied to collection attribute types and substructs one collection from another.
user.update! do |t|
t.delete(hobbies: ['skying'])
end
Operation set
just changes an attribute value:
user.update! do |t|
t.set(age: 21)
end
All the operations work like ADD
, DELETE
and PUT
actions supported by AttributeUpdates
parameter of UpdateItem
operation.
It’s an atomic operation. So adding or deleting elements in a collection or incrementing or decrementing a numeric field is atomic and does not interfere with other write requests.
Can update a model conditionaly:
user.update!(if: { age: 20 }) do |t|
t.add(age: 1)
end
If a document doesn’t meet conditions it raises Dynamoid::Errors::StaleObjectError
exception.
It will increment the lock_version
attribute if a table has the column, but will not check it. Thus, a concurrent save
call will never cause an update!
to fail, but an update!
may cause a concurrent save
to fail.
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 |
# File 'lib/dynamoid/persistence.rb', line 612 def update!(conditions = {}) run_callbacks(:update) do = {} if range_key value = read_attribute(range_key) = self.class.attributes[range_key] [:range_key] = Dumping.dump_field(value, ) end begin table_name = self.class.table_name = .merge(conditions: conditions) new_attrs = Dynamoid.adapter.update_item(table_name, hash_key, ) do |t| t.add(lock_version: 1) if self.class.attributes[:lock_version] if self.class. time_now = DateTime.now.in_time_zone(Time.zone) time_now_dumped = Dumping.dump_field(time_now, self.class.attributes[:updated_at]) t.set(updated_at: time_now_dumped) end yield t end load(Undumping.undump_attributes(new_attrs, self.class.attributes)) rescue Dynamoid::Errors::ConditionalCheckFailedException raise Dynamoid::Errors::StaleObjectError.new(self, 'update') end end self end |
#update_attribute(attribute, value) ⇒ Dynamoid::Document
Update a single attribute, saving the object afterwards.
Returns true
if saving is successful and false
otherwise.
user.update_attribute(:last_name, 'Tylor')
Raises a Dynamoid::Errors::UnknownAttribute
exception if any of the attributes is not on the model
551 552 553 554 555 556 |
# File 'lib/dynamoid/persistence.rb', line 551 def update_attribute(attribute, value) # final implementation is in the Dynamoid::Validation module write_attribute(attribute, value) save self end |
#update_attributes(attributes) ⇒ true|false
Update multiple attributes at once, saving the object once the updates are complete. Returns true
if saving is successful and false
otherwise.
user.update_attributes(age: 27, last_name: 'Tylor')
Raises a Dynamoid::Errors::UnknownAttribute
exception if any of the attributes is not on the model
515 516 517 518 |
# File 'lib/dynamoid/persistence.rb', line 515 def update_attributes(attributes) attributes.each { |attribute, value| write_attribute(attribute, value) } save end |
#update_attributes!(attributes) ⇒ Object
Update multiple attributes at once, saving the object once the updates are complete.
user.update_attributes!(age: 27, last_name: 'Tylor')
Raises a Dynamoid::Errors::DocumentNotValid
exception if some vaidation fails.
Raises a Dynamoid::Errors::UnknownAttribute
exception if any of the attributes is not on the model
532 533 534 535 |
# File 'lib/dynamoid/persistence.rb', line 532 def update_attributes!(attributes) attributes.each { |attribute, value| write_attribute(attribute, value) } save! end |