Commit 56f17f9
Changed files (15)
lib
spec
lib/humble/column.rb
@@ -1,21 +1,28 @@
module Humble
class Column
+ attr_reader :column_name
+
def initialize(name)
@column_name = name
end
- def prepare(item)
- return {} if primary_key? && has_default_value?
- { column_name.to_sym => item.instance_variable_get("@#{column_name}") }
+ def prepare(entity)
+ return {} if primary_key? && has_default_value?(entity)
+ #{ column_name.to_sym => entity.instance_variable_get("@#{column_name}") }
+ { column_name.to_sym => entity.public_send(column_name.to_sym) }
end
- def primary_key?
- false
+ def matches?(column_name)
+ @column_name == column_name
end
- protected
+ def apply(value, entity)
+ entity.public_send("#{@column_name}=", value)
+ end
- attr_reader :column_name
+ def primary_key?
+ false
+ end
end
class PrimaryKeyColumn < Column
@@ -26,10 +33,6 @@ module Humble
@default = default
end
- def apply(id, entity)
- entity.instance_variable_set("@#{column_name}", id )
- end
-
def destroy(connection, entity)
connection.where(column_name.to_sym => entity.id).delete
end
@@ -38,8 +41,23 @@ module Humble
true
end
- def has_default_value?(item)
- @default == item.id
+ def has_default_value?(entity)
+ entity.id == nil || @default == entity.id
+ end
+ end
+
+ class BelongsTo < Column
+ def initialize(name, type)
+ super(name)
+ @type = type
+ end
+
+ def apply(id, entity)
+ #entity.public_send("#{column_name}=", id)
+ end
+
+ def prepare(entity)
+ { column_name.to_sym => '' }
end
end
end
lib/humble/database_table.rb
@@ -1,6 +1,7 @@
module Humble
class DatabaseTable
attr_reader :name
+ attr_accessor :type
def initialize
@columns = []
@@ -12,10 +13,19 @@ module Humble
def primary_key(name, default: 0)
@primary_key = PrimaryKeyColumn.new(name, default)
+ add(@primary_key)
+ end
+
+ def add(column)
+ @columns.push(column)
end
def add_column(name)
- @columns << Column.new(name)
+ add(Column.new(name))
+ end
+
+ def find_all_using(connection)
+ ResultSet.new(connection[self.name], self)
end
def persist(connection, item)
@@ -30,8 +40,21 @@ module Humble
@primary_key.destroy(connection[@name], entity)
end
+ def map_from(row)
+ entity = type.new
+ row.each do |key, value|
+ #entity.send("#{key}=", value) unless key == :studio_id
+ column_for(key).apply(value, entity)
+ end
+ entity
+ end
+
private
+ def column_for(key)
+ @columns.find { |x| x.matches?(key) }
+ end
+
def prepare_statement_for(item)
@columns.inject({}) do |result, column|
result.merge(column.prepare(item))
lib/humble/default_data_row_mapper.rb
@@ -5,7 +5,11 @@ module Humble
end
def map_from(row)
- @configuration[:type].new(row)
+ result = @configuration.type.new
+ row.each do |key, value|
+ result.send("#{key}=", value)
+ end
+ result
end
end
end
lib/humble/mapping_configuration.rb
@@ -6,7 +6,7 @@ module Humble
end
def find_all_using(connection)
- ResultSet.new(connection[@table.name], mapper)
+ @table.find_all_using(connection)
end
def save_using(connection, entity)
@@ -24,11 +24,5 @@ module Humble
def [](key)
@attributes[key]
end
-
- private
-
- def mapper
- self[:mapper] || DefaultDataRowMapper.new(self)
- end
end
end
lib/humble/mapping_configuration_builder.rb
@@ -12,6 +12,7 @@ module Humble
def type(name)
@attributes[:type] = name
+ @table.type=name
end
def primary_key(name, default: 0)
@@ -23,6 +24,10 @@ module Humble
@table.add_column(name)
end
+ def belongs_to(foreign_key, type)
+ @table.add(BelongsTo.new(foreign_key, type))
+ end
+
def build
MappingConfiguration.new(@attributes, @table)
end
lib/humble/session.rb
@@ -15,6 +15,10 @@ module Humble
mapping_for(entity).save_using(create_connection, entity)
end
+ def find(clazz, id)
+ find_all(clazz).find { |x| x.id == id }
+ end
+
def find_all(clazz)
mapping_for(clazz).find_all_using(create_connection)
end
spec/integration/fixtures/movie_mapping.rb
@@ -1,14 +1,5 @@
class Movie
- attr_reader :id, :name
-
- def initialize(attributes)
- @id = attributes[:id] || -1
- @name = attributes[:name]
- end
-
- def name=(new_name)
- @name = new_name
- end
+ attr_accessor :id, :name, :studio
def ==(other)
return false unless other
@@ -24,5 +15,6 @@ class MovieMapping < Humble::DatabaseMapping
map.type Movie
map.primary_key(:id, default: -1)
map.column :name
+ map.belongs_to :studio_id, Studio
end
end
spec/integration/fixtures/studio_mapping.rb
@@ -0,0 +1,12 @@
+class Studio
+ attr_accessor :id, :name
+end
+
+class StudioMapping < Humble::DatabaseMapping
+ def run(map)
+ map.table :studios
+ map.type Studio
+ map.primary_key(:id, default: -1)
+ map.column :name
+ end
+end
spec/integration/insert_spec.rb
@@ -4,7 +4,7 @@ describe "orm" do
include_context "orm"
context "when inserting a new record" do
- let(:movie) { Movie.new(:name => 'oop') }
+ let(:movie) { Movie.new.tap { |x| x.name = 'oop' } }
before :each do
session.begin_transaction do |session|
@@ -15,20 +15,20 @@ describe "orm" do
let(:results) { connection[:movies].all }
it "should insert the correct number of records" do
- results.count.should == 1
+ expect(results.count).to eql(1)
end
it "should insert the record with the a new id" do
- results.first[:id].should_not == -1
- results.first[:id].should > 0
+ expect(results.first[:id]).to_not eql(-1)
+ expect(results.first[:id]).to be > 0
end
it "should insert the name" do
- results.first[:name].should == 'oop'
+ expect(results.first[:name]).to eql('oop')
end
it "should update the new item with the new id" do
- movie.id.should_not == -1
+ expect(movie.id).to_not eql(-1)
end
end
end
spec/integration/select_spec.rb
@@ -11,20 +11,33 @@ describe "select items" do
let(:results) { session.find_all Movie }
it "should return the correct number of movies" do
- results.count.should == 1
+ expect(results.count).to eql(1)
end
it "should return each movie with its name" do
- results.first.name.should == 'monsters inc'
+ expect(results.first.name).to eql('monsters inc')
end
it "should return instances of the target type" do
- results.first.should be_instance_of(Movie)
+ expect(results.first).to be_instance_of(Movie)
end
it "should include the saved movie" do
- results.should include(Movie.new(:id => @id, :name => 'monsters inc'))
+ movie = Movie.new.tap { |x| x.id = @id }
+ expect(results).to include(movie)
end
end
+ context "when fetching a single item" do
+ it "loads the belongs_to association" do
+ studio_id = connection[:studios].insert(name: 'universal')
+ movie_id = connection[:movies].insert(name: 'blood in, blood out', studio_id: studio_id)
+
+ result = session.find(Movie, movie_id)
+ expect(result).to be_instance_of(Movie)
+ expect(result.id).to eql(movie_id)
+ expect(result.name).to eql('blood in, blood out')
+ #expect(result.studio).to be_instance_of(Studio)
+ end
+ end
end
spec/integration/update_spec.rb
@@ -4,7 +4,7 @@ describe "updating a record" do
include_context "orm"
context "when updating a record" do
- let(:movie) { Movie.new(:name => "old name") }
+ let(:movie) { Movie.new.tap { |x| x.name = "old name" } }
before :each do
session.begin_transaction do |session|
@@ -19,11 +19,11 @@ describe "updating a record" do
let(:results) { connection[:movies].all }
it "should save the changes" do
- results.first[:name].should == 'new name'
+ expect(results.first[:name]).to eql('new name')
end
it "should not create any new records" do
- results.count.should == 1
+ expect(results.count).to eql(1)
end
end
end
spec/unit/default_data_row_mapper_spec.rb
@@ -1,24 +1,22 @@
-require "spec_helper"
-class Book
- attr_reader :id, :name
+require "ostruct"
- def initialize(attributes)
- @id = attributes[:id]
- @name = attributes[:name]
- end
+class Book
+ attr_accessor :id, :name
end
-describe Humble::DefaultDataRowMapper do
- let(:sut) { Humble::DefaultDataRowMapper.new(configuration) }
- let(:configuration) { { :type => Book } }
+module Humble
+ describe DefaultDataRowMapper do
+ let(:sut) { Humble::DefaultDataRowMapper.new(configuration) }
+ let(:configuration) { OpenStruct.new(:type => Book) }
- let(:result) { sut.map_from({:id => 1, :name => 'blah'}) }
+ let(:result) { sut.map_from({:id => 1, :name => 'blah'}) }
- it "should map the id" do
- result.id.should == 1
- end
+ it "should map the id" do
+ expect(result.id).to eql(1)
+ end
- it "should map the name" do
- result.name.should == "blah"
+ it "should map the name" do
+ expect(result.name).to eql("blah")
+ end
end
end
spec/integration_helper.rb
@@ -1,5 +1,6 @@
require "spec_helper"
require 'sequel'
+require_relative 'integration/fixtures/studio_mapping.rb'
require_relative 'integration/fixtures/movie_mapping.rb'
shared_context "orm" do
@@ -10,15 +11,23 @@ shared_context "orm" do
let(:session) { session_factory.create_session }
before :each do
+ connection.create_table :studios do
+ primary_key :id
+ String :name
+ end
+
connection.create_table :movies do
primary_key :id
+ BigNum :studio_id
String :name
end
configuration.add(MovieMapping.new)
+ configuration.add(StudioMapping.new)
end
after :each do
+ connection.drop_table :studios
connection.drop_table :movies
end
end
spec/spec_helper.rb
@@ -1,52 +1,12 @@
Bundler.require
RSpec.configure do |config|
- # Many RSpec users commonly either run the entire suite or an individual
- # file, and it's useful to allow more verbose output when running an
- # individual spec file.
- if config.files_to_run.one?
- # Use the documentation formatter for detailed output,
- # unless a formatter has already been configured
- # (e.g. via a command-line flag).
- config.default_formatter = 'doc'
- end
-
- # Print the 10 slowest examples and example groups at the
- # end of the spec run, to help surface which specs are running
- # particularly slow.
- config.profile_examples = 10
-
- # Run specs in random order to surface order dependencies. If you find an
- # order dependency and want to debug it, you can fix the order by providing
- # the seed, which is printed after each run.
- # --seed 1234
config.order = :random
-
- # Seed global randomization in this process using the `--seed` CLI option.
- # Setting this allows you to use `--seed` to deterministically reproduce
- # test failures related to randomization by passing the same `--seed` value
- # as the one that triggered the failure.
Kernel.srand config.seed
-
- # rspec-expectations config goes here. You can use an alternate
- # assertion/expectation library such as wrong or the stdlib/minitest
- # assertions if you prefer.
config.expect_with :rspec do |expectations|
- # Enable only the newer, non-monkey-patching expect syntax.
- # For more details, see:
- # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
- expectations.syntax = :expect
+ expectations.syntax = [:expect, :should]
end
-
- # rspec-mocks config goes here. You can use an alternate test double
- # library (such as bogus or mocha) by changing the `mock_with` option here.
config.mock_with :rspec do |mocks|
- # Enable only the newer, non-monkey-patching expect syntax.
- # For more details, see:
- # - http://teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
- mocks.syntax = :expect
-
- # Prevents you from mocking or stubbing a method that does not exist on
- # a real object. This is generally recommended.
+ mocks.syntax = [:expect, :should]
mocks.verify_partial_doubles = true
end
end
.rspec
@@ -1,3 +1,2 @@
--color
---warnings
--require spec_helper