mirror of
https://github.com/aasm/aasm
synced 2023-03-27 23:22:41 -04:00
Add [dynamoid](http://github.com/Veraticus/Dynamoid) support.
This commit is contained in:
parent
ea0b5a8a23
commit
30b1edb1e7
17 changed files with 452 additions and 0 deletions
|
@ -26,6 +26,11 @@ gemfile:
|
|||
- gemfiles/rails_4.2_mongoid_5.gemfile
|
||||
- gemfiles/rails_4.2_mongo_mapper.gemfile
|
||||
|
||||
before_script:
|
||||
- mkdir /tmp/dynamodb
|
||||
- wget -O - http://dynamodb-local.s3-website-us-west-2.amazonaws.com/dynamodb_local_latest | tar xz --directory /tmp/dynamodb
|
||||
- java -Djava.library.path=/tmp/dynamodb/DynamoDBLocal_lib -jar /tmp/dynamodb/DynamoDBLocal.jar -inMemory -delayTransientStatuses -port 30180 &
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rvm: rbx-2.2.1
|
||||
|
|
2
Gemfile
2
Gemfile
|
@ -7,6 +7,8 @@ gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
|||
gem "rails", "~>4.2"
|
||||
gem 'mongoid', '~>4.0' if Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.create('1.9.3')
|
||||
gem 'sequel'
|
||||
gem 'dynamoid', '~> 1'
|
||||
gem 'aws-sdk', '~>2'
|
||||
# Since mongoid V4 requires incompatible bson V2, cannot have mongoid (V4 or greater)
|
||||
# and mongo_mapper ( or mongo ) in the same application
|
||||
# gem 'mongo_mapper', '~> 0.13'
|
||||
|
|
|
@ -8,5 +8,7 @@ gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
|||
gem "rails", "4.0.13"
|
||||
gem 'mongoid', '~>4.0' if Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.create('1.9.3')
|
||||
gem 'sequel'
|
||||
gem 'dynamoid', '~> 1', :platforms => :ruby
|
||||
gem 'aws-sdk', '~>2', :platforms => :ruby
|
||||
|
||||
gemspec :path => "../"
|
||||
|
|
|
@ -10,5 +10,7 @@ gem "rails", "4.0.13"
|
|||
gem 'sequel'
|
||||
gem 'mongo_mapper', '~>0.13'
|
||||
gem 'bson_ext', :platforms => :ruby
|
||||
gem 'dynamoid', '~> 1', :platforms => :ruby
|
||||
gem 'aws-sdk', '~>2', :platforms => :ruby
|
||||
|
||||
gemspec :path => "../"
|
||||
|
|
|
@ -8,5 +8,7 @@ gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
|||
gem "rails", "4.1.9"
|
||||
gem 'mongoid', '~>4.0' if Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.create('1.9.3')
|
||||
gem 'sequel'
|
||||
gem 'dynamoid', '~> 1', :platforms => :ruby
|
||||
gem 'aws-sdk', '~>2', :platforms => :ruby
|
||||
|
||||
gemspec :path => "../"
|
||||
|
|
|
@ -10,5 +10,7 @@ gem "rails", "4.1.9"
|
|||
gem 'sequel'
|
||||
gem 'mongo_mapper', '~> 0.13'
|
||||
gem 'bson_ext', :platforms => :ruby
|
||||
gem 'dynamoid', '~> 1', :platforms => :ruby
|
||||
gem 'aws-sdk', '~>2', :platforms => :ruby
|
||||
|
||||
gemspec :path => "../"
|
||||
|
|
|
@ -8,5 +8,7 @@ gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
|||
gem "rails", "4.2.0"
|
||||
gem 'mongoid', '~>4.0' if Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.create('1.9.3')
|
||||
gem 'sequel'
|
||||
gem 'dynamoid', '~> 1', :platforms => :ruby
|
||||
gem 'aws-sdk', '~>2', :platforms => :ruby
|
||||
|
||||
gemspec :path => "../"
|
||||
|
|
|
@ -10,5 +10,7 @@ gem "rails", "4.2.0"
|
|||
gem 'sequel'
|
||||
gem 'mongo_mapper'
|
||||
gem 'bson_ext', :platforms => :ruby
|
||||
gem 'dynamoid', '~> 1', :platforms => :ruby
|
||||
gem 'aws-sdk', '~>2', :platforms => :ruby
|
||||
|
||||
gemspec :path => "../"
|
||||
|
|
|
@ -8,5 +8,7 @@ gem "activerecord-jdbcsqlite3-adapter", :platforms => :jruby
|
|||
gem "rails", "4.2.0"
|
||||
gem 'mongoid', '~>5.0' if Gem::Version.create(RUBY_VERSION.dup) >= Gem::Version.create('1.9.3')
|
||||
gem 'sequel'
|
||||
gem 'dynamoid', '~> 1', :platforms => :ruby
|
||||
gem 'aws-sdk', '~>2', :platforms => :ruby
|
||||
|
||||
gemspec :path => "../"
|
||||
|
|
|
@ -14,6 +14,8 @@ module AASM
|
|||
include_persistence base, :mongo_mapper
|
||||
elsif hierarchy.include?("Sequel::Model")
|
||||
include_persistence base, :sequel
|
||||
elsif hierarchy.include?("Dynamoid::Document")
|
||||
include_persistence base, :dynamoid
|
||||
else
|
||||
include_persistence base, :plain
|
||||
end
|
||||
|
|
94
lib/aasm/persistence/dynamoid_persistence.rb
Normal file
94
lib/aasm/persistence/dynamoid_persistence.rb
Normal file
|
@ -0,0 +1,94 @@
|
|||
require_relative 'base'
|
||||
|
||||
module AASM
|
||||
module Persistence
|
||||
module DynamoidPersistence
|
||||
def self.included(base)
|
||||
base.send(:include, AASM::Persistence::Base)
|
||||
base.send(:include, AASM::Persistence::DynamoidPersistence::InstanceMethods)
|
||||
|
||||
base.after_initialize :aasm_ensure_initial_state
|
||||
|
||||
# Because Dynamoid only use define_method to add attribute assignment method in Class.
|
||||
#
|
||||
# In AASM::Base.initialize, it redefines and calls super in this method without superclass method.
|
||||
# We override method_missing to solve this problem.
|
||||
#
|
||||
base.class_eval %Q(
|
||||
def method_missing(method_name, *arguments, &block)
|
||||
if (AASM::StateMachine[self.class].keys.map { |state_machine_name| self.class.aasm(state_machine_name).attribute_name.to_s + "=" }).include? method_name.to_s
|
||||
attribute_name = method_name.to_s.gsub("=", '')
|
||||
write_attribute(attribute_name.to_sym, *arguments)
|
||||
else
|
||||
super
|
||||
end
|
||||
end
|
||||
)
|
||||
end
|
||||
|
||||
module InstanceMethods
|
||||
|
||||
# Writes <tt>state</tt> to the state column and persists it to the database
|
||||
# using update_attribute (which bypasses validation)
|
||||
#
|
||||
# foo = Foo.find(1)
|
||||
# foo.aasm.current_state # => :opened
|
||||
# foo.close!
|
||||
# foo.aasm.current_state # => :closed
|
||||
# Foo.find(1).aasm.current_state # => :closed
|
||||
#
|
||||
# NOTE: intended to be called from an event
|
||||
def aasm_write_state(state, name=:default)
|
||||
old_value = read_attribute(self.class.aasm(name).attribute_name)
|
||||
write_attribute(self.class.aasm(name).attribute_name, state.to_s)
|
||||
|
||||
unless self.save(:validate => false)
|
||||
write_attribute(self.class.aasm(name).attribute_name, old_value)
|
||||
return false
|
||||
end
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
# Writes <tt>state</tt> to the state column, but does not persist it to the database
|
||||
#
|
||||
# foo = Foo.find(1)
|
||||
# foo.aasm.current_state # => :opened
|
||||
# foo.close
|
||||
# foo.aasm.current_state # => :closed
|
||||
# Foo.find(1).aasm.current_state # => :opened
|
||||
# foo.save
|
||||
# foo.aasm.current_state # => :closed
|
||||
# Foo.find(1).aasm.current_state # => :closed
|
||||
#
|
||||
# NOTE: intended to be called from an event
|
||||
def aasm_write_state_without_persistence(state, name=:default)
|
||||
write_attribute(self.class.aasm(name).attribute_name, state.to_s)
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Ensures that if the aasm_state column is nil and the record is new
|
||||
# that the initial state gets populated before validation on create
|
||||
#
|
||||
# foo = Foo.new
|
||||
# foo.aasm_state # => nil
|
||||
# foo.valid?
|
||||
# foo.aasm_state # => "open" (where :open is the initial state)
|
||||
#
|
||||
#
|
||||
# foo = Foo.find(:first)
|
||||
# foo.aasm_state # => 1
|
||||
# foo.aasm_state = nil
|
||||
# foo.valid?
|
||||
# foo.aasm_state # => nil
|
||||
#
|
||||
def aasm_ensure_initial_state
|
||||
AASM::StateMachine[self.class].keys.each do |state_machine_name|
|
||||
aasm(state_machine_name).enter_initial_state if send(self.class.aasm(state_machine_name).attribute_name).blank?
|
||||
end
|
||||
end
|
||||
end # InstanceMethods
|
||||
end
|
||||
end # Persistence
|
||||
end # AASM
|
37
spec/models/dynamoid/complex_dynamoid_example.rb
Normal file
37
spec/models/dynamoid/complex_dynamoid_example.rb
Normal file
|
@ -0,0 +1,37 @@
|
|||
class ComplexDynamoidExample
|
||||
include Dynamoid::Document
|
||||
include AASM
|
||||
|
||||
field :left
|
||||
field :right
|
||||
|
||||
aasm :left, :column => 'left' do
|
||||
state :one, :initial => true
|
||||
state :two
|
||||
state :three
|
||||
|
||||
event :increment do
|
||||
transitions :from => :one, :to => :two
|
||||
transitions :from => :two, :to => :three
|
||||
end
|
||||
event :reset do
|
||||
transitions :from => :three, :to => :one
|
||||
end
|
||||
end
|
||||
|
||||
aasm :right, :column => 'right' do
|
||||
state :alpha, :initial => true
|
||||
state :beta
|
||||
state :gamma
|
||||
|
||||
event :level_up do
|
||||
transitions :from => :alpha, :to => :beta
|
||||
transitions :from => :beta, :to => :gamma
|
||||
end
|
||||
event :level_down do
|
||||
transitions :from => :gamma, :to => :beta
|
||||
transitions :from => :beta, :to => :alpha
|
||||
end
|
||||
end
|
||||
|
||||
end
|
18
spec/models/dynamoid/dynamoid_multiple.rb
Normal file
18
spec/models/dynamoid/dynamoid_multiple.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
class DynamoidMultiple
|
||||
include Dynamoid::Document
|
||||
include AASM
|
||||
|
||||
field :status
|
||||
|
||||
attr_accessor :default
|
||||
|
||||
aasm :left, :column => :status
|
||||
aasm :left do
|
||||
state :alpha, :initial => true
|
||||
state :beta
|
||||
state :gamma
|
||||
event :release do
|
||||
transitions :from => [:alpha, :beta, :gamma], :to => :beta
|
||||
end
|
||||
end
|
||||
end
|
18
spec/models/dynamoid/dynamoid_simple.rb
Normal file
18
spec/models/dynamoid/dynamoid_simple.rb
Normal file
|
@ -0,0 +1,18 @@
|
|||
class DynamoidSimple
|
||||
include Dynamoid::Document
|
||||
include AASM
|
||||
|
||||
field :status
|
||||
|
||||
attr_accessor :default
|
||||
|
||||
aasm :column => :status
|
||||
aasm do
|
||||
state :alpha, :initial => true
|
||||
state :beta
|
||||
state :gamma
|
||||
event :release do
|
||||
transitions :from => [:alpha, :beta, :gamma], :to => :beta
|
||||
end
|
||||
end
|
||||
end
|
|
@ -18,6 +18,39 @@ def load_schema
|
|||
require File.dirname(__FILE__) + "/database.rb"
|
||||
end
|
||||
|
||||
# Dynamoid initialization
|
||||
begin
|
||||
require 'dynamoid'
|
||||
require 'aws-sdk-resources'
|
||||
|
||||
ENV['ACCESS_KEY'] ||= 'abcd'
|
||||
ENV['SECRET_KEY'] ||= '1234'
|
||||
|
||||
Aws.config.update({
|
||||
region: 'us-west-2',
|
||||
credentials: Aws::Credentials.new(ENV['ACCESS_KEY'], ENV['SECRET_KEY'])
|
||||
})
|
||||
|
||||
Dynamoid.configure do |config|
|
||||
config.namespace = "dynamoid_tests"
|
||||
config.endpoint = 'http://127.0.0.1:30180'
|
||||
config.warn_on_scan = false
|
||||
end
|
||||
|
||||
Dynamoid.logger.level = Logger::FATAL
|
||||
|
||||
RSpec.configure do |c|
|
||||
c.before(:each) do
|
||||
Dynamoid.adapter.list_tables.each do |table|
|
||||
Dynamoid.adapter.delete_table(table) if table =~ /^#{Dynamoid::Config.namespace}/
|
||||
end
|
||||
Dynamoid.adapter.tables.clear
|
||||
end
|
||||
end
|
||||
rescue LoadError
|
||||
# Without Dynamoid settings
|
||||
end
|
||||
|
||||
# custom spec helpers
|
||||
Dir[File.dirname(__FILE__) + "/spec_helpers/**/*.rb"].sort.each { |f| require File.expand_path(f) }
|
||||
|
||||
|
|
140
spec/unit/persistence/dynamoid_persistence_multiple_spec.rb
Normal file
140
spec/unit/persistence/dynamoid_persistence_multiple_spec.rb
Normal file
|
@ -0,0 +1,140 @@
|
|||
describe 'dynamoid' do
|
||||
begin
|
||||
require 'dynamoid'
|
||||
require 'logger'
|
||||
require 'spec_helper'
|
||||
|
||||
Dir[File.dirname(__FILE__) + "/../../models/dynamoid/*.rb"].sort.each do |f|
|
||||
require File.expand_path(f)
|
||||
end
|
||||
|
||||
before(:all) do
|
||||
@model = DynamoidMultiple
|
||||
end
|
||||
|
||||
describe "instance methods" do
|
||||
let(:model) {@model.new}
|
||||
|
||||
it "should respond to aasm persistence methods" do
|
||||
expect(model).to respond_to(:aasm_read_state)
|
||||
expect(model).to respond_to(:aasm_write_state)
|
||||
expect(model).to respond_to(:aasm_write_state_without_persistence)
|
||||
end
|
||||
|
||||
it "should return the initial state when new and the aasm field is nil" do
|
||||
expect(model.aasm(:left).current_state).to eq(:alpha)
|
||||
end
|
||||
|
||||
it "should save the initial state" do
|
||||
model.save
|
||||
expect(model.status).to eq("alpha")
|
||||
end
|
||||
|
||||
it "should return the aasm column when new and the aasm field is not nil" do
|
||||
model.status = "beta"
|
||||
expect(model.aasm(:left).current_state).to eq(:beta)
|
||||
end
|
||||
|
||||
it "should return the aasm column when not new and the aasm_column is not nil" do
|
||||
model.save
|
||||
model.status = "gamma"
|
||||
expect(model.aasm(:left).current_state).to eq(:gamma)
|
||||
end
|
||||
|
||||
it "should allow a nil state" do
|
||||
model.save
|
||||
model.status = nil
|
||||
expect(model.aasm(:left).current_state).to be_nil
|
||||
end
|
||||
|
||||
it "should not change the state if state is not loaded" do
|
||||
model.release
|
||||
model.save
|
||||
model.reload
|
||||
expect(model.aasm(:left).current_state).to eq(:beta)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'subclasses' do
|
||||
it "should have the same states as its parent class" do
|
||||
expect(Class.new(@model).aasm(:left).states).to eq(@model.aasm(:left).states)
|
||||
end
|
||||
|
||||
it "should have the same events as its parent class" do
|
||||
expect(Class.new(@model).aasm(:left).events).to eq(@model.aasm(:left).events)
|
||||
end
|
||||
|
||||
it "should have the same column as its parent even for the new dsl" do
|
||||
expect(@model.aasm(:left).attribute_name).to eq(:status)
|
||||
expect(Class.new(@model).aasm(:left).attribute_name).to eq(:status)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'initial states' do
|
||||
it 'should support conditions' do
|
||||
@model.aasm(:left) do
|
||||
initial_state lambda{ |m| m.default }
|
||||
end
|
||||
|
||||
expect(@model.new(:default => :beta).aasm(:left).current_state).to eq(:beta)
|
||||
expect(@model.new(:default => :gamma).aasm(:left).current_state).to eq(:gamma)
|
||||
end
|
||||
end
|
||||
|
||||
describe "complex example" do
|
||||
it "works" do
|
||||
record = ComplexDynamoidExample.new
|
||||
expect(record.aasm(:left).current_state).to eql :one
|
||||
expect(record.aasm(:right).current_state).to eql :alpha
|
||||
|
||||
record.save
|
||||
expect_aasm_states record, :one, :alpha
|
||||
record.reload
|
||||
expect_aasm_states record, :one, :alpha
|
||||
|
||||
record.increment!
|
||||
expect_aasm_states record, :two, :alpha
|
||||
record.reload
|
||||
expect_aasm_states record, :two, :alpha
|
||||
|
||||
record.level_up!
|
||||
expect_aasm_states record, :two, :beta
|
||||
record.reload
|
||||
expect_aasm_states record, :two, :beta
|
||||
|
||||
record.increment!
|
||||
expect { record.increment! }.to raise_error(AASM::InvalidTransition)
|
||||
expect_aasm_states record, :three, :beta
|
||||
record.reload
|
||||
expect_aasm_states record, :three, :beta
|
||||
|
||||
record.level_up!
|
||||
expect_aasm_states record, :three, :gamma
|
||||
record.reload
|
||||
expect_aasm_states record, :three, :gamma
|
||||
|
||||
record.level_down # without saving
|
||||
expect_aasm_states record, :three, :beta
|
||||
record.reload
|
||||
expect_aasm_states record, :three, :gamma
|
||||
|
||||
record.level_down # without saving
|
||||
expect_aasm_states record, :three, :beta
|
||||
record.reset!
|
||||
expect_aasm_states record, :one, :beta
|
||||
end
|
||||
|
||||
def expect_aasm_states(record, left_state, right_state)
|
||||
expect(record.aasm(:left).current_state).to eql left_state.to_sym
|
||||
expect(record.left).to eql left_state.to_s
|
||||
expect(record.aasm(:right).current_state).to eql right_state.to_sym
|
||||
expect(record.right).to eql right_state.to_s
|
||||
end
|
||||
end
|
||||
|
||||
rescue LoadError
|
||||
puts "------------------------------------------------------------------------"
|
||||
puts "Not running Dynamoid multiple-specs because dynamoid gem is not installed!!!"
|
||||
puts "------------------------------------------------------------------------"
|
||||
end
|
||||
end
|
89
spec/unit/persistence/dynamoid_persistence_spec.rb
Normal file
89
spec/unit/persistence/dynamoid_persistence_spec.rb
Normal file
|
@ -0,0 +1,89 @@
|
|||
describe 'dynamoid' do
|
||||
begin
|
||||
require 'dynamoid'
|
||||
require 'logger'
|
||||
require 'spec_helper'
|
||||
|
||||
Dir[File.dirname(__FILE__) + "/../../models/dynamoid/*.rb"].sort.each do |f|
|
||||
require File.expand_path(f)
|
||||
end
|
||||
|
||||
before(:all) do
|
||||
@model = DynamoidSimple
|
||||
end
|
||||
|
||||
describe "instance methods" do
|
||||
let(:model) {@model.new}
|
||||
|
||||
it "should respond to aasm persistence methods" do
|
||||
expect(model).to respond_to(:aasm_read_state)
|
||||
expect(model).to respond_to(:aasm_write_state)
|
||||
expect(model).to respond_to(:aasm_write_state_without_persistence)
|
||||
end
|
||||
|
||||
it "should return the initial state when new and the aasm field is nil" do
|
||||
expect(model.aasm.current_state).to eq(:alpha)
|
||||
end
|
||||
|
||||
it "should save the initial state" do
|
||||
model.save
|
||||
expect(model.status).to eq("alpha")
|
||||
end
|
||||
|
||||
it "should return the aasm column when new and the aasm field is not nil" do
|
||||
model.status = "beta"
|
||||
expect(model.aasm.current_state).to eq(:beta)
|
||||
end
|
||||
|
||||
it "should return the aasm column when not new and the aasm_column is not nil" do
|
||||
model.save
|
||||
model.status = "gamma"
|
||||
expect(model.aasm.current_state).to eq(:gamma)
|
||||
end
|
||||
|
||||
it "should allow a nil state" do
|
||||
model.save
|
||||
model.status = nil
|
||||
expect(model.aasm.current_state).to be_nil
|
||||
end
|
||||
|
||||
it "should not change the state if state is not loaded" do
|
||||
model.release
|
||||
model.save
|
||||
model.reload
|
||||
expect(model.aasm.current_state).to eq(:beta)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'subclasses' do
|
||||
it "should have the same states as its parent class" do
|
||||
expect(Class.new(@model).aasm.states).to eq(@model.aasm.states)
|
||||
end
|
||||
|
||||
it "should have the same events as its parent class" do
|
||||
expect(Class.new(@model).aasm.events).to eq(@model.aasm.events)
|
||||
end
|
||||
|
||||
it "should have the same column as its parent even for the new dsl" do
|
||||
expect(@model.aasm.attribute_name).to eq(:status)
|
||||
expect(Class.new(@model).aasm.attribute_name).to eq(:status)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'initial states' do
|
||||
it 'should support conditions' do
|
||||
@model.aasm do
|
||||
initial_state lambda{ |m| m.default }
|
||||
end
|
||||
|
||||
expect(@model.new(:default => :beta).aasm.current_state).to eq(:beta)
|
||||
expect(@model.new(:default => :gamma).aasm.current_state).to eq(:gamma)
|
||||
end
|
||||
end
|
||||
|
||||
rescue LoadError
|
||||
puts "------------------------------------------------------------------------"
|
||||
puts "Not running Dynamoid specs because dynamoid gem is not installed!!!"
|
||||
puts "------------------------------------------------------------------------"
|
||||
end
|
||||
end
|
Loading…
Reference in a new issue