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
@@ -28,7 +28,9 @@ module Sequel
28
28
  # Symbols, SQL::Identifiers, SQL::QualifiedIdentifiers, and
29
29
  # SQL::AliasedExpressions.
30
30
  def columns
31
- return @columns if @columns
31
+ if cols = _columns
32
+ return cols
33
+ end
32
34
  if (pcs = probable_columns) && pcs.all?
33
35
  self.columns = pcs
34
36
  else
@@ -42,9 +42,9 @@ class Array
42
42
  # this array as a value in a filter, but may be necessary if you are using it as a
43
43
  # value with placeholder SQL:
44
44
  #
45
- # DB[:a].filter([:a, :b]=>[[1, 2], [3, 4]]) # SQL: (a, b) IN ((1, 2), (3, 4))
46
- # DB[:a].filter('(a, b) IN ?', [[1, 2], [3, 4]]) # SQL: (a, b) IN ((1 = 2) AND (3 = 4))
47
- # DB[:a].filter('(a, b) IN ?', [[1, 2], [3, 4]].sql_value_list) # SQL: (a, b) IN ((1, 2), (3, 4))
45
+ # DB[:a].where([:a, :b]=>[[1, 2], [3, 4]]) # SQL: (a, b) IN ((1, 2), (3, 4))
46
+ # DB[:a].where('(a, b) IN ?', [[1, 2], [3, 4]]) # SQL: (a, b) IN ((1 = 2) AND (3 = 4))
47
+ # DB[:a].where('(a, b) IN ?', [[1, 2], [3, 4]].sql_value_list) # SQL: (a, b) IN ((1, 2), (3, 4))
48
48
  def sql_value_list
49
49
  ::Sequel::SQL::ValueList.new(self)
50
50
  end
@@ -174,10 +174,10 @@ class String
174
174
  # Converts a string into a <tt>Sequel::LiteralString</tt>, in order to override string
175
175
  # literalization, e.g.:
176
176
  #
177
- # DB[:items].filter(:abc => 'def').sql #=>
177
+ # DB[:items].where(:abc => 'def').sql #=>
178
178
  # "SELECT * FROM items WHERE (abc = 'def')"
179
179
  #
180
- # DB[:items].filter(:abc => 'def'.lit).sql #=>
180
+ # DB[:items].where(:abc => 'def'.lit).sql #=>
181
181
  # "SELECT * FROM items WHERE (abc = def)"
182
182
  #
183
183
  # You can also provide arguments, to create a <tt>Sequel::SQL::PlaceholderLiteralString</tt>:
@@ -38,9 +38,9 @@ module Sequel::CoreRefinements
38
38
  # this array as a value in a filter, but may be necessary if you are using it as a
39
39
  # value with placeholder SQL:
40
40
  #
41
- # DB[:a].filter([:a, :b]=>[[1, 2], [3, 4]]) # SQL: (a, b) IN ((1, 2), (3, 4))
42
- # DB[:a].filter('(a, b) IN ?', [[1, 2], [3, 4]]) # SQL: (a, b) IN ((1 = 2) AND (3 = 4))
43
- # DB[:a].filter('(a, b) IN ?', [[1, 2], [3, 4]].sql_value_list) # SQL: (a, b) IN ((1, 2), (3, 4))
41
+ # DB[:a].where([:a, :b]=>[[1, 2], [3, 4]]) # SQL: (a, b) IN ((1, 2), (3, 4))
42
+ # DB[:a].where('(a, b) IN ?', [[1, 2], [3, 4]]) # SQL: (a, b) IN ((1 = 2) AND (3 = 4))
43
+ # DB[:a].where('(a, b) IN ?', [[1, 2], [3, 4]].sql_value_list) # SQL: (a, b) IN ((1, 2), (3, 4))
44
44
  def sql_value_list
45
45
  ::Sequel::SQL::ValueList.new(self)
46
46
  end
@@ -167,10 +167,10 @@ module Sequel::CoreRefinements
167
167
  # Converts a string into a <tt>Sequel::LiteralString</tt>, in order to override string
168
168
  # literalization, e.g.:
169
169
  #
170
- # DB[:items].filter(:abc => 'def').sql #=>
170
+ # DB[:items].where(:abc => 'def').sql #=>
171
171
  # "SELECT * FROM items WHERE (abc = 'def')"
172
172
  #
173
- # DB[:items].filter(:abc => 'def'.lit).sql #=>
173
+ # DB[:items].where(:abc => 'def'.lit).sql #=>
174
174
  # "SELECT * FROM items WHERE (abc = def)"
175
175
  #
176
176
  # You can also provide arguments, to create a <tt>Sequel::SQL::PlaceholderLiteralString</tt>:
@@ -35,6 +35,8 @@
35
35
 
36
36
  module Sequel
37
37
  module DuplicateColumnsHandler
38
+ CALLER_ARGS = RUBY_VERSION >= '2.0' ? [0,1] : [0]
39
+
38
40
  # Customize handling of duplicate columns for this dataset.
39
41
  def on_duplicate_columns(handler = (raise Error, "Must provide either an argument or a block to on_duplicate_columns" unless block_given?; nil), &block)
40
42
  raise Error, "Cannot provide both an argument and a block to on_duplicate_columns" if handler && block
@@ -47,14 +49,14 @@ module Sequel
47
49
  if cols && cols.uniq.size != cols.size
48
50
  handle_duplicate_columns(cols)
49
51
  end
50
- @columns = cols
52
+ super
51
53
  end
52
54
 
53
55
  private
54
56
 
55
57
  # Invoke the appropriate behavior when duplicate columns are present.
56
58
  def handle_duplicate_columns(cols)
57
- message = "One or more duplicate columns present in #{cols.inspect}"
59
+ message = "#{caller(*CALLER_ARGS).first}: One or more duplicate columns present in #{cols.inspect}"
58
60
 
59
61
  case duplicate_columns_handler_type(cols)
60
62
  when :raise
@@ -0,0 +1,69 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # The freeze_datasets extension freezes a databases's datasets by
4
+ # default, and makes it so the databases's datasets are always
5
+ # frozen. This makes sure you can never accidentally modify a
6
+ # dataset that may be used elsewhere (such as a model class's
7
+ # dataset or the same dataset being used in another thread).
8
+ # Frozen datasets can also perform caching for many
9
+ # different methods that can significantly improve performance.
10
+ #
11
+ # In addition to the caching provided by frozen datasets, this
12
+ # also adds caching of Database#from calls if the method is
13
+ # called with a single Symbol argument and not a block. In
14
+ # addition to speeding up Dataset#from itself, because it
15
+ # returns a cached dataset, all caching done by that dataset
16
+ # can also improve performance.
17
+ #
18
+ # Usage:
19
+ #
20
+ # DB.extension(:freeze_datasets)
21
+ #
22
+ # Related module: Sequel::FreezeDatasets
23
+
24
+ #
25
+ module Sequel
26
+ class Database
27
+ module FreezeDatasets
28
+ module DatasetMethods
29
+ # Make dup be an alias to clone, so that it
30
+ # returns a frozen dataset.
31
+ def dup
32
+ clone
33
+ end
34
+ end
35
+
36
+ # Reset the default dataset for this database after
37
+ # loading the extension.
38
+ def self.extended(db)
39
+ db.extend_datasets(DatasetMethods)
40
+ end
41
+
42
+ # Cache returned dataset if given a single argument and no block.
43
+ def from(*args, &block)
44
+ if !block && args.length == 1 && (table = args[0]).is_a?(Symbol)
45
+ @default_dataset.send(:cached_dataset, :"_from_#{table}_ds"){super}
46
+ else
47
+ super
48
+ end
49
+ end
50
+
51
+ # Freeze datasets created from this dataset.
52
+ def dataset
53
+ super.freeze
54
+ end
55
+
56
+ private
57
+
58
+ # Clear the cache of the default dataset when removing a cached
59
+ # schema, in order to clear the from table cache.
60
+ def remove_cached_schema(table)
61
+ cache = @default_dataset.send(:cache)
62
+ Sequel.synchronize{cache.clear}
63
+ super
64
+ end
65
+ end
66
+
67
+ register_extension(:freeze_datasets, FreezeDatasets)
68
+ end
69
+ end
@@ -0,0 +1,196 @@
1
+ # frozen-string-literal: true
2
+ #
3
+ # The identifier_mangling extension adds support for to change
4
+ # the default identifier mangling for datasets, as well as all
5
+ # datasets for a given database.
6
+ #
7
+ # # Use uppercase identifiers in database, and lowercase in ruby.
8
+ # # Default behavior of Sequel, as the SQL standard behavior
9
+ # # folds unquoted identifiers to uppercase.
10
+ # DB.identifier_input_method = :upcase
11
+ # DB.identifier_output_method = :downcase
12
+ #
13
+ # # Don't modify identifiers.
14
+ # # Default behavior of Sequel on PostgreSQL, MySQL, SQLite,
15
+ # # as they fold unquoted identifiers to lowercase.
16
+ # DB.identifier_input_method = nil
17
+ # DB.identifier_output_method = nil
18
+ #
19
+ # You can also choose to turn on or off identifier quoting:
20
+ #
21
+ # # Quote identifiers. Sequel's default behavior.
22
+ # DB.quote_identifiers = true
23
+ #
24
+ # # Don't quote identifiers. Sequel's default behavior on DB2.
25
+ # DB.quote_identifiers = false
26
+ #
27
+ # To modify the identifiers on a per-dataset basis:
28
+ #
29
+ # ds = DB[:a].with_input_indentifier(:upcase).
30
+ # with_output_identifier(:downcase).
31
+ # with_quote_identifiers(true)
32
+ #
33
+ # To load the extension into the database:
34
+ #
35
+ # DB.extension :identifier_mangling
36
+ #
37
+ # Historically, Sequel supported these methods by default on
38
+ # Databases and Datasets. Sequel 4 will continue to support
39
+ # the methods for backwards compatibility, by loading this
40
+ # extension automatically for databases unless the
41
+ # <tt>:identifier_mangling=>false</tt> Database option is
42
+ # used.
43
+ #
44
+ # Related modules: Sequel::IdentifierMangling::DatabaseMethods,
45
+ # Sequel::IdentifierMangling::DatasetMethods
46
+
47
+ #
48
+ module Sequel
49
+ module IdentifierMangling
50
+ module DatabaseMethods
51
+ def self.extended(db)
52
+ db.instance_exec do
53
+ @identifier_input_method = nil
54
+ @identifier_output_method = nil
55
+ @quote_identifiers = nil
56
+ reset_identifier_mangling
57
+ extend_datasets(DatasetMethods)
58
+ end
59
+ end
60
+
61
+ # The identifier input method to use by default for this database (default: adapter default)
62
+ attr_reader :identifier_input_method
63
+
64
+ # The identifier output method to use by default for this database (default: adapter default)
65
+ attr_reader :identifier_output_method
66
+
67
+ # Set the method to call on identifiers going into the database:
68
+ #
69
+ # DB[:items] # SELECT * FROM items
70
+ # DB.identifier_input_method = :upcase
71
+ # DB[:items] # SELECT * FROM ITEMS
72
+ def identifier_input_method=(v)
73
+ reset_default_dataset
74
+ @identifier_input_method = v
75
+ end
76
+
77
+ # Set the method to call on identifiers coming from the database:
78
+ #
79
+ # DB[:items].first # {:id=>1, :name=>'foo'}
80
+ # DB.identifier_output_method = :upcase
81
+ # DB[:items].first # {:ID=>1, :NAME=>'foo'}
82
+ def identifier_output_method=(v)
83
+ reset_default_dataset
84
+ @identifier_output_method = v
85
+ end
86
+
87
+ # Set whether to quote identifiers (columns and tables) for this database:
88
+ #
89
+ # DB[:items] # SELECT * FROM items
90
+ # DB.quote_identifiers = true
91
+ # DB[:items] # SELECT * FROM "items"
92
+ def quote_identifiers=(v)
93
+ reset_default_dataset
94
+ @quote_identifiers = v
95
+ end
96
+
97
+ # Returns true if the database quotes identifiers.
98
+ def quote_identifiers?
99
+ @quote_identifiers
100
+ end
101
+
102
+ private
103
+
104
+ # Return a dataset that uses the default identifier input and output methods
105
+ # for this database. Used when parsing metadata so that column symbols are
106
+ # returned as expected.
107
+ def _metadata_dataset
108
+ super.
109
+ with_identifier_input_method(identifier_input_method_default).
110
+ with_identifier_output_method(identifier_output_method_default)
111
+ end
112
+
113
+ # Upcase identifiers on input if database folds unquoted identifiers to
114
+ # uppercase.
115
+ def identifier_input_method_default
116
+ return super if defined?(super)
117
+ :upcase if folds_unquoted_identifiers_to_uppercase?
118
+ end
119
+
120
+ # Downcase identifiers on output if database folds unquoted identifiers to
121
+ # uppercase.
122
+ def identifier_output_method_default
123
+ return super if defined?(super)
124
+ :downcase if folds_unquoted_identifiers_to_uppercase?
125
+ end
126
+
127
+ # Reset the identifier mangling options. Overrides any already set on
128
+ # the instance. Only for internal use by shared adapters.
129
+ def reset_identifier_mangling
130
+ @quote_identifiers = @opts.fetch(:quote_identifiers){(qi = Database.quote_identifiers).nil? ? quote_identifiers_default : qi}
131
+ @identifier_input_method = @opts.fetch(:identifier_input_method){(iim = Database.identifier_input_method).nil? ? identifier_input_method_default : (iim if iim)}
132
+ @identifier_output_method = @opts.fetch(:identifier_output_method){(iom = Database.identifier_output_method).nil? ? identifier_output_method_default : (iom if iom)}
133
+ reset_default_dataset
134
+ end
135
+ end
136
+
137
+ module DatasetMethods
138
+ # The String instance method to call on identifiers before sending them to
139
+ # the database.
140
+ def identifier_input_method
141
+ @opts.fetch(:identifier_input_method, db.identifier_input_method)
142
+ end
143
+
144
+ # Set the method to call on identifiers going into the database for this dataset
145
+ def identifier_input_method=(v)
146
+ raise_if_frozen!
147
+ skip_symbol_cache!
148
+ @opts[:identifier_input_method] = v
149
+ end
150
+
151
+ # The String instance method to call on identifiers before sending them to
152
+ # the database.
153
+ def identifier_output_method
154
+ @opts.fetch(:identifier_output_method, db.identifier_output_method)
155
+ end
156
+
157
+ # Set the method to call on identifiers coming the database for this dataset
158
+ def identifier_output_method=(v)
159
+ raise_if_frozen!
160
+ @opts[:identifier_output_method] = v
161
+ end
162
+
163
+ # Check with the database to see if identifier quoting is enabled
164
+ def quote_identifiers?
165
+ @opts.fetch(:quote_identifiers, db.quote_identifiers?)
166
+ end
167
+
168
+ # Return a modified dataset with identifier_input_method set.
169
+ def with_identifier_input_method(meth)
170
+ clone(:identifier_input_method=>meth, :skip_symbol_cache=>true)
171
+ end
172
+
173
+ # Return a modified dataset with identifier_output_method set.
174
+ def with_identifier_output_method(meth)
175
+ clone(:identifier_output_method=>meth)
176
+ end
177
+
178
+ private
179
+
180
+ # Convert the identifier to the version used in the database via
181
+ # identifier_input_method.
182
+ def input_identifier(v)
183
+ (i = identifier_input_method) ? v.to_s.send(i) : v.to_s
184
+ end
185
+
186
+ # Modify the identifier returned from the database based on the
187
+ # identifier_output_method.
188
+ def output_identifier(v)
189
+ v = 'untitled' if v == ''
190
+ (i = identifier_output_method) ? v.to_s.send(i).to_sym : v.to_sym
191
+ end
192
+ end
193
+ end
194
+
195
+ Database.register_extension(:identifier_mangling, IdentifierMangling::DatabaseMethods)
196
+ end
@@ -5,7 +5,7 @@
5
5
  #
6
6
  # :float :: use to_f instead of Float()
7
7
  # :integer :: use to_i instead of Integer()
8
- # :decimal :: don't check string conversion with Float()
8
+ # :decimal :: use 0.0 for unsupported strings
9
9
  # :string :: silently allow hash and array conversion to string
10
10
  #
11
11
  # To load the extension into the database:
@@ -17,6 +17,8 @@
17
17
  #
18
18
  module Sequel
19
19
  module LooserTypecasting
20
+ private
21
+
20
22
  # Typecast the value to a Float using to_f instead of Kernel.Float
21
23
  def typecast_value_float(value)
22
24
  value.to_f
@@ -32,13 +34,15 @@ module Sequel
32
34
  value.to_s
33
35
  end
34
36
 
35
- # Typecast the value to a BigDecimal, without checking if strings
36
- # have a valid format.
37
- def typecast_value_decimal(value)
38
- if value.is_a?(String)
37
+ if RUBY_VERSION >= '2.4'
38
+ def _typecast_value_string_to_decimal(value)
39
+ BigDecimal.new(value)
40
+ rescue
41
+ BigDecimal.new('0.0')
42
+ end
43
+ else
44
+ def _typecast_value_string_to_decimal(value)
39
45
  BigDecimal.new(value)
40
- else
41
- super
42
46
  end
43
47
  end
44
48
  end
@@ -687,7 +687,7 @@ module Sequel
687
687
  checked_transaction(m) do
688
688
  m.apply(db, direction)
689
689
  fi = f.downcase
690
- direction == :up ? ds.insert(column=>fi) : ds.filter(column=>fi).delete
690
+ direction == :up ? ds.insert(column=>fi) : ds.where(column=>fi).delete
691
691
  end
692
692
  db.log_info("Finished applying migration #{f}, direction: #{direction}, took #{sprintf('%0.6f', Time.now - t)} seconds")
693
693
  end
@@ -41,7 +41,7 @@ module Sequel
41
41
  module Nullifiable
42
42
  # Return a cloned nullified dataset.
43
43
  def nullify
44
- clone.nullify!
44
+ clone.with_extend(NullDataset)
45
45
  end
46
46
 
47
47
  # Nullify the current dataset
@@ -54,7 +54,10 @@ module Sequel
54
54
  # Create a new dataset from the dataset (which won't
55
55
  # be nulled) to get the columns if they aren't already cached.
56
56
  def columns
57
- @columns ||= db.dataset.clone(@opts).columns
57
+ if cols = _columns
58
+ return cols
59
+ end
60
+ self.columns = db.dataset.clone(@opts).columns
58
61
  end
59
62
 
60
63
  # Return 0 without sending a database query.
@@ -39,9 +39,14 @@ module Sequel
39
39
  # number of records for this dataset.
40
40
  def paginate(page_no, page_size, record_count=nil)
41
41
  raise(Error, "You cannot paginate a dataset that already has a limit") if @opts[:limit]
42
- paginated = limit(page_size, (page_no - 1) * page_size)
43
- paginated.extend(Dataset::Pagination)
44
- paginated.set_pagination_info(page_no, page_size, record_count || count)
42
+
43
+ record_count ||= count
44
+ page_count = (record_count / page_size.to_f).ceil
45
+ page_count = 1 if page_count == 0
46
+
47
+ limit(page_size, (page_no - 1) * page_size).
48
+ with_extend(Dataset::Pagination).
49
+ clone(:page_size=>page_size, :current_page=>page_no, :pagination_record_count=>record_count, :page_count=>page_count)
45
50
  end
46
51
 
47
52
  # Yields a paginated dataset for each page and returns the receiver. Does
@@ -61,49 +66,59 @@ module Sequel
61
66
  # Holds methods that only relate to paginated datasets. Paginated dataset
62
67
  # have pages starting at 1 (page 1 is offset 0, page 1 is offset page_size).
63
68
  module Pagination
69
+ Sequel::Dataset.def_deprecated_opts_setter(self, :page_size, :page_count, :current_page, :pagination_record_count)
70
+
64
71
  # The number of records per page (the final page may have fewer than
65
72
  # this number of records).
66
- attr_accessor :page_size
73
+ def page_size
74
+ @opts[:page_size]
75
+ end
67
76
 
68
77
  # The number of pages in the dataset before pagination, of which
69
78
  # this paginated dataset is one. Empty datasets are considered
70
79
  # to have a single page.
71
- attr_accessor :page_count
80
+ def page_count
81
+ @opts[:page_count]
82
+ end
72
83
 
73
84
  # The current page of the dataset, starting at 1 and not 0.
74
- attr_accessor :current_page
85
+ def current_page
86
+ @opts[:current_page]
87
+ end
75
88
 
76
89
  # The total number of records in the dataset before pagination.
77
- attr_accessor :pagination_record_count
90
+ def pagination_record_count
91
+ @opts[:pagination_record_count]
92
+ end
78
93
 
79
94
  # Returns the record range for the current page
80
95
  def current_page_record_range
81
- return (0..0) if @current_page > @page_count
96
+ return (0..0) if current_page > page_count
82
97
 
83
- a = 1 + (@current_page - 1) * @page_size
84
- b = a + @page_size - 1
85
- b = @pagination_record_count if b > @pagination_record_count
98
+ a = 1 + (current_page - 1) * page_size
99
+ b = a + page_size - 1
100
+ b = pagination_record_count if b > pagination_record_count
86
101
  a..b
87
102
  end
88
103
 
89
104
  # Returns the number of records in the current page
90
105
  def current_page_record_count
91
- return 0 if @current_page > @page_count
106
+ return 0 if current_page > page_count
92
107
 
93
- a = 1 + (@current_page - 1) * @page_size
94
- b = a + @page_size - 1
95
- b = @pagination_record_count if b > @pagination_record_count
108
+ a = 1 + (current_page - 1) * page_size
109
+ b = a + page_size - 1
110
+ b = pagination_record_count if b > pagination_record_count
96
111
  b - a + 1
97
112
  end
98
113
 
99
114
  # Returns true if the current page is the first page
100
115
  def first_page?
101
- @current_page == 1
116
+ current_page == 1
102
117
  end
103
118
 
104
119
  # Returns true if the current page is the last page
105
120
  def last_page?
106
- @current_page == @page_count
121
+ current_page == page_count
107
122
  end
108
123
 
109
124
  # Returns the next page number or nil if the current page is the last page
@@ -121,15 +136,19 @@ module Sequel
121
136
  current_page > 1 ? (current_page - 1) : nil
122
137
  end
123
138
 
124
- # Sets the pagination info for this paginated dataset, and returns self.
139
+ # SEQUEL5: Remove
140
+ # :nocov:
125
141
  def set_pagination_info(page_no, page_size, record_count)
126
- @current_page = page_no
127
- @page_size = page_size
128
- @pagination_record_count = record_count
129
- @page_count = (record_count / page_size.to_f).ceil
130
- @page_count = 1 if @page_count == 0
142
+ Sequel::Deprecation.deprecate("Dataset#set_pagination_info", "It should no longer be necessary to call this method.")
143
+ self.current_page = page_no
144
+ self.page_size = page_size
145
+ self.pagination_record_count = record_count
146
+ page_count = (record_count / page_size.to_f).ceil
147
+ page_count = 1 if page_count == 0
148
+ self.page_count = page_count
131
149
  self
132
150
  end
151
+ # :nocov:
133
152
  end
134
153
  end
135
154