diff --git a/lib/aasm/persistence.rb b/lib/aasm/persistence.rb
index d376322..6b01079 100644
--- a/lib/aasm/persistence.rb
+++ b/lib/aasm/persistence.rb
@@ -12,6 +12,9 @@ module AASM
elsif hierarchy.include?("Mongoid::Document")
require_files_for(:mongoid)
base.send(:include, AASM::Persistence::MongoidPersistence)
+ elsif hierarchy.include?("Sequel::Model")
+ require_files_for(:sequel)
+ base.send(:include, AASM::Persistence::SequelPersistence)
end
end
diff --git a/lib/aasm/persistence/sequel_persistence.rb b/lib/aasm/persistence/sequel_persistence.rb
new file mode 100644
index 0000000..0801a1e
--- /dev/null
+++ b/lib/aasm/persistence/sequel_persistence.rb
@@ -0,0 +1,108 @@
+module AASM
+ module Persistence
+ module SequelPersistence
+ def self.included(base)
+ base.send(:include, AASM::Persistence::Base)
+ base.send(:include, AASM::Persistence::SequelPersistence::InstanceMethods)
+ end
+
+ module InstanceMethods
+ def before_validation
+ aasm_ensure_initial_state
+ super
+ end
+
+ def before_create
+ aasm_ensure_initial_state
+ super
+ end
+
+ # Returns the value of the aasm_column - called from aasm.current_state
+ #
+ # If it's a new record, and the aasm state column is blank it returns the initial state
+ #
+ # class Foo < Sequel::Model
+ # include AASM
+ # aasm :column => :status do
+ # state :opened
+ # state :closed
+ # end
+ # end
+ #
+ # foo = Foo.new
+ # foo.current_state # => :opened
+ # foo.close
+ # foo.current_state # => :closed
+ #
+ # foo = Foo[1]
+ # foo.current_state # => :opened
+ # foo.aasm_state = nil
+ # foo.current_state # => nil
+ #
+ # NOTE: intended to be called from an event
+ #
+ # This allows for nil aasm states - be sure to add validation to your model
+ def aasm_read_state
+ state = send(self.class.aasm_column)
+ if new? && state.to_s.strip.empty?
+ aasm.determine_state_name(self.class.aasm.initial_state)
+ elsif state.nil?
+ nil
+ else
+ state.to_sym
+ end
+ end
+
+ # 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.enter_initial_state if
+ send(self.class.aasm_column).to_s.strip.empty?
+ end
+
+ # Writes state to the state column and persists it to the database
+ #
+ # foo = Foo[1]
+ # foo.aasm.current_state # => :opened
+ # foo.close!
+ # foo.aasm.current_state # => :closed
+ # Foo[1].aasm.current_state # => :closed
+ #
+ # NOTE: intended to be called from an event
+ def aasm_write_state state
+ aasm_column = self.class.aasm_column
+ update_ony({aasm_column => state.to_s}, aasm_column)
+ end
+
+ # Writes state to the state column, but does not persist it to the database
+ #
+ # foo = Foo[1]
+ # foo.aasm.current_state # => :opened
+ # foo.close
+ # foo.aasm.current_state # => :closed
+ # Foo[1].aasm.current_state # => :opened
+ # foo.save
+ # foo.aasm.current_state # => :closed
+ # Foo[1].aasm.current_state # => :closed
+ #
+ # NOTE: intended to be called from an event
+ def aasm_write_state_without_persistence state
+ send("#{self.class.aasm_column}=", state.to_s)
+ end
+ end
+ end
+ end
+end
diff --git a/spec/unit/persistence/sequel_persistence_spec.rb b/spec/unit/persistence/sequel_persistence_spec.rb
new file mode 100644
index 0000000..0eb970b
--- /dev/null
+++ b/spec/unit/persistence/sequel_persistence_spec.rb
@@ -0,0 +1,103 @@
+
+describe 'sequel' do
+ begin
+ require 'sequel'
+ require 'logger'
+ require 'spec_helper'
+
+ before(:all) do
+ db = Sequel.sqlite
+ # if you want to see the statements while running the spec enable the following line
+ # db.loggers << Logger.new($stderr)
+ db.create_table(:models) do
+ primary_key :id
+ String :status
+ end
+
+ @model = Class.new(Sequel::Model(db)) do
+ set_dataset(:models)
+ attr_accessor :default
+ include AASM
+ 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
+ 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 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
+ allow(model).to receive(:new?).and_return(false)
+ model.status = "gamma"
+ expect(model.aasm.current_state).to eq(:gamma)
+ end
+
+ it "should allow a nil state" do
+ allow(model).to receive(:new?).and_return(false)
+ model.status = nil
+ expect(model.aasm.current_state).to be_nil
+ end
+
+ it "should call aasm_ensure_initial_state on validation before create" do
+ expect(model).to receive(:aasm_ensure_initial_state).and_return(true)
+ model.valid?
+ end
+
+ it "should call aasm_ensure_initial_state before create, even if skipping validations" do
+ expect(model).to receive(:aasm_ensure_initial_state).and_return(true)
+ model.save(:validate => false)
+ 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_column).to eq(:status)
+ expect(Class.new(@model).aasm_column).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 "Not running Sequel specs because sequel gem if not installed!!!"
+ end
+end