sequel 4.41.0 → 4.42.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 (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