sequel 3.46.0 → 3.47.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (170) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +96 -0
  3. data/Rakefile +7 -1
  4. data/bin/sequel +6 -4
  5. data/doc/active_record.rdoc +1 -1
  6. data/doc/advanced_associations.rdoc +14 -35
  7. data/doc/association_basics.rdoc +66 -4
  8. data/doc/migration.rdoc +4 -0
  9. data/doc/opening_databases.rdoc +6 -0
  10. data/doc/postgresql.rdoc +302 -0
  11. data/doc/release_notes/3.47.0.txt +270 -0
  12. data/doc/security.rdoc +6 -0
  13. data/lib/sequel/adapters/ibmdb.rb +9 -9
  14. data/lib/sequel/adapters/jdbc.rb +22 -7
  15. data/lib/sequel/adapters/jdbc/postgresql.rb +7 -2
  16. data/lib/sequel/adapters/mock.rb +2 -0
  17. data/lib/sequel/adapters/postgres.rb +44 -13
  18. data/lib/sequel/adapters/shared/mssql.rb +1 -1
  19. data/lib/sequel/adapters/shared/mysql.rb +2 -2
  20. data/lib/sequel/adapters/shared/postgres.rb +94 -55
  21. data/lib/sequel/adapters/shared/sqlite.rb +3 -1
  22. data/lib/sequel/adapters/sqlite.rb +2 -2
  23. data/lib/sequel/adapters/utils/pg_types.rb +1 -14
  24. data/lib/sequel/adapters/utils/split_alter_table.rb +3 -3
  25. data/lib/sequel/connection_pool/threaded.rb +1 -1
  26. data/lib/sequel/core.rb +1 -1
  27. data/lib/sequel/database/connecting.rb +2 -2
  28. data/lib/sequel/database/features.rb +5 -0
  29. data/lib/sequel/database/misc.rb +47 -5
  30. data/lib/sequel/database/query.rb +2 -2
  31. data/lib/sequel/dataset/actions.rb +4 -2
  32. data/lib/sequel/dataset/misc.rb +1 -1
  33. data/lib/sequel/dataset/prepared_statements.rb +1 -1
  34. data/lib/sequel/dataset/query.rb +8 -6
  35. data/lib/sequel/dataset/sql.rb +8 -6
  36. data/lib/sequel/extensions/constraint_validations.rb +5 -2
  37. data/lib/sequel/extensions/migration.rb +10 -8
  38. data/lib/sequel/extensions/pagination.rb +3 -0
  39. data/lib/sequel/extensions/pg_array.rb +85 -25
  40. data/lib/sequel/extensions/pg_hstore.rb +8 -1
  41. data/lib/sequel/extensions/pg_hstore_ops.rb +4 -1
  42. data/lib/sequel/extensions/pg_inet.rb +16 -13
  43. data/lib/sequel/extensions/pg_interval.rb +6 -2
  44. data/lib/sequel/extensions/pg_json.rb +18 -11
  45. data/lib/sequel/extensions/pg_range.rb +17 -2
  46. data/lib/sequel/extensions/pg_range_ops.rb +7 -5
  47. data/lib/sequel/extensions/pg_row.rb +29 -12
  48. data/lib/sequel/extensions/pretty_table.rb +3 -0
  49. data/lib/sequel/extensions/query.rb +3 -0
  50. data/lib/sequel/extensions/schema_caching.rb +2 -0
  51. data/lib/sequel/extensions/schema_dumper.rb +3 -1
  52. data/lib/sequel/extensions/select_remove.rb +3 -0
  53. data/lib/sequel/model.rb +8 -2
  54. data/lib/sequel/model/associations.rb +39 -27
  55. data/lib/sequel/model/base.rb +99 -38
  56. data/lib/sequel/model/plugins.rb +25 -0
  57. data/lib/sequel/plugins/association_autoreloading.rb +27 -22
  58. data/lib/sequel/plugins/association_dependencies.rb +1 -7
  59. data/lib/sequel/plugins/auto_validations.rb +110 -0
  60. data/lib/sequel/plugins/boolean_readers.rb +1 -6
  61. data/lib/sequel/plugins/caching.rb +6 -13
  62. data/lib/sequel/plugins/class_table_inheritance.rb +1 -0
  63. data/lib/sequel/plugins/composition.rb +14 -7
  64. data/lib/sequel/plugins/constraint_validations.rb +2 -13
  65. data/lib/sequel/plugins/defaults_setter.rb +1 -6
  66. data/lib/sequel/plugins/dirty.rb +8 -0
  67. data/lib/sequel/plugins/error_splitter.rb +54 -0
  68. data/lib/sequel/plugins/force_encoding.rb +1 -5
  69. data/lib/sequel/plugins/hook_class_methods.rb +1 -6
  70. data/lib/sequel/plugins/input_transformer.rb +79 -0
  71. data/lib/sequel/plugins/instance_filters.rb +7 -1
  72. data/lib/sequel/plugins/instance_hooks.rb +7 -1
  73. data/lib/sequel/plugins/json_serializer.rb +5 -10
  74. data/lib/sequel/plugins/lazy_attributes.rb +20 -7
  75. data/lib/sequel/plugins/list.rb +1 -6
  76. data/lib/sequel/plugins/many_through_many.rb +1 -2
  77. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +23 -39
  78. data/lib/sequel/plugins/optimistic_locking.rb +1 -5
  79. data/lib/sequel/plugins/pg_row.rb +4 -2
  80. data/lib/sequel/plugins/pg_typecast_on_load.rb +3 -7
  81. data/lib/sequel/plugins/prepared_statements.rb +1 -5
  82. data/lib/sequel/plugins/prepared_statements_safe.rb +2 -11
  83. data/lib/sequel/plugins/rcte_tree.rb +2 -2
  84. data/lib/sequel/plugins/serialization.rb +11 -13
  85. data/lib/sequel/plugins/serialization_modification_detection.rb +13 -1
  86. data/lib/sequel/plugins/single_table_inheritance.rb +4 -4
  87. data/lib/sequel/plugins/static_cache.rb +67 -19
  88. data/lib/sequel/plugins/string_stripper.rb +7 -27
  89. data/lib/sequel/plugins/subclasses.rb +3 -5
  90. data/lib/sequel/plugins/tactical_eager_loading.rb +2 -2
  91. data/lib/sequel/plugins/timestamps.rb +2 -7
  92. data/lib/sequel/plugins/touch.rb +5 -8
  93. data/lib/sequel/plugins/tree.rb +1 -6
  94. data/lib/sequel/plugins/typecast_on_load.rb +1 -5
  95. data/lib/sequel/plugins/update_primary_key.rb +26 -14
  96. data/lib/sequel/plugins/validation_class_methods.rb +31 -16
  97. data/lib/sequel/plugins/validation_helpers.rb +50 -26
  98. data/lib/sequel/plugins/xml_serializer.rb +3 -6
  99. data/lib/sequel/sql.rb +1 -1
  100. data/lib/sequel/version.rb +1 -1
  101. data/spec/adapters/postgres_spec.rb +131 -15
  102. data/spec/adapters/sqlite_spec.rb +1 -1
  103. data/spec/core/connection_pool_spec.rb +16 -17
  104. data/spec/core/database_spec.rb +111 -40
  105. data/spec/core/dataset_spec.rb +65 -74
  106. data/spec/core/expression_filters_spec.rb +6 -5
  107. data/spec/core/object_graph_spec.rb +0 -1
  108. data/spec/core/schema_spec.rb +23 -23
  109. data/spec/core/spec_helper.rb +5 -1
  110. data/spec/extensions/association_dependencies_spec.rb +1 -1
  111. data/spec/extensions/association_proxies_spec.rb +1 -1
  112. data/spec/extensions/auto_validations_spec.rb +90 -0
  113. data/spec/extensions/caching_spec.rb +6 -0
  114. data/spec/extensions/class_table_inheritance_spec.rb +8 -1
  115. data/spec/extensions/composition_spec.rb +12 -5
  116. data/spec/extensions/constraint_validations_spec.rb +4 -4
  117. data/spec/extensions/core_refinements_spec.rb +29 -79
  118. data/spec/extensions/dirty_spec.rb +14 -0
  119. data/spec/extensions/error_splitter_spec.rb +18 -0
  120. data/spec/extensions/identity_map_spec.rb +0 -1
  121. data/spec/extensions/input_transformer_spec.rb +54 -0
  122. data/spec/extensions/instance_filters_spec.rb +6 -0
  123. data/spec/extensions/instance_hooks_spec.rb +12 -1
  124. data/spec/extensions/json_serializer_spec.rb +0 -1
  125. data/spec/extensions/lazy_attributes_spec.rb +64 -55
  126. data/spec/extensions/looser_typecasting_spec.rb +1 -1
  127. data/spec/extensions/many_through_many_spec.rb +3 -4
  128. data/spec/extensions/many_to_one_pk_lookup_spec.rb +53 -15
  129. data/spec/extensions/migration_spec.rb +16 -0
  130. data/spec/extensions/null_dataset_spec.rb +1 -1
  131. data/spec/extensions/pg_array_spec.rb +48 -1
  132. data/spec/extensions/pg_hstore_ops_spec.rb +10 -2
  133. data/spec/extensions/pg_hstore_spec.rb +5 -0
  134. data/spec/extensions/pg_inet_spec.rb +5 -0
  135. data/spec/extensions/pg_interval_spec.rb +7 -3
  136. data/spec/extensions/pg_json_spec.rb +6 -1
  137. data/spec/extensions/pg_range_ops_spec.rb +4 -1
  138. data/spec/extensions/pg_range_spec.rb +5 -0
  139. data/spec/extensions/pg_row_plugin_spec.rb +13 -0
  140. data/spec/extensions/pg_row_spec.rb +28 -19
  141. data/spec/extensions/pg_typecast_on_load_spec.rb +6 -1
  142. data/spec/extensions/prepared_statements_associations_spec.rb +1 -1
  143. data/spec/extensions/query_literals_spec.rb +1 -1
  144. data/spec/extensions/rcte_tree_spec.rb +2 -2
  145. data/spec/extensions/schema_spec.rb +2 -2
  146. data/spec/extensions/serialization_modification_detection_spec.rb +8 -0
  147. data/spec/extensions/serialization_spec.rb +15 -1
  148. data/spec/extensions/sharding_spec.rb +1 -1
  149. data/spec/extensions/single_table_inheritance_spec.rb +1 -1
  150. data/spec/extensions/static_cache_spec.rb +59 -9
  151. data/spec/extensions/tactical_eager_loading_spec.rb +19 -4
  152. data/spec/extensions/update_primary_key_spec.rb +17 -1
  153. data/spec/extensions/validation_class_methods_spec.rb +25 -0
  154. data/spec/extensions/validation_helpers_spec.rb +59 -3
  155. data/spec/integration/associations_test.rb +5 -5
  156. data/spec/integration/eager_loader_test.rb +32 -63
  157. data/spec/integration/model_test.rb +2 -2
  158. data/spec/integration/plugin_test.rb +88 -56
  159. data/spec/integration/prepared_statement_test.rb +1 -1
  160. data/spec/integration/schema_test.rb +1 -1
  161. data/spec/integration/timezone_test.rb +0 -1
  162. data/spec/integration/transaction_test.rb +0 -1
  163. data/spec/model/association_reflection_spec.rb +1 -1
  164. data/spec/model/associations_spec.rb +106 -84
  165. data/spec/model/base_spec.rb +4 -4
  166. data/spec/model/eager_loading_spec.rb +8 -8
  167. data/spec/model/model_spec.rb +27 -9
  168. data/spec/model/plugins_spec.rb +71 -0
  169. data/spec/model/record_spec.rb +99 -13
  170. metadata +12 -2
@@ -76,7 +76,7 @@
76
76
  # DB.extension :pg_hstore
77
77
  #
78
78
  # If you are not using the native postgres adapter, you probably
79
- # also want to use the typecast_on_load plugin in the model, and
79
+ # also want to use the pg_typecast_on_load plugin in the model, and
80
80
  # set it to typecast the hstore column(s) on load.
81
81
  #
82
82
  # This extension requires the delegate and strscan libraries.
@@ -136,6 +136,13 @@ module Sequel
136
136
  end
137
137
 
138
138
  module DatabaseMethods
139
+ def self.extended(db)
140
+ db.instance_eval do
141
+ add_named_conversion_procs(conversion_procs, :hstore=>PG_NAMED_TYPES[:hstore])
142
+ @schema_type_classes[:hstore] = HStore
143
+ end
144
+ end
145
+
139
146
  # Handle hstores in bound variables
140
147
  def bound_variable_arg(arg, conn)
141
148
  case arg
@@ -29,7 +29,7 @@
29
29
  # This creates a Sequel::Postgres::HStoreOp object that can be used
30
30
  # for easier querying:
31
31
  #
32
- # h - 'a' # hstore_column - 'a'
32
+ # h - 'a' # hstore_column - CAST('a' AS text)
33
33
  # h['a'] # hstore_column -> 'a'
34
34
  #
35
35
  # h.concat(:other_hstore_column) # ||
@@ -82,6 +82,9 @@ 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)
87
+ end
85
88
  HStoreOp.new(super)
86
89
  end
87
90
 
@@ -11,7 +11,7 @@
11
11
  # DB.extension :pg_inet
12
12
  #
13
13
  # If you are not using the native postgres adapter, you probably
14
- # also want to use the typecast_on_load plugin in the model, and
14
+ # also want to use the pg_typecast_on_load plugin in the model, and
15
15
  # set it to typecast the inet/cidr column(s) on load.
16
16
  #
17
17
  # This extension integrates with the pg_array extension. If you plan
@@ -33,12 +33,15 @@ module Sequel
33
33
  module Postgres
34
34
  # Methods enabling Database object integration with the inet/cidr types.
35
35
  module InetDatabaseMethods
36
-
37
36
  # Reset the conversion procs when extending the Database object, so
38
37
  # it will pick up the inet/cidr converter. Also, extend the datasets
39
38
  # with support for literalizing the IPAddr types.
40
39
  def self.extended(db)
41
- db.extend_datasets(InetDatasetMethods)
40
+ db.instance_eval do
41
+ extend_datasets(InetDatasetMethods)
42
+ copy_conversion_procs([869, 650, 1041, 651, 1040])
43
+ @schema_type_classes[:ipaddr] = IPAddr
44
+ end
42
45
  end
43
46
 
44
47
  # Convert an IPAddr arg to a string. Probably not necessary, but done
@@ -52,16 +55,6 @@ module Sequel
52
55
  end
53
56
  end
54
57
 
55
- # Make the column type detection recognize the inet and cidr types.
56
- def schema_column_type(db_type)
57
- case db_type
58
- when 'inet', 'cidr'
59
- :ipaddr
60
- else
61
- super
62
- end
63
- end
64
-
65
58
  private
66
59
 
67
60
  # Handle inet[]/cidr[] types in bound variables.
@@ -74,6 +67,16 @@ module Sequel
74
67
  end
75
68
  end
76
69
 
70
+ # Make the column type detection recognize the inet and cidr types.
71
+ def schema_column_type(db_type)
72
+ case db_type
73
+ when 'inet', 'cidr'
74
+ :ipaddr
75
+ else
76
+ super
77
+ end
78
+ end
79
+
77
80
  # Typecast the given value to an IPAddr object.
78
81
  def typecast_value_ipaddr(value)
79
82
  case value
@@ -16,7 +16,7 @@
16
16
  # DB.extension :pg_interval
17
17
  #
18
18
  # If you are not using the native postgres adapter, you probably
19
- # also want to use the typecast_on_load plugin in the model, and
19
+ # also want to use the pg_typecast_on_load plugin in the model, and
20
20
  # set it to typecast the interval type column(s) on load.
21
21
  #
22
22
  # This extension integrates with the pg_array extension. If you plan
@@ -119,7 +119,11 @@ module Sequel
119
119
  # Reset the conversion procs if using the native postgres adapter,
120
120
  # and extend the datasets to correctly literalize ActiveSupport::Duration values.
121
121
  def self.extended(db)
122
- db.extend_datasets(IntervalDatasetMethods)
122
+ db.instance_eval do
123
+ extend_datasets(IntervalDatasetMethods)
124
+ copy_conversion_procs([1186, 1187])
125
+ @schema_type_classes[:interval] = ActiveSupport::Duration
126
+ end
123
127
  end
124
128
 
125
129
  # Handle ActiveSupport::Duration values in bound variables.
@@ -43,7 +43,7 @@
43
43
  # DB.extension :pg_json
44
44
  #
45
45
  # If you are not using the native postgres adapter, you probably
46
- # also want to use the typecast_on_load plugin in the model, and
46
+ # also want to use the pg_typecast_on_load plugin in the model, and
47
47
  # set it to typecast the json column(s) on load.
48
48
  #
49
49
  # This extension integrates with the pg_array extension. If you plan
@@ -93,6 +93,13 @@ module Sequel
93
93
 
94
94
  # Methods enabling Database object integration with the json type.
95
95
  module JSONDatabaseMethods
96
+ def self.extended(db)
97
+ db.instance_eval do
98
+ copy_conversion_procs([114, 199])
99
+ @schema_type_classes[:json] = [JSONHash, JSONArray]
100
+ end
101
+ end
102
+
96
103
  # Parse the given string as json, returning either a JSONArray
97
104
  # or JSONHash instance, and raising an error if the JSON
98
105
  # parsing does not yield an array or hash.
@@ -123,16 +130,6 @@ module Sequel
123
130
  end
124
131
  end
125
132
 
126
- # Make the column type detection recognize the json type.
127
- def schema_column_type(db_type)
128
- case db_type
129
- when 'json'
130
- :json
131
- else
132
- super
133
- end
134
- end
135
-
136
133
  private
137
134
 
138
135
  # Handle json[] types in bound variables.
@@ -145,6 +142,16 @@ module Sequel
145
142
  end
146
143
  end
147
144
 
145
+ # Make the column type detection recognize the json type.
146
+ def schema_column_type(db_type)
147
+ case db_type
148
+ when 'json'
149
+ :json
150
+ else
151
+ super
152
+ end
153
+ end
154
+
148
155
  # Given a value to typecast to the json column
149
156
  # * If given a JSONArray or JSONHash, just return the value
150
157
  # * If given an Array, return a JSONArray
@@ -46,7 +46,7 @@
46
46
  # DB.extension :pg_range
47
47
  #
48
48
  # If you are not using the native postgres adapter, you probably
49
- # also want to use the typecast_on_load plugin in the model, and
49
+ # also want to use the pg_typecast_on_load plugin in the model, and
50
50
  # set it to typecast the range type column(s) on load.
51
51
  #
52
52
  # This extension integrates with the pg_array extension. If you plan
@@ -185,7 +185,22 @@ module Sequel
185
185
  # Reset the conversion procs if using the native postgres adapter,
186
186
  # and extend the datasets to correctly literalize ruby Range values.
187
187
  def self.extended(db)
188
- db.extend_datasets(DatasetMethods)
188
+ db.instance_eval do
189
+ extend_datasets(DatasetMethods)
190
+ copy_conversion_procs([3904, 3906, 3912, 3926, 3905, 3907, 3913, 3927])
191
+ [:int4range, :numrange, :tsrange, :tstzrange, :daterange, :int8range].each do |v|
192
+ @schema_type_classes[v] = PGRange
193
+ end
194
+ end
195
+
196
+ procs = db.conversion_procs
197
+ procs[3908] = Parser.new("tsrange", procs[1114])
198
+ procs[3910] = Parser.new("tstzrange", procs[1184])
199
+ if defined?(PGArray::Creator)
200
+ procs[3909] = PGArray::Creator.new("tsrange", procs[3908])
201
+ procs[3911] = PGArray::Creator.new("tstzrange", procs[3910])
202
+ end
203
+
189
204
  end
190
205
 
191
206
  # Define a private range typecasting method for the given type that uses
@@ -29,12 +29,12 @@
29
29
  # for easier querying:
30
30
  #
31
31
  # r.contains(:other) # range @> other
32
- # r.contained_by(:other) # range <@ other
32
+ # r.contained_by(:other) # range <@ other
33
33
  # r.overlaps(:other) # range && other
34
34
  # r.left_of(:other) # range << other
35
35
  # r.right_of(:other) # range >> other
36
- # r.starts_before(:other) # range &< other
37
- # r.ends_after(:other) # range &> other
36
+ # r.starts_after(:other) # range &> other
37
+ # r.ends_before(:other) # range &< other
38
38
  # r.adjacent_to(:other) # range -|- other
39
39
  #
40
40
  # r.lower # lower(range)
@@ -66,8 +66,8 @@ module Sequel
66
66
  :contained_by => ["(".freeze, " <@ ".freeze, ")".freeze].freeze,
67
67
  :left_of => ["(".freeze, " << ".freeze, ")".freeze].freeze,
68
68
  :right_of => ["(".freeze, " >> ".freeze, ")".freeze].freeze,
69
- :starts_before => ["(".freeze, " &< ".freeze, ")".freeze].freeze,
70
- :ends_after => ["(".freeze, " &> ".freeze, ")".freeze].freeze,
69
+ :ends_before => ["(".freeze, " &< ".freeze, ")".freeze].freeze,
70
+ :starts_after => ["(".freeze, " &> ".freeze, ")".freeze].freeze,
71
71
  :adjacent_to => ["(".freeze, " -|- ".freeze, ")".freeze].freeze,
72
72
  :overlaps => ["(".freeze, " && ".freeze, ")".freeze].freeze,
73
73
  }
@@ -79,6 +79,8 @@ module Sequel
79
79
  OPERATORS.keys.each do |f|
80
80
  class_eval("def #{f}(v); operator(:#{f}, v) end", __FILE__, __LINE__)
81
81
  end
82
+ alias starts_before ends_before
83
+ alias ends_after starts_after
82
84
 
83
85
  # These operators are already supported by the wrapper, but for ranges they
84
86
  # return ranges, so wrap the results in another RangeOp.
@@ -66,6 +66,18 @@
66
66
  #
67
67
  # DB[:table].insert(:address=>DB.row_type(:address, :street=>'123 Sesame St.', :city=>'Some City', :zip=>'12345'))
68
68
  #
69
+ # Note that registering row types without providing an explicit :converter option
70
+ # creates anonymous classes. This results in ruby being unable to Marshal such
71
+ # objects. You can work around this by assigning the anonymous class to a constant.
72
+ # To get a list of such anonymous classes, you can use the following code:
73
+ #
74
+ # DB.conversion_procs.select{|k,v| v.is_a?(Sequel::Postgres::PGRow::Parser) && \
75
+ # v.converter && (v.converter.name.nil? || v.converter.name == '') }.map{|k,v| v}
76
+ #
77
+ # If you are not using the native postgres adapter, you probably
78
+ # also want to use the pg_typecast_on_load plugin in the model, and
79
+ # set it to typecast the composite type column(s) on load.
80
+ #
69
81
  # This extension requires both the strscan and delegate libraries.
70
82
 
71
83
  require 'delegate'
@@ -98,7 +110,7 @@ module Sequel
98
110
  # This is done so that instances of this subclass are
99
111
  # automatically casted to the database type when literalizing.
100
112
  def self.subclass(db_type)
101
- sc = Class.new(self) do
113
+ Class.new(self) do
102
114
  @db_type = db_type
103
115
  end
104
116
  end
@@ -146,7 +158,7 @@ module Sequel
146
158
  # Create a new subclass of this class with the given database
147
159
  # type and columns.
148
160
  def self.subclass(db_type, columns)
149
- sc = Class.new(self) do
161
+ Class.new(self) do
150
162
  @db_type = db_type
151
163
  @columns = columns
152
164
  end
@@ -196,6 +208,8 @@ module Sequel
196
208
  end
197
209
  end
198
210
 
211
+ ROW_TYPE_CLASSES = [HashRow, ArrayRow]
212
+
199
213
  # This parser-like class splits the PostgreSQL
200
214
  # row-valued/composite type output string format
201
215
  # into an array of strings. Note this class makes
@@ -377,6 +391,7 @@ module Sequel
377
391
  @row_types = {}
378
392
  @row_schema_types = {}
379
393
  extend(@row_type_method_module = Module.new)
394
+ copy_conversion_procs([2249, 2287])
380
395
  end
381
396
  end
382
397
 
@@ -431,11 +446,12 @@ module Sequel
431
446
 
432
447
  # Get column names and oids for each of the members of the composite type.
433
448
  res = from(:pg_attribute).
449
+ join(:pg_type, :oid=>:atttypid).
434
450
  where(:attrelid=>rel_oid).
435
451
  where{attnum > 0}.
436
452
  exclude(:attisdropped).
437
453
  order(:attnum).
438
- select_map([:attname, :atttypid])
454
+ select_map([:attname, Sequel.case({0=>:atttypid}, :pg_type__typbasetype, :pg_type__typbasetype).as(:atttypid)])
439
455
  if res.empty?
440
456
  raise Error, "no columns for row type #{db_type.inspect} in database"
441
457
  end
@@ -471,6 +487,7 @@ module Sequel
471
487
 
472
488
  @row_types[db_type] = opts.merge(:parser=>parser)
473
489
  @row_schema_types[schema_type_string] = schema_type_symbol
490
+ @schema_type_classes[schema_type_symbol] = ROW_TYPE_CLASSES
474
491
  @row_type_method_module.class_eval do
475
492
  meth = :"typecast_value_#{schema_type_symbol}"
476
493
  define_method(meth) do |v|
@@ -523,15 +540,6 @@ module Sequel
523
540
  end
524
541
  end
525
542
 
526
- # Make the column type detection handle registered row types.
527
- def schema_column_type(db_type)
528
- if type = @row_schema_types[db_type]
529
- type
530
- else
531
- super
532
- end
533
- end
534
-
535
543
  private
536
544
 
537
545
  # Format composite types used in bound variable arrays.
@@ -546,6 +554,15 @@ module Sequel
546
554
  super
547
555
  end
548
556
  end
557
+
558
+ # Make the column type detection handle registered row types.
559
+ def schema_column_type(db_type)
560
+ if type = @row_schema_types[db_type]
561
+ type
562
+ else
563
+ super
564
+ end
565
+ end
549
566
  end
550
567
  end
551
568
 
@@ -24,4 +24,7 @@ module Sequel
24
24
  Sequel::PrettyTable.print(rows, cols.empty? ? ds.columns : cols)
25
25
  end
26
26
  end
27
+
28
+ Database.register_extension(:pretty_table){}
29
+ Dataset.register_extension(:pretty_table){}
27
30
  end
@@ -51,4 +51,7 @@ module Sequel
51
51
  end
52
52
  end
53
53
  end
54
+
55
+ Dataset.register_extension(:query){}
56
+ Database.register_extension(:query){}
54
57
  end
@@ -73,4 +73,6 @@ module Sequel
73
73
  load_schema_cache(file) if File.exist?(file)
74
74
  end
75
75
  end
76
+
77
+ Database.register_extension(:schema_caching){}
76
78
  end
@@ -149,7 +149,7 @@ END_MIG
149
149
  # be :type. The other options added should modify that type (e.g. :size). If a
150
150
  # database type is not recognized, return it as a String type.
151
151
  def column_schema_to_ruby_type(schema)
152
- case t = schema[:db_type].downcase
152
+ case schema[:db_type].downcase
153
153
  when /\A(medium|small)?int(?:eger)?(?:\((\d+)\))?( unsigned)?\z/o
154
154
  if !$1 && $2 && $2.to_i >= 10 && $3
155
155
  # Unsigned integer type with 10 digits can potentially contain values which
@@ -483,4 +483,6 @@ END_MIG
483
483
  end
484
484
  end
485
485
  end
486
+
487
+ Database.register_extension(:schema_dumper){}
486
488
  end
@@ -36,4 +36,7 @@ module Sequel
36
36
  end
37
37
  end
38
38
  end
39
+
40
+ Database.register_extension(:select_remove){}
41
+ Dataset.register_extension(:select_remove){}
39
42
  end
@@ -72,7 +72,7 @@ module Sequel
72
72
 
73
73
  # Class methods added to model that call the method of the same name on the dataset
74
74
  DATASET_METHODS = (Dataset::ACTION_METHODS + Dataset::QUERY_METHODS +
75
- [:each_page, :each_server, :print]) - [:and, :or, :[], :[]=, :columns, :columns!]
75
+ [:each_page, :each_server, :print, :destroy, :with_pk, :with_pk!]) - [:and, :or, :[], :[]=, :columns, :columns!]
76
76
 
77
77
  # Class instance variables to set to nil when a subclass is created, for -w compliance
78
78
  EMPTY_INSTANCE_VARIABLES = [:@overridable_methods_module, :@db]
@@ -114,7 +114,8 @@ module Sequel
114
114
  :@typecast_empty_string_to_nil=>nil, :@typecast_on_assignment=>nil,
115
115
  :@raise_on_typecast_failure=>nil, :@plugins=>:dup, :@setter_methods=>nil,
116
116
  :@use_after_commit_rollback=>nil, :@fast_pk_lookup_sql=>nil,
117
- :@fast_instance_delete_sql=>nil}
117
+ :@fast_instance_delete_sql=>nil, :@default_eager_limit_strategy=>nil,
118
+ :@db=>nil, :@default_set_fields_options=>:dup}
118
119
 
119
120
  # Regular expression that determines if a method name is normal in the sense that
120
121
  # it could be used literally in ruby code without using send. Used to
@@ -128,8 +129,13 @@ module Sequel
128
129
  @allowed_columns = nil
129
130
  @db = nil
130
131
  @db_schema = nil
132
+ @dataset = nil
131
133
  @dataset_method_modules = []
134
+ @default_eager_limit_strategy = nil
135
+ @default_set_fields_options = {}
132
136
  @overridable_methods_module = nil
137
+ @fast_pk_lookup_sql = nil
138
+ @fast_instance_delete_sql = nil
133
139
  @plugins = []
134
140
  @primary_key = :id
135
141
  @raise_on_save_failure = true
@@ -663,10 +663,8 @@ module Sequel
663
663
  # milestones, allowing for further filtering/limiting/etc.
664
664
  #
665
665
  # If you want to override the behavior of the add_/remove_/remove_all_/ methods
666
- # or the association setter method, there are private instance methods created that are prepended
667
- # with an underscore (e.g. _add_milestone or _portfolio=). The private instance methods can be
668
- # easily overridden, but you shouldn't override the public instance methods without
669
- # calling super, as they deal with callbacks and caching.
666
+ # or the association setter method, use the :adder, :remover, :clearer, and/or :setter
667
+ # options. These options override the default behavior.
670
668
  #
671
669
  # By default the classes for the associations are inferred from the association
672
670
  # name, so for example the Project#portfolio will return an instance of
@@ -739,7 +737,9 @@ module Sequel
739
737
  # model object can be associated with many current model objects.
740
738
  #
741
739
  # The following options can be supplied:
742
- # === All Types
740
+ # === Multiple Types
741
+ # :adder :: Proc used to define the private _add_* method for doing the database work
742
+ # to associate the given object to the current object (*_to_many assocations).
743
743
  # :after_add :: Symbol, Proc, or array of both/either specifying a callback to call
744
744
  # after a new item is added to the association.
745
745
  # :after_load :: Symbol, Proc, or array of both/either specifying a callback to call
@@ -764,6 +764,8 @@ module Sequel
764
764
  # given, uses the association's name, which is camelized (and
765
765
  # singularized unless the type is :many_to_one or :one_to_one). If this is specified
766
766
  # as a string or symbol, you must specify the full class name (e.g. "SomeModule::MyModel").
767
+ # :clearer :: Proc used to define the private _remove_all_* method for doing the database work
768
+ # to remove all objects associated to the current object (*_to_many assocations).
767
769
  # :clone :: Merge the current options and block into the options and block used in defining
768
770
  # the given association. Can be used to DRY up a bunch of similar associations that
769
771
  # all share the same options such as :class and :key, while changing the order and block used.
@@ -837,12 +839,16 @@ module Sequel
837
839
  # if it exists. By default, Sequel will try to determine it by looking at the
838
840
  # associated model's assocations for a association that matches
839
841
  # the current association's key(s). Set to nil to not use a reciprocal.
842
+ # :remover :: Proc used to define the private _remove_* method for doing the database work
843
+ # to remove the association between the given object and the current object (*_to_many assocations).
840
844
  # :select :: the columns to select. Defaults to the associated class's
841
845
  # table_name.* in a many_to_many association, which means it doesn't include the attributes from the
842
846
  # join table. If you want to include the join table attributes, you can
843
847
  # use this option, but beware that the join table attributes can clash with
844
848
  # attributes from the model table, so you should alias any attributes that have
845
849
  # the same name in both the join table and the associated table.
850
+ # :setter :: Proc used to define the private _*= method for doing the work to setup the assocation
851
+ # between the given object and the current object (*_to_one associations).
846
852
  # :validate :: Set to false to not validate when implicitly saving any associated object.
847
853
  # === :many_to_one
848
854
  # :key :: foreign key in current model's table that references
@@ -990,13 +996,6 @@ module Sequel
990
996
  ds
991
997
  end
992
998
 
993
- # Copy the association reflections to the subclass
994
- def inherited(subclass)
995
- super
996
- subclass.instance_variable_set(:@association_reflections, association_reflections.dup)
997
- subclass.default_eager_limit_strategy = default_eager_limit_strategy
998
- end
999
-
1000
999
  # Shortcut for adding a many_to_many association, see #associate
1001
1000
  def many_to_many(name, opts={}, &block)
1002
1001
  associate(:many_to_many, name, opts, &block)
@@ -1016,6 +1015,9 @@ module Sequel
1016
1015
  def one_to_one(name, opts={}, &block)
1017
1016
  associate(:one_to_one, name, opts, &block)
1018
1017
  end
1018
+
1019
+ Plugins.inherited_instance_variables(self, :@association_reflections=>:dup, :@default_eager_limit_strategy=>nil)
1020
+ Plugins.def_dataset_methods(self, [:eager, :eager_graph])
1019
1021
 
1020
1022
  private
1021
1023
 
@@ -1034,7 +1036,7 @@ module Sequel
1034
1036
  oproc = lambda do |x|
1035
1037
  case x
1036
1038
  when Symbol
1037
- t, c, a = ds.send(:split_symbol, x)
1039
+ t, c, _ = ds.send(:split_symbol, x)
1038
1040
  if t && t.to_sym == table
1039
1041
  SQL::QualifiedIdentifier.new(dsa, c)
1040
1042
  else
@@ -1140,7 +1142,7 @@ module Sequel
1140
1142
  raise(Error, "mismatched number of right keys: #{rcks.inspect} vs #{rcpks.inspect}") unless rcks.length == rcpks.length
1141
1143
  end
1142
1144
  uses_lcks = opts[:uses_left_composite_keys] = lcks.length > 1
1143
- uses_rcks = opts[:uses_right_composite_keys] = rcks.length > 1
1145
+ opts[:uses_right_composite_keys] = rcks.length > 1
1144
1146
  opts[:cartesian_product_number] ||= 1
1145
1147
  join_table = (opts[:join_table] ||= opts.default_join_table)
1146
1148
  left_key_alias = opts[:left_key_alias] ||= opts.default_associated_key_alias
@@ -1203,18 +1205,23 @@ module Sequel
1203
1205
 
1204
1206
  return if opts[:read_only]
1205
1207
 
1206
- association_module_private_def(opts._add_method, opts) do |o|
1208
+ adder = opts[:adder] || proc do |o|
1207
1209
  h = {}
1208
1210
  lcks.zip(lcpks).each{|k, pk| h[k] = send(pk)}
1209
1211
  rcks.zip(opts.right_primary_key_methods).each{|k, pk| h[k] = o.send(pk)}
1210
1212
  _join_table_dataset(opts).insert(h)
1211
1213
  end
1212
- association_module_private_def(opts._remove_method, opts) do |o|
1214
+ association_module_private_def(opts._add_method, opts, &adder)
1215
+
1216
+ remover = opts[:remover] || proc do |o|
1213
1217
  _join_table_dataset(opts).where(lcks.zip(lcpks.map{|k| send(k)}) + rcks.zip(opts.right_primary_key_methods.map{|k| o.send(k)})).delete
1214
1218
  end
1215
- association_module_private_def(opts._remove_all_method, opts) do
1219
+ association_module_private_def(opts._remove_method, opts, &remover)
1220
+
1221
+ clearer = opts[:clearer] || proc do
1216
1222
  _join_table_dataset(opts).where(lcks.zip(lcpks.map{|k| send(k)})).delete
1217
1223
  end
1224
+ association_module_private_def(opts._remove_all_method, opts, &clearer)
1218
1225
 
1219
1226
  def_add_method(opts)
1220
1227
  def_remove_methods(opts)
@@ -1236,7 +1243,6 @@ module Sequel
1236
1243
  raise(Error, "mismatched number of keys: #{cks.inspect} vs #{cpks.inspect}") unless cks.length == cpks.length
1237
1244
  end
1238
1245
  uses_cks = opts[:uses_composite_keys] = cks.length > 1
1239
- qualify = opts[:qualify] != false
1240
1246
  opts[:cartesian_product_number] ||= 0
1241
1247
  opts[:dataset] ||= proc do
1242
1248
  opts.associated_dataset.where(opts.predicate_keys.zip(cks.map{|k| send(k)}))
@@ -1274,7 +1280,8 @@ module Sequel
1274
1280
 
1275
1281
  return if opts[:read_only]
1276
1282
 
1277
- association_module_private_def(opts._setter_method, opts){|o| cks.zip(opts.primary_key_methods).each{|k, pk| send(:"#{k}=", (o.send(pk) if o))}}
1283
+ setter = opts[:setter] || proc{|o| cks.zip(opts.primary_key_methods).each{|k, pk| send(:"#{k}=", (o.send(pk) if o))}}
1284
+ association_module_private_def(opts._setter_method, opts, &setter)
1278
1285
  association_module_def(opts.setter_method, opts){|o| set_associated_object(opts, o)}
1279
1286
  end
1280
1287
 
@@ -1369,7 +1376,7 @@ module Sequel
1369
1376
  validate = opts[:validate]
1370
1377
 
1371
1378
  if one_to_one
1372
- association_module_private_def(opts._setter_method, opts) do |o|
1379
+ setter = opts[:setter] || proc do |o|
1373
1380
  up_ds = _apply_association_options(opts, opts.associated_dataset.where(cks.zip(cpks.map{|k| send(k)})))
1374
1381
  if o
1375
1382
  up_ds = up_ds.exclude(o.pk_hash) unless o.new?
@@ -1380,21 +1387,27 @@ module Sequel
1380
1387
  o.save(:validate=>validate) || raise(Sequel::Error, "invalid associated object, cannot save") if o
1381
1388
  end
1382
1389
  end
1390
+ association_module_private_def(opts._setter_method, opts, &setter)
1383
1391
  association_module_def(opts.setter_method, opts){|o| set_one_to_one_associated_object(opts, o)}
1384
1392
  else
1385
- association_module_private_def(opts._add_method, opts) do |o|
1393
+ adder = opts[:adder] || proc do |o|
1386
1394
  cks.zip(cpks).each{|k, pk| o.send(:"#{k}=", send(pk))}
1387
1395
  o.save(:validate=>validate) || raise(Sequel::Error, "invalid associated object, cannot save")
1388
1396
  end
1389
- def_add_method(opts)
1397
+ association_module_private_def(opts._add_method, opts, &adder)
1390
1398
 
1391
- association_module_private_def(opts._remove_method, opts) do |o|
1399
+ remover = opts[:remover] || proc do |o|
1392
1400
  cks.each{|k| o.send(:"#{k}=", nil)}
1393
1401
  o.save(:validate=>validate) || raise(Sequel::Error, "invalid associated object, cannot save")
1394
1402
  end
1395
- association_module_private_def(opts._remove_all_method, opts) do
1403
+ association_module_private_def(opts._remove_method, opts, &remover)
1404
+
1405
+ clearer = opts[:clearer] || proc do
1396
1406
  _apply_association_options(opts, opts.associated_dataset.where(cks.zip(cpks.map{|k| send(k)}))).update(ck_nil_hash)
1397
1407
  end
1408
+ association_module_private_def(opts._remove_all_method, opts, &clearer)
1409
+
1410
+ def_add_method(opts)
1398
1411
  def_remove_methods(opts)
1399
1412
  end
1400
1413
  end
@@ -1511,8 +1524,8 @@ module Sequel
1511
1524
  else
1512
1525
  _load_associated_object(opts, dynamic_opts)
1513
1526
  end
1514
- else
1515
- [] if opts.returns_array?
1527
+ elsif opts.returns_array?
1528
+ []
1516
1529
  end
1517
1530
  end
1518
1531
 
@@ -1911,7 +1924,6 @@ module Sequel
1911
1924
  else
1912
1925
  alias_base = r[:graph_alias_base]
1913
1926
  end
1914
- assoc_name = r[:name]
1915
1927
  assoc_table_alias = ds.unused_table_alias(alias_base)
1916
1928
  loader = r[:eager_grapher]
1917
1929
  if !associations.empty?