sequel 2.11.0 → 2.12.0

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.
Files changed (162) hide show
  1. data/CHANGELOG +168 -0
  2. data/README.rdoc +77 -95
  3. data/Rakefile +100 -80
  4. data/bin/sequel +2 -1
  5. data/doc/advanced_associations.rdoc +23 -32
  6. data/doc/cheat_sheet.rdoc +23 -40
  7. data/doc/dataset_filtering.rdoc +6 -6
  8. data/doc/prepared_statements.rdoc +22 -22
  9. data/doc/release_notes/2.12.0.txt +534 -0
  10. data/doc/schema.rdoc +3 -1
  11. data/doc/sharding.rdoc +8 -8
  12. data/doc/virtual_rows.rdoc +65 -0
  13. data/lib/sequel.rb +1 -1
  14. data/lib/{sequel_core → sequel}/adapters/ado.rb +3 -3
  15. data/lib/{sequel_core → sequel}/adapters/db2.rb +0 -0
  16. data/lib/{sequel_core → sequel}/adapters/dbi.rb +1 -1
  17. data/lib/{sequel_core → sequel}/adapters/do.rb +9 -5
  18. data/lib/{sequel_core → sequel}/adapters/do/mysql.rb +1 -1
  19. data/lib/{sequel_core → sequel}/adapters/do/postgres.rb +1 -1
  20. data/lib/{sequel_core → sequel}/adapters/do/sqlite.rb +1 -1
  21. data/lib/{sequel_core → sequel}/adapters/firebird.rb +84 -80
  22. data/lib/{sequel_core → sequel}/adapters/informix.rb +1 -1
  23. data/lib/{sequel_core → sequel}/adapters/jdbc.rb +21 -14
  24. data/lib/{sequel_core → sequel}/adapters/jdbc/h2.rb +14 -13
  25. data/lib/{sequel_core → sequel}/adapters/jdbc/mysql.rb +1 -1
  26. data/lib/{sequel_core → sequel}/adapters/jdbc/oracle.rb +1 -1
  27. data/lib/{sequel_core → sequel}/adapters/jdbc/postgresql.rb +1 -1
  28. data/lib/{sequel_core → sequel}/adapters/jdbc/sqlite.rb +1 -1
  29. data/lib/{sequel_core → sequel}/adapters/mysql.rb +60 -39
  30. data/lib/{sequel_core → sequel}/adapters/odbc.rb +8 -4
  31. data/lib/{sequel_core → sequel}/adapters/openbase.rb +0 -0
  32. data/lib/{sequel_core → sequel}/adapters/oracle.rb +38 -7
  33. data/lib/{sequel_core → sequel}/adapters/postgres.rb +24 -24
  34. data/lib/{sequel_core → sequel}/adapters/shared/mssql.rb +5 -5
  35. data/lib/{sequel_core → sequel}/adapters/shared/mysql.rb +126 -71
  36. data/lib/{sequel_core → sequel}/adapters/shared/oracle.rb +7 -10
  37. data/lib/{sequel_core → sequel}/adapters/shared/postgres.rb +159 -125
  38. data/lib/{sequel_core → sequel}/adapters/shared/progress.rb +1 -2
  39. data/lib/{sequel_core → sequel}/adapters/shared/sqlite.rb +72 -67
  40. data/lib/{sequel_core → sequel}/adapters/sqlite.rb +11 -7
  41. data/lib/{sequel_core → sequel}/adapters/utils/date_format.rb +0 -0
  42. data/lib/{sequel_core → sequel}/adapters/utils/stored_procedures.rb +0 -0
  43. data/lib/{sequel_core → sequel}/adapters/utils/unsupported.rb +19 -0
  44. data/lib/{sequel_core → sequel}/connection_pool.rb +7 -5
  45. data/lib/sequel/core.rb +221 -0
  46. data/lib/{sequel_core → sequel}/core_sql.rb +91 -49
  47. data/lib/{sequel_core → sequel}/database.rb +264 -149
  48. data/lib/{sequel_core/schema/generator.rb → sequel/database/schema_generator.rb} +6 -2
  49. data/lib/{sequel_core/database/schema.rb → sequel/database/schema_methods.rb} +12 -12
  50. data/lib/sequel/database/schema_sql.rb +224 -0
  51. data/lib/{sequel_core → sequel}/dataset.rb +78 -236
  52. data/lib/{sequel_core → sequel}/dataset/convenience.rb +99 -61
  53. data/lib/{sequel_core/object_graph.rb → sequel/dataset/graph.rb} +16 -14
  54. data/lib/{sequel_core → sequel}/dataset/prepared_statements.rb +1 -1
  55. data/lib/{sequel_core → sequel}/dataset/sql.rb +150 -99
  56. data/lib/sequel/deprecated.rb +593 -0
  57. data/lib/sequel/deprecated_migration.rb +91 -0
  58. data/lib/sequel/exceptions.rb +48 -0
  59. data/lib/sequel/extensions/blank.rb +42 -0
  60. data/lib/{sequel_model → sequel/extensions}/inflector.rb +8 -1
  61. data/lib/{sequel_core → sequel/extensions}/migration.rb +1 -1
  62. data/lib/{sequel_core/dataset → sequel/extensions}/pagination.rb +0 -0
  63. data/lib/{sequel_core → sequel/extensions}/pretty_table.rb +7 -0
  64. data/lib/{sequel_core/dataset → sequel/extensions}/query.rb +7 -0
  65. data/lib/sequel/extensions/string_date_time.rb +47 -0
  66. data/lib/sequel/metaprogramming.rb +43 -0
  67. data/lib/sequel/model.rb +110 -0
  68. data/lib/sequel/model/associations.rb +1300 -0
  69. data/lib/sequel/model/base.rb +937 -0
  70. data/lib/sequel/model/deprecated.rb +204 -0
  71. data/lib/sequel/model/deprecated_hooks.rb +103 -0
  72. data/lib/sequel/model/deprecated_inflector.rb +335 -0
  73. data/lib/sequel/model/deprecated_validations.rb +388 -0
  74. data/lib/sequel/model/errors.rb +39 -0
  75. data/lib/{sequel_model → sequel/model}/exceptions.rb +4 -4
  76. data/lib/sequel/model/inflections.rb +208 -0
  77. data/lib/sequel/model/plugins.rb +76 -0
  78. data/lib/sequel/plugins/caching.rb +122 -0
  79. data/lib/sequel/plugins/hook_class_methods.rb +122 -0
  80. data/lib/sequel/plugins/schema.rb +53 -0
  81. data/lib/sequel/plugins/serialization.rb +117 -0
  82. data/lib/sequel/plugins/single_table_inheritance.rb +63 -0
  83. data/lib/sequel/plugins/validation_class_methods.rb +384 -0
  84. data/lib/sequel/plugins/validation_helpers.rb +150 -0
  85. data/lib/{sequel_core → sequel}/sql.rb +125 -190
  86. data/lib/{sequel_core → sequel}/version.rb +2 -1
  87. data/lib/sequel_core.rb +1 -172
  88. data/lib/sequel_model.rb +1 -91
  89. data/spec/adapters/firebird_spec.rb +5 -5
  90. data/spec/adapters/informix_spec.rb +1 -1
  91. data/spec/adapters/mysql_spec.rb +128 -42
  92. data/spec/adapters/oracle_spec.rb +47 -19
  93. data/spec/adapters/postgres_spec.rb +64 -52
  94. data/spec/adapters/spec_helper.rb +1 -1
  95. data/spec/adapters/sqlite_spec.rb +12 -17
  96. data/spec/{sequel_core → core}/connection_pool_spec.rb +10 -10
  97. data/spec/{sequel_core → core}/core_ext_spec.rb +19 -19
  98. data/spec/{sequel_core → core}/core_sql_spec.rb +68 -71
  99. data/spec/{sequel_core → core}/database_spec.rb +135 -99
  100. data/spec/{sequel_core → core}/dataset_spec.rb +398 -242
  101. data/spec/{sequel_core → core}/expression_filters_spec.rb +13 -13
  102. data/spec/core/migration_spec.rb +263 -0
  103. data/spec/{sequel_core → core}/object_graph_spec.rb +10 -10
  104. data/spec/{sequel_core → core}/pretty_table_spec.rb +2 -2
  105. data/spec/{sequel_core → core}/schema_generator_spec.rb +0 -0
  106. data/spec/{sequel_core → core}/schema_spec.rb +8 -10
  107. data/spec/{sequel_core → core}/spec_helper.rb +29 -2
  108. data/spec/{sequel_core → core}/version_spec.rb +0 -0
  109. data/spec/extensions/blank_spec.rb +67 -0
  110. data/spec/extensions/caching_spec.rb +201 -0
  111. data/spec/{sequel_model/hooks_spec.rb → extensions/hook_class_methods_spec.rb} +8 -23
  112. data/spec/{sequel_model → extensions}/inflector_spec.rb +3 -0
  113. data/spec/{sequel_core → extensions}/migration_spec.rb +4 -4
  114. data/spec/extensions/pagination_spec.rb +99 -0
  115. data/spec/extensions/pretty_table_spec.rb +91 -0
  116. data/spec/extensions/query_spec.rb +85 -0
  117. data/spec/{sequel_model → extensions}/schema_spec.rb +22 -1
  118. data/spec/extensions/serialization_spec.rb +109 -0
  119. data/spec/extensions/single_table_inheritance_spec.rb +53 -0
  120. data/spec/{sequel_model → extensions}/spec_helper.rb +13 -4
  121. data/spec/extensions/string_date_time_spec.rb +93 -0
  122. data/spec/{sequel_model/validations_spec.rb → extensions/validation_class_methods_spec.rb} +15 -103
  123. data/spec/extensions/validation_helpers_spec.rb +291 -0
  124. data/spec/integration/dataset_test.rb +31 -0
  125. data/spec/integration/eager_loader_test.rb +17 -30
  126. data/spec/integration/schema_test.rb +8 -5
  127. data/spec/integration/spec_helper.rb +17 -0
  128. data/spec/integration/transaction_test.rb +68 -0
  129. data/spec/{sequel_model → model}/association_reflection_spec.rb +0 -0
  130. data/spec/{sequel_model → model}/associations_spec.rb +23 -10
  131. data/spec/{sequel_model → model}/base_spec.rb +29 -20
  132. data/spec/{sequel_model → model}/caching_spec.rb +16 -14
  133. data/spec/{sequel_model → model}/dataset_methods_spec.rb +0 -0
  134. data/spec/{sequel_model → model}/eager_loading_spec.rb +8 -8
  135. data/spec/model/hooks_spec.rb +472 -0
  136. data/spec/model/inflector_spec.rb +126 -0
  137. data/spec/{sequel_model → model}/model_spec.rb +25 -20
  138. data/spec/model/plugins_spec.rb +142 -0
  139. data/spec/{sequel_model → model}/record_spec.rb +121 -62
  140. data/spec/model/schema_spec.rb +92 -0
  141. data/spec/model/spec_helper.rb +124 -0
  142. data/spec/model/validations_spec.rb +1080 -0
  143. metadata +136 -107
  144. data/lib/sequel_core/core_ext.rb +0 -217
  145. data/lib/sequel_core/dataset/callback.rb +0 -13
  146. data/lib/sequel_core/dataset/schema.rb +0 -15
  147. data/lib/sequel_core/deprecated.rb +0 -26
  148. data/lib/sequel_core/exceptions.rb +0 -44
  149. data/lib/sequel_core/schema.rb +0 -2
  150. data/lib/sequel_core/schema/sql.rb +0 -325
  151. data/lib/sequel_model/association_reflection.rb +0 -267
  152. data/lib/sequel_model/associations.rb +0 -499
  153. data/lib/sequel_model/base.rb +0 -539
  154. data/lib/sequel_model/caching.rb +0 -82
  155. data/lib/sequel_model/dataset_methods.rb +0 -26
  156. data/lib/sequel_model/eager_loading.rb +0 -370
  157. data/lib/sequel_model/hooks.rb +0 -101
  158. data/lib/sequel_model/plugins.rb +0 -62
  159. data/lib/sequel_model/record.rb +0 -568
  160. data/lib/sequel_model/schema.rb +0 -49
  161. data/lib/sequel_model/validations.rb +0 -429
  162. data/spec/sequel_model/plugins_spec.rb +0 -80
@@ -1,499 +0,0 @@
1
- # Associations are used in order to specify relationships between model classes
2
- # that reflect relations between tables in the database using foreign keys.
3
- #
4
- # Each kind of association adds a number of methods to the model class which
5
- # are specialized according to the association type and optional parameters
6
- # given in the definition. Example:
7
- #
8
- # class Project < Sequel::Model
9
- # many_to_one :portfolio
10
- # one_to_many :milestones
11
- # end
12
- #
13
- # The project class now has the following instance methods:
14
- # * portfolio - Returns the associated portfolio.
15
- # * portfolio=(obj) - Sets the associated portfolio to the object,
16
- # but the change is not persisted until you save the record.
17
- # * portfolio_dataset - Returns a dataset that would return the associated
18
- # portfolio, only useful in fairly specific circumstances.
19
- # * milestones - Returns an array of associated milestones
20
- # * add_milestone(obj) - Associates the passed milestone with this object.
21
- # * remove_milestone(obj) - Removes the association with the passed milestone.
22
- # * remove_all_milestones - Removes associations with all associated milestones.
23
- # * milestones_dataset - Returns a dataset that would return the associated
24
- # milestones, allowing for further filtering/limiting/etc.
25
- #
26
- # If you want to override the behavior of the add_/remove_/remove_all_ methods,
27
- # there are private instance methods created that a prepended with an
28
- # underscore (e.g. _add_milestone). The private instance methods can be
29
- # easily overridden, but you shouldn't override the public instance methods,
30
- # as they deal with how associations are cached.
31
- #
32
- # By default the classes for the associations are inferred from the association
33
- # name, so for example the Project#portfolio will return an instance of
34
- # Portfolio, and Project#milestones will return an array of Milestone
35
- # instances, in similar fashion to how ActiveRecord infers class names.
36
- #
37
- # Association definitions are also reflected by the class, e.g.:
38
- #
39
- # Project.associations
40
- # => [:portfolio, :milestones]
41
- # Project.association_reflection(:portfolio)
42
- # => {:type => :many_to_one, :name => :portfolio, :class_name => "Portfolio"}
43
- #
44
- # Associations can be defined by either using the associate method, or by
45
- # calling one of the three methods: many_to_one, one_to_many, many_to_many.
46
- # Sequel::Model also provides aliases for these methods that conform to
47
- # ActiveRecord conventions: belongs_to, has_many, has_and_belongs_to_many.
48
- # For example, the following three statements are equivalent:
49
- #
50
- # associate :one_to_many, :attributes
51
- # one_to_many :attributes
52
- # has_many :attributes
53
- module Sequel::Model::Associations
54
- # This module contains methods added to all association datasets
55
- module DatasetMethods
56
- # The model object that created the association dataset
57
- attr_accessor :model_object
58
-
59
- # The association reflection related to the association dataset
60
- attr_accessor :association_reflection
61
- end
62
-
63
- # Array of all association reflections for this model class
64
- def all_association_reflections
65
- association_reflections.values
66
- end
67
-
68
- # Associates a related model with the current model. The following types are
69
- # supported:
70
- #
71
- # * :many_to_one - Foreign key in current model's table points to
72
- # associated model's primary key. Each associated model object can
73
- # be associated with more than one current model objects. Each current
74
- # model object can be associated with only one associated model object.
75
- # Similar to ActiveRecord's belongs_to.
76
- # * :one_to_many - Foreign key in associated model's table points to this
77
- # model's primary key. Each current model object can be associated with
78
- # more than one associated model objects. Each associated model object
79
- # can be associated with only one current model object.
80
- # Similar to ActiveRecord's has_many.
81
- # * :many_to_many - A join table is used that has a foreign key that points
82
- # to this model's primary key and a foreign key that points to the
83
- # associated model's primary key. Each current model object can be
84
- # associated with many associated model objects, and each associated
85
- # model object can be associated with many current model objects.
86
- # Similar to ActiveRecord's has_and_belongs_to_many.
87
- #
88
- # A one to one relationship can be set up with a many_to_one association
89
- # on the table with the foreign key, and a one_to_many association with the
90
- # :one_to_one option specified on the table without the foreign key. The
91
- # two associations will operate similarly, except that the many_to_one
92
- # association setter doesn't update the database until you call save manually.
93
- #
94
- # The following options can be supplied:
95
- # * *ALL types*:
96
- # - :after_add - Symbol, Proc, or array of both/either specifying a callback to call
97
- # after a new item is added to the association.
98
- # - :after_load - Symbol, Proc, or array of both/either specifying a callback to call
99
- # after the associated record(s) have been retrieved from the database. Not called
100
- # when eager loading via eager_graph, but called when eager loading via eager.
101
- # - :after_remove - Symbol, Proc, or array of both/either specifying a callback to call
102
- # after an item is removed from the association.
103
- # - :allow_eager - If set to false, you cannot load the association eagerly
104
- # via eager or eager_graph
105
- # - :before_add - Symbol, Proc, or array of both/either specifying a callback to call
106
- # before a new item is added to the association.
107
- # - :before_remove - Symbol, Proc, or array of both/either specifying a callback to call
108
- # before an item is removed from the association.
109
- # - :class - The associated class or its name. If not
110
- # given, uses the association's name, which is camelized (and
111
- # singularized unless the type is :many_to_one)
112
- # - :clone - Merge the current options and block into the options and block used in defining
113
- # the given association. Can be used to DRY up a bunch of similar associations that
114
- # all share the same options such as :class and :key, while changing the order and block used.
115
- # - :conditions - The conditions to use to filter the association, can be any argument passed to filter.
116
- # - :dataset - A proc that is instance_evaled to get the base dataset
117
- # to use for the _dataset method (before the other options are applied).
118
- # - :eager - The associations to eagerly load via EagerLoading#eager when loading the associated object(s).
119
- # For many_to_one associations, this is ignored unless this association is
120
- # being eagerly loaded, as it doesn't save queries unless multiple objects
121
- # can be loaded at once.
122
- # - :eager_block - If given, use the block instead of the default block when
123
- # eagerly loading. To not use a block when eager loading (when one is used normally),
124
- # set to nil.
125
- # - :eager_graph - The associations to eagerly load via EagerLoading#eager_graph when loading the associated object(s).
126
- # For many_to_one associations, this is ignored unless this association is
127
- # being eagerly loaded, as it doesn't save queries unless multiple objects
128
- # can be loaded at once.
129
- # - :eager_grapher - A proc to use to implement eager loading via eager graph, overriding the default.
130
- # Takes three arguments, a dataset, an alias to use for the table to graph for this association,
131
- # and the alias that was used for the current table (since you can cascade associations),
132
- # Should return a copy of the dataset with the association graphed into it.
133
- # - :eager_loader - A proc to use to implement eager loading, overriding the default. Takes three arguments,
134
- # a key hash (used solely to enhance performance), an array of records,
135
- # and a hash of dependent associations. The associated records should
136
- # be queried from the database and the associations cache for each
137
- # record should be populated for this to work correctly.
138
- # - :extend - A module or array of modules to extend the dataset with.
139
- # - :graph_block - The block to pass to join_table when eagerly loading
140
- # the association via eager_graph.
141
- # - :graph_conditions - The additional conditions to use on the SQL join when eagerly loading
142
- # the association via eager_graph. Should be a hash or an array of all two pairs. If not
143
- # specified, the :conditions option is used if it is a hash or array of all two pairs.
144
- # - :graph_join_type - The type of SQL join to use when eagerly loading the association via
145
- # eager_graph. Defaults to :left_outer.
146
- # - :graph_only_conditions - The conditions to use on the SQL join when eagerly loading
147
- # the association via eager_graph, instead of the default conditions specified by the
148
- # foreign/primary keys. This option causes the :graph_conditions option to be ignored.
149
- # - :graph_select - A column or array of columns to select from the associated table
150
- # when eagerly loading the association via eager_graph. Defaults to all
151
- # columns in the associated table.
152
- # - :limit - Limit the number of records to the provided value. Use
153
- # an array with two arguments for the value to specify a limit and offset.
154
- # - :order - the column(s) by which to order the association dataset. Can be a
155
- # singular column or an array.
156
- # - :order_eager_graph - Whether to add the order to the dataset's order when graphing
157
- # via eager graph. Defaults to true, so set to false to disable.
158
- # - :read_only - Do not add a setter method (for many_to_one or one_to_many with :one_to_one),
159
- # or add_/remove_/remove_all_ methods (for one_to_many, many_to_many)
160
- # - :reciprocal - the symbol name of the reciprocal association,
161
- # if it exists. By default, sequel will try to determine it by looking at the
162
- # associated model's assocations for a association that matches
163
- # the current association's key(s). Set to nil to not use a reciprocal.
164
- # - :select - the attributes to select. Defaults to the associated class's
165
- # table_name.*, which means it doesn't include the attributes from the
166
- # join table in a many_to_many association. If you want to include the join table attributes, you can
167
- # use this option, but beware that the join table attributes can clash with
168
- # attributes from the model table, so you should alias any attributes that have
169
- # the same name in both the join table and the associated table.
170
- # * :many_to_one:
171
- # - :key - foreign_key in current model's table that references
172
- # associated model's primary key, as a symbol. Defaults to :"#{name}_id".
173
- # - :primary_key - column in the associated table that :key option references, as a symbol.
174
- # Defaults to the primary key of the associated table.
175
- # * :one_to_many:
176
- # - :key - foreign key in associated model's table that references
177
- # current model's primary key, as a symbol. Defaults to
178
- # :"#{self.name.underscore}_id".
179
- # - :one_to_one: Create a getter and setter similar to those of many_to_one
180
- # associations. The getter returns a singular matching record, or raises an
181
- # error if multiple records match. The setter updates the record given and removes
182
- # associations with all other records. When this option is used, the other
183
- # association methods usually added are either removed or made private,
184
- # so using this is similar to using many_to_one, in terms of the methods
185
- # it adds, the main difference is that the foreign key is in the associated
186
- # table instead of the current table.
187
- # - :primary_key - column in the current table that :key option references, as a symbol.
188
- # Defaults to primary key of the current table.
189
- # * :many_to_many:
190
- # - :graph_join_table_block - The block to pass to join_table for
191
- # the join table when eagerly loading the association via eager_graph.
192
- # - :graph_join_table_conditions - The additional conditions to use on the SQL join for
193
- # the join table when eagerly loading the association via eager_graph. Should be a hash
194
- # or an array of all two pairs.
195
- # - :graph_join_type - The type of SQL join to use for the join table when eagerly
196
- # loading the association via eager_graph. Defaults to the :graph_join_type option or
197
- # :left_outer.
198
- # - :graph_join_table_only_conditions - The conditions to use on the SQL join for the join
199
- # table when eagerly loading the association via eager_graph, instead of the default
200
- # conditions specified by the foreign/primary keys. This option causes the
201
- # :graph_join_table_conditions option to be ignored.
202
- # - :join_table - name of table that includes the foreign keys to both
203
- # the current model and the associated model, as a symbol. Defaults to the name
204
- # of current model and name of associated model, pluralized,
205
- # underscored, sorted, and joined with '_'.
206
- # - :left_key - foreign key in join table that points to current model's
207
- # primary key, as a symbol. Defaults to :"#{self.name.underscore}_id".
208
- # - :left_primary_key - column in current table that :left_key points to, as a symbol.
209
- # Defaults to primary key of current table.
210
- # - :right_key - foreign key in join table that points to associated
211
- # model's primary key, as a symbol. Defaults to Defaults to :"#{name.to_s.singularize}_id".
212
- # - :right_primary_key - column in associated table that :right_key points to, as a symbol.
213
- # Defaults to primary key of the associated table.
214
- # - :uniq - Adds a after_load callback that makes the array of objects unique.
215
- def associate(type, name, opts = {}, &block)
216
- raise(Error, 'invalid association type') unless assoc_class = ASSOCIATION_TYPES[type]
217
- raise(Error, 'Model.associate name argument must be a symbol') unless Symbol === name
218
-
219
- # merge early so we don't modify opts
220
- orig_opts = opts.dup
221
- orig_opts = association_reflection(opts[:clone])[:orig_opts].merge(orig_opts) if opts[:clone]
222
- opts = orig_opts.merge(:type => type, :name => name, :cache => true, :model => self)
223
- opts[:block] = block if block
224
- opts = assoc_class.new.merge!(opts)
225
- opts[:eager_block] = block unless opts.include?(:eager_block)
226
- opts[:graph_join_type] ||= :left_outer
227
- opts[:order_eager_graph] = true unless opts.include?(:order_eager_graph)
228
- conds = opts[:conditions]
229
- opts[:graph_conditions] = conds if !opts.include?(:graph_conditions) and (conds.is_a?(Hash) or (conds.is_a?(Array) and conds.all_two_pairs?))
230
- opts[:graph_conditions] = opts[:graph_conditions] ? opts[:graph_conditions].to_a : []
231
- opts[:graph_select] = Array(opts[:graph_select]) if opts[:graph_select]
232
- [:before_add, :before_remove, :after_add, :after_remove, :after_load, :extend].each do |cb_type|
233
- opts[cb_type] = Array(opts[cb_type])
234
- end
235
-
236
- # find class
237
- case opts[:class]
238
- when String, Symbol
239
- # Delete :class to allow late binding
240
- opts[:class_name] ||= opts.delete(:class).to_s
241
- when Class
242
- opts[:class_name] ||= opts[:class].name
243
- end
244
-
245
- send(:"def_#{type}", opts)
246
-
247
- orig_opts.delete(:clone)
248
- orig_opts.merge!(:class_name=>opts[:class_name], :class=>opts[:class], :block=>block)
249
- opts[:orig_opts] = orig_opts
250
- # don't add to association_reflections until we are sure there are no errors
251
- association_reflections[name] = opts
252
- end
253
-
254
- # The association reflection hash for the association of the given name.
255
- def association_reflection(name)
256
- association_reflections[name]
257
- end
258
-
259
- # Array of association name symbols
260
- def associations
261
- association_reflections.keys
262
- end
263
-
264
- # Shortcut for adding a one_to_many association, see associate
265
- def one_to_many(*args, &block)
266
- associate(:one_to_many, *args, &block)
267
- end
268
- alias_method :has_many, :one_to_many
269
-
270
- # Shortcut for adding a many_to_one association, see associate
271
- def many_to_one(*args, &block)
272
- associate(:many_to_one, *args, &block)
273
- end
274
- alias_method :belongs_to, :many_to_one
275
-
276
- # Shortcut for adding a many_to_many association, see associate
277
- def many_to_many(*args, &block)
278
- associate(:many_to_many, *args, &block)
279
- end
280
- alias_method :has_and_belongs_to_many, :many_to_many
281
-
282
- private
283
-
284
- # Add a method to the association module
285
- def association_module_def(name, &block)
286
- overridable_methods_module.class_def(name, &block)
287
- end
288
-
289
- # Add a method to the association module
290
- def association_module_private_def(name, &block)
291
- association_module_def(name, &block)
292
- overridable_methods_module.send(:private, name)
293
- end
294
-
295
- # Add the add_ instance method
296
- def def_add_method(opts)
297
- association_module_def(opts.add_method){|o| add_associated_object(opts, o)}
298
- end
299
-
300
- # Adds association methods to the model for *_to_many associations.
301
- def def_association_dataset_methods(opts)
302
- # If a block is given, define a helper method for it, because it takes
303
- # an argument. This is unnecessary in Ruby 1.9, as that has instance_exec.
304
- association_module_private_def(opts.dataset_helper_method, &opts[:block]) if opts[:block]
305
- association_module_private_def(opts._dataset_method, &opts[:dataset])
306
- association_module_def(opts.dataset_method){_dataset(opts)}
307
- association_module_def(opts.association_method){|*reload| load_associated_objects(opts, reload[0])}
308
- end
309
-
310
- # Adds many_to_many association instance methods
311
- def def_many_to_many(opts)
312
- name = opts[:name]
313
- model = self
314
- left = (opts[:left_key] ||= opts.default_left_key)
315
- right = (opts[:right_key] ||= opts.default_right_key)
316
- left_pk = (opts[:left_primary_key] ||= self.primary_key)
317
- opts[:class_name] ||= name.to_s.singularize.camelize
318
- join_table = (opts[:join_table] ||= opts.default_join_table)
319
- left_key_alias = opts[:left_key_alias] ||= :x_foreign_key_x
320
- left_key_select = opts[:left_key_select] ||= left.qualify(join_table).as(opts[:left_key_alias])
321
- graph_jt_conds = opts[:graph_join_table_conditions] = opts[:graph_join_table_conditions] ? opts[:graph_join_table_conditions].to_a : []
322
- opts[:graph_join_table_join_type] ||= opts[:graph_join_type]
323
- opts[:after_load].unshift(:array_uniq!) if opts[:uniq]
324
- opts[:dataset] ||= proc{opts.associated_class.inner_join(join_table, [[right, opts.right_primary_key], [left, send(left_pk)]])}
325
- database = db
326
-
327
- opts[:eager_loader] ||= proc do |key_hash, records, associations|
328
- h = key_hash[left_pk]
329
- records.each{|object| object.associations[name] = []}
330
- model.eager_loading_dataset(opts, opts.associated_class.inner_join(join_table, [[right, opts.right_primary_key], [left, h.keys]]), Array(opts.select) + Array(left_key_select), associations).all do |assoc_record|
331
- next unless objects = h[assoc_record.values.delete(left_key_alias)]
332
- objects.each{|object| object.associations[name].push(assoc_record)}
333
- end
334
- end
335
-
336
- join_type = opts[:graph_join_type]
337
- select = opts[:graph_select]
338
- use_only_conditions = opts.include?(:graph_only_conditions)
339
- only_conditions = opts[:graph_only_conditions]
340
- conditions = opts[:graph_conditions]
341
- graph_block = opts[:graph_block]
342
- use_jt_only_conditions = opts.include?(:graph_join_table_only_conditions)
343
- jt_only_conditions = opts[:graph_join_table_only_conditions]
344
- jt_join_type = opts[:graph_join_table_join_type]
345
- jt_graph_block = opts[:graph_join_table_block]
346
- opts[:eager_grapher] ||= proc do |ds, assoc_alias, table_alias|
347
- ds = ds.graph(join_table, use_jt_only_conditions ? jt_only_conditions : [[left, left_pk]] + graph_jt_conds, :select=>false, :table_alias=>ds.send(:eager_unique_table_alias, ds, join_table), :join_type=>jt_join_type, :implicit_qualifier=>table_alias, &jt_graph_block)
348
- ds.graph(opts.associated_class, use_only_conditions ? only_conditions : [[opts.right_primary_key, right]] + conditions, :select=>select, :table_alias=>assoc_alias, :join_type=>join_type, &graph_block)
349
- end
350
-
351
- def_association_dataset_methods(opts)
352
-
353
- return if opts[:read_only]
354
-
355
- association_module_private_def(opts._add_method) do |o|
356
- database.dataset.from(join_table).insert(left=>send(left_pk), right=>o.send(opts.right_primary_key))
357
- end
358
- association_module_private_def(opts._remove_method) do |o|
359
- database.dataset.from(join_table).filter([[left, send(left_pk)], [right, o.send(opts.right_primary_key)]]).delete
360
- end
361
- association_module_private_def(opts._remove_all_method) do
362
- database.dataset.from(join_table).filter(left=>send(left_pk)).delete
363
- end
364
-
365
- def_add_method(opts)
366
- def_remove_methods(opts)
367
- end
368
-
369
- # Adds many_to_one association instance methods
370
- def def_many_to_one(opts)
371
- name = opts[:name]
372
- model = self
373
- opts[:key] = opts.default_key unless opts.include?(:key)
374
- key = opts[:key]
375
- opts[:class_name] ||= name.to_s.camelize
376
- opts[:dataset] ||= proc do
377
- klass = opts.associated_class
378
- klass.filter(opts.primary_key.qualify(klass.table_name)=>send(key))
379
- end
380
- opts[:eager_loader] ||= proc do |key_hash, records, associations|
381
- h = key_hash[key]
382
- keys = h.keys
383
- # Default the cached association to nil, so any object that doesn't have it
384
- # populated will have cached the negative lookup.
385
- records.each{|object| object.associations[name] = nil}
386
- # Skip eager loading if no objects have a foreign key for this association
387
- unless keys.empty?
388
- klass = opts.associated_class
389
- model.eager_loading_dataset(opts, klass.filter(opts.primary_key.qualify(klass.table_name)=>keys), opts.select, associations).all do |assoc_record|
390
- next unless objects = h[assoc_record.send(opts.primary_key)]
391
- objects.each{|object| object.associations[name] = assoc_record}
392
- end
393
- end
394
- end
395
-
396
- join_type = opts[:graph_join_type]
397
- select = opts[:graph_select]
398
- use_only_conditions = opts.include?(:graph_only_conditions)
399
- only_conditions = opts[:graph_only_conditions]
400
- conditions = opts[:graph_conditions]
401
- graph_block = opts[:graph_block]
402
- opts[:eager_grapher] ||= proc do |ds, assoc_alias, table_alias|
403
- ds.graph(opts.associated_class, use_only_conditions ? only_conditions : [[opts.primary_key, key]] + conditions, :select=>select, :table_alias=>assoc_alias, :join_type=>join_type, :implicit_qualifier=>table_alias, &graph_block)
404
- end
405
-
406
- def_association_dataset_methods(opts)
407
-
408
- return if opts[:read_only]
409
-
410
- association_module_private_def(opts._setter_method){|o| send(:"#{key}=", (o.send(opts.primary_key) if o))}
411
- association_module_def(opts.setter_method){|o| set_associated_object(opts, o)}
412
- end
413
-
414
- # Adds one_to_many association instance methods
415
- def def_one_to_many(opts)
416
- name = opts[:name]
417
- model = self
418
- key = (opts[:key] ||= opts.default_key)
419
- primary_key = (opts[:primary_key] ||= self.primary_key)
420
- opts[:class_name] ||= name.to_s.singularize.camelize
421
- opts[:dataset] ||= proc do
422
- klass = opts.associated_class
423
- klass.filter(key.qualify(klass.table_name) => send(primary_key))
424
- end
425
- opts[:eager_loader] ||= proc do |key_hash, records, associations|
426
- h = key_hash[primary_key]
427
- records.each{|object| object.associations[name] = []}
428
- reciprocal = opts.reciprocal
429
- klass = opts.associated_class
430
- model.eager_loading_dataset(opts, klass.filter(key.qualify(klass.table_name)=>h.keys), opts.select, associations).all do |assoc_record|
431
- next unless objects = h[assoc_record[key]]
432
- objects.each do |object|
433
- object.associations[name].push(assoc_record)
434
- assoc_record.associations[reciprocal] = object if reciprocal
435
- end
436
- end
437
- end
438
-
439
- join_type = opts[:graph_join_type]
440
- select = opts[:graph_select]
441
- use_only_conditions = opts.include?(:graph_only_conditions)
442
- only_conditions = opts[:graph_only_conditions]
443
- conditions = opts[:graph_conditions]
444
- graph_block = opts[:graph_block]
445
- opts[:eager_grapher] ||= proc do |ds, assoc_alias, table_alias|
446
- ds = ds.graph(opts.associated_class, use_only_conditions ? only_conditions : [[key, primary_key]] + conditions, :select=>select, :table_alias=>assoc_alias, :join_type=>join_type, :implicit_qualifier=>table_alias, &graph_block)
447
- # We only load reciprocals for one_to_many associations, as other reciprocals don't make sense
448
- ds.opts[:eager_graph][:reciprocals][assoc_alias] = opts.reciprocal
449
- ds
450
- end
451
-
452
- def_association_dataset_methods(opts)
453
-
454
- unless opts[:read_only]
455
- association_module_private_def(opts._add_method) do |o|
456
- o.send(:"#{key}=", send(primary_key))
457
- o.save || raise(Sequel::Error, "invalid associated object, cannot save")
458
- end
459
- def_add_method(opts)
460
-
461
- unless opts[:one_to_one]
462
- association_module_private_def(opts._remove_method) do |o|
463
- o.send(:"#{key}=", nil)
464
- o.save || raise(Sequel::Error, "invalid associated object, cannot save")
465
- end
466
- association_module_private_def(opts._remove_all_method) do
467
- opts.associated_class.filter(key=>send(primary_key)).update(key=>nil)
468
- end
469
- def_remove_methods(opts)
470
- end
471
- end
472
- if opts[:one_to_one]
473
- overridable_methods_module.send(:private, opts.association_method, opts.dataset_method)
474
- n = name.to_s.singularize.to_sym
475
- raise(Sequel::Error, "one_to_many association names should still be plural even when using the :one_to_one option") if n == name
476
- association_module_def(n) do |*o|
477
- objs = send(name, *o)
478
- raise(Sequel::Error, "multiple values found for a one-to-one relationship") if objs.length > 1
479
- objs.first
480
- end
481
- unless opts[:read_only]
482
- overridable_methods_module.send(:private, opts.add_method)
483
- association_module_def(:"#{n}=") do |o|
484
- klass = opts.associated_class
485
- model.db.transaction do
486
- send(opts.add_method, o)
487
- klass.filter(Sequel::SQL::BooleanExpression.new(:AND, {key=>send(primary_key)}, ~{klass.primary_key=>o.pk}.sql_expr)).update(key=>nil)
488
- end
489
- end
490
- end
491
- end
492
- end
493
-
494
- # Add the remove_ and remove_all instance methods
495
- def def_remove_methods(opts)
496
- association_module_def(opts.remove_method){|o| remove_associated_object(opts, o)}
497
- association_module_def(opts.remove_all_method){remove_all_associated_objects(opts)}
498
- end
499
- end