Skip to content
Browse files

Committing plugin source files! Let's see if it works.

  • Loading branch information...
1 parent a50cd7e commit 9c68f8ff2537993320e4ad75c160bdfb8db012e7 @daicoden committed May 11, 2010
Showing with 783 additions and 0 deletions.
  1. +163 −0 lib/sequel_proc_error_handling.rb
  2. +534 −0 spec/sequel_proc_error_handling_spec.rb
  3. +86 −0 spec/spec_helper.rb
View
163 lib/sequel_proc_error_handling.rb
@@ -0,0 +1,163 @@
+module Sequel
+ module Plugins
+ # Proc Error Handling is a plugin to help handle validation errors
+ # by providing context specific error handling as proc objects.
+ #
+ # example:
+ #
+ # filter_restricted = proc do |klass, values|
+ # if $!.message =~ /doesn't exist or access is restricted to it/
+ # values.delete_if { |k,v| klass.restricted_columns.include? k }
+ # :retry
+ # end
+ # end
+ #
+ # Foo.new(:restricted_column => 'value') # raises error
+ # Foo.new(:restricted_column => 'value', filter_restricted) # No Error
+ #
+ # This plugin is helpful when you don't want to be changing a model's
+ # error settings to acomodate unverified data in one area of the code,
+ # but still want the strict errors in a more secure area of the code.
+ module ProcErrorHandling
+ def self.apply(model)
+ end
+
+ def self.configure(model,&block)
+ end
+
+ module InstanceMethods
+ def update(hash,*error_proc)
+ super(hash)
+ rescue
+ result = PEH.send(:process_error_proc,error_proc,self,hash)
+ retry if result == :retry
+ result
+ end
+
+ def update_all(hash, *error_proc)
+ super(hash)
+ rescue
+ result = PEH.send(:process_error_proc,error_proc,self,hash)
+ retry if result == :retry
+ result
+ end
+
+ def update_except(hash, *except)
+ error_procs = []
+ error_procs.unshift except.pop while except.last.is_a? Proc
+
+ # Only want to retry the update, don't want to clear error_procs
+ begin
+ super(hash,*except)
+ rescue
+ result = PEH.send(:process_error_proc,error_procs,self,hash)
+ retry if result == :retry
+ result
+ end
+ end
+
+ def update_only(hash, *only)
+ error_procs = []
+ error_procs.unshift only.pop while only.last.is_a? Proc
+
+ begin
+ super(hash,*only)
+ rescue
+ result = PEH.send(:process_error_proc,error_procs,self,hash)
+ retry if result == :retry
+ result
+ end
+ end
+
+ def initialize(values = {}, *args,&block)
+ orig = args.dup
+ error_procs = []
+ error_procs.unshift args.pop while args.last.is_a? Proc
+ from_db = args.pop || false # First value will be nil or boolean
+ raise ArgumentError,
+ "Invalid Arguments passed to #new #{orig.inpsect}" unless args.empty?
+
+ begin
+ super(values,from_db,&block)
+ rescue
+ result = PEH.send(:process_error_proc,error_procs,self,values)
+ retry if result == :retry
+ # Special for new since we can't return anything else
+ if result.is_a? self.class
+ values = result.values
+ from_db = true unless result.new?
+ retry
+ end
+ # Should not get here... means result was something other
+ # then :raise, :retry, nil, or an instance of self.class
+ raise "#new can not return any other object, there is" <<
+ " an error in your PEH proc"
+ end
+ end
+
+ def save(*columns)
+ error_procs = []
+ error_procs.unshift columns.pop while columns.last.is_a? Proc
+
+ begin
+ super(*columns)
+ rescue
+ result = PEH.send(:process_error_proc,error_procs,self,values)
+ retry if result == :retry
+ result
+ end
+ end
+
+ end
+
+ module ClassMethods
+ def create(values = {}, *error_proc, &block)
+ new(values,*error_proc, &block).save *error_proc
+ end
+
+ def on_error(&block)
+ @peh_error_block = block
+ end
+
+ def peh_error_occured(model)
+ if @peh_error_block
+ @peh_error_block.call(model)
+ elsif superclass.respond_to? :peh_error_occured
+ superclass.peh_error_occured(model)
+ end
+ end
+ end
+
+ module DatasetMethods
+ end
+
+ def self.process_error_proc(procs,obj,hash)
+ klass = obj.class
+ # if procs is nil then compact array and result will be nil
+ # if procs is single proc wrap in array so code runs normaly
+ # if procs is array execute each one till value returned
+ procs = [procs].compact unless procs.is_a? Array
+ result = procs.each do |ep|
+ val = ep.call(klass,hash)
+ break val unless val.nil?
+ end
+ # if result is the original array then error handling failed
+ result = (result == procs) ? nil : result
+
+ if result == :raise or result.nil?
+ klass.peh_error_occured(obj)
+ raise $!
+ end
+ if result != nil and result != :retry and result.class != obj.class
+ raise Sequel::Error, "An error handling proc must return either " <<
+ "nil, :raise, :retry, or an instance of the klass it is rescuing."
+ end
+ result
+ end
+
+ private_class_method :process_error_proc
+ end
+
+ PEH = ProcErrorHandling
+ end
+end
View
534 spec/sequel_proc_error_handling_spec.rb
@@ -0,0 +1,534 @@
+require File.join(File.dirname(__FILE__), "spec_helper")
+
+# Someone please tell me that there is actually a good mocking system...
+# looking at other plugins they mock the database for each response,
+# GAH!!! :-/
+describe "Sequel::Plugins::ProcErrorHandling" do
+ before(:each) do
+ @db = db = MODEL_DB.clone
+ def db.schema(table,opts={})
+ {
+ foos: [
+ [ :id, type: :integer, primary_key: true ],
+ [ :value, type: :string ],
+ [ :unique, type: :string ],
+ [ :required, type: :string ],
+ [ :restricted, type: :string ]
+ ]
+ }[table]
+ end
+
+ def db.dataset(*args)
+ ds = super(*args)
+ def ds.columns
+ {
+ [:foos] => [:id, :value, :unique, :required]
+ }[opts[:from] + (opts[:join] || []).map { |x| x.table }]
+ end
+ ds
+ end
+
+ class ::Foo < Sequel::Model(db)
+ set_restricted_columns :restricted
+ def validate
+ errors.add(:required, "is required.") unless required
+ errors.add(:unique, "must be unique.") if
+ m = self.class.first("unique = ?",unique) and m.id != self.id
+ end
+ end
+ @c = ::Foo
+ @c.plugin :proc_error_handling
+
+ def valid_attributes
+ {
+ value: 'value',
+ unique: "unique#{Foo.count}",
+ required: 'required'
+ }
+ end
+ @ds = Foo.dataset
+ @db.reset
+
+ ::GET_BY_UNIQUE0 =
+ "SELECT * FROM foos WHERE (unique = 'unique0') LIMIT 1" unless
+ defined? ::GET_BY_UNIQUE0
+ ::GET_BY_UNIQUE1 =
+ "SELECT * FROM foos WHERE (unique = 'unique1') LIMIT 1" unless
+ defined? ::GET_BY_UNIQUE1
+ ::GET_FOO_COUNT =
+ "SELECT COUNT(*) AS count FROM foos LIMIT 1" unless
+ defined? ::GET_FOO_COUNT
+ ::GET_ATTRS0_WITH_INSERT = "SELECT * FROM foos WHERE (id IN ('INSERT " <<
+ "INTO foos (value, unique, required) VALUES (''value'', ''unique0'', " <<
+ "''required'')')) LIMIT 1" unless defined? ::GET_ATTRS0_WITH_INSERT
+ ::GET_ATTRS0_WITH_WTF = "SELECT * FROM foos WHERE (id IN ('INSERT INTO " <<
+ "foos (value, unique, required) VALUES (''value'', ''unique0'', " <<
+ "''required'')', 'INSERT INTO foos (value, unique, required, id) " <<
+ "VALUES (''value'', ''unique0'', ''required'', (''INSERT INTO foos " <<
+ "(value, unique, required) VALUES (''''value'''', ''''unique0'''', " <<
+ "''''required'''')''))')) LIMIT 1" unless defined? ::GET_ATTRS0_WITH_WTF
+ ::GET_ATTRS0_MOCK_SUCKS = "SELECT * FROM foos WHERE (id IN ('INSERT " <<
+ "INTO foos (value, unique, required) VALUES (''value'', ''unique0'', " <<
+ "''required'')', 'INSERT INTO foos (value, unique, required) VALUES " <<
+ "(''value'', ''unique0'', ''required'')')) LIMIT 1" unless
+ defined? ::GET_ATTRS0_MOCK_SUCKS
+ ::INSERT_VALID_ATTRS0 = "INSERT INTO foos (value, unique, required) " <<
+ "VALUES ('value', 'unique0', 'required')" unless
+ defined? ::INSERT_VALID_ATTRS0
+ ::GET_ATTRS1_WITH_INSERT = "SELECT * FROM foos WHERE (id IN ('INSERT " <<
+ "INTO foos (value, unique, required) VALUES (''value'', ''unique1'', " <<
+ "''required'')')) LIMIT 1" unless defined? ::GET_ATTRS1_WITH_INSERT
+ ::GET_ATTRS1_WITH_WTF = "SELECT * FROM foos WHERE (id IN ('INSERT INTO " <<
+ "foos (value, unique, required) VALUES (''value'', ''unique1'', " <<
+ "''required'')', 'INSERT INTO foos (value, unique, required, id) " <<
+ "VALUES (''value'', ''unique1'', ''required'', (''INSERT INTO foos " <<
+ "(value, unique, required) VALUES (''''value'''', ''''unique1'''', " <<
+ "''''required'''')''))')) LIMIT 1" unless defined? ::GET_ATTRS1_WITH_WTF
+ ::GET_ATTRS1_MOCK_SUCKS = "SELECT * FROM foos WHERE (id IN ('INSERT " <<
+ "INTO foos (value, unique, required) VALUES (''value'', ''unique1'', " <<
+ "''required'')', 'INSERT INTO foos (value, unique, required) VALUES " <<
+ "(''value'', ''unique1'', ''required'')')) LIMIT 1" unless
+ defined? ::GET_ATTRS1_MOCK_SUCKS
+ ::INSERT_VALID_ATTRS1 = "INSERT INTO foos (value, unique, required) " <<
+ "VALUES ('value', 'unique1', 'required')" unless
+ defined? ::INSERT_VALID_ATTRS1
+
+ def define_virgin_dataset(ds)
+ def ds.fetch_rows(sql)
+ case sql
+ when GET_BY_UNIQUE0
+ #nop
+ when GET_FOO_COUNT
+ yield({:count => 0})
+ when INSERT_VALID_ATTRS0,
+ GET_ATTRS0_WITH_INSERT,
+ GET_ATTRS0_WITH_WTF,
+ GET_ATTRS0_MOCK_SUCKS
+ yield({
+ id: 1,
+ value: 'value',
+ unique: 'unique0',
+ required: 'required'
+ })
+ else
+ raise "SQL not handled #{sql}"
+ end
+ end
+ end
+
+ def define_one_record_dataset(ds)
+ def ds.fetch_rows(sql)
+ case sql
+ when GET_BY_UNIQUE0
+ yield({:id => 1, :value => 'value',
+ :unique => 'unique0',
+ :required => 'required'})
+ when GET_FOO_COUNT
+ yield({:count => 1})
+ when INSERT_VALID_ATTRS1,
+ GET_ATTRS1_WITH_INSERT,
+ GET_ATTRS1_WITH_WTF,
+ GET_ATTRS1_MOCK_SUCKS
+ yield({
+ id: 2,
+ value: 'value',
+ unique: 'unique1',
+ required: 'required'})
+ when GET_BY_UNIQUE1
+ else
+ raise "SQL not handled #{sql}"
+ end
+ end
+ end
+
+ def unique_handle
+ proc do |klass,values|
+ if $!.message =~ /must be unique./
+ record = klass.first("unique = ?", values[:unique])
+ record if record.required == values[:required] and
+ record.value == values[:value]
+ end
+ end
+ end
+
+ def required_handle
+ proc do |klass, values|
+ unless values[:required]
+ values[:required] = 'required'
+ :retry
+ end
+ end
+ end
+
+ def false_on_error
+ proc { |klass, values| false }
+ end
+ end
+
+ after(:each) do
+ Object.send(:remove_const, :Foo)
+ end
+
+ it "should implement the plugin framework" do
+ Sequel::Plugins::PEH.should respond_to(:apply)
+ Sequel::Plugins::PEH.should respond_to(:configure)
+
+ defined?(Sequel::Plugins::PEH::InstanceMethods).should eql("constant")
+ defined?(Sequel::Plugins::PEH::ClassMethods).should eql("constant")
+ defined?(Sequel::Plugins::PEH::DatasetMethods).should eql("constant")
+ end
+
+ describe "a proc error handler", :shared => true do
+ it "should error unless result is :retry, nil, or instance of klass" do
+ define_one_record_dataset(@ds)
+
+ # Bad attrs because DB is returning a unique model
+ bad_attrs = valid_attributes.merge :unique => 'unique0'
+ args = [ bad_attrs.dup, *@peh_args ]
+ lambda{ @peh_base.send(@peh_method, *args) }.
+ should raise_error Sequel::ValidationFailed
+ args = [ bad_attrs.dup, *@peh_args ]
+ lambda { @peh_base.send(@peh_method,*args,false_on_error) }.
+ should raise_error Sequel::Error
+ end
+
+ it "should pass error if error not handled" do
+ define_virgin_dataset(@ds)
+
+ bad_attrs = valid_attributes.delete_if { |k,v| k == :required }
+ args = [ bad_attrs.dup, *@peh_args ]
+ lambda{@peh_base.send(@peh_method, *args,unique_handle) }.
+ should raise_error Sequel::ValidationFailed
+ end
+
+ it "should retry DB transaction if specified by block" do
+ define_virgin_dataset(@ds)
+
+ bad_attrs = valid_attributes.delete_if { |k,v| k == :required }
+ args = [ bad_attrs.dup, *@peh_args ]
+ lambda{ @peh_base.send(@peh_method, *args) }.
+ should raise_error Sequel::ValidationFailed
+
+ args = [ bad_attrs.dup, *@peh_args ]
+ @peh_base.send(@peh_method, *args,required_handle).
+ should be_an_instance_of @c
+ end
+
+ it "should take an array of error procs to handle multiple items" do
+ define_one_record_dataset(@ds)
+
+ bad_attrs = valid_attributes.merge(:unique => 'unique0').
+ delete_if { |k,v| k == :required }
+
+ args = [ bad_attrs.dup, *@peh_args ]
+ lambda{ @peh_base.send(@peh_method, *args) }.
+ should raise_error(Sequel::ValidationFailed)
+
+ args = [ bad_attrs.dup, *@peh_args ]
+ lambda{ @peh_base.send(@peh_method, *args,unique_handle) }.
+ should raise_error(Sequel::ValidationFailed)
+
+ args = [ bad_attrs.dup, *@peh_args ]
+ lambda{ @peh_base.send(@peh_method, *args,required_handle) }.
+ should raise_error(Sequel::ValidationFailed)
+
+ args = [ bad_attrs.dup, *@peh_args ]
+ @peh_base.send(@peh_method, *args,unique_handle,required_handle).
+ should be_an_instance_of(@c)
+ end
+
+ it "should raise an error regardless of other handlers if :raise " <<
+ "returned in a block" do
+ define_virgin_dataset(@ds)
+ bad_attrs = valid_attributes
+ bad_attrs[:required] = nil
+ base1 = (@peh_base == @c) ? @c : @peh_base.dup
+ base2 = (@peh_base == @c) ? @c : @peh_base.dup
+ base3 = (@peh_base == @c) ? @c : @peh_base.dup
+
+ args = [ bad_attrs.dup, *@peh_args ]
+ base1.send(@peh_method, *args,required_handle).
+ should be_an_instance_of(@c)
+
+ args = [ bad_attrs.dup, *@peh_args ]
+ base2.send(@peh_method, *args,required_handle, proc{:raise}).
+ should be_an_instance_of(@c)
+
+ args = [ bad_attrs.dup, *@peh_args ]
+ lambda{base3.send(@peh_method, *args, proc{:raise},required_handle)}.
+ should raise_error Sequel::ValidationFailed
+ end
+
+ it "should execute specified block on error" do
+ error_model = nil
+ @c.on_error{ |m| @error_model = m}
+
+ define_one_record_dataset(@ds)
+ bad_attrs = valid_attributes.merge :unique => 'unique0'
+
+ args = [ bad_attrs.dup, *@peh_args ]
+ lambda{
+ @peh_base.send(@peh_method,*args)
+ }.should raise_error Sequel::ValidationFailed
+
+ @error_model.should be_an_instance_of(@c)
+ end
+
+ it "should run the error block of a superclass if no block given" do
+ begin
+ class ::Bar < Foo
+ def validate
+ errors.add(:unique, "must be unique.") if
+ self.class.first("unique = ?",unique)
+ end
+ end
+ Bar.plugin :proc_error_handling
+
+ Foo.on_error{ |m| @error_model = m}
+
+ @peh_base = (@peh_base == @c) ? Bar : Bar.new
+
+ define_one_record_dataset(@ds)
+ bad_attrs = valid_attributes.merge :unique => 'unique0'
+
+ args = [ bad_attrs.dup, *@peh_args ]
+ lambda{ @peh_base.send(@peh_method,*args) }.
+ should raise_error Sequel::ValidationFailed
+
+ @error_model.should be_an_instance_of(Bar)
+ ensure
+ Object.send(:remove_const, :Bar)
+ end
+ end
+
+ end
+
+ describe "(#create)" do
+ before(:each) do
+ @peh_base = @c
+ @peh_method = :create
+ @peh_args = []
+ end
+
+ it "should function normaly with no error handling" do
+ # Inserting a new record in virgin tabel
+ define_virgin_dataset(@ds)
+
+ attrs = valid_attributes
+ @c.create(attrs).should be_an_instance_of(@c)
+ @db.sqls.last.should eql INSERT_VALID_ATTRS0
+ @db.reset
+
+ #mock of dataset with 1 record of id 1
+ define_one_record_dataset(@ds)
+
+ # Unique Failure
+ bad_attrs = attrs.dup
+ lambda{ @c.create(bad_attrs.dup) }.should(
+ raise_error(Sequel::ValidationFailed)
+ )
+ attrs = valid_attributes
+ @c.create(attrs).should be_an_instance_of(@c)
+ @db.sqls.last.should eql INSERT_VALID_ATTRS1
+ @db.reset
+
+ #Required Failure
+ bad_attrs = valid_attributes.delete_if { |k,v| k == :required }
+ lambda{@c.create(bad_attrs.dup)}.should raise_error Sequel::ValidationFailed
+ @db.reset
+
+ @c.create(bad_attrs.dup) { |m| m.required = 'required' }
+ @db.sqls.last.should eql INSERT_VALID_ATTRS1
+ end
+
+ it_should_behave_like "a proc error handler"
+
+ end
+
+ describe "(#update)" do
+ before(:each) do
+ @peh_base = @c.new
+ @peh_method = :update
+ @peh_args = []
+ end
+
+ it_should_behave_like "a proc error handler"
+ end
+
+ describe "(#update_all)" do
+ before(:each) do
+ @peh_base = @c.new
+ @peh_method = :update_all
+ @peh_args = []
+ end
+
+ it_should_behave_like "a proc error handler"
+ end
+
+ describe "(#update_except)" do
+ before(:each) do
+ @peh_base = @c.new
+ @peh_method = :update_except
+ @peh_args = [:a_column]
+ end
+
+ it_should_behave_like "a proc error handler"
+ end
+
+ describe "(#update_only)" do
+ before(:each) do
+ @peh_base = @c.new
+ @peh_method = :update_only
+ @peh_args = [:value, :required, :unique]
+ end
+
+ it_should_behave_like "a proc error handler"
+ end
+
+ describe "(#new)" do
+ it "should recover when a proc is supplied" do
+ define_virgin_dataset(@ds)
+ bad_params = valid_attributes.merge :restricted => 'restricted'
+ lambda{@c.new(bad_params.dup)}.should raise_error
+
+ @c.new(bad_params.dup,proc { |a,b| b.delete(:restricted); :retry }).
+ should be_an_instance_of(@c)
+ end
+
+ it "should load a copy of itself from the db if object is returned by proc" do
+ define_one_record_dataset(@ds)
+ bad_params = valid_attributes.merge :restricted => 'restricted'
+ lambda{@c.new(bad_params.dup)}.should raise_error
+
+ m = @c.new(bad_params.dup,proc { |a,b| a.first("unique = ?",'unique0') })
+ m.should be_an_instance_of(@c)
+ m.should_not be_new
+ m.unique.should eql('unique0')
+ m.required.should eql('required')
+ m.should be_valid
+ end
+ end
+
+ describe "(#save)" do
+ before(:each) do
+ @peh_base = @c.new
+ @peh_methd = :save
+ end
+
+ it "should error unless result is :retry, nil, or instance of klass" do
+ define_one_record_dataset(@ds)
+
+ # Bad attrs because DB is returning a unique model
+ bad_attrs = valid_attributes.merge :unique => 'unique0'
+ m = @c.new(bad_attrs.dup)
+ lambda{ m.save }.
+ should raise_error Sequel::ValidationFailed
+ lambda { m.save(false_on_error) }.
+ should raise_error Sequel::Error
+ end
+
+ it "should pass error if error not handled" do
+ define_virgin_dataset(@ds)
+
+ bad_attrs = valid_attributes.delete_if { |k,v| k == :required }
+ m = @c.new(bad_attrs)
+ lambda{m.save(unique_handle) }.
+ should raise_error Sequel::ValidationFailed
+ end
+
+ it "should retry DB transaction if specified by block" do
+ define_virgin_dataset(@ds)
+
+ bad_attrs = valid_attributes.delete_if { |k,v| k == :required }
+ m = @c.new(bad_attrs.dup)
+ lambda{ m.save }.
+ should raise_error Sequel::ValidationFailed
+
+ m.save(required_handle).
+ should be_an_instance_of @c
+ end
+
+ it "should take an array of error procs to handle multiple items" do
+ define_one_record_dataset(@ds)
+
+ bad_attrs = valid_attributes.merge(:unique => 'unique0').
+ delete_if { |k,v| k == :required }
+
+ m = @c.new(bad_attrs.dup)
+ lambda{ m.save }.
+ should raise_error(Sequel::ValidationFailed)
+
+ m = @c.new(bad_attrs.dup)
+ lambda{ m.save unique_handle }.
+ should raise_error(Sequel::ValidationFailed)
+
+ m = @c.new(bad_attrs.dup)
+ lambda{ m.save required_handle }.
+ should raise_error(Sequel::ValidationFailed)
+
+ m = @c.new(bad_attrs.dup)
+ m.save(unique_handle,required_handle).
+ should be_an_instance_of(@c)
+ end
+
+ it "should raise an error regardless of other handlers if :raise " <<
+ "returned in a block" do
+ define_virgin_dataset(@ds)
+ bad_attrs = valid_attributes
+ bad_attrs[:required] = nil
+
+ m = @c.new(bad_attrs.dup)
+ m.save(required_handle).
+ should be_an_instance_of(@c)
+
+ m = @c.new(bad_attrs.dup)
+ m.save(required_handle, proc{:raise}).
+ should be_an_instance_of(@c)
+
+ m = @c.new(bad_attrs.dup)
+ lambda{m.save(proc{:raise},required_handle)}.
+ should raise_error Sequel::ValidationFailed
+ end
+
+ it "should execute specified block on error" do
+ error_model = nil
+ @c.on_error{ |m| @error_model = m}
+
+ define_one_record_dataset(@ds)
+ bad_attrs = valid_attributes.merge :unique => 'unique0'
+
+ m = @c.new(bad_attrs.dup)
+ lambda{
+ m.save
+ }.should raise_error Sequel::ValidationFailed
+
+ @error_model.should be_an_instance_of(@c)
+ end
+
+ it "should run the error block of a superclass if no block given" do
+ begin
+ class ::Bar < Foo
+ def validate
+ errors.add(:unique, "must be unique.") if
+ self.class.first("unique = ?",unique)
+ end
+ end
+ Bar.plugin :proc_error_handling
+
+ Foo.on_error{ |m| @error_model = m}
+
+ define_one_record_dataset(@ds)
+ bad_attrs = valid_attributes.merge :unique => 'unique0'
+
+ m = Bar.new bad_attrs.dup
+
+ lambda{ m.save }.
+ should raise_error Sequel::ValidationFailed
+
+ @error_model.should be_an_instance_of(Bar)
+ ensure
+ Object.send(:remove_const, :Bar)
+ end
+ end
+ end
+end
View
86 spec/spec_helper.rb
@@ -0,0 +1,86 @@
+require 'rubygems'
+
+require 'sequel/core'
+require 'sequel/model'
+
+Sequel.extension(*%w'string_date_time inflector pagination query pretty_table blank migration schema_dumper looser_typecasting sql_expr thread_local_timezones')
+{:hook_class_methods=>[], :schema=>[], :validation_class_methods=>[]}.each{|p, opts| Sequel::Model.plugin(p, *opts)}
+
+class MockDataset < Sequel::Dataset
+ def insert(*args)
+ @db.execute insert_sql(*args)
+ end
+
+ def update(*args)
+ @db.execute update_sql(*args)
+ 1
+ end
+
+ def delete(*args)
+ @db.execute delete_sql(*args)
+ 1
+ end
+
+ def fetch_rows(sql)
+ return if sql =~ /information_schema/
+ @db.execute(sql)
+ yield({:id => 1, :x => 1})
+ end
+
+ def quoted_identifier(c)
+ "\"#{c}\""
+ end
+end
+
+class MockDatabase < Sequel::Database
+ @@quote_identifiers = false
+ self.identifier_input_method = nil
+ self.identifier_output_method = nil
+ attr_reader :sqls
+
+ def execute(sql, opts={})
+ @sqls ||= []
+ @sqls << sql
+ end
+
+ def new_sqls
+ s = sqls
+ reset
+ s
+ end
+
+ def reset
+ @sqls = []
+ end
+
+ def schema(table_name, opts)
+ if table_name
+ [[:id, {:primary_key=>true}]]
+ else
+ {table_name=>[[:id, {:primary_key=>true}]]}
+ end
+ end
+
+ def transaction(opts={}); yield; end
+
+ def dataset(opts=nil); MockDataset.new(self, opts); end
+end
+
+class << Sequel::Model
+ alias orig_columns columns
+ def columns(*cols)
+ return if cols.empty?
+ define_method(:columns){cols}
+ @dataset.instance_variable_set(:@columns, cols) if @dataset
+ def_column_accessor(*cols)
+ @columns = cols
+ @db_schema = {}
+ cols.each{|c| @db_schema[c] = {}}
+ end
+ def simple_table
+ nil
+ end
+end
+
+Sequel::Model.db = MODEL_DB = MockDatabase.new
+Sequel::Model.use_transactions = false

0 comments on commit 9c68f8f

Please sign in to comment.
Something went wrong with that request. Please try again.