<commit_before>require 'monitor'
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))

require DataMapper.root / 'spec' / 'unit' / 'adapters' / 'adapter_shared_spec'

# TODO: make a shared adapter spec for all the DAO objects to adhere to

describe DataMapper::Adapters::DataObjectsAdapter do
  before :all do
    class Cheese
      include DataMapper::Resource
      property :id, Integer, :serial => true
      property :name, String, :nullable => false
      property :color, String, :default => 'yellow'
      property :notes, String, :length => 100, :lazy => true
    end
  end

  before do
    @uri     = Addressable::URI.parse('mock://localhost')
    @adapter = DataMapper::Adapters::DataObjectsAdapter.new(:default, @uri)
  end

  it_should_behave_like 'a DataMapper Adapter'

  describe "#find_by_sql" do

    before do
      class Plupp
        include DataMapper::Resource
        property :id, Integer, :key => true
        property :name, String
      end
    end

    it "should be added to DataMapper::Resource::ClassMethods" do
      DataMapper::Resource::ClassMethods.instance_methods.include?("find_by_sql").should == true
      Plupp.should respond_to(:find_by_sql)
    end

    describe "when called" do

      before do
        @reader = mock("reader")
        @reader.stub!(:next!).and_return(false)
        @reader.stub!(:close)
        @connection = mock("connection")
        @connection.stub!(:close)
        @command = mock("command")
        @adapter = Plupp.repository.adapter
        @repository = Plupp.repository
        @repository.stub!(:adapter).and_return(@adapter)
        @adapter.stub!(:create_connection).and_return(@connection)
        @adapter.should_receive(:is_a?).any_number_of_times.with(DataMapper::Adapters::DataObjectsAdapter).and_return(true)
      end

      it "should accept a single String argument with or without options hash" do
        @connection.should_receive(:create_command).twice.with("SELECT * FROM plupps").and_return(@command)
        @command.should_receive(:set_types).twice.with([Fixnum, String])
        @command.should_receive(:execute_reader).twice.and_return(@reader)
        Plupp.should_receive(:repository).any_number_of_times.and_return(@repository)
        Plupp.should_receive(:repository).any_number_of_times.with(:plupp_repo).and_return(@repository)
        Plupp.find_by_sql("SELECT * FROM plupps").to_a
        Plupp.find_by_sql("SELECT * FROM plupps", :repository => :plupp_repo).to_a
      end

      it "should accept an Array argument with or without options hash" do
        @connection.should_receive(:create_command).twice.with("SELECT * FROM plupps WHERE plur = ?").and_return(@command)
        @command.should_receive(:set_types).twice.with([Fixnum, String])
        @command.should_receive(:execute_reader).twice.with("my pretty plur").and_return(@reader)
        Plupp.should_receive(:repository).any_number_of_times.and_return(@repository)
        Plupp.should_receive(:repository).any_number_of_times.with(:plupp_repo).and_return(@repository)
        Plupp.find_by_sql(["SELECT * FROM plupps WHERE plur = ?", "my pretty plur"]).to_a
        Plupp.find_by_sql(["SELECT * FROM plupps WHERE plur = ?", "my pretty plur"], :repository => :plupp_repo).to_a
      end

      it "should accept a Query argument with or without options hash" do
        @connection.should_receive(:create_command).twice.with("SELECT \"name\" FROM \"plupps\" WHERE \"name\" = ?").and_return(@command)
        @command.should_receive(:set_types).twice.with([Fixnum, String])
        @command.should_receive(:execute_reader).twice.with(Plupp.properties[:name]).and_return(@reader)
        Plupp.should_receive(:repository).any_number_of_times.and_return(@repository)
        Plupp.should_receive(:repository).any_number_of_times.with(:plupp_repo).and_return(@repository)
        Plupp.find_by_sql(DataMapper::Query.new(@repository, Plupp, "name" => "my pretty plur", :fields => ["name"])).to_a
        Plupp.find_by_sql(DataMapper::Query.new(@repository, Plupp, "name" => "my pretty plur", :fields => ["name"]), :repository => :plupp_repo).to_a
      end

      it "requires a Repository that is a DataObjectsRepository to work" do
        non_do_adapter = mock("non do adapter")
        non_do_repo = mock("non do repo")
        non_do_repo.stub!(:adapter).and_return(non_do_adapter)
        Plupp.should_receive(:repository).any_number_of_times.with(:plupp_repo).and_return(non_do_repo)
        Proc.new do
          Plupp.find_by_sql(:repository => :plupp_repo)
        end.should raise_error(Exception, /DataObjectsAdapter/)
      end

      it "requires some kind of query to work at all" do
        Plupp.should_receive(:repository).any_number_of_times.with(:plupp_repo).and_return(@repository)
        Proc.new do
          Plupp.find_by_sql(:repository => :plupp_repo)
        end.should raise_error(Exception, /requires a query/)
      end

    end

  end

  describe '#uri options' do
    it 'should transform a fully specified option hash into a URI' do
      options = {
        :adapter => 'mysql',
        :host => 'davidleal.com',
        :username => 'me',
        :password => '<PASSWORD>',
        :port => 5000,
        :database => 'you_can_call_me_al',
        :socket => 'nosock'
      }

      adapter = DataMapper::Adapters::DataObjectsAdapter.new(:spec, options)
      adapter.uri.should ==
        Addressable::URI.parse("mysql://me:<EMAIL>:5000/you_can_call_me_al?socket=nosock")
    end

    it 'should transform a minimal options hash into a URI' do
      options = {
        :adapter => 'mysql',
        :database => 'you_can_call_me_al'
      }

      adapter = DataMapper::Adapters::DataObjectsAdapter.new(:spec, options)
      adapter.uri.should == Addressable::URI.parse("mysql:///you_can_call_me_al")
    end

    it 'should accept the uri when no overrides exist' do
      uri = Addressable::URI.parse("protocol:///")
      DataMapper::Adapters::DataObjectsAdapter.new(:spec, uri).uri.should == uri
    end
  end

  describe '#create' do
    before do
      @result = mock('result', :to_i => 1, :insert_id => 1)

      @adapter.stub!(:execute).and_return(@result)

      @property   = mock('property', :field => 'property', :instance_variable_name => '@property', :serial? => false)
      @repository = mock('repository')
      @model      = mock('model', :storage_name => 'models', :key => [ @property ])
      @resource   = mock('resource', :class => @model, :dirty_attributes => [ @property ], :instance_variable_get => 'bind value')
    end

    it 'should use only dirty properties' do
      @resource.should_receive(:dirty_attributes).with(no_args).once.and_return([ @property ])
      @adapter.create(@repository, @resource)
    end

    it 'should use the properties field accessors' do
      @property.should_receive(:field).with(no_args).once.and_return('property')
      @adapter.create(@repository, @resource)
    end

    it 'should get the bind values' do
      @property.should_receive(:instance_variable_name).with(no_args).once.and_return('@property')
      @resource.should_receive(:instance_variable_get).with('@property').once.and_return('bind value')
      @adapter.create(@repository, @resource)
    end

    it 'should generate an SQL statement when create_with_returning? is false' do
      statement = 'INSERT INTO "models" ("property") VALUES (?)'
      @adapter.should_receive(:create_with_returning?).with(no_args).and_return(false)
      @adapter.should_receive(:execute).with(statement, 'bind value').once.and_return(@result)
      @adapter.create(@repository, @resource)
    end

    it 'should generate an SQL statement when create_with_returning? is true' do
      statement = 'INSERT INTO "models" ("property") VALUES (?) RETURNING "property"'
      @property.should_receive(:serial?).with(no_args).and_return(true)
      @adapter.should_receive(:create_with_returning?).with(no_args).and_return(true)
      @adapter.should_receive(:execute).with(statement, 'bind value').once.and_return(@result)
      @adapter.create(@repository, @resource)
    end

    it 'should return false if number of rows created is 0' do
      @result.should_receive(:to_i).with(no_args).once.and_return(0)
      @adapter.create(@repository, @resource).should be_false
    end

    it 'should return true if number of rows created is 1' do
      @result.should_receive(:to_i).with(no_args).once.and_return(1)
      @adapter.create(@repository, @resource).should be_true
    end

    it 'should set the resource primary key if the model key size is 1 and the key is serial' do
      @model.key.size.should == 1
      @property.should_receive(:serial?).and_return(true)
      @result.should_receive(:insert_id).and_return(111)
      @resource.should_receive(:instance_variable_set).with('@property', 111)
      @adapter.create(@repository, @resource)
    end
  end

  describe '#read' do
    before do
      @primitive  = mock('primitive')
      @property   = mock('property', :field => 'property', :primitive => @primitive)
      @properties = mock('properties', :defaults => [ @property ])
      @repository = mock('repository', :name => :default, :kind_of? => true)
      @model      = mock('model', :properties => @properties, :< => true, :inheritance_property => nil, :key => [ @property ], :storage_name => 'models')
      @key        = mock('key')
      @resource   = mock('resource')
      @collection = mock('collection', :first => @resource)

      @reader     = mock('reader', :close => true, :next! => false)
      @command    = mock('command', :set_types => nil, :execute_reader => @reader)
      @connection = mock('connection', :close => true, :create_command => @command)

      DataObjects::Connection.stub!(:new).and_return(@connection)
      DataMapper::Collection.stub!(:new).and_return(@collection)
    end

    it 'should lookup the model properties with the repository' do
      @repository.should_receive(:name).with(no_args).at_least(:once).and_return(:default)
      @model.should_receive(:properties).with(:default).once.and_return(@properties)
      @adapter.read(@repository, @model, @key)
    end

    it 'should use the model default properties' do
      @properties.should_receive(:defaults).with(no_args).once.and_return([ @property ])
      @adapter.read(@repository, @model, @key)
    end

    it 'should create a collection under the hood for retrieving the resource' do
      DataMapper::Collection.should_receive(:new).with(@repository, @model, { @property => 0 }).and_return(@collection)
      @reader.should_receive(:next!).and_return(true)
      @reader.should_receive(:values).with(no_args).once.and_return({ :property => 'value' })
      @collection.should_receive(:load).with({ :property => 'value' }).once
      @collection.should_receive(:first).with(no_args).once.and_return(@resource)
      @adapter.read(@repository, @model, @key).should == @resource
    end

    it 'should generate an SQL statement' do
      statement = 'SELECT "property" FROM "models" WHERE "property" = ? LIMIT 1'
      @model.should_not_receive(:key).with(:default).once.and_return([ @property ])
      @connection.should_receive(:create_command).with(statement).once.and_return(@command)
      @adapter.read(@repository, @model, @key)
    end

    it 'should generate an SQL statement with composite keys' do
      other_property = mock('other property', :field => 'other')
      statement = 'SELECT "property" FROM "models" WHERE "property" = ? AND "other" = ? LIMIT 1'
      @model.should_receive(:key).with(:default).once.and_return([ @property, other_property ])
      @connection.should_receive(:create_command).with(statement).once.and_return(@command)
      @adapter.read(@repository, @model, @key)
    end

    it 'should set the return types to the property primitives' do
      @command.should_receive(:set_types).with([ @primitive ]).once
      @adapter.read(@repository, @model, @key)
    end

    it 'should close the reader' do
      @reader.should_receive(:close).with(no_args).once
      @adapter.read(@repository, @model, @key)
    end

    it 'should close the connection' do
      @connection.should_receive(:close).with(no_args)
      @adapter.read(@repository, @model, @key)
    end
  end

  describe '#update' do
    before do
      @result = mock('result', :to_i => 1, :insert_id => 1)

      @adapter.stub!(:execute).and_return(@result)

      @property = mock('property', :field => 'property', :instance_variable_name => '@property', :serial? => false)
      @model    = mock('model', :storage_name => 'models', :key => [ @property ])
      @resource = mock('resource', :class => @model, :key => [ 1 ], :dirty_attributes => [ @property ], :instance_variable_get => 'bind value')

      DataObjects::Connection.stub!(:new).and_return(@connection)
    end

    it 'should use only dirty properties' do
      @resource.should_receive(:dirty_attributes).with(no_args).once.and_return([ @property ])
      @adapter.update(@repository, @resource)
    end

    it 'should use the properties field accessors' do
      @property.should_receive(:field).with(no_args).twice.and_return('property')
      @adapter.update(@repository, @resource)
    end

    it 'should get the bind values' do
      @property.should_receive(:instance_variable_name).with(no_args).once.and_return('@property')
      @resource.should_receive(:instance_variable_get).with('@property').once.and_return('bind value')
      @adapter.update(@repository, @resource)
    end

    it 'should get the key' do
      @resource.should_receive(:key).with(no_args).once.and_return([ 1 ])
      @adapter.update(@repository, @resource)
    end

    it 'should generate an SQL statement' do
      statement = 'UPDATE "models" SET "property" = ? WHERE "property" = ?'
      @adapter.should_receive(:execute).with(statement, 'bind value', 1).once.and_return(@result)
      @adapter.update(@repository, @resource)
    end

    it 'should return false if number of rows updated is 0' do
      @result.should_receive(:to_i).with(no_args).once.and_return(0)
      @adapter.update(@repository, @resource).should be_false
    end

    it 'should return true if number of rows updated is 1' do
      @result.should_receive(:to_i).with(no_args).once.and_return(1)
      @adapter.update(@repository, @resource).should be_true
    end

    it 'should not try to update if there are no dirty attributes' do
      repository = mock("repository")
      resource = mock("resource")
      resource.stub!(:dirty_attributes).and_return({})
      @adapter.update(repository, resource).should == false<commit_msg>Simplified specs<commit_after>require 'monitor'
require File.expand_path(File.join(File.dirname(__FILE__), '..', '..', 'spec_helper'))

require DataMapper.root / 'spec' / 'unit' / 'adapters' / 'adapter_shared_spec'

# TODO: make a shared adapter spec for all the DAO objects to adhere to

describe DataMapper::Adapters::DataObjectsAdapter do
  before :all do
    class Cheese
      include DataMapper::Resource
      property :id, Integer, :serial => true
      property :name, String, :nullable => false
      property :color, String, :default => 'yellow'
      property :notes, String, :length => 100, :lazy => true
    end
  end

  before do
    @uri     = Addressable::URI.parse('mock://localhost')
    @adapter = DataMapper::Adapters::DataObjectsAdapter.new(:default, @uri)
  end

  it_should_behave_like 'a DataMapper Adapter'

  describe "#find_by_sql" do

    before do
      class Plupp
        include DataMapper::Resource
        property :id, Integer, :key => true
        property :name, String
      end
    end

    it "should be added to DataMapper::Resource::ClassMethods" do
      DataMapper::Resource::ClassMethods.instance_methods.include?("find_by_sql").should == true
      Plupp.should respond_to(:find_by_sql)
    end

    describe "when called" do

      before do
        @reader = mock("reader")
        @reader.stub!(:next!).and_return(false)
        @reader.stub!(:close)
        @connection = mock("connection")
        @connection.stub!(:close)
        @command = mock("command")
        @adapter = Plupp.repository.adapter
        @repository = Plupp.repository
        @repository.stub!(:adapter).and_return(@adapter)
        @adapter.stub!(:create_connection).and_return(@connection)
        @adapter.should_receive(:is_a?).any_number_of_times.with(DataMapper::Adapters::DataObjectsAdapter).and_return(true)
      end

      it "should accept a single String argument with or without options hash" do
        @connection.should_receive(:create_command).twice.with("SELECT * FROM plupps").and_return(@command)
        @command.should_receive(:set_types).twice.with([Fixnum, String])
        @command.should_receive(:execute_reader).twice.and_return(@reader)
        Plupp.should_receive(:repository).any_number_of_times.and_return(@repository)
        Plupp.should_receive(:repository).any_number_of_times.with(:plupp_repo).and_return(@repository)
        Plupp.find_by_sql("SELECT * FROM plupps").to_a
        Plupp.find_by_sql("SELECT * FROM plupps", :repository => :plupp_repo).to_a
      end

      it "should accept an Array argument with or without options hash" do
        @connection.should_receive(:create_command).twice.with("SELECT * FROM plupps WHERE plur = ?").and_return(@command)
        @command.should_receive(:set_types).twice.with([Fixnum, String])
        @command.should_receive(:execute_reader).twice.with("my pretty plur").and_return(@reader)
        Plupp.should_receive(:repository).any_number_of_times.and_return(@repository)
        Plupp.should_receive(:repository).any_number_of_times.with(:plupp_repo).and_return(@repository)
        Plupp.find_by_sql(["SELECT * FROM plupps WHERE plur = ?", "my pretty plur"]).to_a
        Plupp.find_by_sql(["SELECT * FROM plupps WHERE plur = ?", "my pretty plur"], :repository => :plupp_repo).to_a
      end

      it "should accept a Query argument with or without options hash" do
        @connection.should_receive(:create_command).twice.with("SELECT \"name\" FROM \"plupps\" WHERE \"name\" = ?").and_return(@command)
        @command.should_receive(:set_types).twice.with([Fixnum, String])
        @command.should_receive(:execute_reader).twice.with(Plupp.properties[:name]).and_return(@reader)
        Plupp.should_receive(:repository).any_number_of_times.and_return(@repository)
        Plupp.should_receive(:repository).any_number_of_times.with(:plupp_repo).and_return(@repository)
        Plupp.find_by_sql(DataMapper::Query.new(@repository, Plupp, "name" => "my pretty plur", :fields => ["name"])).to_a
        Plupp.find_by_sql(DataMapper::Query.new(@repository, Plupp, "name" => "my pretty plur", :fields => ["name"]), :repository => :plupp_repo).to_a
      end

      it "requires a Repository that is a DataObjectsRepository to work" do
        non_do_adapter = mock("non do adapter")
        non_do_repo = mock("non do repo")
        non_do_repo.stub!(:adapter).and_return(non_do_adapter)
        Plupp.should_receive(:repository).any_number_of_times.with(:plupp_repo).and_return(non_do_repo)
        Proc.new do
          Plupp.find_by_sql(:repository => :plupp_repo)
        end.should raise_error(Exception, /DataObjectsAdapter/)
      end

      it "requires some kind of query to work at all" do
        Plupp.should_receive(:repository).any_number_of_times.with(:plupp_repo).and_return(@repository)
        Proc.new do
          Plupp.find_by_sql(:repository => :plupp_repo)
        end.should raise_error(Exception, /requires a query/)
      end

    end

  end

  describe '#uri options' do
    it 'should transform a fully specified option hash into a URI' do
      options = {
        :adapter => 'mysql',
        :host => 'davidleal.com',
        :username => 'me',
        :password => '<PASSWORD>',
        :port => 5000,
        :database => 'you_can_call_me_al',
        :socket => 'nosock'
      }

      adapter = DataMapper::Adapters::DataObjectsAdapter.new(:spec, options)
      adapter.uri.should ==
        Addressable::URI.parse("mysql://me:mypass@davidleal.com:5000/you_can_call_me_al?socket=nosock")
    end

    it 'should transform a minimal options hash into a URI' do
      options = {
        :adapter => 'mysql',
        :database => 'you_can_call_me_al'
      }

      adapter = DataMapper::Adapters::DataObjectsAdapter.new(:spec, options)
      adapter.uri.should == Addressable::URI.parse("mysql:///you_can_call_me_al")
    end

    it 'should accept the uri when no overrides exist' do
      uri = Addressable::URI.parse("protocol:///")
      DataMapper::Adapters::DataObjectsAdapter.new(:spec, uri).uri.should == uri
    end
  end

  describe '#create' do
    before do
      @result = mock('result', :to_i => 1, :insert_id => 1)

      @adapter.stub!(:execute).and_return(@result)

      @property   = mock('property', :field => 'property', :instance_variable_name => '@property', :serial? => false)
      @repository = mock('repository')
      @model      = mock('model', :storage_name => 'models', :key => [ @property ])
      @resource   = mock('resource', :class => @model, :dirty_attributes => [ @property ], :instance_variable_get => 'bind value')
    end

    it 'should use only dirty properties' do
      @resource.should_receive(:dirty_attributes).with(no_args).once.and_return([ @property ])
      @adapter.create(@repository, @resource)
    end

    it 'should use the properties field accessors' do
      @property.should_receive(:field).with(no_args).once.and_return('property')
      @adapter.create(@repository, @resource)
    end

    it 'should get the bind values' do
      @property.should_receive(:instance_variable_name).with(no_args).once.and_return('@property')
      @resource.should_receive(:instance_variable_get).with('@property').once.and_return('bind value')
      @adapter.create(@repository, @resource)
    end

    it 'should generate an SQL statement when create_with_returning? is false' do
      statement = 'INSERT INTO "models" ("property") VALUES (?)'
      @adapter.should_receive(:create_with_returning?).with(no_args).and_return(false)
      @adapter.should_receive(:execute).with(statement, 'bind value').once.and_return(@result)
      @adapter.create(@repository, @resource)
    end

    it 'should generate an SQL statement when create_with_returning? is true' do
      statement = 'INSERT INTO "models" ("property") VALUES (?) RETURNING "property"'
      @property.should_receive(:serial?).with(no_args).and_return(true)
      @adapter.should_receive(:create_with_returning?).with(no_args).and_return(true)
      @adapter.should_receive(:execute).with(statement, 'bind value').once.and_return(@result)
      @adapter.create(@repository, @resource)
    end

    it 'should return false if number of rows created is 0' do
      @result.should_receive(:to_i).with(no_args).once.and_return(0)
      @adapter.create(@repository, @resource).should be_false
    end

    it 'should return true if number of rows created is 1' do
      @result.should_receive(:to_i).with(no_args).once.and_return(1)
      @adapter.create(@repository, @resource).should be_true
    end

    it 'should set the resource primary key if the model key size is 1 and the key is serial' do
      @model.key.size.should == 1
      @property.should_receive(:serial?).and_return(true)
      @result.should_receive(:insert_id).and_return(111)
      @resource.should_receive(:instance_variable_set).with('@property', 111)
      @adapter.create(@repository, @resource)
    end
  end

  describe '#read' do
    before do
      @primitive  = mock('primitive')
      @property   = mock('property', :field => 'property', :primitive => @primitive)
      @properties = mock('properties', :defaults => [ @property ])
      @repository = mock('repository', :name => :default, :kind_of? => true)
      @model      = mock('model', :properties => @properties, :< => true, :inheritance_property => nil, :key => [ @property ], :storage_name => 'models')
      @key        = mock('key')
      @resource   = mock('resource')
      @collection = mock('collection', :first => @resource)

      @reader     = mock('reader', :close => true, :next! => false)
      @command    = mock('command', :set_types => nil, :execute_reader => @reader)
      @connection = mock('connection', :close => true, :create_command => @command)

      DataObjects::Connection.stub!(:new).and_return(@connection)
      DataMapper::Collection.stub!(:new).and_return(@collection)
    end

    it 'should lookup the model properties with the repository' do
      @repository.should_receive(:name).with(no_args).at_least(:once).and_return(:default)
      @model.should_receive(:properties).with(:default).once.and_return(@properties)
      @adapter.read(@repository, @model, @key)
    end

    it 'should use the model default properties' do
      @properties.should_receive(:defaults).with(no_args).once.and_return([ @property ])
      @adapter.read(@repository, @model, @key)
    end

    it 'should create a collection under the hood for retrieving the resource' do
      DataMapper::Collection.should_receive(:new).with(@repository, @model, { @property => 0 }).and_return(@collection)
      @reader.should_receive(:next!).and_return(true)
      @reader.should_receive(:values).with(no_args).once.and_return({ :property => 'value' })
      @collection.should_receive(:load).with({ :property => 'value' }).once
      @collection.should_receive(:first).with(no_args).once.and_return(@resource)
      @adapter.read(@repository, @model, @key).should == @resource
    end

    it 'should generate an SQL statement' do
      statement = 'SELECT "property" FROM "models" WHERE "property" = ? LIMIT 1'
      @model.should_not_receive(:key).with(:default).once.and_return([ @property ])
      @connection.should_receive(:create_command).with(statement).once.and_return(@command)
      @adapter.read(@repository, @model, @key)
    end

    it 'should generate an SQL statement with composite keys' do
      other_property = mock('other property', :field => 'other')
      statement = 'SELECT "property" FROM "models" WHERE "property" = ? AND "other" = ? LIMIT 1'
      @model.should_receive(:key).with(:default).once.and_return([ @property, other_property ])
      @connection.should_receive(:create_command).with(statement).once.and_return(@command)
      @adapter.read(@repository, @model, @key)
    end

    it 'should set the return types to the property primitives' do
      @command.should_receive(:set_types).with([ @primitive ]).once
      @adapter.read(@repository, @model, @key)
    end

    it 'should close the reader' do
      @reader.should_receive(:close).with(no_args).once
      @adapter.read(@repository, @model, @key)
    end

    it 'should close the connection' do
      @connection.should_receive(:close).with(no_args)
      @adapter.read(@repository, @model, @key)
    end
  end

  describe '#update' do
    before do
      @result = mock('result', :to_i => 1, :insert_id => 1)

      @adapter.stub!(:execute).and_return(@result)

      @property = mock('property', :field => 'property', :instance_variable_name => '@property', :serial? => false)
      @model    = mock('model', :storage_name => 'models', :key => [ @property ])
      @resource = mock('resource', :class => @model, :key => [ 1 ], :dirty_attributes => [ @property ], :instance_variable_get => 'bind value')

      DataObjects::Connection.stub!(:new).and_return(@connection)
    end

    it 'should use only dirty properties' do
      @resource.should_receive(:dirty_attributes).with(no_args).once.and_return([ @property ])
      @adapter.update(@repository, @resource)
    end

    it 'should use the properties field accessors' do
      @property.should_receive(:field).with(no_args).twice.and_return('property')
      @adapter.update(@repository, @resource)
    end

    it 'should get the bind values' do
      @property.should_receive(:instance_variable_name).with(no_args).once.and_return('@property')
      @resource.should_receive(:instance_variable_get).with('@property').once.and_return('bind value')
      @adapter.update(@repository, @resource)
    end

    it 'should get the key' do
      @resource.should_receive(:key).with(no_args).once.and_return([ 1 ])
      @adapter.update(@repository, @resource)
    end

    it 'should generate an SQL statement' do
      statement = 'UPDATE "models" SET "property" = ? WHERE "property" = ?'
      @adapter.should_receive(:execute).with(statement, 'bind value', 1).once.and_return(@result)
      @adapter.update(@repository, @resource)
    end

    it 'should return false if number of rows updated is 0' do
      @result.should_receive(:to_i).with(no_args).once.and_return(0)
      @adapter.update(@repository, @resource).should be_false
    end

    it 'should return true if number of rows updated is 1' do
      @result.should_receive(:to_i).with(no_args).once.and_return(1)
      @adapter.update(@repository, @resource).should be_true
    end

    it 'should not try to update if there are no dirty attributes' do
      @resource.should_receive(:dirty_attributes).with(no_args).once.and_return([])
      @adapter.update(@repository, @resource).should be_false
{'fraction_non_alphanumeric': 0.1377730675874329, 'fraction_numerical': 0.002529828040067006, 'mean_word_length': 3.7906976744186047, 'pattern_counts': {'":': 0, '<': 8, '<?xml version=': 0, '>': 138, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 1, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1362497', 'n_tokens_mistral': 8907, 'n_tokens_neox': 8574, 'n_words': 1890}