mirror of
https://github.com/aasm/aasm
synced 2023-03-27 23:22:41 -04:00
Add [sequel](http://sequel.jeremyevans.net/) support.
I am trying to migrate some activerecord code to sequel, and this makes aasm work for sequel out of the box. This is not yet feature complete as for activerecord, missing some scope related features. However this could be a start, and to be honest, since we're not using them, this is far good enough for us. I have tried my best to make this aligned with activerecord and mongoid, and I've overridden `aasm_read_state` for sequel, because there's no `new_record?` but only `new?` in sequel, and there's no `blank?`, either. (which I believe is provided in activesupport, which sequel does not depend on, and I don't want to force people to depend on that.) Thanks for considering.
This commit is contained in:
parent
421b60fb1f
commit
c1461fbf6c
3 changed files with 214 additions and 0 deletions
|
@ -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
|
||||
|
||||
|
|
108
lib/aasm/persistence/sequel_persistence.rb
Normal file
108
lib/aasm/persistence/sequel_persistence.rb
Normal file
|
@ -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 <tt>aasm.current_state</tt>
|
||||
#
|
||||
# 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 <tt>state</tt> 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 <tt>state</tt> 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
|
103
spec/unit/persistence/sequel_persistence_spec.rb
Normal file
103
spec/unit/persistence/sequel_persistence_spec.rb
Normal file
|
@ -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
|
Loading…
Reference in a new issue