ardm 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (93) hide show
  1. checksums.yaml +5 -13
  2. data/Gemfile +1 -2
  3. data/LICENSE +2 -2
  4. data/README.md +72 -16
  5. data/ardm.gemspec +1 -0
  6. data/lib/ardm.rb +2 -1
  7. data/lib/ardm/active_record.rb +8 -1
  8. data/lib/ardm/active_record/associations.rb +33 -4
  9. data/lib/ardm/active_record/base.rb +2 -0
  10. data/lib/ardm/active_record/collection.rb +5 -0
  11. data/lib/ardm/active_record/data_mapper_constant.rb +1 -0
  12. data/lib/ardm/active_record/data_mapper_constant_proxy.rb +24 -0
  13. data/lib/ardm/active_record/finalize.rb +18 -0
  14. data/lib/ardm/active_record/predicate_builder/array_handler.rb +10 -16
  15. data/lib/ardm/active_record/predicate_builder/rails3.rb +42 -15
  16. data/lib/ardm/active_record/predicate_builder/rails4.rb +39 -13
  17. data/lib/ardm/active_record/property.rb +24 -12
  18. data/lib/ardm/active_record/query.rb +9 -18
  19. data/lib/ardm/active_record/record.rb +54 -11
  20. data/lib/ardm/active_record/relation.rb +36 -6
  21. data/lib/ardm/active_record/repository.rb +6 -2
  22. data/lib/ardm/data_mapper.rb +2 -0
  23. data/lib/ardm/data_mapper/record.rb +3 -9
  24. data/lib/ardm/version.rb +1 -1
  25. data/spec/ardm/datamapper_constants_spec.rb +31 -0
  26. data/spec/fixtures/article.rb +2 -0
  27. data/spec/integration/api_key_spec.rb +3 -3
  28. data/spec/integration/bcrypt_hash_spec.rb +7 -7
  29. data/spec/integration/comma_separated_list_spec.rb +11 -11
  30. data/spec/integration/dirty_minder_spec.rb +23 -39
  31. data/spec/integration/enum_spec.rb +11 -11
  32. data/spec/integration/epoch_time_spec.rb +6 -6
  33. data/spec/integration/file_path_spec.rb +23 -23
  34. data/spec/integration/flag_spec.rb +11 -13
  35. data/spec/integration/ip_address_spec.rb +15 -15
  36. data/spec/integration/json_spec.rb +7 -7
  37. data/spec/integration/slug_spec.rb +6 -6
  38. data/spec/integration/uri_spec.rb +11 -11
  39. data/spec/integration/uuid_spec.rb +16 -16
  40. data/spec/integration/yaml_spec.rb +8 -8
  41. data/spec/public/model_spec.rb +193 -0
  42. data/spec/public/property/binary_spec.rb +4 -4
  43. data/spec/public/property/boolean_spec.rb +3 -3
  44. data/spec/public/property/class_spec.rb +2 -2
  45. data/spec/public/property/date_spec.rb +2 -2
  46. data/spec/public/property/date_time_spec.rb +2 -2
  47. data/spec/public/property/decimal_spec.rb +2 -2
  48. data/spec/public/property/discriminator_spec.rb +21 -20
  49. data/spec/public/property/float_spec.rb +2 -2
  50. data/spec/public/property/integer_spec.rb +2 -2
  51. data/spec/public/property/object_spec.rb +14 -13
  52. data/spec/public/property/serial_spec.rb +2 -2
  53. data/spec/public/property/string_spec.rb +2 -2
  54. data/spec/public/property/text_spec.rb +2 -2
  55. data/spec/public/property/time_spec.rb +2 -2
  56. data/spec/public/property_spec.rb +44 -48
  57. data/spec/public/resource_spec.rb +278 -0
  58. data/spec/schema.rb +33 -4
  59. data/spec/semipublic/property/boolean_spec.rb +5 -5
  60. data/spec/semipublic/property/class_spec.rb +3 -3
  61. data/spec/semipublic/property/date_spec.rb +8 -8
  62. data/spec/semipublic/property/date_time_spec.rb +9 -9
  63. data/spec/semipublic/property/decimal_spec.rb +16 -16
  64. data/spec/semipublic/property/float_spec.rb +16 -16
  65. data/spec/semipublic/property/integer_spec.rb +16 -16
  66. data/spec/semipublic/property/lookup_spec.rb +4 -4
  67. data/spec/semipublic/property/text_spec.rb +2 -2
  68. data/spec/semipublic/property/time_spec.rb +10 -10
  69. data/spec/semipublic/property_spec.rb +4 -4
  70. data/spec/shared/finder_shared_spec.rb +1151 -0
  71. data/spec/shared/flags_shared_spec.rb +6 -6
  72. data/spec/shared/identity_function_group.rb +1 -1
  73. data/spec/shared/public_property_spec.rb +26 -25
  74. data/spec/shared/resource_spec.rb +1218 -0
  75. data/spec/shared/semipublic_property_spec.rb +23 -22
  76. data/spec/spec_helper.rb +17 -0
  77. data/spec/unit/bcrypt_hash_spec.rb +15 -15
  78. data/spec/unit/csv_spec.rb +11 -11
  79. data/spec/unit/dirty_minder_spec.rb +3 -5
  80. data/spec/unit/enum_spec.rb +17 -17
  81. data/spec/unit/epoch_time_spec.rb +8 -8
  82. data/spec/unit/file_path_spec.rb +9 -9
  83. data/spec/unit/flag_spec.rb +9 -9
  84. data/spec/unit/ip_address_spec.rb +9 -9
  85. data/spec/unit/json_spec.rb +11 -11
  86. data/spec/unit/paranoid_boolean_spec.rb +19 -17
  87. data/spec/unit/paranoid_datetime_spec.rb +21 -19
  88. data/spec/unit/regexp_spec.rb +4 -4
  89. data/spec/unit/uri_spec.rb +8 -8
  90. data/spec/unit/yaml_spec.rb +9 -9
  91. metadata +35 -27
  92. data/lib/ardm/active_record/not_found.rb +0 -7
  93. data/lib/ardm/data_mapper/not_found.rb +0 -5
checksums.yaml CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- Mzk3NGRlZjc5N2E0Nzc4MjFkZmI5ZDA3MWNiNDVjNTE3NzQ1ZTM5Mg==
5
- data.tar.gz: !binary |-
6
- YmZlNzI5MzMzMjdlZDQwYjExZjcxYjZiNjA5YTkyZTBmM2QxOGZlMQ==
2
+ SHA1:
3
+ metadata.gz: 866545bbe125ccbada17fad21e0fcc1b3ff15fa0
4
+ data.tar.gz: 6d5ebf8a7cf672ec89125d8bace07470229ecd33
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- ZmViYjY2MmFiMjRmOGZiM2U1M2ZhY2MyN2I4YzJhZDc4NDcyYTcwZWE3ODQy
10
- MTA5OWQ2ODUzMmRhN2M3ZWM2MWUyODkxOWU0ZmU2OTFjZGIwN2Y1ZmVkZGNh
11
- Nzk3M2I3NzhmOTNiZDcxNjVkY2E2ZWE2MTY1MmQ1NGIwMjc3OTI=
12
- data.tar.gz: !binary |-
13
- NzcxYzU2NDRiMjU5NjVkYTVhNjNiZGEyMGRhYWVlYmYxOTc2ZDBhN2Q0YjE2
14
- NzI3MTYzNDg5ODRjZTY1Y2U1N2JiYmMzZDdmNDlhYTBkYmZiYTJiMmFjMjk1
15
- MWUzMmExYjQ5NGQxN2IxZjc2ZTIwZGU0ZGIzNzE4ZGM5Y2JiYTg=
6
+ metadata.gz: 60564ee06c22d8e54564a87ec294896b74f6753f2ce004cc615f325ef8521025eeaf821d7fb3e359de45b9a9ef3124b4ae663ebe6b26849b93ae494d121b8346
7
+ data.tar.gz: 7403cb0bbd7f8b636b572267977a9302fa4e35c4027bcede569b77f49645027df75e4ab1db2658e3976fbf0e773fa5b6748f169d9c82774cec728dd3c9dee572
data/Gemfile CHANGED
@@ -3,11 +3,10 @@ source 'https://rubygems.org'
3
3
  gemspec
4
4
 
5
5
  gem 'pry'
6
- gem 'pry-debugger'
7
6
 
8
7
  group :test do
9
8
  gem 'sqlite3'
10
- gem 'activerecord', '~> 4.0.0'
9
+ gem 'activerecord', '~> 3.2'
11
10
  gem 'addressable'
12
11
  gem 'database_cleaner'
13
12
  end
data/LICENSE CHANGED
@@ -1,5 +1,5 @@
1
- Code to adapt dm-types and dm-core properties to Active Record copyright (c) 2013 Martin Emde
2
- Code from dm-types and dm-core originally Copyright (c) 2011 Sam Smoot, Dan Kubb
1
+ Adaptation of dm-core to run atop Active Record Copyright (c) 2013 Engine Yard
2
+ dm-types and dm-core source code Copyright (c) 2011 Sam Smoot, Dan Kubb
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining
5
5
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -2,32 +2,44 @@
2
2
 
3
3
  ActiveRecord plugin to provide a smooth migration from DataMapper to ActiveRecord.
4
4
 
5
+ This code is currently in development and not feature complete.
6
+ Your code is probably different than mine, so please contribute to bridge
7
+ the gap from DataMapper to ActiveRecord and Rails 4.
8
+
5
9
  ## Why
6
10
 
7
11
  Ardm is intended for applications running Rails with DataMapper 1.2 who need
8
- to migrate to ActiveRecord. Lets examine some of the reasons why you might
9
- move to ActiveRecord.
12
+ to migrate to ActiveRecord so they can move forward onto Rails 4.
13
+ Lets examine some of the reasons why you might move to ActiveRecord.
10
14
 
11
15
  * DataMapper is no longer under development. Ruby Object Mapper (ROM) is the
12
- imlicit replacement for DataMapper, but it's not a supported migration. ROM
13
- is a completely new codebase and very few of the idioms transfer.
16
+ implicit replacement for DataMapper, but it's not a supported migration.
17
+ ROM is a completely new codebase and very few of the idioms transfer.
14
18
  * DataMapper produces inefficient queries. Includes, joins, and subqueries are
15
19
  either not supported or incorrect. Enabling subqueries in DM speeds up queries
16
20
  but causes other subtle query problems than can produce bad SQL that may
17
21
  select incorrect records.
18
- * DataMapper cannot currently run on Rails4. Someone may take the initiative to
22
+ * DataMapper cannot currently run on Rails 4. Someone may take the initiative to
19
23
  upgrade DataMapper to work on Rails4, but I think you're much better off
20
24
  moving to ActiveRecord.
21
25
  * Arel is awesome. ActiveRecord and Arel together is quite nice. With the added
22
- support properties and the advances in Rails4, I think this upgrade is a must.
23
- * ActiveRecord is used in more applications, better tested, and more performant.
26
+ support properties and the advances in Rails 4, I think this upgrade is a must.
27
+ * ActiveRecord is used in more applications, is better tested, and is more
28
+ performant than DataMapper.
24
29
 
25
30
  ## Installation
26
31
 
27
- Incremental migration from DataMapper to ActiveRecord.
32
+ require 'ardm'
33
+
34
+ Run your project using the ORM environment variable.
35
+
36
+ ORM=activerecord bundle exec rake spec
37
+ ORM=datamapper bundle exec rake spec
38
+
39
+ ## Incremental migration from DataMapper to ActiveRecord
28
40
 
29
- ActiveRecord requires your models to inherit from ActiveRecord::Base, but makes
30
- it difficult to approach the migration incrementally. All or nothing is a scary
41
+ ActiveRecord requires your models to inherit from ActiveRecord::Base, which makes
42
+ it difficult to approach this migration incrementally. All or nothing is a scary
31
43
  way to switch ORMs. To solve this, Ardm supplies Ardm::Record.
32
44
 
33
45
  Ardm::Record will be the new base class. You'll need to search and replace
@@ -50,16 +62,60 @@ Example:
50
62
 
51
63
  With this new base clase you can switch between ActiveRecord and DataMapper
52
64
  by flipping a swith in your application. This approach allows you to continue
53
- developing your application in DataMapper while you work on teasing out all
65
+ developing your application in DataMapper while you work on removing all
54
66
  the "datamapper-isms" from your code. This library attempts to take care of
55
67
  most DataMapper features, but there are probably tons of small variations
56
68
  that are not accounted for.
57
69
 
58
- ## Usage
59
-
60
- require 'ardm'
61
-
62
-
70
+ ## General Strategy
71
+
72
+ This is a complex thing to approach. I'm hoping this project can make this move
73
+ into a repeatable strategy rather than everyone needing to create their own
74
+ unique solution.
75
+
76
+ 1. Get the application running with Ardm installed. Don't even think about
77
+ ActiveRecord until you have Ardm working in DataMapper mode and you can
78
+ deploy your application normally with ardm installed.
79
+ 2. Start to remove references to `DataMapper` by using the conversions
80
+ mentioned below. The idea is to remove the `DataMapper` constant completely
81
+ so you can run without `dm-core` when in ActiveRecord mode.
82
+ 3. Once your application runs smoothly in DataMapper mode with all the
83
+ constants using Ardm, try to get the application to start the test run
84
+ in ActiveRecord mode. This will probably require a bunch of hunting through
85
+ the application for datamapper-isms that are not accounted for in Ardm.
86
+ **Please help by contributing these fixes back to Ardm!**
87
+ 4. Make all your tests pass in ActiveRecord and DataMapper mode. This is an
88
+ ideal. You could decide that you're close enough and start sacrificing
89
+ DataMapper specific code for ActiveRecord code. You can branch around
90
+ picky code with the `Ardme.activerecord?` and `Ardm.datamapper?` helpers.
91
+
92
+ ## Conversions
93
+
94
+ Things that access DataMapper directly can be replaced with Ardm invocations:
95
+
96
+ DataMapper.finalize => Ardm::Record.finalize (no-op in AR mode)
97
+ DataMapper.repository => Ardm::Record.repository
98
+ DataMapper.logger => Ardm::Record.logger
99
+
100
+ DataMapper::ObjectNotFoundError => Ardm::Record::NotFound
101
+ ActiveRecord::RecordNotFound => Ardm::Record::NotFound
102
+
103
+ DataMapper::Property => Ardm::Property
104
+ DataMapper::Property::String => Ardm::Property::String
105
+
106
+ This pattern follows for most DataMapper module methods. When running in
107
+ DataMapper mode, these simply forward. In ActiveRecord mode, they provide
108
+ adapters for accessing the same data through ActiveRecord.
109
+
110
+ If you run into code that is particularly difficult to convert, you can
111
+ duplicate the code and write a different version for each ORM:
112
+
113
+ if Ardm.activerecord?
114
+ Thing.where(Thing.arel_table[:field].matches('something'))
115
+ else
116
+ # This is just an example. This should actually work fine in Ardm.
117
+ Thing.all(:field.like => 'something')
118
+ end
63
119
 
64
120
  ## Copyright
65
121
 
data/ardm.gemspec CHANGED
@@ -7,6 +7,7 @@ Gem::Specification.new do |gem|
7
7
  gem.summary = "ActiveRecord plugin to provide a smooth migration from DataMapper to ActiveRecord"
8
8
  gem.description = gem.summary
9
9
  gem.homepage = "http://github.com/engineyard/ardm"
10
+ gem.license = "MIT"
10
11
 
11
12
  gem.files = `git ls-files`.split("\n")
12
13
  gem.test_files = `git ls-files -- {spec}/*`.split("\n")
data/lib/ardm.rb CHANGED
@@ -1,5 +1,6 @@
1
- puts __FILE__
2
1
  module Ardm
2
+ NotImplemented = Class.new(RuntimeError)
3
+
3
4
  # Check which ORM is loaded in Ardm.
4
5
  #
5
6
  # @api public
@@ -1,4 +1,3 @@
1
- puts __FILE__
2
1
  require 'ardm'
3
2
 
4
3
  # only load support libs in active record mode (dm will supply its own libs)
@@ -29,11 +28,19 @@ require 'active_record/relation'
29
28
 
30
29
  require 'ardm/active_record/record'
31
30
  require 'ardm/active_record/relation'
31
+ require 'ardm/active_record/data_mapper_constant_proxy'
32
32
 
33
33
  module Ardm
34
34
  Record = Ardm::ActiveRecord::Record
35
+ SaveFailureError = ::ActiveRecord::RecordNotSaved
36
+ RecordNotFound = ::ActiveRecord::RecordNotFound
37
+
38
+ def self.define_datamapper_constant!
39
+ require 'ardm/active_record/data_mapper_constant'
40
+ end
35
41
  end
36
42
 
43
+
37
44
  #::ActiveRecord::Base.class_eval do
38
45
  # include Ardm::ActiveRecord::Base
39
46
  #end
@@ -40,13 +40,42 @@ module Ardm
40
40
  end
41
41
 
42
42
  module ClassMethods
43
- def belongs_to(field, options={})
43
+
44
+ def dump_associations_hash(options)
45
+ options.inject({}) do |new_attrs, (key, value)|
46
+ if reflection = reflect_on_association(key.to_sym)
47
+ if value.is_a?(ActiveRecord::Base)
48
+ new_attrs[reflection.foreign_key] = value.id
49
+ if reflection.respond_to?(:polymorphic?) && reflection.polymorphic?
50
+ new_attrs[reflection.foreign_type] = value.class.base_class
51
+ end
52
+ else
53
+ new_attrs[reflection.foreign_key] = value
54
+ end
55
+ else
56
+ new_attrs[key] = value
57
+ end
58
+ new_attrs
59
+ end
60
+ end
61
+
62
+ def belongs_to(field, *args)
63
+ options = args.shift || {}
64
+
65
+ if String === options || Class === options # belongs_to :name, 'Class', options: 'here'
66
+ options = (args.last || {}).merge(:model => options.to_s)
67
+ end
68
+
69
+ unless Hash === options
70
+ raise ArgumentError, "bad belongs_to #{field} options format #{options.inspect}"
71
+ end
72
+
44
73
  options.delete(:default)
45
74
  options.delete(:required)
46
75
  opts = Ardm::ActiveRecord::Associations.convert_options(self, options)
47
76
  super field, opts
48
77
  assoc = reflect_on_association(field)
49
- property assoc.foreign_key, Ardm::Property::Integer
78
+ property assoc.foreign_key, assoc.klass.key.first.class
50
79
  nil
51
80
  end
52
81
 
@@ -57,8 +86,8 @@ module Ardm
57
86
  def has(count, name, *args)
58
87
  options = args.shift || {}
59
88
 
60
- if String === options # has n, :name, 'Class', options: 'here'
61
- options = (args.last || {}).merge(:model => options)
89
+ if String === options || Class === options # has n, :name, 'Class', options: 'here'
90
+ options = (args.last || {}).merge(:model => options.to_s)
62
91
  end
63
92
 
64
93
  unless Hash === options
@@ -2,6 +2,7 @@ require 'active_support/concern'
2
2
 
3
3
  require 'ardm/active_record/associations'
4
4
  require 'ardm/active_record/dirty'
5
+ require 'ardm/active_record/finalize'
5
6
  require 'ardm/active_record/hooks'
6
7
  require 'ardm/active_record/is'
7
8
  require 'ardm/active_record/inheritance'
@@ -35,6 +36,7 @@ module Ardm
35
36
  extend ActiveSupport::Concern
36
37
 
37
38
  include Ardm::ActiveRecord::Associations
39
+ include Ardm::ActiveRecord::Finalize
38
40
  include Ardm::ActiveRecord::Hooks
39
41
  include Ardm::ActiveRecord::Dirty
40
42
  include Ardm::ActiveRecord::Is
@@ -0,0 +1,5 @@
1
+ require 'active_record/relation'
2
+
3
+ module Ardm
4
+ Collection = ::ActiveRecord::Relation
5
+ end
@@ -0,0 +1 @@
1
+ ::DataMapper = Ardm::ActiveRecord::DataMapperConstantProxy
@@ -0,0 +1,24 @@
1
+ module Ardm
2
+ module ActiveRecord
3
+ module DataMapperConstantProxy
4
+
5
+ class << self
6
+ extend Forwardable
7
+ def_delegators 'Ardm::Record',
8
+ :finalize,
9
+ :repository,
10
+ :logger,
11
+ :logger=
12
+ end
13
+
14
+ module Resource
15
+ end
16
+
17
+ ObjectNotFoundError = ::ActiveRecord::RecordNotFound
18
+ SaveFailureError = ::ActiveRecord::RecordNotSaved
19
+
20
+ Property = Ardm::Property
21
+ Collection = Ardm::Collection
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,18 @@
1
+ module Ardm
2
+ module ActiveRecord
3
+ module Finalize
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ class_attribute :on_finalize
8
+ self.on_finalize = []
9
+ end
10
+
11
+ module ClassMethods
12
+ def finalize
13
+ on_finalize.each { |f| f.call }
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -3,27 +3,21 @@ module Ardm
3
3
  module PredicateBuilder
4
4
  class ArrayHandler # :nodoc:
5
5
  def call(attribute, value)
6
- values = value.map { |x| x.is_a?(::ActiveRecord::Base) ? x.id : x }
7
- ranges, values = values.partition { |v| v.is_a?(::Range) }
8
-
9
- values_predicate = if values.include?(nil)
10
- values = values.compact
11
-
12
- case values.length
13
- when 0
6
+ if value.include?(nil)
7
+ values = value.compact
8
+ if values.length == 0
14
9
  attribute.eq(nil)
15
- when 1
16
- attribute.eq(values.first).or(attribute.eq(nil))
17
10
  else
18
- attribute.in(values).or(attribute.eq(nil))
11
+ call(attribute, values).or(attribute.eq(nil))
19
12
  end
20
13
  else
21
- attribute.in(values)
22
- end
14
+ values = value.map { |x| x.is_a?(::ActiveRecord::Base) ? x.id : x }
15
+ ranges, values = values.partition { |v| v.is_a?(::Range) }
23
16
 
24
- array_predicates = ranges.map { |range| attribute.in(range) }
25
- array_predicates << values_predicate
26
- array_predicates.inject { |composite, predicate| composite.or(predicate) }
17
+ array_predicates = ranges.map { |range| attribute.in(range) }
18
+ array_predicates << attribute.in(values)
19
+ array_predicates.inject { |composite, predicate| composite.or(predicate) }
20
+ end
27
21
  end
28
22
  end
29
23
  end
@@ -40,7 +40,9 @@ module Ardm
40
40
 
41
41
  def build_from_hash(klass, attributes, default_table)
42
42
  queries = []
43
- klass = attributes.klass # HAX (this method is added to the attributes hash by expand_hash_conditions_for_aggregates
43
+ # HAX (this method is added to the attributes hash by expand_hash_conditions_for_aggregates
44
+ # Rails 3 calls build_form_hash with the first arg that is not the klass.
45
+ klass = attributes.klass
44
46
 
45
47
  attributes.each do |column, value|
46
48
  table = default_table
@@ -85,26 +87,51 @@ module Ardm
85
87
  end
86
88
 
87
89
  def expand(klass, table, column, value)
88
- queries = []
90
+ if klass && association = klass.reflect_on_association(column.to_sym)
91
+ expand_association(association, table, column, value)
92
+ else
93
+ [build(table[column], value)]
94
+ end
95
+ end
89
96
 
90
- # Find the foreign key when using queries such as:
91
- # Post.where(author: author)
92
- #
93
- # For polymorphic relationships, find the foreign key and type:
94
- # PriceEstimate.where(estimate_of: treasure)
95
- if klass && reflection = klass.reflect_on_association(column.to_sym)
96
- column = reflection.foreign_key
97
- if value.is_a?(Base) && reflection.respond_to?(:polymorphic?) && reflection.polymorphic?
98
- queries << build(table[reflection.foreign_type], value.class.base_class)
97
+ # Find the foreign key when using queries such as:
98
+ # Post.where(author: author)
99
+ #
100
+ # For polymorphic relationships, find the foreign key and type:
101
+ # PriceEstimate.where(estimate_of: treasure)
102
+ #
103
+ # Attempt to build a query that makes sense for an association name
104
+ # in the query, but if we can't generate a propery query, fallback
105
+ # to using the original key we received.
106
+ def expand_association(association, table, column, value)
107
+ queries = []
108
+ case association.macro
109
+ when :belongs_to
110
+ if association.polymorphic? && base_class = polymorphic_base_class_from_value(value)
111
+ queries << build(table[association.foreign_type], base_class)
99
112
  end
113
+ queries << build(table[association.foreign_key], value)
114
+ when :has_many, :has_one
115
+ table = Arel::Table.new(association.klass.table_name, table.engine)
116
+ queries << build(table[association.klass.primary_key], value)
117
+ else
118
+ queries << build(table[column], value)
100
119
  end
101
-
102
- #puts "expand(#{klass.name}, #{column.inspect}, #{value.inspect})"
103
-
104
- queries << build(table[column], value)
105
120
  queries
106
121
  end
107
122
 
123
+ def polymorphic_base_class_from_value(value)
124
+ case value
125
+ when Relation
126
+ value.klass.base_class
127
+ when Array
128
+ val = value.compact.first
129
+ val.class.base_class if val.is_a?(Base)
130
+ when Base
131
+ value.class.base_class
132
+ end
133
+ end
134
+
108
135
  def references(attributes)
109
136
  attributes.map do |key, value|
110
137
  if value.is_a?(Hash)