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.
@@ -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
@@ -0,0 +1,8 @@
1
+ module OrmAdapter
2
+ # Extend into a class that has an OrmAdapter
3
+ module ToAdapter
4
+ def to_adapter
5
+ @_to_adapter ||= self::OrmAdapter.new(self)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,3 @@
1
+ module OrmAdapter
2
+ VERSION = "0.4.1"
3
+ end
@@ -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