sequel 3.47.0 → 3.48.0

Sign up to get free protection for your applications and to get access to all the features.
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