sequel 4.41.0 → 4.42.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (256) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +98 -0
  3. data/README.rdoc +23 -10
  4. data/doc/active_record.rdoc +4 -4
  5. data/doc/advanced_associations.rdoc +2 -2
  6. data/doc/association_basics.rdoc +5 -2
  7. data/doc/cheat_sheet.rdoc +3 -3
  8. data/doc/core_extensions.rdoc +2 -2
  9. data/doc/dataset_basics.rdoc +4 -4
  10. data/doc/dataset_filtering.rdoc +1 -1
  11. data/doc/migration.rdoc +19 -1
  12. data/doc/prepared_statements.rdoc +2 -2
  13. data/doc/release_notes/4.42.0.txt +221 -0
  14. data/doc/testing.rdoc +3 -1
  15. data/lib/sequel/adapters/ado/access.rb +0 -1
  16. data/lib/sequel/adapters/ado/mssql.rb +0 -1
  17. data/lib/sequel/adapters/do/mysql.rb +0 -1
  18. data/lib/sequel/adapters/do/postgres.rb +0 -1
  19. data/lib/sequel/adapters/do/sqlite3.rb +0 -1
  20. data/lib/sequel/adapters/ibmdb.rb +21 -25
  21. data/lib/sequel/adapters/jdbc.rb +8 -16
  22. data/lib/sequel/adapters/jdbc/as400.rb +0 -1
  23. data/lib/sequel/adapters/jdbc/cubrid.rb +0 -1
  24. data/lib/sequel/adapters/jdbc/db2.rb +0 -1
  25. data/lib/sequel/adapters/jdbc/derby.rb +0 -1
  26. data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -1
  27. data/lib/sequel/adapters/jdbc/h2.rb +0 -1
  28. data/lib/sequel/adapters/jdbc/hsqldb.rb +0 -1
  29. data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -1
  30. data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -1
  31. data/lib/sequel/adapters/jdbc/jtds.rb +0 -1
  32. data/lib/sequel/adapters/jdbc/mssql.rb +0 -1
  33. data/lib/sequel/adapters/jdbc/mysql.rb +0 -1
  34. data/lib/sequel/adapters/jdbc/oracle.rb +0 -1
  35. data/lib/sequel/adapters/jdbc/postgresql.rb +0 -13
  36. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +0 -1
  37. data/lib/sequel/adapters/jdbc/sqlite.rb +0 -1
  38. data/lib/sequel/adapters/jdbc/sqlserver.rb +3 -4
  39. data/lib/sequel/adapters/mock.rb +54 -12
  40. data/lib/sequel/adapters/mysql.rb +1 -1
  41. data/lib/sequel/adapters/mysql2.rb +11 -17
  42. data/lib/sequel/adapters/odbc/mssql.rb +0 -1
  43. data/lib/sequel/adapters/oracle.rb +8 -20
  44. data/lib/sequel/adapters/postgres.rb +11 -29
  45. data/lib/sequel/adapters/shared/access.rb +5 -12
  46. data/lib/sequel/adapters/shared/cubrid.rb +4 -13
  47. data/lib/sequel/adapters/shared/db2.rb +4 -2
  48. data/lib/sequel/adapters/shared/firebird.rb +2 -4
  49. data/lib/sequel/adapters/shared/informix.rb +4 -2
  50. data/lib/sequel/adapters/shared/mssql.rb +3 -5
  51. data/lib/sequel/adapters/shared/mysql.rb +4 -14
  52. data/lib/sequel/adapters/shared/oracle.rb +1 -3
  53. data/lib/sequel/adapters/shared/postgres.rb +16 -38
  54. data/lib/sequel/adapters/shared/progress.rb +0 -2
  55. data/lib/sequel/adapters/shared/sqlanywhere.rb +0 -2
  56. data/lib/sequel/adapters/shared/sqlite.rb +20 -16
  57. data/lib/sequel/adapters/sqlite.rb +8 -20
  58. data/lib/sequel/adapters/swift/mysql.rb +0 -1
  59. data/lib/sequel/adapters/swift/postgres.rb +0 -1
  60. data/lib/sequel/adapters/swift/sqlite.rb +0 -1
  61. data/lib/sequel/adapters/tinytds.rb +4 -12
  62. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +1 -1
  63. data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -2
  64. data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +11 -34
  65. data/lib/sequel/adapters/utils/stored_procedures.rb +9 -22
  66. data/lib/sequel/adapters/utils/unmodified_identifiers.rb +26 -0
  67. data/lib/sequel/ast_transformer.rb +2 -2
  68. data/lib/sequel/database/dataset.rb +1 -1
  69. data/lib/sequel/database/dataset_defaults.rb +0 -66
  70. data/lib/sequel/database/features.rb +6 -0
  71. data/lib/sequel/database/misc.rb +31 -17
  72. data/lib/sequel/database/query.rb +7 -4
  73. data/lib/sequel/database/schema_methods.rb +1 -1
  74. data/lib/sequel/dataset.rb +8 -8
  75. data/lib/sequel/dataset/actions.rb +140 -46
  76. data/lib/sequel/dataset/features.rb +1 -5
  77. data/lib/sequel/dataset/graph.rb +7 -8
  78. data/lib/sequel/dataset/misc.rb +127 -56
  79. data/lib/sequel/dataset/mutation.rb +9 -20
  80. data/lib/sequel/dataset/placeholder_literalizer.rb +10 -1
  81. data/lib/sequel/dataset/prepared_statements.rb +102 -46
  82. data/lib/sequel/dataset/query.rb +155 -72
  83. data/lib/sequel/dataset/sql.rb +26 -9
  84. data/lib/sequel/extensions/columns_introspection.rb +3 -1
  85. data/lib/sequel/extensions/core_extensions.rb +5 -5
  86. data/lib/sequel/extensions/core_refinements.rb +5 -5
  87. data/lib/sequel/extensions/duplicate_columns_handler.rb +4 -2
  88. data/lib/sequel/extensions/freeze_datasets.rb +69 -0
  89. data/lib/sequel/extensions/identifier_mangling.rb +196 -0
  90. data/lib/sequel/extensions/looser_typecasting.rb +11 -7
  91. data/lib/sequel/extensions/migration.rb +1 -1
  92. data/lib/sequel/extensions/null_dataset.rb +5 -2
  93. data/lib/sequel/extensions/pagination.rb +42 -23
  94. data/lib/sequel/extensions/pg_enum.rb +3 -3
  95. data/lib/sequel/extensions/query.rb +3 -3
  96. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +15 -8
  97. data/lib/sequel/model/associations.rb +25 -8
  98. data/lib/sequel/model/base.rb +88 -29
  99. data/lib/sequel/model/dataset_module.rb +37 -0
  100. data/lib/sequel/plugins/association_pks.rb +4 -4
  101. data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
  102. data/lib/sequel/plugins/constraint_validations.rb +1 -2
  103. data/lib/sequel/plugins/csv_serializer.rb +2 -2
  104. data/lib/sequel/plugins/dataset_associations.rb +8 -8
  105. data/lib/sequel/plugins/eager_each.rb +2 -2
  106. data/lib/sequel/plugins/instance_filters.rb +1 -1
  107. data/lib/sequel/plugins/json_serializer.rb +2 -2
  108. data/lib/sequel/plugins/lazy_attributes.rb +1 -1
  109. data/lib/sequel/plugins/list.rb +4 -4
  110. data/lib/sequel/plugins/prepared_statements.rb +2 -4
  111. data/lib/sequel/plugins/prepared_statements_associations.rb +1 -3
  112. data/lib/sequel/plugins/prepared_statements_with_pk.rb +1 -1
  113. data/lib/sequel/plugins/rcte_tree.rb +13 -13
  114. data/lib/sequel/plugins/sharding.rb +1 -1
  115. data/lib/sequel/plugins/single_table_inheritance.rb +9 -4
  116. data/lib/sequel/plugins/tactical_eager_loading.rb +4 -4
  117. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  118. data/lib/sequel/plugins/validation_helpers.rb +1 -1
  119. data/lib/sequel/plugins/xml_serializer.rb +2 -2
  120. data/lib/sequel/sql.rb +69 -36
  121. data/lib/sequel/version.rb +1 -1
  122. data/spec/adapters/db2_spec.rb +10 -0
  123. data/spec/adapters/firebird_spec.rb +1 -1
  124. data/spec/adapters/mssql_spec.rb +4 -5
  125. data/spec/adapters/mysql_spec.rb +9 -9
  126. data/spec/adapters/postgres_spec.rb +67 -68
  127. data/spec/adapters/spec_helper.rb +6 -1
  128. data/spec/adapters/sqlite_spec.rb +29 -15
  129. data/spec/core/connection_pool_spec.rb +14 -14
  130. data/spec/core/database_spec.rb +38 -180
  131. data/spec/core/dataset_mutation_spec.rb +253 -0
  132. data/spec/core/dataset_spec.rb +394 -537
  133. data/spec/core/expression_filters_spec.rb +34 -32
  134. data/spec/core/mock_adapter_spec.rb +27 -35
  135. data/spec/core/placeholder_literalizer_spec.rb +2 -4
  136. data/spec/core/schema_generator_spec.rb +4 -4
  137. data/spec/core/schema_spec.rb +1 -2
  138. data/spec/core_extensions_spec.rb +22 -29
  139. data/spec/extensions/active_model_spec.rb +6 -6
  140. data/spec/extensions/association_dependencies_spec.rb +2 -2
  141. data/spec/extensions/blacklist_security_spec.rb +3 -3
  142. data/spec/extensions/boolean_readers_spec.rb +12 -12
  143. data/spec/extensions/caching_spec.rb +13 -10
  144. data/spec/extensions/class_table_inheritance_spec.rb +38 -43
  145. data/spec/extensions/column_conflicts_spec.rb +1 -3
  146. data/spec/extensions/columns_introspection_spec.rb +2 -3
  147. data/spec/extensions/composition_spec.rb +5 -3
  148. data/spec/extensions/constraint_validations_plugin_spec.rb +5 -5
  149. data/spec/extensions/constraint_validations_spec.rb +14 -8
  150. data/spec/extensions/core_refinements_spec.rb +22 -29
  151. data/spec/extensions/csv_serializer_spec.rb +7 -6
  152. data/spec/extensions/date_arithmetic_spec.rb +15 -15
  153. data/spec/extensions/defaults_setter_spec.rb +2 -2
  154. data/spec/extensions/delay_add_association_spec.rb +1 -1
  155. data/spec/extensions/dirty_spec.rb +19 -10
  156. data/spec/extensions/duplicate_columns_handler_spec.rb +12 -18
  157. data/spec/extensions/eager_each_spec.rb +12 -16
  158. data/spec/extensions/empty_array_consider_nulls_spec.rb +1 -1
  159. data/spec/extensions/eval_inspect_spec.rb +4 -3
  160. data/spec/extensions/force_encoding_spec.rb +12 -12
  161. data/spec/extensions/freeze_datasets_spec.rb +31 -0
  162. data/spec/extensions/graph_each_spec.rb +6 -18
  163. data/spec/extensions/hook_class_methods_spec.rb +7 -7
  164. data/spec/extensions/identifier_mangling_spec.rb +307 -0
  165. data/spec/extensions/instance_filters_spec.rb +5 -6
  166. data/spec/extensions/instance_hooks_spec.rb +12 -12
  167. data/spec/extensions/json_serializer_spec.rb +12 -15
  168. data/spec/extensions/lazy_attributes_spec.rb +4 -4
  169. data/spec/extensions/list_spec.rb +19 -21
  170. data/spec/extensions/many_through_many_spec.rb +108 -163
  171. data/spec/extensions/meta_def_spec.rb +7 -2
  172. data/spec/extensions/migration_spec.rb +10 -12
  173. data/spec/extensions/mssql_optimistic_locking_spec.rb +4 -3
  174. data/spec/extensions/named_timezones_spec.rb +4 -3
  175. data/spec/extensions/nested_attributes_spec.rb +2 -2
  176. data/spec/extensions/null_dataset_spec.rb +17 -12
  177. data/spec/extensions/optimistic_locking_spec.rb +4 -5
  178. data/spec/extensions/pagination_spec.rb +8 -10
  179. data/spec/extensions/pg_array_associations_spec.rb +28 -27
  180. data/spec/extensions/pg_array_ops_spec.rb +2 -1
  181. data/spec/extensions/pg_array_spec.rb +6 -2
  182. data/spec/extensions/pg_enum_spec.rb +5 -3
  183. data/spec/extensions/pg_hstore_ops_spec.rb +3 -1
  184. data/spec/extensions/pg_hstore_spec.rb +7 -6
  185. data/spec/extensions/pg_inet_ops_spec.rb +2 -1
  186. data/spec/extensions/pg_inet_spec.rb +2 -1
  187. data/spec/extensions/pg_interval_spec.rb +2 -1
  188. data/spec/extensions/pg_json_ops_spec.rb +2 -1
  189. data/spec/extensions/pg_json_spec.rb +6 -3
  190. data/spec/extensions/pg_loose_count_spec.rb +1 -0
  191. data/spec/extensions/pg_range_ops_spec.rb +3 -1
  192. data/spec/extensions/pg_range_spec.rb +9 -5
  193. data/spec/extensions/pg_row_ops_spec.rb +2 -1
  194. data/spec/extensions/pg_row_plugin_spec.rb +4 -6
  195. data/spec/extensions/pg_row_spec.rb +5 -3
  196. data/spec/extensions/pg_static_cache_updater_spec.rb +2 -1
  197. data/spec/extensions/pg_typecast_on_load_spec.rb +1 -1
  198. data/spec/extensions/prepared_statements_associations_spec.rb +1 -1
  199. data/spec/extensions/prepared_statements_spec.rb +12 -11
  200. data/spec/extensions/pretty_table_spec.rb +1 -1
  201. data/spec/extensions/query_spec.rb +8 -5
  202. data/spec/extensions/rcte_tree_spec.rb +39 -39
  203. data/spec/extensions/round_timestamps_spec.rb +2 -2
  204. data/spec/extensions/schema_dumper_spec.rb +3 -2
  205. data/spec/extensions/schema_spec.rb +2 -2
  206. data/spec/extensions/scissors_spec.rb +1 -2
  207. data/spec/extensions/sequel_3_dataset_methods_spec.rb +30 -17
  208. data/spec/extensions/serialization_modification_detection_spec.rb +2 -2
  209. data/spec/extensions/serialization_spec.rb +15 -13
  210. data/spec/extensions/set_overrides_spec.rb +14 -8
  211. data/spec/extensions/sharding_spec.rb +9 -18
  212. data/spec/extensions/shared_caching_spec.rb +3 -4
  213. data/spec/extensions/single_table_inheritance_spec.rb +11 -11
  214. data/spec/extensions/skip_create_refresh_spec.rb +2 -1
  215. data/spec/extensions/spec_helper.rb +1 -1
  216. data/spec/extensions/split_values_spec.rb +2 -2
  217. data/spec/extensions/sql_comments_spec.rb +6 -0
  218. data/spec/extensions/static_cache_spec.rb +7 -9
  219. data/spec/extensions/string_agg_spec.rb +30 -29
  220. data/spec/extensions/tactical_eager_loading_spec.rb +4 -5
  221. data/spec/extensions/thread_local_timezones_spec.rb +2 -2
  222. data/spec/extensions/timestamps_spec.rb +28 -3
  223. data/spec/extensions/to_dot_spec.rb +1 -2
  224. data/spec/extensions/tree_spec.rb +33 -29
  225. data/spec/extensions/typecast_on_load_spec.rb +1 -1
  226. data/spec/extensions/unlimited_update_spec.rb +1 -0
  227. data/spec/extensions/update_primary_key_spec.rb +11 -7
  228. data/spec/extensions/update_refresh_spec.rb +1 -1
  229. data/spec/extensions/uuid_spec.rb +0 -1
  230. data/spec/extensions/validate_associated_spec.rb +1 -1
  231. data/spec/extensions/validation_class_methods_spec.rb +10 -10
  232. data/spec/extensions/validation_helpers_spec.rb +10 -10
  233. data/spec/extensions/xml_serializer_spec.rb +7 -3
  234. data/spec/integration/associations_test.rb +31 -31
  235. data/spec/integration/dataset_test.rb +17 -19
  236. data/spec/integration/eager_loader_test.rb +24 -24
  237. data/spec/integration/model_test.rb +6 -6
  238. data/spec/integration/plugin_test.rb +43 -43
  239. data/spec/integration/prepared_statement_test.rb +6 -6
  240. data/spec/integration/schema_test.rb +63 -52
  241. data/spec/integration/spec_helper.rb +6 -1
  242. data/spec/integration/transaction_test.rb +13 -13
  243. data/spec/model/association_reflection_spec.rb +17 -17
  244. data/spec/model/associations_spec.rb +101 -96
  245. data/spec/model/base_spec.rb +175 -49
  246. data/spec/model/class_dataset_methods_spec.rb +5 -9
  247. data/spec/model/dataset_methods_spec.rb +5 -5
  248. data/spec/model/eager_loading_spec.rb +209 -235
  249. data/spec/model/hooks_spec.rb +15 -15
  250. data/spec/model/model_spec.rb +28 -21
  251. data/spec/model/plugins_spec.rb +4 -5
  252. data/spec/model/record_spec.rb +59 -57
  253. data/spec/model/spec_helper.rb +1 -1
  254. data/spec/model/validations_spec.rb +6 -6
  255. data/spec/spec_config.rb +1 -1
  256. metadata +10 -2
@@ -7,7 +7,7 @@
7
7
  #
8
8
  # It allows creation of enum types using create_enum:
9
9
  #
10
- # DB.create_enum(:type_name, %w'value1 value2 value3')
10
+ # DB.create_enum(:enum_type_name, %w'value1 value2 value3')
11
11
  #
12
12
  # You can also add values to existing enums via add_enum_value:
13
13
  #
@@ -15,7 +15,7 @@
15
15
  #
16
16
  # If you want to drop an enum type, you can use drop_enum:
17
17
  #
18
- # DB.drop_enum(:type_name)
18
+ # DB.drop_enum(:enum_type_name)
19
19
  #
20
20
  # Just like any user-created type, after creating the type, you
21
21
  # can create tables that have a column of that type:
@@ -44,7 +44,7 @@
44
44
  #
45
45
  # Sequel.migration do
46
46
  # change do
47
- # create_enum(:type_name, %w'value1 value2 value3')
47
+ # create_enum(:enum_type_name, %w'value1 value2 value3')
48
48
  # end
49
49
  # end
50
50
  #
@@ -6,7 +6,7 @@
6
6
  #
7
7
  # dataset = DB[:items].query do
8
8
  # select :x, :y, :z
9
- # filter{(x > 1) & (y > 2)}
9
+ # where{(x > 1) & (y > 2)}
10
10
  # reverse :z
11
11
  # end
12
12
  #
@@ -45,13 +45,13 @@ module Sequel
45
45
  #
46
46
  # dataset = DB[:items].query do
47
47
  # select :x, :y, :z
48
- # filter{(x > 1) & (y > 2)}
48
+ # where{(x > 1) & (y > 2)}
49
49
  # reverse :z
50
50
  # end
51
51
  #
52
52
  # Which is the same as:
53
53
  #
54
- # dataset = DB[:items].select(:x, :y, :z).filter{(x > 1) & (y > 2)}.reverse(:z)
54
+ # dataset = DB[:items].select(:x, :y, :z).where{(x > 1) & (y > 2)}.reverse(:z)
55
55
  def query(&block)
56
56
  query = Dataset::Query.new(self)
57
57
  query.instance_eval(&block)
@@ -27,12 +27,19 @@
27
27
  module Sequel
28
28
  module Sequel3DatasetMethods
29
29
  COMMA = Dataset::COMMA
30
- # The database related to this dataset. This is the Database instance that
31
- # will execute all of this dataset's queries.
32
- attr_writer :db
30
+ # Change the database for this dataset.
31
+ def db=(v)
32
+ raise_if_frozen!
33
+ @db = v
34
+ @cache = {}
35
+ end
33
36
 
34
- # The hash of options for this dataset, keys are symbols.
35
- attr_writer :opts
37
+ # Change the options for this dataset.
38
+ def opts=(v)
39
+ raise_if_frozen!
40
+ @opts = v
41
+ @cache = {}
42
+ end
36
43
 
37
44
  # Update all records matching the conditions with the values specified.
38
45
  # Returns the number of rows affected.
@@ -40,7 +47,7 @@ module Sequel
40
47
  # DB[:table][:id=>1] = {:id=>2} # UPDATE table SET id = 2 WHERE id = 1
41
48
  # # => 1 # number of rows affected
42
49
  def []=(conditions, values)
43
- filter(conditions).update(values)
50
+ where(conditions).update(values)
44
51
  end
45
52
 
46
53
  # Inserts multiple values. If a block is given it is invoked for each
@@ -71,7 +78,7 @@ module Sequel
71
78
  # given table. If no columns are currently selected, select all
72
79
  # columns of the given table.
73
80
  #
74
- # DB[:items].filter(:id=>1).qualify_to(:i)
81
+ # DB[:items].where(:id=>1).qualify_to(:i)
75
82
  # # SELECT i.* FROM items WHERE (i.id = 1)
76
83
  def qualify_to(table)
77
84
  qualify(table)
@@ -83,7 +90,7 @@ module Sequel
83
90
  # has columns with the same name as columns in the current dataset.
84
91
  # See +qualify_to+.
85
92
  #
86
- # DB[:items].filter(:id=>1).qualify_to_first_source
93
+ # DB[:items].where(:id=>1).qualify_to_first_source
87
94
  # # SELECT items.* FROM items WHERE (items.id = 1)
88
95
  def qualify_to_first_source
89
96
  qualify
@@ -68,9 +68,9 @@ module Sequel
68
68
 
69
69
  # Apply all non-instance specific changes to the given dataset and return it.
70
70
  def apply_dataset_changes(ds)
71
- ds.extend(AssociationDatasetMethods)
72
- ds.association_reflection = self
73
- self[:extend].each{|m| ds.extend(m)}
71
+ ds = ds.with_extend(AssociationDatasetMethods).
72
+ clone(:association_reflection => self)
73
+ self[:extend].each{|m| ds = ds.with_extend(m)}
74
74
  ds = ds.select(*select) if select
75
75
  if c = self[:conditions]
76
76
  ds = (c.is_a?(Array) && !Sequel.condition_specifier?(c)) ? ds.where(*c) : ds.where(c)
@@ -263,6 +263,7 @@ module Sequel
263
263
 
264
264
  eager_limit =
265
265
  if el = ds.opts[:eager_limit]
266
+ raise Error, "The :eager_limit dataset option is not supported for associations returning a single record" unless returns_array?
266
267
  strategy ||= true_eager_graph_limit_strategy
267
268
  if el.is_a?(Array)
268
269
  el
@@ -276,6 +277,7 @@ module Sequel
276
277
  strategy = true_eager_graph_limit_strategy if strategy == :union
277
278
  # Correlated subqueries are not supported for regular eager loading
278
279
  strategy = :ruby if strategy == :correlated_subquery
280
+ strategy = nil if strategy == :ruby && assign_singular?
279
281
  objects = apply_eager_limit_strategy(ds, strategy, eager_limit).all
280
282
  elsif strategy == :union
281
283
  objects = []
@@ -1358,11 +1360,17 @@ module Sequel
1358
1360
 
1359
1361
  # This module contains methods added to all association datasets
1360
1362
  module AssociationDatasetMethods
1363
+ Dataset.def_deprecated_opts_setter(self, :model, :association_reflection)
1364
+
1361
1365
  # The model object that created the association dataset
1362
- attr_accessor :model_object
1366
+ def model_object
1367
+ @opts[:model_object]
1368
+ end
1363
1369
 
1364
1370
  # The association reflection related to the association dataset
1365
- attr_accessor :association_reflection
1371
+ def association_reflection
1372
+ @opts[:association_reflection]
1373
+ end
1366
1374
  end
1367
1375
 
1368
1376
  # Each kind of association adds a number of instance methods to the model class which
@@ -1501,6 +1509,10 @@ module Sequel
1501
1509
  # the given association. Can be used to DRY up a bunch of similar associations that
1502
1510
  # all share the same options such as :class and :key, while changing the order and block used.
1503
1511
  # :conditions :: The conditions to use to filter the association, can be any argument passed to where.
1512
+ # This option is not respected when using eager_graph or association_join, unless it
1513
+ # is hash or array of two element arrays. Consider also specifying the :graph_block
1514
+ # option if the value for this option is not a hash or array of two element arrays
1515
+ # and you plan to use this association in eager_graph or association_join.
1504
1516
  # :dataset :: A proc that is instance_execed to get the base dataset to use (before the other
1505
1517
  # options are applied). If the proc accepts an argument, it is passed the related
1506
1518
  # association reflection.
@@ -2118,7 +2130,7 @@ module Sequel
2118
2130
  unless ds.kind_of?(AssociationDatasetMethods)
2119
2131
  ds = opts.apply_dataset_changes(ds)
2120
2132
  end
2121
- ds.model_object = self
2133
+ ds = ds.clone(:model_object => self)
2122
2134
  ds = ds.eager_graph(opts[:eager_graph]) if opts[:eager_graph] && opts.eager_graph_lazy_dataset?
2123
2135
  ds = instance_exec(ds, &opts[:block]) if opts[:block]
2124
2136
  ds
@@ -2697,7 +2709,7 @@ END
2697
2709
  def ungraphed
2698
2710
  ds = super.clone(:eager_graph=>nil)
2699
2711
  if (eg = @opts[:eager_graph]) && (rp = eg[:row_proc])
2700
- ds.row_proc = rp
2712
+ ds = ds.with_row_proc(rp)
2701
2713
  end
2702
2714
  ds
2703
2715
  end
@@ -2737,9 +2749,14 @@ END
2737
2749
  end
2738
2750
  local_opts = ds.opts[:eager_graph][:local]
2739
2751
  limit_strategy = r.eager_graph_limit_strategy(local_opts[:limit_strategy])
2752
+
2753
+ if r[:conditions] && !Sequel.condition_specifier?(r[:conditions]) && !r[:orig_opts].has_key?(:graph_conditions) && !r[:orig_opts].has_key?(:graph_only_conditions) && !r.has_key?(:graph_block)
2754
+ Sequel::Deprecation.deprecate("Ignoring :conditions for #{r[:model]} #{r[:name]} association during eager_graph/association_join, consider specifying :graph_block") unless r[:ignore_conditions_warning]
2755
+ end
2756
+
2740
2757
  ds = loader.call(:self=>ds, :table_alias=>assoc_table_alias, :implicit_qualifier=>(ta == ds.opts[:eager_graph][:master]) ? first_source : qualifier_from_alias_symbol(ta, first_source), :callback=>callback, :join_type=>local_opts[:join_type], :join_only=>local_opts[:join_only], :limit_strategy=>limit_strategy, :from_self_alias=>ds.opts[:eager_graph][:master])
2741
2758
  if r[:order_eager_graph] && (order = r.fetch(:graph_order, r[:order]))
2742
- ds = ds.order_more(*qualified_expression(order, assoc_table_alias))
2759
+ ds = ds.order_append(*qualified_expression(order, assoc_table_alias))
2743
2760
  end
2744
2761
  eager_graph = ds.opts[:eager_graph]
2745
2762
  eager_graph[:requirements][assoc_table_alias] = requirements.dup
@@ -286,25 +286,42 @@ module Sequel
286
286
  # Returns the module given or the anonymous module created.
287
287
  #
288
288
  # # Usage with existing module
289
- # Artist.dataset_module Sequel::ColumnsIntrospection
289
+ # Album.dataset_module Sequel::ColumnsIntrospection
290
290
  #
291
291
  # # Usage with anonymous module
292
- # Artist.dataset_module do
292
+ # Album.dataset_module do
293
293
  # def foo
294
294
  # :bar
295
295
  # end
296
296
  # end
297
- # Artist.dataset.foo
297
+ # Album.dataset.foo
298
298
  # # => :bar
299
- # Artist.foo
299
+ # Album.foo
300
300
  # # => :bar
301
301
  #
302
302
  # Any anonymous modules created are actually instances of Sequel::Model::DatasetModule
303
- # (a Module subclass), which allows you to call the subset method on them:
304
- #
305
- # Artist.dataset_module do
306
- # subset :released, Sequel.identifier(release_date) > Sequel::CURRENT_DATE
303
+ # (a Module subclass), which allows you to call the subset method on them, which
304
+ # defines a dataset method that adds a filter. There are also a number of other
305
+ # methods with the same names as the dataset methods, which can use to define
306
+ # named dataset methods:
307
+ #
308
+ # Album.dataset_module do
309
+ # subset :released, Sequel.identifier(release_date) <= Sequel::CURRENT_DATE
310
+ # order :by_release_date, :release_date
311
+ # select :for_select_options, :id, :name, :release_date
307
312
  # end
313
+ # Album.released.sql
314
+ # # => "SELECT * FROM artists WHERE (release_date <= CURRENT_DATE)"
315
+ # Album.by_release_date.sql
316
+ # # => "SELECT * FROM artists ORDER BY release_date"
317
+ # Album.for_select_options.sql
318
+ # # => "SELECT id, name, release_date FROM artists"
319
+ # Album.released.by_release_date.for_select_options.sql
320
+ # # => "SELECT id, name, release_date FROM artists WHERE (release_date <= CURRENT_DATE) ORDER BY release_date"
321
+ #
322
+ # The following methods are supported: distinct, exclude, exclude_having, grep, group, group_and_count,
323
+ # group_append, having, limit, offset, order, order_append, order_prepend, select, select_all,
324
+ # select_append, select_group, where, and server.
308
325
  #
309
326
  # Any public methods in the dataset module will have class methods created that
310
327
  # call the method on the dataset, assuming that the class method is not already
@@ -388,14 +405,15 @@ module Sequel
388
405
  # If a block is not given, just define a class method on the model for each argument
389
406
  # that calls the dataset method of the same argument name.
390
407
  #
391
- # It is recommended that you define methods inside a block passed to #dataset_module
392
- # instead of using this method, as #dataset_module allows you to use normal
393
- # ruby def syntax.
408
+ # Using dataset_module is recommended over using this method. In addition to allowing
409
+ # more natural ruby syntax for defining methods manually, it also offers numerous
410
+ # helper methods that make defining common dataset methods more easily, as well as
411
+ # supporting dataset caching (assuming the arguments allow it).
394
412
  #
395
413
  # # Add new dataset method and class method that calls it
396
414
  # Artist.def_dataset_method(:by_name){order(:name)}
397
- # Artist.filter(:name.like('A%')).by_name
398
- # Artist.by_name.filter(:name.like('A%'))
415
+ # Artist.where(:name.like('A%')).by_name
416
+ # Artist.by_name.where(:name.like('A%'))
399
417
  #
400
418
  # # Just add a class method that calls an existing dataset method
401
419
  # Artist.def_dataset_method(:server!)
@@ -424,7 +442,7 @@ module Sequel
424
442
  # Use optimized finder
425
443
  first_where(args.first)
426
444
  else
427
- filter(*args, &block).first
445
+ where(*args, &block).first
428
446
  end
429
447
  end
430
448
 
@@ -707,7 +725,7 @@ module Sequel
707
725
  # plan to join other tables to this table and you want the column references
708
726
  # to be qualified.
709
727
  #
710
- # Artist.filter(Artist.qualified_primary_key_hash(1))
728
+ # Artist.where(Artist.qualified_primary_key_hash(1))
711
729
  # # SELECT * FROM artists WHERE (artists.id = 1)
712
730
  def qualified_primary_key_hash(value, qualifier=table_name)
713
731
  case key = @primary_key
@@ -802,11 +820,10 @@ module Sequel
802
820
  @columns = superclass.instance_variable_get(:@columns)
803
821
  @db_schema = superclass.instance_variable_get(:@db_schema)
804
822
  else
805
- @dataset_method_modules.each{|m| @dataset.extend(m)} if @dataset_method_modules
823
+ @dataset = @dataset.with_extend(*@dataset_method_modules.reverse) if @dataset_method_modules
806
824
  @db_schema = get_db_schema
807
825
  end
808
826
 
809
- @dataset.model = self if @dataset.respond_to?(:model=)
810
827
  reset_instance_dataset
811
828
  self
812
829
  end
@@ -868,7 +885,14 @@ module Sequel
868
885
  # dataset methods that accept arguments, you should use define a
869
886
  # method directly inside a #dataset_module block.
870
887
  def subset(name, *args, &block)
871
- def_dataset_method(name){filter(*args, &block)}
888
+ if block || args.flatten.any?{|arg| arg.is_a?(Proc)}
889
+ def_dataset_method(name){filter(*args, &block)}
890
+ else
891
+ key = :"_subset_#{name}_ds"
892
+ def_dataset_method(name) do
893
+ cached_dataset(key){filter(*args)}
894
+ end
895
+ end
872
896
  end
873
897
 
874
898
  # Returns name of primary table for the dataset. If the table for the dataset
@@ -933,15 +957,15 @@ module Sequel
933
957
  else
934
958
  raise(Error, "Model.set_dataset takes one of the following classes as an argument: Symbol, LiteralString, SQL::Identifier, SQL::QualifiedIdentifier, SQL::AliasedExpression, Dataset")
935
959
  end
936
- set_dataset_row_proc(ds)
937
- ds
960
+
961
+ set_dataset_row_proc(ds.clone(:model=>self))
938
962
  end
939
963
 
940
964
  # Add the module to the class's dataset_method_modules. Extend the dataset with the
941
965
  # module if the model has a dataset. Add dataset methods to the class for all
942
966
  # public dataset methods.
943
967
  def dataset_extend(mod, opts=OPTS)
944
- @dataset.extend(mod) if @dataset
968
+ @dataset = @dataset.with_extend(mod) if @dataset
945
969
  reset_instance_dataset
946
970
  dataset_method_modules << mod
947
971
  unless opts[:create_class_methods] == false
@@ -1204,7 +1228,7 @@ module Sequel
1204
1228
 
1205
1229
  # Set the dataset's row_proc to the current model.
1206
1230
  def set_dataset_row_proc(ds)
1207
- ds.row_proc = self
1231
+ ds.with_row_proc(self)
1208
1232
  end
1209
1233
 
1210
1234
  # Reset the fast primary key lookup SQL when the simple_pk value changes.
@@ -1791,7 +1815,7 @@ module Sequel
1791
1815
  # Set the shard that this object is tied to. Returns self.
1792
1816
  def set_server(s)
1793
1817
  @server = s
1794
- @this.opts[:server] = s if @this
1818
+ @this = @this.server(s) if @this
1795
1819
  self
1796
1820
  end
1797
1821
 
@@ -2368,10 +2392,14 @@ module Sequel
2368
2392
  # Dataset methods are methods that the model class extends its dataset with in
2369
2393
  # the call to set_dataset.
2370
2394
  module DatasetMethods
2395
+ Dataset.def_deprecated_opts_setter(self, :model)
2396
+
2371
2397
  # The model class associated with this dataset
2372
2398
  #
2373
2399
  # Artist.dataset.model # => Artist
2374
- attr_accessor :model
2400
+ def model
2401
+ @opts[:model]
2402
+ end
2375
2403
 
2376
2404
  # Assume if a single integer is given that it is a lookup by primary
2377
2405
  # key, and call with_pk with the argument.
@@ -2449,8 +2477,8 @@ module Sequel
2449
2477
  # Album.last
2450
2478
  # # SELECT * FROM albums ORDER BY id DESC LIMIT 1
2451
2479
  def last(*a, &block)
2452
- if opts[:order].nil? && model && (pk = model.primary_key)
2453
- order(*pk).last(*a, &block)
2480
+ if ds = _primary_key_order
2481
+ ds.last(*a, &block)
2454
2482
  else
2455
2483
  super
2456
2484
  end
@@ -2465,8 +2493,8 @@ module Sequel
2465
2493
  # # SELECT * FROM albums ORDER BY id LIMIT 1000 OFFSET 2000
2466
2494
  # # ...
2467
2495
  def paged_each(*a, &block)
2468
- if opts[:order].nil? && model && (pk = model.primary_key)
2469
- order(*pk).paged_each(*a, &block)
2496
+ if ds = _primary_key_order
2497
+ ds.paged_each(*a, &block)
2470
2498
  else
2471
2499
  super
2472
2500
  end
@@ -2500,7 +2528,11 @@ module Sequel
2500
2528
  # Artist.dataset.with_pk([1, 2])
2501
2529
  # # SELECT * FROM artists WHERE ((artists.id1 = 1) AND (artists.id2 = 2)) LIMIT 1
2502
2530
  def with_pk(pk)
2503
- first(model.qualified_primary_key_hash(pk))
2531
+ if loader = _with_pk_loader
2532
+ loader.first(*pk)
2533
+ else
2534
+ first(model.qualified_primary_key_hash(pk))
2535
+ end
2504
2536
  end
2505
2537
 
2506
2538
  # Same as with_pk, but raises NoMatchingRow instead of returning nil if no
@@ -2508,6 +2540,33 @@ module Sequel
2508
2540
  def with_pk!(pk)
2509
2541
  with_pk(pk) || raise(NoMatchingRow.new(self))
2510
2542
  end
2543
+
2544
+ private
2545
+
2546
+ # If the dataset is not already ordered, and the model has a primary key,
2547
+ # return a clone ordered by the primary key.
2548
+ def _primary_key_order
2549
+ if @opts[:order].nil? && model && (pk = model.primary_key)
2550
+ cached_dataset(:_pk_order_ds){order(*pk)}
2551
+ end
2552
+ end
2553
+
2554
+ # A cached placeholder literalizer, if one exists for the current dataset.
2555
+ def _with_pk_loader
2556
+ cached_placeholder_literalizer(:_with_pk_loader) do |pl|
2557
+ table = model.table_name
2558
+ cond = case primary_key = model.primary_key
2559
+ when Array
2560
+ primary_key.map{|key| [SQL::QualifiedIdentifier.new(table, key), pl.arg]}
2561
+ when Symbol
2562
+ {SQL::QualifiedIdentifier.new(table, primary_key)=>pl.arg}
2563
+ else
2564
+ raise(Error, "#{model} does not have a primary key")
2565
+ end
2566
+
2567
+ where(cond).limit(1)
2568
+ end
2569
+ end
2511
2570
  end
2512
2571
 
2513
2572
  extend ClassMethods
@@ -20,6 +20,43 @@ module Sequel
20
20
  @model.subset(name, *args, &block)
21
21
  end
22
22
 
23
+ # Alias for subset
24
+ def where(name, *args, &block)
25
+ subset(name, *args, &block)
26
+ end
27
+
28
+ %w'exclude exclude_having having'.map(&:to_sym).each do |meth|
29
+ define_method(meth) do |name, *args, &block|
30
+ if block || args.flatten.any?{|arg| arg.is_a?(Proc)}
31
+ @model.def_dataset_method(name){send(meth, *args, &block)}
32
+ else
33
+ key = :"_#{meth}_#{name}_ds"
34
+ @model.def_dataset_method(name) do
35
+ cached_dataset(key){send(meth, *args)}
36
+ end
37
+ end
38
+ end
39
+ end
40
+
41
+ meths = (<<-METHS).split.map(&:to_sym)
42
+ distinct grep group group_and_count group_append
43
+ limit offset order order_append order_prepend
44
+ select select_all select_append select_group server
45
+ METHS
46
+
47
+ meths.each do |meth|
48
+ define_method(meth) do |name, *args, &block|
49
+ if block
50
+ @model.def_dataset_method(name){send(meth, *args, &block)}
51
+ else
52
+ key = :"_#{meth}_#{name}_ds"
53
+ @model.def_dataset_method(name) do
54
+ cached_dataset(key){send(meth, *args)}
55
+ end
56
+ end
57
+ end
58
+ end
59
+
23
60
  private
24
61
 
25
62
  # Add a class method to the related model that