sequel 3.28.0 → 3.29.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (148) hide show
  1. data/CHANGELOG +119 -3
  2. data/Rakefile +5 -3
  3. data/bin/sequel +1 -5
  4. data/doc/model_hooks.rdoc +9 -1
  5. data/doc/opening_databases.rdoc +49 -40
  6. data/doc/prepared_statements.rdoc +27 -6
  7. data/doc/release_notes/3.28.0.txt +2 -2
  8. data/doc/release_notes/3.29.0.txt +459 -0
  9. data/doc/sharding.rdoc +7 -1
  10. data/doc/testing.rdoc +18 -9
  11. data/doc/transactions.rdoc +41 -1
  12. data/lib/sequel/adapters/ado.rb +28 -17
  13. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  14. data/lib/sequel/adapters/amalgalite.rb +11 -7
  15. data/lib/sequel/adapters/db2.rb +122 -70
  16. data/lib/sequel/adapters/dbi.rb +15 -15
  17. data/lib/sequel/adapters/do.rb +5 -36
  18. data/lib/sequel/adapters/do/mysql.rb +0 -5
  19. data/lib/sequel/adapters/do/postgres.rb +0 -5
  20. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  21. data/lib/sequel/adapters/firebird.rb +3 -6
  22. data/lib/sequel/adapters/ibmdb.rb +24 -16
  23. data/lib/sequel/adapters/informix.rb +2 -4
  24. data/lib/sequel/adapters/jdbc.rb +47 -11
  25. data/lib/sequel/adapters/jdbc/as400.rb +5 -24
  26. data/lib/sequel/adapters/jdbc/db2.rb +0 -5
  27. data/lib/sequel/adapters/jdbc/derby.rb +217 -0
  28. data/lib/sequel/adapters/jdbc/firebird.rb +0 -5
  29. data/lib/sequel/adapters/jdbc/h2.rb +10 -12
  30. data/lib/sequel/adapters/jdbc/hsqldb.rb +166 -0
  31. data/lib/sequel/adapters/jdbc/informix.rb +0 -5
  32. data/lib/sequel/adapters/jdbc/jtds.rb +0 -5
  33. data/lib/sequel/adapters/jdbc/mysql.rb +0 -10
  34. data/lib/sequel/adapters/jdbc/oracle.rb +70 -3
  35. data/lib/sequel/adapters/jdbc/postgresql.rb +0 -11
  36. data/lib/sequel/adapters/jdbc/sqlite.rb +0 -5
  37. data/lib/sequel/adapters/jdbc/sqlserver.rb +0 -5
  38. data/lib/sequel/adapters/jdbc/transactions.rb +56 -7
  39. data/lib/sequel/adapters/mock.rb +315 -0
  40. data/lib/sequel/adapters/mysql.rb +64 -51
  41. data/lib/sequel/adapters/mysql2.rb +15 -9
  42. data/lib/sequel/adapters/odbc.rb +13 -6
  43. data/lib/sequel/adapters/odbc/db2.rb +0 -4
  44. data/lib/sequel/adapters/odbc/mssql.rb +0 -5
  45. data/lib/sequel/adapters/openbase.rb +2 -4
  46. data/lib/sequel/adapters/oracle.rb +333 -51
  47. data/lib/sequel/adapters/postgres.rb +80 -27
  48. data/lib/sequel/adapters/shared/access.rb +0 -6
  49. data/lib/sequel/adapters/shared/db2.rb +13 -15
  50. data/lib/sequel/adapters/shared/firebird.rb +6 -6
  51. data/lib/sequel/adapters/shared/mssql.rb +23 -18
  52. data/lib/sequel/adapters/shared/mysql.rb +6 -6
  53. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
  54. data/lib/sequel/adapters/shared/oracle.rb +185 -30
  55. data/lib/sequel/adapters/shared/postgres.rb +35 -18
  56. data/lib/sequel/adapters/shared/progress.rb +0 -6
  57. data/lib/sequel/adapters/shared/sqlite.rb +116 -37
  58. data/lib/sequel/adapters/sqlite.rb +16 -8
  59. data/lib/sequel/adapters/swift.rb +5 -5
  60. data/lib/sequel/adapters/swift/mysql.rb +0 -5
  61. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  62. data/lib/sequel/adapters/swift/sqlite.rb +6 -4
  63. data/lib/sequel/adapters/tinytds.rb +13 -10
  64. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +8 -0
  65. data/lib/sequel/core.rb +40 -0
  66. data/lib/sequel/database/connecting.rb +1 -2
  67. data/lib/sequel/database/dataset.rb +3 -3
  68. data/lib/sequel/database/dataset_defaults.rb +58 -0
  69. data/lib/sequel/database/misc.rb +62 -2
  70. data/lib/sequel/database/query.rb +113 -49
  71. data/lib/sequel/database/schema_methods.rb +7 -2
  72. data/lib/sequel/dataset/actions.rb +37 -19
  73. data/lib/sequel/dataset/features.rb +24 -0
  74. data/lib/sequel/dataset/graph.rb +7 -6
  75. data/lib/sequel/dataset/misc.rb +11 -3
  76. data/lib/sequel/dataset/mutation.rb +2 -3
  77. data/lib/sequel/dataset/prepared_statements.rb +6 -4
  78. data/lib/sequel/dataset/query.rb +46 -15
  79. data/lib/sequel/dataset/sql.rb +28 -4
  80. data/lib/sequel/extensions/named_timezones.rb +5 -0
  81. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  82. data/lib/sequel/model.rb +2 -1
  83. data/lib/sequel/model/associations.rb +115 -33
  84. data/lib/sequel/model/base.rb +91 -31
  85. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  86. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  87. data/lib/sequel/plugins/force_encoding.rb +6 -6
  88. data/lib/sequel/plugins/identity_map.rb +1 -1
  89. data/lib/sequel/plugins/many_through_many.rb +6 -10
  90. data/lib/sequel/plugins/prepared_statements.rb +12 -1
  91. data/lib/sequel/plugins/prepared_statements_associations.rb +1 -1
  92. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  93. data/lib/sequel/plugins/serialization.rb +6 -1
  94. data/lib/sequel/plugins/sharding.rb +0 -5
  95. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  96. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  97. data/lib/sequel/plugins/update_primary_key.rb +1 -1
  98. data/lib/sequel/timezones.rb +42 -42
  99. data/lib/sequel/version.rb +1 -1
  100. data/spec/adapters/mssql_spec.rb +29 -29
  101. data/spec/adapters/mysql_spec.rb +86 -104
  102. data/spec/adapters/oracle_spec.rb +48 -76
  103. data/spec/adapters/postgres_spec.rb +98 -33
  104. data/spec/adapters/spec_helper.rb +0 -5
  105. data/spec/adapters/sqlite_spec.rb +24 -21
  106. data/spec/core/connection_pool_spec.rb +9 -15
  107. data/spec/core/core_sql_spec.rb +20 -31
  108. data/spec/core/database_spec.rb +491 -227
  109. data/spec/core/dataset_spec.rb +638 -1051
  110. data/spec/core/expression_filters_spec.rb +0 -1
  111. data/spec/core/mock_adapter_spec.rb +378 -0
  112. data/spec/core/object_graph_spec.rb +48 -114
  113. data/spec/core/schema_generator_spec.rb +3 -3
  114. data/spec/core/schema_spec.rb +51 -114
  115. data/spec/core/spec_helper.rb +3 -90
  116. data/spec/extensions/class_table_inheritance_spec.rb +1 -1
  117. data/spec/extensions/dataset_associations_spec.rb +199 -0
  118. data/spec/extensions/instance_hooks_spec.rb +71 -0
  119. data/spec/extensions/named_timezones_spec.rb +22 -2
  120. data/spec/extensions/nested_attributes_spec.rb +3 -0
  121. data/spec/extensions/schema_spec.rb +1 -1
  122. data/spec/extensions/serialization_modification_detection_spec.rb +1 -0
  123. data/spec/extensions/serialization_spec.rb +5 -8
  124. data/spec/extensions/spec_helper.rb +4 -0
  125. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  126. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  127. data/spec/integration/associations_test.rb +123 -12
  128. data/spec/integration/dataset_test.rb +140 -47
  129. data/spec/integration/eager_loader_test.rb +19 -21
  130. data/spec/integration/model_test.rb +80 -1
  131. data/spec/integration/plugin_test.rb +179 -128
  132. data/spec/integration/prepared_statement_test.rb +92 -91
  133. data/spec/integration/schema_test.rb +42 -23
  134. data/spec/integration/spec_helper.rb +25 -31
  135. data/spec/integration/timezone_test.rb +38 -12
  136. data/spec/integration/transaction_test.rb +161 -34
  137. data/spec/integration/type_test.rb +3 -3
  138. data/spec/model/association_reflection_spec.rb +83 -7
  139. data/spec/model/associations_spec.rb +393 -676
  140. data/spec/model/base_spec.rb +186 -116
  141. data/spec/model/dataset_methods_spec.rb +7 -27
  142. data/spec/model/eager_loading_spec.rb +343 -867
  143. data/spec/model/hooks_spec.rb +160 -79
  144. data/spec/model/model_spec.rb +118 -165
  145. data/spec/model/plugins_spec.rb +7 -13
  146. data/spec/model/record_spec.rb +138 -207
  147. data/spec/model/spec_helper.rb +10 -73
  148. metadata +14 -8
@@ -90,9 +90,9 @@ module Sequel
90
90
  @cti_columns = {table_name=>columns}
91
91
  @cti_table_map = opts[:table_map] || {}
92
92
  dataset.row_proc = if key
93
- lambda{|r| (m.call(r[key]) rescue model).load(r)}
93
+ lambda{|r| (m.call(r[key]) rescue model).call(r)}
94
94
  else
95
- lambda{|r| model.load(r)}
95
+ model
96
96
  end
97
97
  end
98
98
  end
@@ -152,9 +152,9 @@ module Sequel
152
152
  subclass.instance_eval do
153
153
  m = method(:constantize)
154
154
  dataset.row_proc = if cti_key
155
- lambda{|r| (m.call(r[ck]) rescue subclass).load(r)}
155
+ lambda{|r| (m.call(r[ck]) rescue subclass).call(r)}
156
156
  else
157
- lambda{|r| subclass.load(r)}
157
+ subclass
158
158
  end
159
159
  (columns - [cbm.primary_key]).each{|a| define_lazy_attribute_getter(a)}
160
160
  cti_tables.reverse.each do |table|
@@ -0,0 +1,100 @@
1
+ module Sequel
2
+ module Plugins
3
+ # DatasetAssociations allows you to easily use your model associations
4
+ # via datasets. For each association you define, it creates a dataset
5
+ # method for that association that returns a dataset of all objects
6
+ # that are associated to objects in the current dataset. Here's a simple
7
+ # example:
8
+ #
9
+ # class Artist < Sequel::Model
10
+ # plugin :dataset_associations
11
+ # one_to_many :albums
12
+ # end
13
+ # Artist.filter(id=>1..100).albums
14
+ # # SELECT * FROM albums
15
+ # # WHERE (albums.artist_id IN (
16
+ # # SELECT id FROM artists
17
+ # # WHERE ((id >= 1) AND (id <= 100))))
18
+ #
19
+ # This works for all of the association types that ship with Sequel,
20
+ # including the many_through_many type. Most association options that
21
+ # are supported when eager loading are supported when using a
22
+ # dataset association. However, associations that use :limit or
23
+ # one_to_one associations that are really one_to_many relationships
24
+ # in the database will not work correctly, returning all associated
25
+ # objects.
26
+ #
27
+ # As the dataset methods return datasets, you can easily chain the
28
+ # methods to get associated datasets of associated datasets:
29
+ #
30
+ # Artist.filter(id=>1..100).albums.filter{name < 'M'}.tags
31
+ # # SELECT tags.* FROM tags
32
+ # # WHERE (tags.id IN (
33
+ # # SELECT albums_tags.tag_id FROM albums
34
+ # # INNER JOIN albums_tags
35
+ # # ON (albums_tags.album_id = albums.id)
36
+ # # WHERE
37
+ # # ((albums.artist_id IN (
38
+ # # SELECT id FROM artists
39
+ # # WHERE ((id >= 1) AND (id <= 100)))
40
+ # # AND
41
+ # # (name < 'M')))))
42
+ #
43
+ # Usage:
44
+ #
45
+ # # Make all model subclasses create association methods for datasets
46
+ # Sequel::Model.plugin :dataset_associations
47
+ #
48
+ # # Make the Album class create association methods for datasets
49
+ # Album.plugin :dataset_associations
50
+ module DatasetAssociations
51
+ module ClassMethods
52
+ # Set up a dataset method for each association to return an associated dataset
53
+ def associate(type, name, *)
54
+ ret = super
55
+ r = association_reflection(name)
56
+ meth = r.returns_array? ? name : pluralize(name).to_sym
57
+ def_dataset_method(meth){associated(name)}
58
+ ret
59
+ end
60
+ end
61
+
62
+ module DatasetMethods
63
+ # For the association given by +name+, return a dataset of associated objects
64
+ # such that it would return the union of calling the association method on
65
+ # all objects returned by the current dataset.
66
+ #
67
+ # This supports most options that are supported when eager loading. It doesn't
68
+ # support limits on the associations, or one_to_one associations that are really
69
+ # one_to_many and use an order to select the first matching object. In both of
70
+ # those cases, this will return an array of all matching objects.
71
+ def associated(name)
72
+ raise Error, "unrecognized association name: #{name.inspect}" unless r = model.association_reflection(name)
73
+ ds = r.associated_class.dataset
74
+ sds = opts[:limit] ? self : unordered
75
+ ds = case r[:type]
76
+ when :many_to_one
77
+ ds.filter(r.qualified_primary_key=>sds.select(*Array(r[:qualified_key])))
78
+ when :one_to_one, :one_to_many
79
+ ds.filter(r.qualified_key=>sds.select(*Array(r.qualified_primary_key)))
80
+ when :many_to_many
81
+ ds.filter(r.qualified_right_primary_key=>sds.select(*Array(r.qualified_right_key)).
82
+ join(r[:join_table], r[:left_keys].zip(r[:left_primary_keys]), :implicit_qualifier=>model.table_name))
83
+ when :many_through_many
84
+ fre = r.reverse_edges.first
85
+ fe, *edges = r.edges
86
+ sds = sds.select(*Array(r.qualify(fre[:table], fre[:left]))).
87
+ join(fe[:table], Array(fe[:right]).zip(Array(fe[:left])), :implicit_qualifier=>model.table_name)
88
+ edges.each{|e| sds = sds.join(e[:table], Array(e[:right]).zip(Array(e[:left])))}
89
+ ds.filter(r.qualified_right_primary_key=>sds)
90
+ else
91
+ raise Error, "unrecognized association type for association #{name.inspect}: #{r[:type].inspect}"
92
+ end
93
+ ds = model.apply_association_dataset_opts(r, ds)
94
+ r[:extend].each{|m| ds.extend(m)}
95
+ ds
96
+ end
97
+ end
98
+ end
99
+ end
100
+ end
@@ -8,7 +8,7 @@ module Sequel
8
8
  # attribute, the resulting value is forced to a given encoding if the
9
9
  # value is a string. There are two ways to specify the encoding. You
10
10
  # can either do so in the plugin call itself, or via the
11
- # forced_encoding class accessor:
11
+ # forced_encoding class accessor.
12
12
  #
13
13
  # Usage:
14
14
  #
@@ -46,6 +46,11 @@ module Sequel
46
46
  super(force_hash_encoding(row))
47
47
  end
48
48
 
49
+ # Force the encoding of all string values when setting the instance's values.
50
+ def set_values(row)
51
+ super(force_hash_encoding(row))
52
+ end
53
+
49
54
  private
50
55
 
51
56
  # Force the encoding for all string values in the given row hash.
@@ -55,11 +60,6 @@ module Sequel
55
60
  row
56
61
  end
57
62
 
58
- # Force the encoding of all string values when setting the instance's values.
59
- def set_values(row)
60
- super(force_hash_encoding(row))
61
- end
62
-
63
63
  # Force the encoding of all returned strings to the model's forced_encoding.
64
64
  def typecast_value(column, value)
65
65
  s = super
@@ -163,7 +163,7 @@ module Sequel
163
163
  # certain fields in an initial query, make modifications to some of those
164
164
  # fields and request other, potentially overlapping fields in a new query,
165
165
  # and not have the second query override fields you modified.
166
- def load(row)
166
+ def call(row)
167
167
  return super unless idm = identity_map
168
168
  if o = idm[identity_map_key(Array(primary_key).map{|x| row[x]})]
169
169
  o.merge_db_update(row)
@@ -63,11 +63,8 @@ module Sequel
63
63
  self[:eager_loading_predicate_key] ||= begin
64
64
  calculate_edges
65
65
  e = self[:edges].first
66
- if self[:uses_left_composite_keys]
67
- e[:right].map{|k| SQL::QualifiedIdentifier.new(e[:table], k)}
68
- else
69
- SQL::QualifiedIdentifier.new(e[:table], e[:right])
70
- end
66
+ f = self[:final_reverse_edge]
67
+ qualify(f[:alias], e[:right])
71
68
  end
72
69
  end
73
70
 
@@ -200,9 +197,8 @@ module Sequel
200
197
  ds = opts.associated_class
201
198
  opts.reverse_edges.each{|t| ds = ds.join(t[:table], Array(t[:left]).zip(Array(t[:right])), :table_alias=>t[:alias])}
202
199
  ft = opts[:final_reverse_edge]
203
- conds = uses_lcks ? [[left_keys.map{|k| SQL::QualifiedIdentifier.new(ft[:table], k)}, h.keys]] : [[left_key, h.keys]]
204
- ds = ds.join(ft[:table], Array(ft[:left]).zip(Array(ft[:right])) + conds, :table_alias=>ft[:alias])
205
- ds = model.eager_loading_dataset(opts, ds, Array(opts.select), eo[:associations], eo)
200
+ ds = ds.join(ft[:table], Array(ft[:left]).zip(Array(ft[:right])) + [[opts.eager_loading_predicate_key, h.keys]], :table_alias=>ft[:alias])
201
+ ds = model.eager_loading_dataset(opts, ds, nil, eo[:associations], eo)
206
202
  case opts.eager_limit_strategy
207
203
  when :window_function
208
204
  delete_rn = true
@@ -262,7 +258,7 @@ module Sequel
262
258
  edges = ref.edges
263
259
  first, rest = edges.first, edges[1..-1]
264
260
  last = edges.last
265
- ds = model.db[first[:table]].select(*Array(first[:right]).map{|x| ::Sequel::SQL::QualifiedIdentifier.new(first[:table], x)})
261
+ ds = model.db[first[:table]].select(*Array(ref.qualify(first[:table], first[:right])))
266
262
  rest.each{|e| ds = ds.join(e[:table], e.fetch(:only_conditions, (Array(e[:right]).zip(Array(e[:left])) + e[:conditions])), :table_alias=>ds.unused_table_alias(e[:table]), &e[:block])}
267
263
  last_alias = if rest.empty?
268
264
  first[:table]
@@ -270,7 +266,7 @@ module Sequel
270
266
  last_join = ds.opts[:join].last
271
267
  last_join.table_alias || last_join.table
272
268
  end
273
- exp = association_filter_key_expression(Array(ref[:final_edge][:left]).map{|x| ::Sequel::SQL::QualifiedIdentifier.new(last_alias, x)}, ref.right_primary_keys, obj)
269
+ exp = association_filter_key_expression(ref.qualify(last_alias, Array(ref[:final_edge][:left])), ref.right_primary_keys, obj)
274
270
  if exp == SQL::Constants::FALSE
275
271
  association_filter_handle_inversion(op, exp, Array(lpks))
276
272
  else
@@ -85,7 +85,18 @@ module Sequel
85
85
  # Return an array of two element arrays with the column symbol as the first entry and the
86
86
  # placeholder symbol as the second entry.
87
87
  def prepared_statement_key_array(keys)
88
- Array(keys).map{|k| [k, :"$#{k}"]}
88
+ if dataset.requires_placeholder_type_specifiers?
89
+ sch = db_schema
90
+ Array(keys).map do |k|
91
+ if (s = sch[k]) && (t = s[:type])
92
+ [k, :"$#{k}__#{t}"]
93
+ else
94
+ [k, :"$#{k}"]
95
+ end
96
+ end
97
+ else
98
+ Array(keys).map{|k| [k, :"$#{k}"]}
99
+ end
89
100
  end
90
101
 
91
102
  # Return a hash mapping column symbols to placeholder symbols.
@@ -51,7 +51,7 @@ module Sequel
51
51
  when :one_to_many
52
52
  association_bound_variable_hash(opts.associated_class.table_name, opts[:keys], opts[:primary_keys])
53
53
  when :many_to_many
54
- association_bound_variable_hash(opts[:join_table], opts[:left_keys], opts[:left_primary_keys])
54
+ association_bound_variable_hash(opts.join_table_alias, opts[:left_keys], opts[:left_primary_keys])
55
55
  when :many_through_many
56
56
  opts.reverse_edges
57
57
  association_bound_variable_hash(opts[:final_reverse_edge][:alias], Array(opts[:left_key]), opts[:left_primary_keys])
@@ -109,7 +109,15 @@ module Sequel
109
109
  ka = opts[:key_alias] ||= :x_root_x
110
110
  t = opts[:cte_name] ||= :t
111
111
  opts[:reciprocal] = nil
112
- c_all = SQL::ColumnAll.new(model.table_name)
112
+ c_all = if model.dataset.recursive_cte_requires_column_aliases?
113
+ # Work around Oracle/ruby-oci8 bug that returns integers as BigDecimals in recursive queries.
114
+ conv_bd = model.db.database_type == :oracle
115
+ col_aliases = model.dataset.columns
116
+ model_table = model.table_name
117
+ col_aliases.map{|c| SQL::QualifiedIdentifier.new(model_table, c)}
118
+ else
119
+ [SQL::ColumnAll.new(model.table_name)]
120
+ end
113
121
 
114
122
  a = opts.merge(opts.fetch(:ancestors, {}))
115
123
  ancestors = a.fetch(:name, :ancestors)
@@ -125,9 +133,9 @@ module Sequel
125
133
  end
126
134
  table_alias = model.dataset.schema_and_table(model.table_name)[1].to_sym
127
135
  model.from(t => table_alias).
128
- with_recursive(t, base_ds.select_all,
129
- recursive_ds.
130
- select(c_all))
136
+ with_recursive(t, col_aliases ? base_ds.select(*col_aliases) : base_ds.select_all,
137
+ recursive_ds.select(*c_all),
138
+ :args=>col_aliases)
131
139
  end
132
140
  aal = Array(a[:after_load])
133
141
  aal << proc do |m, ancs|
@@ -163,9 +171,9 @@ module Sequel
163
171
  end
164
172
  r = model.association_reflection(ancestors)
165
173
  base_case = model.filter(prkey=>id_map.keys).
166
- select(SQL::AliasedExpression.new(prkey, ka), c_all)
174
+ select(SQL::AliasedExpression.new(prkey, ka), *c_all)
167
175
  recursive_case = model.join(t, key=>prkey).
168
- select(SQL::QualifiedIdentifier.new(t, ka), c_all)
176
+ select(SQL::QualifiedIdentifier.new(t, ka), *c_all)
169
177
  if c = r[:conditions]
170
178
  (base_case, recursive_case) = [base_case, recursive_case].collect do |ds|
171
179
  (c.is_a?(Array) && !Sequel.condition_specifier?(c)) ? ds.filter(*c) : ds.filter(c)
@@ -175,7 +183,8 @@ module Sequel
175
183
  elds = model.eager_loading_dataset(r,
176
184
  model.from(t => table_alias).
177
185
  with_recursive(t, base_case,
178
- recursive_case),
186
+ recursive_case,
187
+ :args=>(([ka] + col_aliases) if col_aliases)),
179
188
  r.select,
180
189
  eo[:associations], eo)
181
190
  elds = elds.select_append(ka) unless elds.opts[:select] == nil
@@ -192,7 +201,9 @@ module Sequel
192
201
  (children_map[obj[key]] ||= []) << obj
193
202
  end
194
203
 
195
- if roots = id_map[obj.values.delete(ka)]
204
+ kv = obj.values.delete(ka)
205
+ kv = kv.to_i if conv_bd && kv.is_a?(BigDecimal)
206
+ if roots = id_map[kv]
196
207
  roots.each do |root|
197
208
  root.associations[ancestors] << obj
198
209
  end
@@ -222,9 +233,9 @@ module Sequel
222
233
  end
223
234
  table_alias = model.dataset.schema_and_table(model.table_name)[1].to_sym
224
235
  model.from(t => table_alias).
225
- with_recursive(t, base_ds.select_all,
226
- recursive_ds.
227
- select(SQL::ColumnAll.new(model.table_name)))
236
+ with_recursive(t, col_aliases ? base_ds.select(*col_aliases) : base_ds.select_all,
237
+ recursive_ds.select(*c_all),
238
+ :args=>col_aliases)
228
239
  end
229
240
  dal = Array(d[:after_load])
230
241
  dal << proc do |m, descs|
@@ -259,9 +270,9 @@ module Sequel
259
270
  end
260
271
  r = model.association_reflection(descendants)
261
272
  base_case = model.filter(key=>id_map.keys).
262
- select(SQL::AliasedExpression.new(key, ka), c_all)
273
+ select(SQL::AliasedExpression.new(key, ka), *c_all)
263
274
  recursive_case = model.join(t, prkey=>key).
264
- select(SQL::QualifiedIdentifier.new(t, ka), c_all)
275
+ select(SQL::QualifiedIdentifier.new(t, ka), *c_all)
265
276
  if c = r[:conditions]
266
277
  (base_case, recursive_case) = [base_case, recursive_case].collect do |ds|
267
278
  (c.is_a?(Array) && !Sequel.condition_specifier?(c)) ? ds.filter(*c) : ds.filter(c)
@@ -276,7 +287,8 @@ module Sequel
276
287
  end
277
288
  table_alias = model.dataset.schema_and_table(model.table_name)[1].to_sym
278
289
  elds = model.eager_loading_dataset(r,
279
- model.from(t => table_alias).with_recursive(t, base_case, recursive_case),
290
+ model.from(t => table_alias).with_recursive(t, base_case, recursive_case,
291
+ :args=>(([ka] + col_aliases + (level ? [la] : [])) if col_aliases)),
280
292
  r.select,
281
293
  associations, eo)
282
294
  elds = elds.select_append(ka) unless elds.opts[:select] == nil
@@ -296,7 +308,9 @@ module Sequel
296
308
  parent_map[opk] = obj
297
309
  end
298
310
 
299
- if root = id_map[obj.values.delete(ka)].first
311
+ kv = obj.values.delete(ka)
312
+ kv = kv.to_i if conv_bd && kv.is_a?(BigDecimal)
313
+ if root = id_map[kv].first
300
314
  root.associations[descendants] << obj
301
315
  end
302
316
 
@@ -110,7 +110,7 @@ module Sequel
110
110
  attr_reader :deserialized_values
111
111
 
112
112
  # Set @deserialized_values to the empty hash
113
- def initialize(*args, &block)
113
+ def initialize_set(values)
114
114
  @deserialized_values = {}
115
115
  super
116
116
  end
@@ -127,6 +127,11 @@ module Sequel
127
127
  super
128
128
  end
129
129
 
130
+ def set_values(*)
131
+ @deserialized_values ||= {}
132
+ super
133
+ end
134
+
130
135
  private
131
136
 
132
137
  # Deserialize the column from either marshal or yaml format
@@ -90,11 +90,6 @@ module Sequel
90
90
  use_server(super)
91
91
  end
92
92
 
93
- # Make sure to use the correct shard when using a transaction
94
- def checked_transaction(opts={}, &block)
95
- super(@server ? {:server=>@server}.merge(opts) : opts, &block)
96
- end
97
-
98
93
  # If creating the object by doing <tt>add_association</tt> for a
99
94
  # +many_to_many+ association, make sure the associated object is created on the
100
95
  # current object's shard, unless the passed object already has an assigned shard.
@@ -124,7 +124,7 @@ module Sequel
124
124
  # Return an instance of the class specified by sti_key,
125
125
  # used by the row_proc.
126
126
  def sti_load(r)
127
- sti_class(sti_model_map[r[sti_key]]).load(r)
127
+ sti_class(sti_model_map[r[sti_key]]).call(r)
128
128
  end
129
129
 
130
130
  # Make sure that all subclasses of the parent class correctly include
@@ -5,7 +5,7 @@ module Sequel
5
5
  # typecast correctly (with correct being defined as how the model object
6
6
  # would typecast the same column values).
7
7
  #
8
- # This plugin modifies Model.load to call the setter methods (which typecast
8
+ # This plugin modifies Model#set_values to call the setter methods (which typecast
9
9
  # by default) for all columns given. You can either specify the columns to
10
10
  # typecast on load in the plugin call itself, or afterwards using
11
11
  # add_typecast_on_load_columns:
@@ -41,16 +41,11 @@ module Sequel
41
41
  super
42
42
  subclass.instance_variable_set(:@typecast_on_load_columns, typecast_on_load_columns.dup)
43
43
  end
44
-
45
- # Call the setter method for each of the typecast on load columns,
46
- # ensuring the model object will have the correct typecasting even
47
- # if the database doesn't typecast the columns correctly.
48
- def load(values)
49
- super.load_typecast
50
- end
51
44
  end
52
45
 
53
46
  module InstanceMethods
47
+ # Call the setter method for each of the model's typecast_on_load_columns
48
+ # with the current value, so it can be typecasted correctly.
54
49
  def load_typecast
55
50
  model.typecast_on_load_columns.each do |c|
56
51
  if v = values[c]
@@ -61,10 +56,12 @@ module Sequel
61
56
  self
62
57
  end
63
58
 
64
- private
65
-
66
- def _refresh(dataset)
67
- super.load_typecast
59
+ # Typecast values using #load_typecast when the values are retrieved from
60
+ # the database.
61
+ def set_values(values)
62
+ ret = super
63
+ load_typecast
64
+ ret
68
65
  end
69
66
  end
70
67
  end
@@ -22,7 +22,7 @@ module Sequel
22
22
  module UpdatePrimaryKey
23
23
  module ClassMethods
24
24
  # Cache the pk_hash when loading records
25
- def load(h)
25
+ def call(h)
26
26
  r = super(h)
27
27
  r.pk_hash
28
28
  r