orm_adapter_rails4_fix 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +15 -0
- data/.rspec +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +3 -0
- data/Gemfile.lock.development +129 -0
- data/History.txt +58 -0
- data/LICENSE +20 -0
- data/README.rdoc +71 -0
- data/Rakefile +37 -0
- data/lib/orm_adapter.rb +15 -0
- data/lib/orm_adapter/adapters/active_record.rb +76 -0
- data/lib/orm_adapter/adapters/data_mapper.rb +57 -0
- data/lib/orm_adapter/adapters/mongo_mapper.rb +65 -0
- data/lib/orm_adapter/adapters/mongoid.rb +63 -0
- data/lib/orm_adapter/base.rb +127 -0
- data/lib/orm_adapter/to_adapter.rb +8 -0
- data/lib/orm_adapter/version.rb +3 -0
- data/orm_adapter.gemspec +35 -0
- data/spec/orm_adapter/adapters/active_record_spec.rb +62 -0
- data/spec/orm_adapter/adapters/data_mapper_spec.rb +47 -0
- data/spec/orm_adapter/adapters/mongo_mapper_spec.rb +41 -0
- data/spec/orm_adapter/adapters/mongoid_spec.rb +39 -0
- data/spec/orm_adapter/base_spec.rb +81 -0
- data/spec/orm_adapter/example_app_shared.rb +240 -0
- data/spec/orm_adapter_spec.rb +13 -0
- data/spec/spec_helper.rb +15 -0
- metadata +290 -0
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'dm-core'
|
2
|
+
|
3
|
+
module DataMapper
|
4
|
+
module Model
|
5
|
+
include OrmAdapter::ToAdapter
|
6
|
+
end
|
7
|
+
|
8
|
+
module Resource
|
9
|
+
class OrmAdapter < ::OrmAdapter::Base
|
10
|
+
# get a list of column names for a given class
|
11
|
+
def column_names
|
12
|
+
klass.properties.map(&:name)
|
13
|
+
end
|
14
|
+
|
15
|
+
# @see OrmAdapter::Base#get!
|
16
|
+
def get!(id)
|
17
|
+
klass.get!(id)
|
18
|
+
end
|
19
|
+
|
20
|
+
# @see OrmAdapter::Base#get
|
21
|
+
def get(id)
|
22
|
+
klass.get(id)
|
23
|
+
end
|
24
|
+
|
25
|
+
# @see OrmAdapter::Base#find_first
|
26
|
+
def find_first(options = {})
|
27
|
+
conditions, order = extract_conditions!(options)
|
28
|
+
klass.first :conditions => conditions, :order => order_clause(order)
|
29
|
+
end
|
30
|
+
|
31
|
+
# @see OrmAdapter::Base#find_all
|
32
|
+
def find_all(options = {})
|
33
|
+
conditions, order, limit, offset = extract_conditions!(options)
|
34
|
+
opts = { :conditions => conditions, :order => order_clause(order) }
|
35
|
+
opts = opts.merge({ :limit => limit }) unless limit.nil?
|
36
|
+
opts = opts.merge({ :offset => offset }) unless offset.nil?
|
37
|
+
klass.all opts
|
38
|
+
end
|
39
|
+
|
40
|
+
# @see OrmAdapter::Base#create!
|
41
|
+
def create!(attributes = {})
|
42
|
+
klass.create(attributes)
|
43
|
+
end
|
44
|
+
|
45
|
+
# @see OrmAdapter::Base#destroy
|
46
|
+
def destroy(object)
|
47
|
+
object.destroy if valid_object?(object)
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
def order_clause(order)
|
53
|
+
order.map {|pair| pair.first.send(pair.last)}
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
require 'mongo_mapper'
|
2
|
+
|
3
|
+
module MongoMapper
|
4
|
+
module Document
|
5
|
+
module ClassMethods
|
6
|
+
include OrmAdapter::ToAdapter
|
7
|
+
end
|
8
|
+
|
9
|
+
class OrmAdapter < ::OrmAdapter::Base
|
10
|
+
# get a list of column names for a given class
|
11
|
+
def column_names
|
12
|
+
klass.column_names
|
13
|
+
end
|
14
|
+
|
15
|
+
# @see OrmAdapter::Base#get!
|
16
|
+
def get!(id)
|
17
|
+
klass.find!(wrap_key(id))
|
18
|
+
end
|
19
|
+
|
20
|
+
# @see OrmAdapter::Base#get
|
21
|
+
def get(id)
|
22
|
+
klass.first({ :id => wrap_key(id) })
|
23
|
+
end
|
24
|
+
|
25
|
+
# @see OrmAdapter::Base#find_first
|
26
|
+
def find_first(conditions = {})
|
27
|
+
conditions, order = extract_conditions!(conditions)
|
28
|
+
conditions = conditions.merge(:sort => order) unless order.nil?
|
29
|
+
klass.first(conditions_to_fields(conditions))
|
30
|
+
end
|
31
|
+
|
32
|
+
# @see OrmAdapter::Base#find_all
|
33
|
+
def find_all(conditions = {})
|
34
|
+
conditions, order, limit, offset = extract_conditions!(conditions)
|
35
|
+
conditions = conditions.merge(:sort => order) unless order.nil?
|
36
|
+
conditions = conditions.merge(:limit => limit) unless limit.nil?
|
37
|
+
conditions = conditions.merge(:offset => offset) unless limit.nil? || offset.nil?
|
38
|
+
klass.all(conditions_to_fields(conditions))
|
39
|
+
end
|
40
|
+
|
41
|
+
# @see OrmAdapter::Base#create!
|
42
|
+
def create!(attributes = {})
|
43
|
+
klass.create!(attributes)
|
44
|
+
end
|
45
|
+
|
46
|
+
# @see OrmAdapter::Base#destroy
|
47
|
+
def destroy(object)
|
48
|
+
object.destroy if valid_object?(object)
|
49
|
+
end
|
50
|
+
|
51
|
+
protected
|
52
|
+
|
53
|
+
# converts and documents to ids
|
54
|
+
def conditions_to_fields(conditions)
|
55
|
+
conditions.inject({}) do |fields, (key, value)|
|
56
|
+
if value.is_a?(MongoMapper::Document) && klass.key?("#{key}_id")
|
57
|
+
fields.merge("#{key}_id" => value.id)
|
58
|
+
else
|
59
|
+
fields.merge(key => value)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'mongoid'
|
2
|
+
|
3
|
+
module Mongoid
|
4
|
+
module Document
|
5
|
+
module ClassMethods
|
6
|
+
include OrmAdapter::ToAdapter
|
7
|
+
end
|
8
|
+
|
9
|
+
class OrmAdapter < ::OrmAdapter::Base
|
10
|
+
# get a list of column names for a given class
|
11
|
+
def column_names
|
12
|
+
klass.fields.keys
|
13
|
+
end
|
14
|
+
|
15
|
+
# @see OrmAdapter::Base#get!
|
16
|
+
def get!(id)
|
17
|
+
klass.find(wrap_key(id))
|
18
|
+
end
|
19
|
+
|
20
|
+
# @see OrmAdapter::Base#get
|
21
|
+
def get(id)
|
22
|
+
klass.where(:_id => wrap_key(id)).first
|
23
|
+
end
|
24
|
+
|
25
|
+
# @see OrmAdapter::Base#find_first
|
26
|
+
def find_first(options = {})
|
27
|
+
conditions, order = extract_conditions!(options)
|
28
|
+
klass.limit(1).where(conditions_to_fields(conditions)).order_by(order).first
|
29
|
+
end
|
30
|
+
|
31
|
+
# @see OrmAdapter::Base#find_all
|
32
|
+
def find_all(options = {})
|
33
|
+
conditions, order, limit, offset = extract_conditions!(options)
|
34
|
+
klass.where(conditions_to_fields(conditions)).order_by(order).limit(limit).offset(offset)
|
35
|
+
end
|
36
|
+
|
37
|
+
# @see OrmAdapter::Base#create!
|
38
|
+
def create!(attributes = {})
|
39
|
+
klass.create!(attributes)
|
40
|
+
end
|
41
|
+
|
42
|
+
# @see OrmAdapter::Base#destroy
|
43
|
+
def destroy(object)
|
44
|
+
object.destroy if valid_object?(object)
|
45
|
+
end
|
46
|
+
|
47
|
+
protected
|
48
|
+
|
49
|
+
# converts and documents to ids
|
50
|
+
def conditions_to_fields(conditions)
|
51
|
+
conditions.inject({}) do |fields, (key, value)|
|
52
|
+
if value.is_a?(Mongoid::Document) && klass.fields.keys.include?("#{key}_id")
|
53
|
+
fields.merge("#{key}_id" => value.id)
|
54
|
+
elsif key.to_s == 'id'
|
55
|
+
fields.merge('_id' => value)
|
56
|
+
else
|
57
|
+
fields.merge(key => value)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,127 @@
|
|
1
|
+
module OrmAdapter
|
2
|
+
class Base
|
3
|
+
attr_reader :klass
|
4
|
+
|
5
|
+
# Your ORM adapter needs to inherit from this Base class and its adapter
|
6
|
+
# will be registered. To create an adapter you should create an inner
|
7
|
+
# constant "OrmAdapter" e.g. ActiveRecord::Base::OrmAdapter
|
8
|
+
#
|
9
|
+
# @see orm_adapters/active_record
|
10
|
+
# @see orm_adapters/datamapper
|
11
|
+
# @see orm_adapters/mongoid
|
12
|
+
def self.inherited(adapter)
|
13
|
+
OrmAdapter.adapters << adapter
|
14
|
+
super
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(klass)
|
18
|
+
@klass = klass
|
19
|
+
end
|
20
|
+
|
21
|
+
# Get a list of column/property/field names
|
22
|
+
def column_names
|
23
|
+
raise NotSupportedError
|
24
|
+
end
|
25
|
+
|
26
|
+
# Get an instance by id of the model. Raises an error if a model is not found.
|
27
|
+
# This should comply with ActiveModel#to_key API, i.e.:
|
28
|
+
#
|
29
|
+
# User.to_adapter.get!(@user.to_key) == @user
|
30
|
+
#
|
31
|
+
def get!(id)
|
32
|
+
raise NotSupportedError
|
33
|
+
end
|
34
|
+
|
35
|
+
# Get an instance by id of the model. Returns nil if a model is not found.
|
36
|
+
# This should comply with ActiveModel#to_key API, i.e.:
|
37
|
+
#
|
38
|
+
# User.to_adapter.get(@user.to_key) == @user
|
39
|
+
#
|
40
|
+
def get(id)
|
41
|
+
raise NotSupportedError
|
42
|
+
end
|
43
|
+
|
44
|
+
# Find the first instance, optionally matching conditions, and specifying order
|
45
|
+
#
|
46
|
+
# You can call with just conditions, providing a hash
|
47
|
+
#
|
48
|
+
# User.to_adapter.find_first :name => "Fred", :age => 23
|
49
|
+
#
|
50
|
+
# Or you can specify :order, and :conditions as keys
|
51
|
+
#
|
52
|
+
# User.to_adapter.find_first :conditions => {:name => "Fred", :age => 23}
|
53
|
+
# User.to_adapter.find_first :order => [:age, :desc]
|
54
|
+
# User.to_adapter.find_first :order => :name, :conditions => {:age => 18}
|
55
|
+
#
|
56
|
+
# When specifying :order, it may be
|
57
|
+
# * a single arg e.g. <tt>:order => :name</tt>
|
58
|
+
# * a single pair with :asc, or :desc as last, e.g. <tt>:order => [:name, :desc]</tt>
|
59
|
+
# * an array of single args or pairs (with :asc or :desc as last), e.g. <tt>:order => [[:name, :asc], [:age, :desc]]</tt>
|
60
|
+
#
|
61
|
+
def find_first(options = {})
|
62
|
+
raise NotSupportedError
|
63
|
+
end
|
64
|
+
|
65
|
+
# Find all models, optionally matching conditions, and specifying order
|
66
|
+
# @see OrmAdapter::Base#find_first for how to specify order and conditions
|
67
|
+
def find_all(options = {})
|
68
|
+
raise NotSupportedError
|
69
|
+
end
|
70
|
+
|
71
|
+
# Create a model using attributes
|
72
|
+
def create!(attributes = {})
|
73
|
+
raise NotSupportedError
|
74
|
+
end
|
75
|
+
|
76
|
+
# Destroy an instance by passing in the instance itself.
|
77
|
+
def destroy(object)
|
78
|
+
raise NotSupportedError
|
79
|
+
end
|
80
|
+
|
81
|
+
protected
|
82
|
+
|
83
|
+
def valid_object?(object)
|
84
|
+
object.class == klass
|
85
|
+
end
|
86
|
+
|
87
|
+
def wrap_key(key)
|
88
|
+
key.is_a?(Array) ? key.first : key
|
89
|
+
end
|
90
|
+
|
91
|
+
# given an options hash,
|
92
|
+
# with optional :conditions, :order, :limit and :offset keys,
|
93
|
+
# returns conditions, normalized order, limit and offset
|
94
|
+
def extract_conditions!(options = {})
|
95
|
+
order = normalize_order(options.delete(:order))
|
96
|
+
limit = options.delete(:limit)
|
97
|
+
offset = options.delete(:offset)
|
98
|
+
conditions = options.delete(:conditions) || options
|
99
|
+
|
100
|
+
[conditions, order, limit, offset]
|
101
|
+
end
|
102
|
+
|
103
|
+
# given an order argument, returns an array of pairs, with each pair containing the attribute, and :asc or :desc
|
104
|
+
def normalize_order(order)
|
105
|
+
order = Array(order)
|
106
|
+
|
107
|
+
if order.length == 2 && !order[0].is_a?(Array) && [:asc, :desc].include?(order[1])
|
108
|
+
order = [order]
|
109
|
+
else
|
110
|
+
order = order.map {|pair| pair.is_a?(Array) ? pair : [pair, :asc] }
|
111
|
+
end
|
112
|
+
|
113
|
+
order.each do |pair|
|
114
|
+
pair.length == 2 or raise ArgumentError, "each order clause must be a pair (unknown clause #{pair.inspect})"
|
115
|
+
[:asc, :desc].include?(pair[1]) or raise ArgumentError, "order must be specified with :asc or :desc (unknown key #{pair[1].inspect})"
|
116
|
+
end
|
117
|
+
|
118
|
+
order
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
class NotSupportedError < NotImplementedError
|
123
|
+
def to_s
|
124
|
+
"method not supported by this orm adapter"
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
data/orm_adapter.gemspec
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
$:.push File.expand_path("../lib", __FILE__)
|
2
|
+
require "orm_adapter/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "orm_adapter_rails4_fix"
|
6
|
+
s.version = OrmAdapter::VERSION.dup
|
7
|
+
s.platform = Gem::Platform::RUBY
|
8
|
+
s.authors = ["Ian White", "Jose Valim"]
|
9
|
+
s.description = "Provides a single point of entry for using basic features of ruby ORMs"
|
10
|
+
s.summary = "orm_adapter provides a single point of entry for using basic features of popular ruby ORMs. Its target audience is gem authors who want to support many ruby ORMs."
|
11
|
+
s.email = "ian.w.white@gmail.com"
|
12
|
+
s.homepage = "http://github.com/ianwhite/orm_adapter"
|
13
|
+
|
14
|
+
s.rubyforge_project = "orm_adapter"
|
15
|
+
s.required_rubygems_version = ">= 1.3.6"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_development_dependency "bundler", ">= 1.0.0"
|
22
|
+
s.add_development_dependency "git", ">= 1.2.5"
|
23
|
+
s.add_development_dependency "yard", ">= 0.6.0"
|
24
|
+
s.add_development_dependency "rake", ">= 0.8.7"
|
25
|
+
s.add_development_dependency "activerecord", ">= 3.0.0"
|
26
|
+
s.add_development_dependency "mongoid", ">= 2.0.0.beta.20"
|
27
|
+
s.add_development_dependency "mongo_mapper", ">= 0.9.0"
|
28
|
+
s.add_development_dependency "bson_ext", ">= 1.3.0"
|
29
|
+
s.add_development_dependency "rspec", ">= 2.4.0"
|
30
|
+
s.add_development_dependency "sqlite3", ">= 1.3.2"
|
31
|
+
s.add_development_dependency "datamapper", ">= 1.0"
|
32
|
+
s.add_development_dependency "dm-sqlite-adapter", ">= 1.0"
|
33
|
+
s.add_development_dependency "dm-active_model", ">= 1.0"
|
34
|
+
end
|
35
|
+
|
@@ -0,0 +1,62 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'orm_adapter/example_app_shared'
|
3
|
+
|
4
|
+
if !defined?(ActiveRecord::Base)
|
5
|
+
puts "** require 'active_record' to run the specs in #{__FILE__}"
|
6
|
+
else
|
7
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ":memory:")
|
8
|
+
|
9
|
+
ActiveRecord::Migration.suppress_messages do
|
10
|
+
ActiveRecord::Schema.define(:version => 0) do
|
11
|
+
create_table(:users, :force => true) {|t| t.string :name; t.integer :rating; }
|
12
|
+
create_table(:notes, :force => true) {|t| t.belongs_to :owner, :polymorphic => true }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
module ArOrmSpec
|
17
|
+
class User < ActiveRecord::Base
|
18
|
+
has_many :notes, :as => :owner
|
19
|
+
end
|
20
|
+
|
21
|
+
class AbstractNoteClass < ActiveRecord::Base
|
22
|
+
self.abstract_class = true
|
23
|
+
end
|
24
|
+
|
25
|
+
class Note < AbstractNoteClass
|
26
|
+
belongs_to :owner, :polymorphic => true
|
27
|
+
end
|
28
|
+
|
29
|
+
# here be the specs!
|
30
|
+
describe '[ActiveRecord orm adapter]' do
|
31
|
+
before do
|
32
|
+
User.delete_all
|
33
|
+
Note.delete_all
|
34
|
+
end
|
35
|
+
|
36
|
+
it_should_behave_like "example app with orm_adapter" do
|
37
|
+
let(:user_class) { User }
|
38
|
+
let(:note_class) { Note }
|
39
|
+
end
|
40
|
+
|
41
|
+
describe "#conditions_to_fields" do
|
42
|
+
describe "with non-standard association keys" do
|
43
|
+
class PerverseNote < Note
|
44
|
+
belongs_to :user, :foreign_key => 'owner_id'
|
45
|
+
belongs_to :pwner, :polymorphic => true, :foreign_key => 'owner_id', :foreign_type => 'owner_type'
|
46
|
+
end
|
47
|
+
|
48
|
+
let(:user) { User.create! }
|
49
|
+
let(:adapter) { PerverseNote.to_adapter }
|
50
|
+
|
51
|
+
it "should convert polymorphic object in conditions to the appropriate fields" do
|
52
|
+
adapter.send(:conditions_to_fields, :pwner => user).should == {'owner_id' => user.id, 'owner_type' => user.class.name}
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should convert belongs_to object in conditions to the appropriate fields" do
|
56
|
+
adapter.send(:conditions_to_fields, :user => user).should == {'owner_id' => user.id}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'orm_adapter/example_app_shared'
|
3
|
+
|
4
|
+
if !defined?(DataMapper)
|
5
|
+
puts "** require 'dm-core' to run the specs in #{__FILE__}"
|
6
|
+
else
|
7
|
+
|
8
|
+
DataMapper.setup(:default, 'sqlite::memory:')
|
9
|
+
|
10
|
+
module DmOrmSpec
|
11
|
+
class User
|
12
|
+
include DataMapper::Resource
|
13
|
+
property :id, Serial
|
14
|
+
property :name, String
|
15
|
+
property :rating, Integer
|
16
|
+
has n, :notes, :child_key => [:owner_id]
|
17
|
+
end
|
18
|
+
|
19
|
+
class Note
|
20
|
+
include DataMapper::Resource
|
21
|
+
property :id, Serial
|
22
|
+
property :body, String
|
23
|
+
belongs_to :owner, 'User'
|
24
|
+
end
|
25
|
+
|
26
|
+
require 'dm-migrations'
|
27
|
+
DataMapper.finalize
|
28
|
+
DataMapper.auto_migrate!
|
29
|
+
|
30
|
+
# here be the specs!
|
31
|
+
describe DataMapper::Resource::OrmAdapter do
|
32
|
+
before do
|
33
|
+
User.destroy
|
34
|
+
Note.destroy
|
35
|
+
end
|
36
|
+
|
37
|
+
it_should_behave_like "example app with orm_adapter" do
|
38
|
+
let(:user_class) { User }
|
39
|
+
let(:note_class) { Note }
|
40
|
+
|
41
|
+
def reload_model(model)
|
42
|
+
model.class.get(model.id)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|