sequel 3.47.0 → 3.48.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 (243) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +230 -0
  3. data/README.rdoc +31 -40
  4. data/Rakefile +1 -14
  5. data/doc/active_record.rdoc +29 -29
  6. data/doc/association_basics.rdoc +4 -13
  7. data/doc/cheat_sheet.rdoc +8 -6
  8. data/doc/code_order.rdoc +89 -0
  9. data/doc/core_extensions.rdoc +3 -3
  10. data/doc/dataset_basics.rdoc +7 -8
  11. data/doc/dataset_filtering.rdoc +7 -2
  12. data/doc/mass_assignment.rdoc +2 -3
  13. data/doc/migration.rdoc +8 -8
  14. data/doc/model_hooks.rdoc +11 -7
  15. data/doc/object_model.rdoc +2 -2
  16. data/doc/opening_databases.rdoc +5 -14
  17. data/doc/prepared_statements.rdoc +5 -9
  18. data/doc/querying.rdoc +23 -28
  19. data/doc/reflection.rdoc +11 -0
  20. data/doc/release_notes/3.48.0.txt +477 -0
  21. data/doc/schema_modification.rdoc +12 -5
  22. data/doc/security.rdoc +2 -2
  23. data/doc/sharding.rdoc +1 -2
  24. data/doc/sql.rdoc +10 -13
  25. data/doc/testing.rdoc +8 -4
  26. data/doc/transactions.rdoc +2 -2
  27. data/doc/validations.rdoc +40 -17
  28. data/doc/virtual_rows.rdoc +2 -2
  29. data/lib/sequel/adapters/ado.rb +25 -20
  30. data/lib/sequel/adapters/ado/access.rb +1 -0
  31. data/lib/sequel/adapters/ado/mssql.rb +1 -0
  32. data/lib/sequel/adapters/db2.rb +9 -7
  33. data/lib/sequel/adapters/dbi.rb +16 -16
  34. data/lib/sequel/adapters/do.rb +17 -18
  35. data/lib/sequel/adapters/do/mysql.rb +1 -0
  36. data/lib/sequel/adapters/do/postgres.rb +2 -0
  37. data/lib/sequel/adapters/do/sqlite.rb +1 -0
  38. data/lib/sequel/adapters/firebird.rb +5 -7
  39. data/lib/sequel/adapters/ibmdb.rb +23 -20
  40. data/lib/sequel/adapters/informix.rb +8 -2
  41. data/lib/sequel/adapters/jdbc.rb +39 -35
  42. data/lib/sequel/adapters/jdbc/as400.rb +1 -0
  43. data/lib/sequel/adapters/jdbc/cubrid.rb +1 -0
  44. data/lib/sequel/adapters/jdbc/db2.rb +1 -0
  45. data/lib/sequel/adapters/jdbc/derby.rb +1 -0
  46. data/lib/sequel/adapters/jdbc/firebird.rb +1 -0
  47. data/lib/sequel/adapters/jdbc/h2.rb +1 -0
  48. data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -0
  49. data/lib/sequel/adapters/jdbc/informix.rb +1 -0
  50. data/lib/sequel/adapters/jdbc/jtds.rb +1 -0
  51. data/lib/sequel/adapters/jdbc/mssql.rb +1 -0
  52. data/lib/sequel/adapters/jdbc/mysql.rb +1 -0
  53. data/lib/sequel/adapters/jdbc/oracle.rb +1 -0
  54. data/lib/sequel/adapters/jdbc/postgresql.rb +2 -0
  55. data/lib/sequel/adapters/jdbc/progress.rb +1 -0
  56. data/lib/sequel/adapters/jdbc/sqlite.rb +1 -0
  57. data/lib/sequel/adapters/jdbc/sqlserver.rb +1 -0
  58. data/lib/sequel/adapters/mock.rb +30 -31
  59. data/lib/sequel/adapters/mysql.rb +6 -7
  60. data/lib/sequel/adapters/mysql2.rb +5 -6
  61. data/lib/sequel/adapters/odbc.rb +22 -20
  62. data/lib/sequel/adapters/odbc/mssql.rb +1 -0
  63. data/lib/sequel/adapters/openbase.rb +4 -1
  64. data/lib/sequel/adapters/oracle.rb +10 -8
  65. data/lib/sequel/adapters/postgres.rb +12 -10
  66. data/lib/sequel/adapters/shared/access.rb +6 -0
  67. data/lib/sequel/adapters/shared/cubrid.rb +2 -0
  68. data/lib/sequel/adapters/shared/db2.rb +2 -0
  69. data/lib/sequel/adapters/shared/firebird.rb +2 -0
  70. data/lib/sequel/adapters/shared/informix.rb +2 -0
  71. data/lib/sequel/adapters/shared/mssql.rb +14 -8
  72. data/lib/sequel/adapters/shared/mysql.rb +6 -0
  73. data/lib/sequel/adapters/shared/oracle.rb +2 -0
  74. data/lib/sequel/adapters/shared/postgres.rb +14 -4
  75. data/lib/sequel/adapters/shared/progress.rb +1 -0
  76. data/lib/sequel/adapters/shared/sqlite.rb +4 -3
  77. data/lib/sequel/adapters/sqlite.rb +6 -7
  78. data/lib/sequel/adapters/swift.rb +20 -21
  79. data/lib/sequel/adapters/swift/mysql.rb +1 -0
  80. data/lib/sequel/adapters/swift/postgres.rb +2 -0
  81. data/lib/sequel/adapters/swift/sqlite.rb +1 -0
  82. data/lib/sequel/adapters/tinytds.rb +5 -6
  83. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +68 -0
  84. data/lib/sequel/connection_pool.rb +1 -1
  85. data/lib/sequel/core.rb +57 -50
  86. data/lib/sequel/database/connecting.rb +9 -10
  87. data/lib/sequel/database/dataset.rb +11 -6
  88. data/lib/sequel/database/dataset_defaults.rb +61 -69
  89. data/lib/sequel/database/features.rb +21 -0
  90. data/lib/sequel/database/misc.rb +23 -3
  91. data/lib/sequel/database/query.rb +13 -7
  92. data/lib/sequel/database/schema_methods.rb +6 -6
  93. data/lib/sequel/database/transactions.rb +1 -0
  94. data/lib/sequel/dataset/actions.rb +51 -38
  95. data/lib/sequel/dataset/features.rb +1 -0
  96. data/lib/sequel/dataset/graph.rb +9 -33
  97. data/lib/sequel/dataset/misc.rb +30 -5
  98. data/lib/sequel/dataset/mutation.rb +2 -3
  99. data/lib/sequel/dataset/prepared_statements.rb +1 -1
  100. data/lib/sequel/dataset/query.rb +91 -27
  101. data/lib/sequel/dataset/sql.rb +40 -6
  102. data/lib/sequel/deprecated.rb +74 -0
  103. data/lib/sequel/deprecated_core_extensions.rb +135 -0
  104. data/lib/sequel/extensions/columns_introspection.rb +1 -5
  105. data/lib/sequel/extensions/core_extensions.rb +10 -3
  106. data/lib/sequel/extensions/date_arithmetic.rb +1 -0
  107. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +33 -0
  108. data/lib/sequel/extensions/filter_having.rb +58 -0
  109. data/lib/sequel/extensions/graph_each.rb +63 -0
  110. data/lib/sequel/extensions/hash_aliases.rb +44 -0
  111. data/lib/sequel/extensions/looser_typecasting.rb +14 -3
  112. data/lib/sequel/extensions/migration.rb +2 -3
  113. data/lib/sequel/extensions/named_timezones.rb +14 -1
  114. data/lib/sequel/extensions/null_dataset.rb +7 -1
  115. data/lib/sequel/extensions/pagination.rb +15 -5
  116. data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -0
  117. data/lib/sequel/extensions/pg_hstore_ops.rb +48 -14
  118. data/lib/sequel/extensions/pg_json.rb +7 -7
  119. data/lib/sequel/extensions/pg_range_ops.rb +8 -2
  120. data/lib/sequel/extensions/pg_statement_cache.rb +1 -0
  121. data/lib/sequel/extensions/pretty_table.rb +13 -4
  122. data/lib/sequel/extensions/query.rb +21 -4
  123. data/lib/sequel/extensions/ruby18_symbol_extensions.rb +22 -0
  124. data/lib/sequel/extensions/schema_caching.rb +10 -7
  125. data/lib/sequel/extensions/schema_dumper.rb +35 -48
  126. data/lib/sequel/extensions/select_remove.rb +13 -4
  127. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +117 -0
  128. data/lib/sequel/extensions/set_overrides.rb +43 -0
  129. data/lib/sequel/extensions/to_dot.rb +6 -0
  130. data/lib/sequel/model.rb +12 -6
  131. data/lib/sequel/model/associations.rb +80 -38
  132. data/lib/sequel/model/base.rb +137 -52
  133. data/lib/sequel/model/errors.rb +7 -2
  134. data/lib/sequel/plugins/active_model.rb +13 -0
  135. data/lib/sequel/plugins/after_initialize.rb +43 -0
  136. data/lib/sequel/plugins/association_proxies.rb +63 -7
  137. data/lib/sequel/plugins/auto_validations.rb +56 -16
  138. data/lib/sequel/plugins/blacklist_security.rb +63 -0
  139. data/lib/sequel/plugins/class_table_inheritance.rb +9 -0
  140. data/lib/sequel/plugins/constraint_validations.rb +50 -8
  141. data/lib/sequel/plugins/dataset_associations.rb +2 -0
  142. data/lib/sequel/plugins/hook_class_methods.rb +7 -1
  143. data/lib/sequel/plugins/identity_map.rb +4 -0
  144. data/lib/sequel/plugins/json_serializer.rb +32 -13
  145. data/lib/sequel/plugins/optimistic_locking.rb +1 -1
  146. data/lib/sequel/plugins/rcte_tree.rb +4 -4
  147. data/lib/sequel/plugins/scissors.rb +33 -0
  148. data/lib/sequel/plugins/serialization.rb +1 -1
  149. data/lib/sequel/plugins/single_table_inheritance.rb +6 -0
  150. data/lib/sequel/plugins/tree.rb +5 -1
  151. data/lib/sequel/plugins/validation_class_methods.rb +2 -1
  152. data/lib/sequel/plugins/validation_helpers.rb +15 -11
  153. data/lib/sequel/plugins/xml_serializer.rb +12 -3
  154. data/lib/sequel/sql.rb +12 -2
  155. data/lib/sequel/timezones.rb +1 -1
  156. data/lib/sequel/version.rb +1 -1
  157. data/lib/sequel_core.rb +1 -0
  158. data/lib/sequel_model.rb +1 -0
  159. data/spec/adapters/mssql_spec.rb +24 -57
  160. data/spec/adapters/postgres_spec.rb +27 -55
  161. data/spec/adapters/spec_helper.rb +1 -1
  162. data/spec/adapters/sqlite_spec.rb +1 -1
  163. data/spec/bin_spec.rb +251 -0
  164. data/spec/core/database_spec.rb +46 -32
  165. data/spec/core/dataset_spec.rb +233 -181
  166. data/spec/core/deprecated_spec.rb +78 -0
  167. data/spec/core/expression_filters_spec.rb +3 -4
  168. data/spec/core/mock_adapter_spec.rb +9 -9
  169. data/spec/core/object_graph_spec.rb +9 -19
  170. data/spec/core/schema_spec.rb +3 -1
  171. data/spec/core/spec_helper.rb +19 -0
  172. data/spec/core_extensions_spec.rb +80 -30
  173. data/spec/extensions/after_initialize_spec.rb +24 -0
  174. data/spec/extensions/association_proxies_spec.rb +37 -1
  175. data/spec/extensions/auto_validations_spec.rb +20 -4
  176. data/spec/extensions/blacklist_security_spec.rb +87 -0
  177. data/spec/extensions/boolean_readers_spec.rb +2 -1
  178. data/spec/extensions/class_table_inheritance_spec.rb +7 -0
  179. data/spec/extensions/columns_introspection_spec.rb +3 -3
  180. data/spec/extensions/constraint_validations_plugin_spec.rb +83 -5
  181. data/spec/extensions/core_refinements_spec.rb +7 -7
  182. data/spec/extensions/dataset_associations_spec.rb +2 -2
  183. data/spec/extensions/date_arithmetic_spec.rb +1 -1
  184. data/spec/extensions/defaults_setter_spec.rb +2 -1
  185. data/spec/extensions/empty_array_ignore_nulls_spec.rb +24 -0
  186. data/spec/extensions/filter_having_spec.rb +40 -0
  187. data/spec/extensions/graph_each_spec.rb +109 -0
  188. data/spec/extensions/hash_aliases_spec.rb +16 -0
  189. data/spec/extensions/hook_class_methods_spec.rb +2 -2
  190. data/spec/extensions/identity_map_spec.rb +3 -3
  191. data/spec/extensions/json_serializer_spec.rb +19 -19
  192. data/spec/extensions/lazy_attributes_spec.rb +1 -0
  193. data/spec/extensions/list_spec.rb +13 -13
  194. data/spec/extensions/looser_typecasting_spec.rb +10 -3
  195. data/spec/extensions/many_through_many_spec.rb +1 -1
  196. data/spec/extensions/migration_spec.rb +7 -7
  197. data/spec/extensions/named_timezones_spec.rb +6 -0
  198. data/spec/extensions/nested_attributes_spec.rb +2 -2
  199. data/spec/extensions/null_dataset_spec.rb +1 -1
  200. data/spec/extensions/pagination_spec.rb +2 -2
  201. data/spec/extensions/pg_hstore_ops_spec.rb +75 -0
  202. data/spec/extensions/pg_range_ops_spec.rb +4 -2
  203. data/spec/extensions/pg_row_plugin_spec.rb +1 -1
  204. data/spec/extensions/pretty_table_spec.rb +1 -1
  205. data/spec/extensions/query_literals_spec.rb +1 -1
  206. data/spec/extensions/query_spec.rb +3 -3
  207. data/spec/extensions/schema_caching_spec.rb +3 -3
  208. data/spec/extensions/schema_dumper_spec.rb +27 -2
  209. data/spec/extensions/schema_spec.rb +2 -2
  210. data/spec/extensions/scissors_spec.rb +26 -0
  211. data/spec/extensions/select_remove_spec.rb +1 -1
  212. data/spec/extensions/sequel_3_dataset_methods_spec.rb +102 -0
  213. data/spec/extensions/set_overrides_spec.rb +45 -0
  214. data/spec/extensions/single_table_inheritance_spec.rb +10 -0
  215. data/spec/extensions/spec_helper.rb +24 -1
  216. data/spec/extensions/static_cache_spec.rb +1 -1
  217. data/spec/extensions/string_stripper_spec.rb +2 -1
  218. data/spec/extensions/to_dot_spec.rb +1 -1
  219. data/spec/extensions/typecast_on_load_spec.rb +3 -2
  220. data/spec/extensions/update_primary_key_spec.rb +2 -2
  221. data/spec/extensions/validation_class_methods_spec.rb +19 -19
  222. data/spec/extensions/validation_helpers_spec.rb +30 -21
  223. data/spec/extensions/xml_serializer_spec.rb +5 -5
  224. data/spec/integration/associations_test.rb +10 -30
  225. data/spec/integration/dataset_test.rb +20 -24
  226. data/spec/integration/eager_loader_test.rb +5 -5
  227. data/spec/integration/model_test.rb +3 -3
  228. data/spec/integration/plugin_test.rb +7 -39
  229. data/spec/integration/schema_test.rb +4 -38
  230. data/spec/integration/spec_helper.rb +2 -1
  231. data/spec/model/association_reflection_spec.rb +70 -5
  232. data/spec/model/associations_spec.rb +11 -11
  233. data/spec/model/base_spec.rb +25 -8
  234. data/spec/model/class_dataset_methods_spec.rb +143 -0
  235. data/spec/model/dataset_methods_spec.rb +1 -1
  236. data/spec/model/eager_loading_spec.rb +25 -25
  237. data/spec/model/hooks_spec.rb +1 -1
  238. data/spec/model/model_spec.rb +22 -7
  239. data/spec/model/plugins_spec.rb +1 -6
  240. data/spec/model/record_spec.rb +37 -29
  241. data/spec/model/spec_helper.rb +23 -1
  242. data/spec/model/validations_spec.rb +15 -17
  243. metadata +32 -3
@@ -0,0 +1,63 @@
1
+ # The graph_each extension adds Dataset#graph_each and
2
+ # makes Dataset#each call #graph_each if the dataset has been graphed.
3
+ # Dataset#graph_each splits result hashes into subhashes per table:
4
+ #
5
+ # DB[:a].graph(:b, :id=>:b_id).all
6
+ # # => {:a=>{:id=>1, :b_id=>2}, :b=>{:id=>2}}
7
+ #
8
+ # You can load this extension into specific datasets:
9
+ #
10
+ # ds = DB[:table]
11
+ # ds.extension(:graph_each)
12
+ #
13
+ # Or you can load it into all of a database's datasets, which
14
+ # is probably the desired behavior if you are using this extension:
15
+ #
16
+ # DB.extension(:graph_each)
17
+
18
+ module Sequel
19
+ module GraphEach
20
+ # Fetch the rows, split them into component table parts,
21
+ # tranform and run the row_proc on each part (if applicable),
22
+ # and yield a hash of the parts.
23
+ def graph_each
24
+ # Reject tables with nil datasets, as they are excluded from
25
+ # the result set
26
+ datasets = @opts[:graph][:table_aliases].to_a.reject{|ta,ds| ds.nil?}
27
+ # Get just the list of table aliases into a local variable, for speed
28
+ table_aliases = datasets.collect{|ta,ds| ta}
29
+ # Get an array of arrays, one for each dataset, with
30
+ # the necessary information about each dataset, for speed
31
+ datasets = datasets.collect{|ta, ds| [ta, ds, ds.row_proc]}
32
+ # Use the manually set graph aliases, if any, otherwise
33
+ # use the ones automatically created by .graph
34
+ column_aliases = @opts[:graph_aliases] || @opts[:graph][:column_aliases]
35
+ fetch_rows(select_sql) do |r|
36
+ graph = {}
37
+ # Create the sub hashes, one per table
38
+ table_aliases.each{|ta| graph[ta]={}}
39
+ # Split the result set based on the column aliases
40
+ # If there are columns in the result set that are
41
+ # not in column_aliases, they are ignored
42
+ column_aliases.each do |col_alias, tc|
43
+ ta, column = tc
44
+ graph[ta][column] = r[col_alias]
45
+ end
46
+ # For each dataset run the row_proc if applicable
47
+ datasets.each do |ta,ds,rp|
48
+ g = graph[ta]
49
+ graph[ta] = if g.values.any?{|x| !x.nil?}
50
+ rp ? rp.call(g) : g
51
+ else
52
+ nil
53
+ end
54
+ end
55
+
56
+ yield graph
57
+ end
58
+ self
59
+ end
60
+ end
61
+
62
+ Dataset.register_extension(:graph_each, GraphEach)
63
+ end
@@ -0,0 +1,44 @@
1
+ # The hash_aliases extension allows Dataset#select and Dataset#from
2
+ # to treat a hash argument as an alias specification, with keys
3
+ # being the expressions and values being the aliases,
4
+ # which was the historical behavior before Sequel 4.
5
+ # It is only recommended to use this for backwards compatibility.
6
+ #
7
+ # You can load this extension into specific datasets:
8
+ #
9
+ # ds = DB[:table]
10
+ # ds.extension(:hash_aliases)
11
+ #
12
+ # Or you can load it into all of a database's datasets, which
13
+ # is probably the desired behavior if you are using this extension:
14
+ #
15
+ # DB.extension(:hash_aliases)
16
+
17
+ module Sequel
18
+ module HashAliases
19
+ def from(*source)
20
+ super(*convert_hash_aliases(source))
21
+ end
22
+
23
+ def select(*columns, &block)
24
+ virtual_row_columns(columns, block)
25
+ super(*convert_hash_aliases(columns), &nil)
26
+ end
27
+
28
+ private
29
+
30
+ def convert_hash_aliases(columns)
31
+ m = []
32
+ columns.each do |i|
33
+ if i.is_a?(Hash)
34
+ m.concat(i.map{|k, v| SQL::AliasedExpression.new(k,v)})
35
+ else
36
+ m << i
37
+ end
38
+ end
39
+ m
40
+ end
41
+ end
42
+
43
+ Dataset.register_extension(:hash_aliases, HashAliases)
44
+ end
@@ -1,6 +1,12 @@
1
- # The LooserTypecasting extension changes the float and integer typecasting to
2
- # use the looser .to_f and .to_i instead of the more strict Kernel.Float and
3
- # Kernel.Integer. To load the extension into the database:
1
+ # The LooserTypecasting extension loosens the default database typecasting
2
+ # for the following types:
3
+ #
4
+ # :float :: use to_f instead of Float()
5
+ # :integer :: use to_i instead of Integer()
6
+ # :decimal :: don't check string conversion with Float()
7
+ # :string :: silently allow hash and array conversion to string
8
+ #
9
+ # To load the extension into the database:
4
10
  #
5
11
  # DB.extension :looser_typecasting
6
12
 
@@ -16,6 +22,11 @@ module Sequel
16
22
  value.to_i
17
23
  end
18
24
 
25
+ # Typecast the value to an Integer using to_i instead of Kernel.Integer
26
+ def typecast_value_string(value)
27
+ value.to_s
28
+ end
29
+
19
30
  # Typecast the value to a BigDecimal, without checking if strings
20
31
  # have a valid format.
21
32
  def typecast_value_decimal(value)
@@ -583,9 +583,8 @@ module Sequel
583
583
  def schema_dataset
584
584
  c = column
585
585
  ds = db.from(table)
586
- if !db.table_exists?(table)
587
- db.create_table(table){Integer c, :default=>0, :null=>false}
588
- elsif !ds.columns.include?(c)
586
+ db.create_table?(table){Integer c, :default=>0, :null=>false}
587
+ unless ds.columns.include?(c)
589
588
  db.alter_table(table){add_column c, Integer, :default=>0, :null=>false}
590
589
  end
591
590
  ds.insert(c=>0) if ds.empty?
@@ -26,6 +26,12 @@
26
26
  # York time. When data is retrieved from the database, it is
27
27
  # converted to Los Angeles time.
28
28
  #
29
+ # If you are using database specific timezones, you may want to load
30
+ # this extension into the database in order to support similar API:
31
+ #
32
+ # DB.extension :named_timezones
33
+ # DB.timezone = 'America/New_York'
34
+ #
29
35
  # Note that typecasting from the database timezone to the application
30
36
  # timezone when fetching rows is dependent on the database adapter,
31
37
  # and only works on adapters where Sequel itself does the conversion.
@@ -37,6 +43,12 @@ module Sequel
37
43
  self.datetime_class = DateTime
38
44
 
39
45
  module NamedTimezones
46
+ module DatabaseMethods
47
+ def timezone=(tz)
48
+ super(Sequel.send(:convert_timezone_setter_arg, tz))
49
+ end
50
+ end
51
+
40
52
  # Handles TZInfo::AmbiguousTime exceptions automatically by providing a
41
53
  # proc called with both the datetime value being converted as well as
42
54
  # the array of TZInfo::TimezonePeriod results. Example:
@@ -47,7 +59,7 @@ module Sequel
47
59
  private
48
60
 
49
61
  # Assume the given DateTime has a correct time but a wrong timezone. It is
50
- # currently in UTC timezone, but it should be converted to the input_timzone.
62
+ # currently in UTC timezone, but it should be converted to the input_timezone.
51
63
  # Keep the time the same but convert the timezone to the input_timezone.
52
64
  # Expects the input_timezone to be a TZInfo::Timezone instance.
53
65
  def convert_input_datetime_other(v, input_timezone)
@@ -82,4 +94,5 @@ module Sequel
82
94
  end
83
95
 
84
96
  extend NamedTimezones
97
+ Database.register_extension(:named_timezones, NamedTimezones::DatabaseMethods)
85
98
  end
@@ -29,11 +29,14 @@
29
29
 
30
30
  module Sequel
31
31
  class Dataset
32
+ module Nullifiable
33
+ end
34
+
32
35
  module NullDataset
33
36
  # Create a new dataset from the dataset (which won't
34
37
  # be nulled) to get the columns if they aren't already cached.
35
38
  def columns
36
- @columns ||= db.dataset(@opts).columns
39
+ @columns ||= db.dataset.clone(@opts).columns
37
40
  end
38
41
 
39
42
  # Return 0 without sending a database query.
@@ -90,7 +93,10 @@ module Sequel
90
93
 
91
94
  # Nullify the current dataset
92
95
  def nullify!
96
+ Sequel::Deprecation.deprecate('Loading the null_dataset extension globally', "Please use Database/Dataset#extension to load the extension into this dataset") unless is_a?(Nullifiable)
93
97
  extend NullDataset
94
98
  end
95
99
  end
100
+
101
+ Dataset.register_extension(:null_dataset, Dataset::Nullifiable)
96
102
  end
@@ -2,19 +2,29 @@
2
2
  # which return paginated (limited and offset) datasets with some helpful methods
3
3
  # that make creating a paginated display easier.
4
4
  #
5
- # To load the extension:
5
+ # This extension uses Object#extend at runtime, which can hurt performance.
6
6
  #
7
- # Sequel.extension :pagination
7
+ # You can load this extension into specific datasets:
8
8
  #
9
- # This extension uses Object#extend at runtime, which can hurt performance.
9
+ # ds = DB[:table]
10
+ # ds.extension(:pagination)
11
+ #
12
+ # Or you can load it into all of a database's datasets, which
13
+ # is probably the desired behavior if you are using this extension:
14
+ #
15
+ # DB.extension(:pagination)
10
16
 
11
17
  module Sequel
18
+ module DatasetPagination
19
+ end
20
+
12
21
  class Dataset
13
22
  # Returns a paginated dataset. The returned dataset is limited to
14
23
  # the page size at the correct offset, and extended with the Pagination
15
24
  # module. If a record count is not provided, does a count of total
16
25
  # number of records for this dataset.
17
26
  def paginate(page_no, page_size, record_count=nil)
27
+ Sequel::Deprecation.deprecate('Loading the pagination extension globally', "Please use Database/Dataset#extension to load the extension into this dataset") unless is_a?(DatasetPagination)
18
28
  raise(Error, "You cannot paginate a dataset that already has a limit") if @opts[:limit]
19
29
  paginated = limit(page_size, (page_no - 1) * page_size)
20
30
  paginated.extend(Pagination)
@@ -24,6 +34,7 @@ module Sequel
24
34
  # Yields a paginated dataset for each page and returns the receiver. Does
25
35
  # a count to find the total number of records for this dataset.
26
36
  def each_page(page_size)
37
+ Sequel::Deprecation.deprecate('Loading the pagination extension globally', "Please use Database/Dataset#extension to load the extension into this dataset") unless is_a?(DatasetPagination)
27
38
  raise(Error, "You cannot paginate a dataset that already has a limit") if @opts[:limit]
28
39
  record_count = count
29
40
  total_pages = (record_count / page_size.to_f).ceil
@@ -104,6 +115,5 @@ module Sequel
104
115
  end
105
116
  end
106
117
 
107
- Database.register_extension(:pagination){}
108
- Dataset.register_extension(:pagination){}
118
+ Dataset.register_extension(:pagination, DatasetPagination)
109
119
  end
@@ -91,6 +91,7 @@ module Sequel
91
91
  module DatabaseMethods
92
92
  # Extend the database's datasets with the necessary code.
93
93
  def self.extended(db)
94
+ Sequel::Deprecation.deprecate('The pg_auto_parameterize extension', 'Please stop loading it') unless defined?(SEQUEL_EXTENSIONS_NO_DEPRECATION_WARNING)
94
95
  db.extend_datasets(DatasetMethods)
95
96
  end
96
97
 
@@ -82,8 +82,10 @@ module Sequel
82
82
  #
83
83
  # hstore_op - 'a' # (hstore - 'a')
84
84
  def -(other)
85
- if other.is_a?(String) && !other.is_a?(Sequel::LiteralString)
86
- other = Sequel.cast_string(other)
85
+ other = if other.is_a?(String) && !other.is_a?(Sequel::LiteralString)
86
+ Sequel.cast_string(other)
87
+ else
88
+ wrap_input_array(wrap_input_hash(other))
87
89
  end
88
90
  HStoreOp.new(super)
89
91
  end
@@ -92,35 +94,40 @@ module Sequel
92
94
  #
93
95
  # hstore_op['a'] # (hstore -> 'a')
94
96
  def [](key)
95
- Sequel::SQL::StringExpression.new(:NOOP, Sequel::SQL::PlaceholderLiteralString.new(LOOKUP, [value, key]))
97
+ v = Sequel::SQL::PlaceholderLiteralString.new(LOOKUP, [value, wrap_input_array(key)])
98
+ if key.is_a?(Array) || (defined?(Sequel::Postgres::PGArray) && key.is_a?(Sequel::Postgres::PGArray)) || (defined?(Sequel::Postgres::ArrayOp) && key.is_a?(Sequel::Postgres::ArrayOp))
99
+ wrap_output_array(v)
100
+ else
101
+ Sequel::SQL::StringExpression.new(:NOOP, v)
102
+ end
96
103
  end
97
104
 
98
105
  # Check if the receiver contains all of the keys in the given array:
99
106
  #
100
107
  # hstore_op.contain_all(:a) # (hstore ?& a)
101
108
  def contain_all(other)
102
- bool_op(CONTAIN_ALL, other)
109
+ bool_op(CONTAIN_ALL, wrap_input_array(other))
103
110
  end
104
111
 
105
112
  # Check if the receiver contains any of the keys in the given array:
106
113
  #
107
114
  # hstore_op.contain_any(:a) # (hstore ?| a)
108
115
  def contain_any(other)
109
- bool_op(CONTAIN_ANY, other)
116
+ bool_op(CONTAIN_ANY, wrap_input_array(other))
110
117
  end
111
118
 
112
119
  # Check if the receiver contains all entries in the other hstore:
113
120
  #
114
121
  # hstore_op.contains(:h) # (hstore @> h)
115
122
  def contains(other)
116
- bool_op(CONTAINS, other)
123
+ bool_op(CONTAINS, wrap_input_hash(other))
117
124
  end
118
125
 
119
126
  # Check if the other hstore contains all entries in the receiver:
120
127
  #
121
128
  # hstore_op.contained_by(:h) # (hstore <@ h)
122
129
  def contained_by(other)
123
- bool_op(CONTAINED_BY, other)
130
+ bool_op(CONTAINED_BY, wrap_input_hash(other))
124
131
  end
125
132
 
126
133
  # Check if the receiver contains a non-NULL value for the given key:
@@ -134,7 +141,7 @@ module Sequel
134
141
  #
135
142
  # hstore_op.delete('a') # delete(hstore, 'a')
136
143
  def delete(key)
137
- HStoreOp.new(function(:delete, key))
144
+ HStoreOp.new(function(:delete, wrap_input_array(wrap_input_hash(key))))
138
145
  end
139
146
 
140
147
  # Transform the receiver into a set of keys and values:
@@ -164,7 +171,7 @@ module Sequel
164
171
  #
165
172
  # hstore_op.keys # akeys(hstore)
166
173
  def keys
167
- function(:akeys)
174
+ wrap_output_array(function(:akeys))
168
175
  end
169
176
  alias akeys keys
170
177
 
@@ -172,7 +179,7 @@ module Sequel
172
179
  #
173
180
  # hstore_op.merge(:a) # (hstore || a)
174
181
  def merge(other)
175
- HStoreOp.new(Sequel::SQL::PlaceholderLiteralString.new(CONCAT, [self, other]))
182
+ HStoreOp.new(Sequel::SQL::PlaceholderLiteralString.new(CONCAT, [self, wrap_input_hash(other)]))
176
183
  end
177
184
  alias concat merge
178
185
 
@@ -201,7 +208,7 @@ module Sequel
201
208
  #
202
209
  # hstore_op.slice(:a) # slice(hstore, a)
203
210
  def slice(keys)
204
- HStoreOp.new(function(:slice, keys))
211
+ HStoreOp.new(function(:slice, wrap_input_array(keys)))
205
212
  end
206
213
 
207
214
  # Return the values as a PostgreSQL set:
@@ -216,7 +223,7 @@ module Sequel
216
223
  #
217
224
  # hstore_op.to_array # hstore_to_array(hstore)
218
225
  def to_array
219
- function(:hstore_to_array)
226
+ wrap_output_array(function(:hstore_to_array))
220
227
  end
221
228
 
222
229
  # Return a nested array of the receiver, with arrays of
@@ -224,14 +231,14 @@ module Sequel
224
231
  #
225
232
  # hstore_op.to_matrix # hstore_to_matrix(hstore)
226
233
  def to_matrix
227
- function(:hstore_to_matrix)
234
+ wrap_output_array(function(:hstore_to_matrix))
228
235
  end
229
236
 
230
237
  # Return the values as a PostgreSQL array:
231
238
  #
232
239
  # hstore_op.values # avals(hstore)
233
240
  def values
234
- function(:avals)
241
+ wrap_output_array(function(:avals))
235
242
  end
236
243
  alias avals values
237
244
 
@@ -248,6 +255,33 @@ module Sequel
248
255
  def function(name, *args)
249
256
  SQL::Function.new(name, self, *args)
250
257
  end
258
+
259
+ # Wrap argument in a PGArray if it is an array
260
+ def wrap_input_array(obj)
261
+ if obj.is_a?(Array) && Sequel.respond_to?(:pg_array)
262
+ Sequel.pg_array(obj)
263
+ else
264
+ obj
265
+ end
266
+ end
267
+
268
+ # Wrap argument in an Hstore if it is a hash
269
+ def wrap_input_hash(obj)
270
+ if obj.is_a?(Hash) && Sequel.respond_to?(:hstore)
271
+ Sequel.hstore(obj)
272
+ else
273
+ obj
274
+ end
275
+ end
276
+
277
+ # Wrap argument in a PGArrayOp if supported
278
+ def wrap_output_array(obj)
279
+ if Sequel.respond_to?(:pg_array_op)
280
+ Sequel.pg_array_op(obj)
281
+ else
282
+ obj
283
+ end
284
+ end
251
285
  end
252
286
 
253
287
  module HStoreOpMethods
@@ -66,11 +66,11 @@ module Sequel
66
66
  class JSONArray < DelegateClass(Array)
67
67
  include Sequel::SQL::AliasMethods
68
68
 
69
- # Convert the array to a string using to_json, append a
69
+ # Convert the array to a json string, append a
70
70
  # literalized version of the string to the sql, and explicitly
71
71
  # cast the string to json.
72
72
  def sql_literal_append(ds, sql)
73
- ds.literal_append(sql, to_json)
73
+ ds.literal_append(sql, Sequel.object_to_json(self))
74
74
  sql << CAST_JSON
75
75
  end
76
76
  end
@@ -79,11 +79,11 @@ module Sequel
79
79
  class JSONHash < DelegateClass(Hash)
80
80
  include Sequel::SQL::AliasMethods
81
81
 
82
- # Convert the array to a string using to_json, append a
82
+ # Convert the hash to a json string, append a
83
83
  # literalized version of the string to the sql, and explicitly
84
84
  # cast the string to json.
85
85
  def sql_literal_append(ds, sql)
86
- ds.literal_append(sql, to_json)
86
+ ds.literal_append(sql, Sequel.object_to_json(self))
87
87
  sql << CAST_JSON
88
88
  end
89
89
 
@@ -106,7 +106,7 @@ module Sequel
106
106
  def self.parse_json(s)
107
107
  begin
108
108
  value = Sequel.parse_json(s)
109
- rescue JSON::ParserError=>e
109
+ rescue Sequel.json_parser_error_class => e
110
110
  raise Sequel.convert_exception_class(e, Sequel::InvalidValue)
111
111
  end
112
112
 
@@ -124,7 +124,7 @@ module Sequel
124
124
  def bound_variable_arg(arg, conn)
125
125
  case arg
126
126
  when JSONArray, JSONHash
127
- arg.to_json
127
+ Sequel.object_to_json(arg)
128
128
  else
129
129
  super
130
130
  end
@@ -136,7 +136,7 @@ module Sequel
136
136
  def bound_variable_array(a)
137
137
  case a
138
138
  when JSONHash, JSONArray
139
- "\"#{a.to_json.gsub('"', '\\"')}\""
139
+ "\"#{Sequel.object_to_json(a).gsub('"', '\\"')}\""
140
140
  else
141
141
  super
142
142
  end