sequel 3.36.1 → 3.37.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (108) hide show
  1. data/CHANGELOG +84 -0
  2. data/Rakefile +13 -0
  3. data/bin/sequel +12 -16
  4. data/doc/advanced_associations.rdoc +36 -67
  5. data/doc/association_basics.rdoc +11 -16
  6. data/doc/release_notes/3.37.0.txt +338 -0
  7. data/doc/schema_modification.rdoc +4 -0
  8. data/lib/sequel/adapters/jdbc/h2.rb +1 -1
  9. data/lib/sequel/adapters/jdbc/postgresql.rb +26 -8
  10. data/lib/sequel/adapters/mysql2.rb +4 -3
  11. data/lib/sequel/adapters/odbc/mssql.rb +2 -2
  12. data/lib/sequel/adapters/postgres.rb +4 -60
  13. data/lib/sequel/adapters/shared/mssql.rb +2 -1
  14. data/lib/sequel/adapters/shared/mysql.rb +0 -5
  15. data/lib/sequel/adapters/shared/postgres.rb +68 -2
  16. data/lib/sequel/adapters/shared/sqlite.rb +17 -1
  17. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +12 -1
  18. data/lib/sequel/adapters/utils/pg_types.rb +76 -0
  19. data/lib/sequel/core.rb +13 -0
  20. data/lib/sequel/database/misc.rb +41 -1
  21. data/lib/sequel/database/schema_generator.rb +23 -10
  22. data/lib/sequel/database/schema_methods.rb +26 -4
  23. data/lib/sequel/dataset/graph.rb +2 -1
  24. data/lib/sequel/dataset/query.rb +62 -2
  25. data/lib/sequel/extensions/_pretty_table.rb +7 -3
  26. data/lib/sequel/extensions/arbitrary_servers.rb +5 -4
  27. data/lib/sequel/extensions/blank.rb +4 -0
  28. data/lib/sequel/extensions/columns_introspection.rb +13 -2
  29. data/lib/sequel/extensions/core_extensions.rb +6 -0
  30. data/lib/sequel/extensions/eval_inspect.rb +158 -0
  31. data/lib/sequel/extensions/inflector.rb +4 -0
  32. data/lib/sequel/extensions/looser_typecasting.rb +5 -4
  33. data/lib/sequel/extensions/migration.rb +4 -1
  34. data/lib/sequel/extensions/named_timezones.rb +4 -0
  35. data/lib/sequel/extensions/null_dataset.rb +4 -0
  36. data/lib/sequel/extensions/pagination.rb +4 -0
  37. data/lib/sequel/extensions/pg_array.rb +219 -168
  38. data/lib/sequel/extensions/pg_array_ops.rb +7 -2
  39. data/lib/sequel/extensions/pg_auto_parameterize.rb +10 -4
  40. data/lib/sequel/extensions/pg_hstore.rb +3 -1
  41. data/lib/sequel/extensions/pg_hstore_ops.rb +7 -2
  42. data/lib/sequel/extensions/pg_inet.rb +28 -3
  43. data/lib/sequel/extensions/pg_interval.rb +192 -0
  44. data/lib/sequel/extensions/pg_json.rb +21 -9
  45. data/lib/sequel/extensions/pg_range.rb +487 -0
  46. data/lib/sequel/extensions/pg_range_ops.rb +122 -0
  47. data/lib/sequel/extensions/pg_statement_cache.rb +3 -2
  48. data/lib/sequel/extensions/pretty_table.rb +12 -1
  49. data/lib/sequel/extensions/query.rb +4 -0
  50. data/lib/sequel/extensions/query_literals.rb +6 -6
  51. data/lib/sequel/extensions/schema_dumper.rb +39 -38
  52. data/lib/sequel/extensions/select_remove.rb +4 -0
  53. data/lib/sequel/extensions/server_block.rb +3 -2
  54. data/lib/sequel/extensions/split_array_nil.rb +65 -0
  55. data/lib/sequel/extensions/sql_expr.rb +4 -0
  56. data/lib/sequel/extensions/string_date_time.rb +4 -0
  57. data/lib/sequel/extensions/thread_local_timezones.rb +9 -3
  58. data/lib/sequel/extensions/to_dot.rb +4 -0
  59. data/lib/sequel/model/associations.rb +150 -91
  60. data/lib/sequel/plugins/identity_map.rb +2 -2
  61. data/lib/sequel/plugins/list.rb +1 -0
  62. data/lib/sequel/plugins/many_through_many.rb +33 -32
  63. data/lib/sequel/plugins/nested_attributes.rb +11 -3
  64. data/lib/sequel/plugins/rcte_tree.rb +2 -2
  65. data/lib/sequel/plugins/schema.rb +1 -1
  66. data/lib/sequel/sql.rb +14 -14
  67. data/lib/sequel/version.rb +2 -2
  68. data/spec/adapters/mysql_spec.rb +25 -0
  69. data/spec/adapters/postgres_spec.rb +572 -28
  70. data/spec/adapters/sqlite_spec.rb +16 -1
  71. data/spec/core/database_spec.rb +61 -2
  72. data/spec/core/dataset_spec.rb +92 -0
  73. data/spec/core/expression_filters_spec.rb +12 -0
  74. data/spec/extensions/arbitrary_servers_spec.rb +1 -1
  75. data/spec/extensions/boolean_readers_spec.rb +25 -25
  76. data/spec/extensions/eval_inspect_spec.rb +58 -0
  77. data/spec/extensions/json_serializer_spec.rb +0 -6
  78. data/spec/extensions/list_spec.rb +1 -1
  79. data/spec/extensions/looser_typecasting_spec.rb +7 -7
  80. data/spec/extensions/many_through_many_spec.rb +81 -0
  81. data/spec/extensions/nested_attributes_spec.rb +21 -4
  82. data/spec/extensions/pg_array_ops_spec.rb +1 -11
  83. data/spec/extensions/pg_array_spec.rb +181 -90
  84. data/spec/extensions/pg_auto_parameterize_spec.rb +3 -3
  85. data/spec/extensions/pg_hstore_spec.rb +1 -3
  86. data/spec/extensions/pg_inet_spec.rb +6 -1
  87. data/spec/extensions/pg_interval_spec.rb +73 -0
  88. data/spec/extensions/pg_json_spec.rb +5 -9
  89. data/spec/extensions/pg_range_ops_spec.rb +49 -0
  90. data/spec/extensions/pg_range_spec.rb +372 -0
  91. data/spec/extensions/pg_statement_cache_spec.rb +1 -2
  92. data/spec/extensions/query_literals_spec.rb +1 -2
  93. data/spec/extensions/schema_dumper_spec.rb +48 -89
  94. data/spec/extensions/serialization_spec.rb +1 -5
  95. data/spec/extensions/server_block_spec.rb +2 -2
  96. data/spec/extensions/spec_helper.rb +12 -2
  97. data/spec/extensions/split_array_nil_spec.rb +24 -0
  98. data/spec/integration/associations_test.rb +4 -4
  99. data/spec/integration/database_test.rb +2 -2
  100. data/spec/integration/dataset_test.rb +4 -4
  101. data/spec/integration/eager_loader_test.rb +6 -6
  102. data/spec/integration/plugin_test.rb +2 -2
  103. data/spec/integration/spec_helper.rb +2 -2
  104. data/spec/model/association_reflection_spec.rb +5 -0
  105. data/spec/model/associations_spec.rb +156 -49
  106. data/spec/model/eager_loading_spec.rb +137 -2
  107. data/spec/model/model_spec.rb +10 -10
  108. metadata +15 -2
data/CHANGELOG CHANGED
@@ -1,3 +1,87 @@
1
+ === 3.37.0 (2012-07-02)
2
+
3
+ * Allow specifying eager_graph alias base on a per-call basis using an AliasedExpression (jeremyevans)
4
+
5
+ * Allow bin/sequel to respect multiple -l options for logging to multiple files (jeremyevans)
6
+
7
+ * Correctly handle cases where SCOPE_IDENTITY is nil in the odbc/mssql adapter (stnoonan, jeremyevans)
8
+
9
+ * Add pg_interval extension, for returning interval types as ActiveSupport::Duration instances (jeremyevans)
10
+
11
+ * Save a new one_to_one associated object once instead of twice in the nested_attributes plugin (jeremyevans)
12
+
13
+ * Don't add unnecessary filter condition when passing a new object to a one_to_one setter method (jeremyevans)
14
+
15
+ * Differentiate between column references and method references in many_through_many associations (jeremyevans)
16
+
17
+ * Use :qualify=>:deep option when joining tables in model association datasets (jeremyevans)
18
+
19
+ * Support :qualify=>:deep option to Dataset#join_table to qualify subexpressions in the expression tree (jeremyevans)
20
+
21
+ * Support :qualify=>false option to Dataset#join_table to not automatically qualify keys/values (jeremyevans)
22
+
23
+ * Make filter by associations support use column references and method references correctly (jeremyevans)
24
+
25
+ * Call super in list plugin before_create (jeremyevans) (#504)
26
+
27
+ * Do not automatically cast String to text in pg_auto_parameterize extension (jeremyevans)
28
+
29
+ * Support alter_table validate_constraint on PostgreSQL for validating constraints previously declared with NOT VALID (jeremyevans)
30
+
31
+ * Support :not_valid option when adding foreign key constraints on PostgreSQL (jeremyevans)
32
+
33
+ * Support exclusion constraints on PostgreSQL (jeremyevans)
34
+
35
+ * Allow for overriding the create/alter table generators used per Database object (jeremyevans)
36
+
37
+ * Make casting to Date/(Time/DateTime) use date/datetime functions on SQLite (jeremyevans)
38
+
39
+ * Add pg_range_ops extension for DSL support for PostgreSQL range operators and functions (jeremyevans)
40
+
41
+ * The json library is now required when running the plugin/extension specs (jeremyevans)
42
+
43
+ * Use change migrations instead of up/down migrations in the schema_dumper (jeremyevans)
44
+
45
+ * Dump unsigned integer columns with a check >= 0 constraint in the schema_dumper (stu314)
46
+
47
+ * Switch the :key_hash entry to the association :eager_loader option to use the method symbol(s) instead of the column symbol(s) (jeremyevans)
48
+
49
+ * Add :id_map entry to the hash passed to the association :eager_loader option, for easier custom eager loading (jeremyevans)
50
+
51
+ * Fix dumping of non-integer foreign key columns in the schema_dumper (jeremyevans) (#502)
52
+
53
+ * Add nested_attributes :fields option to be a proc that is called with the associated object (chanks) (#498)
54
+
55
+ * Add split_array_nil extension, for compiling :col=>[1, nil] to col IN (1) OR col IS NULL (jeremyevans)
56
+
57
+ * Add Database#extension and Dataset#extension for loading extension modules into objects automatically (jeremyevans)
58
+
59
+ * Respect an existing dataset limit when updating on Microsoft SQL Server (jeremyevans)
60
+
61
+ * Add pg_range extension, for dealing with PostgreSQL 9.2+ range types (jeremyevans)
62
+
63
+ * Make pg_array extension convert array members when typecasting Array to PGArray (jeremyevans)
64
+
65
+ * Make jdbc/postgres adapter convert array type elements (e.g. date[] arrays are returned as arrays of Date instances) (jeremyevans)
66
+
67
+ * Make the pg_inet extension handle inet[]/cidr[]/macaddr[] types when used with the pg_array extension (jeremyevans)
68
+
69
+ * Make the pg_json extension handle json[] type when used with the pg_array extension (jeremyevans)
70
+
71
+ * Fix schema parsing of h2 clob types (jeremyevans)
72
+
73
+ * Make the pg_array extension handle array types for scalar types handled by the native postgres adapter (jeremyevans)
74
+
75
+ * Generalize handling of array types in the pg_array extension, allowing easy support of custom array types (jeremyevans)
76
+
77
+ * Remove type conversion of int2vector and money types on PostgreSQL, since previous conversions were wrong (jeremyevans)
78
+
79
+ * Add eval_inspect extension, which makes Sequel::SQL::Expression#inspect attempt to return a string suitable for eval (jeremyevans)
80
+
81
+ * When emulating offset with ROW_NUMBER, default to ordering by all columns if no specific order is given (stnoonan, jeremyevans) (#490)
82
+
83
+ * Work around JRuby 1.6 ruby 1.9 mode bug in Time -> SQLTime conversion (jeremyevans)
84
+
1
85
  === 3.36.1 (2012-06-01)
2
86
 
3
87
  * Fix jdbc adapter when DriverManager#getConnection fails (aportnov) (#488)
data/Rakefile CHANGED
@@ -138,6 +138,19 @@ begin
138
138
  %w'postgres sqlite mysql informix oracle firebird mssql db2'.each do |adapter|
139
139
  spec_with_cov.call("spec_#{adapter}", ["spec/adapters/#{adapter}_spec.rb"] + Dir["spec/integration/*_test.rb"], "Run #{adapter} specs"){|t| t.rcov_opts.concat(%w'--exclude "lib/sequel/([a-z_]+\.rb|connection_pool|database|dataset|model|extensions|plugins)"')}
140
140
  end
141
+
142
+ task :spec_travis=>[:spec, :spec_plugin, :spec_sqlite] do
143
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
144
+ ENV['SEQUEL_PG_SPEC_DB'] = "jdbc:postgresql://localhost/sequel_test?user=postgres"
145
+ ENV['SEQUEL_MY_SPEC_DB'] = "jdbc:mysql://localhost/sequel_test?user=root"
146
+ else
147
+ ENV['SEQUEL_PG_SPEC_DB'] = "postgres://localhost/sequel_test?user=postgres"
148
+ ENV['SEQUEL_MY_SPEC_DB'] = "mysql2://localhost/sequel_test?user=root"
149
+ end
150
+
151
+ Rake::Task['spec_postgres'].invoke
152
+ Rake::Task['spec_mysql'].invoke
153
+ end
141
154
 
142
155
  desc "Run model specs without the associations code"
143
156
  task :spec_model_no_assoc do
data/bin/sequel CHANGED
@@ -4,18 +4,17 @@ require 'rubygems'
4
4
  require 'optparse'
5
5
  require 'sequel'
6
6
 
7
- db_opts = {:test=>true}
8
7
  copy_databases = nil
9
8
  dump_migration = nil
10
9
  dump_schema = nil
11
- echo = nil
12
10
  env = nil
13
- logfile = nil
14
11
  migrate_dir = nil
15
12
  migrate_ver = nil
16
13
  backtrace = nil
14
+ test = true
17
15
  load_dirs = []
18
16
  exclusive_options = []
17
+ loggers = []
19
18
 
20
19
  opts = OptionParser.new do |opts|
21
20
  opts.banner = "Sequel: The Database Toolkit for Ruby"
@@ -54,7 +53,8 @@ opts = OptionParser.new do |opts|
54
53
  end
55
54
 
56
55
  opts.on("-E", "--echo", "echo SQL statements") do
57
- echo = true
56
+ require 'logger'
57
+ loggers << Logger.new($stdout)
58
58
  end
59
59
 
60
60
  opts.on("-I", "--include dir", "specify $LOAD_PATH directory") do |v|
@@ -62,7 +62,8 @@ opts = OptionParser.new do |opts|
62
62
  end
63
63
 
64
64
  opts.on("-l", "--log logfile", "log SQL statements to log file") do |v|
65
- logfile = v
65
+ require 'logger'
66
+ loggers << Logger.new(v)
66
67
  end
67
68
 
68
69
  opts.on("-L", "--load-dir DIR", "loads all *.rb under specifed directory") do |v|
@@ -79,7 +80,7 @@ opts = OptionParser.new do |opts|
79
80
  end
80
81
 
81
82
  opts.on("-N", "--no-test-connection", "do not test the connection") do
82
- db_opts[:test] = false
83
+ test = false
83
84
  end
84
85
 
85
86
  opts.on("-r", "--require lib", "require the library, before executing your script") do |v|
@@ -112,26 +113,21 @@ end
112
113
  error_proc["Error: Must specify -m if using -M"] if migrate_ver && !migrate_dir
113
114
  error_proc["Error: Cannot specify #{exclusive_options.map{|v| "-#{v}"}.join(' and ')} together"] if exclusive_options.length > 1
114
115
 
115
- if logfile || echo
116
- require 'logger'
117
- db_opts[:loggers] = []
118
- db_opts[:loggers] << Logger.new(logfile) if logfile
119
- db_opts[:loggers] << Logger.new($stdout) if echo
120
- end
121
-
122
116
  connect_proc = lambda do |database|
123
117
  db = if database.nil? || database.empty?
124
- Sequel.connect('mock:///', db_opts)
118
+ Sequel.connect('mock:///')
125
119
  elsif File.exist?(database)
126
120
  require 'yaml'
127
121
  env ||= "development"
128
122
  db_config = YAML.load_file(database)
129
123
  db_config = db_config[env] || db_config[env.to_sym] || db_config
130
124
  db_config.keys.each{|k| db_config[k.to_sym] = db_config.delete(k)}
131
- Sequel.connect(db_config.merge!(db_opts))
125
+ Sequel.connect(db_config)
132
126
  else
133
- Sequel.connect(database, db_opts)
127
+ Sequel.connect(database)
134
128
  end
129
+ db.loggers = loggers
130
+ db.test_connection if test
135
131
  db
136
132
  end
137
133
 
@@ -75,19 +75,15 @@ option. Though it can often be verbose (compared to other things in Sequel),
75
75
  it allows you complete control over how to eagerly load associations for a
76
76
  group of objects.
77
77
 
78
- :eager_loader should be a proc that takes 1 or 3 arguments. If the proc
79
- takes one argument, it will be given a hash with the following keys:
78
+ :eager_loader should be a proc that takes a single hash argument, which will
79
+ have at least the following keys:
80
80
 
81
- :key_hash :: A key_hash, described below
81
+ :id_map :: A mapping of key values to arrays of current model instances,
82
+ usage described below
82
83
  :rows :: An array of model objects
83
84
  :associations :: A hash of dependent associations to eagerly load
84
85
  :self :: The dataset that is doing the eager loading
85
-
86
- If the proc takes three arguments, it gets passed the :key_hash, :rows,
87
- and :associations values. The only way to get the :self value is to
88
- accept one argument. The 3 argument procs are allowed for backwards
89
- compatibility, and it is recommended to use the 1 argument proc format
90
- for new code.
86
+ :eager_block :: A dynamic callback for this eager load.
91
87
 
92
88
  Since you are given all of the records, you can do things like filter on
93
89
  associations that are specified by multiple keys, or do multiple
@@ -98,13 +94,12 @@ associations cache for all objects in the array of records. The hash
98
94
  of dependent associations is available for you to cascade the eager
99
95
  loading down multiple levels, but it is up to you to use it.
100
96
 
101
- The key_hash is a performance enhancement that is used by the default
102
- association loaders and is also available to you. It is a hash with keys being
103
- foreign/primary key symbols in the current table, and the values
104
- being hashes where the key is foreign/primary key values and values
105
- being arrays of current model objects having the foreign/primary key
106
- value associated with the key. This is hard to visualize, so I'll
107
- give an example. Let's say you have the following associations
97
+ The id_map is a performance enhancement that is used by the default
98
+ association loaders and is also available to you. It is a hash with keys
99
+ foreign/primary key values, and values being arrays of current model
100
+ objects having the foreign/primary key value associated with the key.
101
+ This may be hard to visualize, so I'll give an example. Let's say you
102
+ have the following associations
108
103
 
109
104
  Album.many_to_one :artist
110
105
  Album.one_to_many :tracks
@@ -113,53 +108,30 @@ and the following two albums in the database:
113
108
 
114
109
  album1 = Album.create(:artist_id=>3) # id: 1
115
110
  album2 = Album.create(:artist_id=>3) # id: 2
111
+ album3 = Album.create(:artist_id=>2) # id: 3
116
112
 
117
113
  If you try to eager load this dataset:
118
114
 
119
115
  Album.eager(:artist, :tracks).all
120
116
 
121
- Then the key_hash provided to the :eager_loader proc would be:
122
-
123
- {:id=>{1=>[album1], 2=>[album2]}, :artist_id=>{3=>[album1, album2]}}
124
-
125
- Let's break down the reason for the makeup of this key_hash. The hash has keys for
126
- each of foreign/primary keys used in the association. In this case, the artist
127
- association needs the artist_id foreign key (since it is a many_to_one), and the
128
- tracks association needs the id primary key (since it is a one_to_many).
129
-
130
- If you only eagerly loaded the artist association:
131
-
132
- Album.eager(:artist).all
133
-
134
- Then the key_hash would only contain artist_id information:
135
-
136
- {:artist_id=>{3=>[album1, album2]}}
137
-
138
- Likewise, if you only eagerly loaded the tracks association:
139
-
140
- Album.eager(:tracks).all
141
-
142
- Then the key_hash would only contain id information:
143
-
144
- {:id=>{1=>[album1], 2=>[album2]}}
145
-
146
- Now, the eager loader for the artist association is only going to care about the
147
- value of the artist_id key in the hash, so it's going to do the equivalent of:
117
+ Then the id_map provided to the artist :eager_loader proc would be:
148
118
 
149
- artist_id_map = key_hash[:artist_id] # {3=>[album1, album2]}
119
+ {3=>[album1, album2], 2=>[album3]}
150
120
 
151
- The artist_id_map contains a mapping of artist_id values to arrays of
152
- album objects. Since it only has a single entry with a key of 3, when eagerly
153
- loading the artists, you only need to look for artists that have an id of 3.
121
+ The artist id_map contains a mapping of artist_id values to arrays of
122
+ album objects. Since both album1 and album2 have the same artist_id,
123
+ the are both in the array related to that key. album3 has a different
124
+ artist_id, so it is in a different array. Eager loading of artists is
125
+ done by looking for any artist having one of the keys in the hash:
154
126
 
155
- artists = Artist.where(:id=>artist_id_map.keys).all
127
+ artists = Artist.where(:id=>id_map.keys).all
156
128
 
157
129
  When the artists are retrieved, you can iterate over them, find entries
158
130
  with matching keys, and manually associate them to the albums:
159
131
 
160
132
  artists.each do |artist|
161
133
  # Find related albums using the artist_id_map
162
- if albums = artist_id_map[artist.id]
134
+ if albums = id_map[artist.id]
163
135
  # Iterate over the albums
164
136
  albums.each do |album|
165
137
  # Manually set the artist association for each album
@@ -168,15 +140,14 @@ with matching keys, and manually associate them to the albums:
168
140
  end
169
141
  end
170
142
 
171
- Similarly, the eager loader for the tracks association is only going to care about the
172
- value of the id key in the hash:
143
+ The id_map provided to the tracks :eager_loader proc would be:
173
144
 
174
- id_map = key_hash[:id] # {1=>[album1], 2=>[album2]}
145
+ {1=>[album1], 2=>[album2], 3=>[album3]}
175
146
 
176
147
  Now the id_map contains a mapping of id values to arrays of album objects (in this
177
148
  case each array only has a single object, because id is the primary key). So when
178
149
  looking for tracks to eagerly load, you only need to look for ones that have an
179
- album_id of 1 or 2:
150
+ album_id with one of the keys in the hash:
180
151
 
181
152
  tracks = Track.where(:album_id=>id_map.keys).all
182
153
 
@@ -213,9 +184,9 @@ So putting everything together, the artist eager loader looks like:
213
184
 
214
185
  :eager_loader=>(proc do |eo_opts|
215
186
  eo_opts[:rows].each{|album| album.associations[:artist] = nil}
216
- artist_id_map = eo_opts[:key_hash][:artist_id]
217
- Artist.where(:id=>artist_id_map.keys).all do |artist|
218
- if albums = artist_id_map[artist.id]
187
+ id_map = eo_opts[:id_map]
188
+ Artist.where(:id=>id_map.keys).all do |artist|
189
+ if albums = id_map[artist.id]
219
190
  albums.each do |album|
220
191
  album.associations[:artist] = artist
221
192
  end
@@ -227,7 +198,7 @@ and the tracks eager loader looks like:
227
198
 
228
199
  :eager_loader=>(proc do |eo_opts|
229
200
  eo_opts[:rows].each{|album| album.associations[:tracks] = []}
230
- id_map = eo_opts[:key_hash][:id]
201
+ id_map = eo_opts[:id_map]
231
202
  Track.where(:id=>id_map.keys).all do |tracks|
232
203
  if albums = id_map[track.album_id]
233
204
  albums.each do |album|
@@ -245,14 +216,12 @@ the custom eager loaders described later in this page are more complex.
245
216
  Basically, the eager loading steps can be broken down into:
246
217
 
247
218
  1. Set default association values (nil/[]) for each of the current objects
248
- 2. Build a custom key map mapping foreign/primary key values to arrays of
249
- current objects (using the key_hash)
250
- 3. Return just related associated objects by filtering the associated class
251
- to include only matching values
252
- 4. Iterating over the returned associated objects, indexing into the custom key
253
- map using the foreign/primary key value in the associated object to get
219
+ 2. Return just related associated objects by filtering the associated class
220
+ to include only rows with keys present in the id_map.
221
+ 3. Iterating over the returned associated objects, indexing into the id_map
222
+ using the foreign/primary key value in the associated object to get
254
223
  current values associated to that specific object.
255
- 5. For each of those current values, updating the cached association value to
224
+ 4. For each of those current values, updating the cached association value to
256
225
  include that specific object.
257
226
 
258
227
  Using the :eager_loader proc, you should be able to eagerly load all associations
@@ -631,7 +600,7 @@ name, with no duplicates?
631
600
  one_to_many :songs, :order=>:songs__name, \
632
601
  :dataset=>proc{Song.select(:songs.*).join(Lyric, :id=>:lyric_id, id=>[:composer_id, :arranger_id, :vocalist_id, :lyricist_id])}, \
633
602
  :eager_loader=>(proc do |eo|
634
- h = eo[:key_hash][:id]
603
+ h = eo[:id_map]
635
604
  ids = h.keys
636
605
  eo[:rows].each{|r| r.associations[:songs] = []}
637
606
  Song.select(:songs.*, :lyrics__composer_id, :lyrics__arranger_id, :lyrics__vocalist_id, :lyrics__lyricist_id)\
@@ -662,11 +631,11 @@ associated tickets.
662
631
  :dataset=>proc{Ticket.filter(:project_id=>id).select{sum(hours).as(hours)}},
663
632
  :eager_loader=>(proc do |eo|
664
633
  eo[:rows].each{|p| p.associations[:ticket_hours] = nil}
665
- Ticket.filter(:project_id=>eo[:key_hash][:id].keys).
634
+ Ticket.filter(:project_id=>eo[:id_map].keys).
666
635
  group(:project_id).
667
636
  select{[project_id, sum(hours).as(hours)]}.
668
637
  all do |t|
669
- p = eo[:key_hash][:id][t.values.delete(:project_id)].first
638
+ p = eo[:id_map][t.values.delete(:project_id)].first
670
639
  p.associations[:ticket_hours] = t
671
640
  end
672
641
  end)
@@ -473,7 +473,7 @@ associations (ones without conditions).
473
473
  == Name Collisions
474
474
 
475
475
  Because associations create instance methods, it's possible to override
476
- existing instance methods if you name an extension the same as an
476
+ existing instance methods if you name an association the same as an
477
477
  existing method. For example, <tt>values</tt> and <tt>associations</tt>
478
478
  would be bad association names.
479
479
 
@@ -1050,7 +1050,7 @@ Column in associated table that :right_key points to, as a symbol.
1050
1050
  Defaults to primary key of the associated table.
1051
1051
 
1052
1052
  Tag.set_primary_key :tid
1053
- Album.many_to_many :tags # :left_primary_key=>:tid
1053
+ Album.many_to_many :tags # :right_primary_key=>:tid
1054
1054
 
1055
1055
  Can use an array of symbols for a composite key association.
1056
1056
 
@@ -1135,8 +1135,6 @@ Called after removing an object from the association:
1135
1135
 
1136
1136
  Called before the _<i>association</i>= method is called to modify the objects:
1137
1137
 
1138
- Called before removing an object from the association:
1139
-
1140
1138
  class Album
1141
1139
  # Don't associate the album with an artist if the year the album was
1142
1140
  # released is less than the year the artist/band started.
@@ -1223,13 +1221,9 @@ For many details and examples of custom eager loaders, please see the
1223
1221
  ==== :eager_loader_key
1224
1222
 
1225
1223
  A symbol for the key column to use to populate the key hash for the eager
1226
- loader. It can be necessary to specify this for custom eager loaders
1227
- where the default key that would be used does not exist, as in that case, Sequel
1228
- would think that the key values are all NULL, and would not attempt to
1229
- eagerly load any associated objects for that association. If you have a
1230
- custom eager loader and aren't sure of a good value to use here, and you
1231
- aren't using the key_hash (first argument to the eager_loader proc), then
1232
- you can probably use the primary key column of the model.
1224
+ loader. Generally does not need to be set manually, defaults to the key
1225
+ method used. Can be set to nil to not populate the key hash (better for
1226
+ performance if a custom eager loader does not use the key_hash).
1233
1227
 
1234
1228
  ==== :eager_block
1235
1229
 
@@ -1340,6 +1334,11 @@ This is mostly useful if you have associations with the same name in many models
1340
1334
  to be able to easily tell which table alias corresponds to which association when eagerly
1341
1335
  graphing multiple associations with the same name.
1342
1336
 
1337
+ You can override this option on a per-graph basis by specifying the association as an
1338
+ SQL::AliasedExpression instead of a symbol:
1339
+
1340
+ Album.eager_graph(Sequel.as(:artist, :a))
1341
+
1343
1342
  ==== :eager_grapher
1344
1343
 
1345
1344
  Sets up a custom grapher to use when eager loading the objects via eager_graph.
@@ -1465,13 +1464,9 @@ aliases defined with <tt>Model.def_column_alias</tt>:
1465
1464
  def_column_alias(:obj_id, :object_id)
1466
1465
  end
1467
1466
  class Obj < Sequel::Model
1468
- many_to_one :things, :key=>:object_id, :key_method=>:obj_id
1467
+ one_to_many :things, :key=>:object_id, :key_method=>:obj_id
1469
1468
  end
1470
1469
 
1471
- Note that for eager loading purposes, you generally need to set the
1472
- <tt>:eager_loader_key</tt> option as well, specifying the underlying
1473
- column(s) to use.
1474
-
1475
1470
  ==== :key_column [+many_to_one+]
1476
1471
 
1477
1472
  Like the :key option, but :key references the method name, while
@@ -0,0 +1,338 @@
1
+ = New Features
2
+
3
+ * Database#extension and Dataset#extension have been added and
4
+ make it much easier to use extensions that just define modules,
5
+ where you previously had to manually extend a Database or
6
+ Dataset object with the module to get the extension's behavior.
7
+ These methods operate similarly to model plugins, where you just
8
+ specify the extension symbol, except that you can specify multiple
9
+ extensions at once:
10
+
11
+ DB.extension(:pg_array, :pg_hstore)
12
+
13
+ For databases, these modify the Database itself (and
14
+ potentially all of its datasets). Dataset#extension operates
15
+ like other dataset methods, returning a modified clone of
16
+ the dataset with the extension added:
17
+
18
+ dataset = dataset.extension(:columns_introspection)
19
+
20
+ Dataset#extension! has also been added for modifying the
21
+ receiver instead of returning a clone.
22
+
23
+ Not all extensions are usable by Database#extension or
24
+ Dataset#extension, the extension has to have specific support
25
+ for it. The following extensions support both
26
+ Database#extension and Dataset#extension:
27
+
28
+ * columns_introspection
29
+ * query_literals
30
+ * split_array_nil
31
+
32
+ The following extensions support just Database#extension:
33
+
34
+ * arbitrary_servers
35
+ * looser_typecasting
36
+ * pg_array
37
+ * pg_auto_parameterize
38
+ * pg_hstore
39
+ * pg_inet
40
+ * pg_interval
41
+ * pg_json
42
+ * pg_range
43
+ * pg_statement_cache
44
+ * server_block
45
+
46
+ Any user that was loading these extensions with Sequel.extension
47
+ and then manually extending objects with the extension's module
48
+ is encouraged to switch to Database#extension and/or
49
+ Dataset#extension.
50
+
51
+ * Dataset join methods now respect a :qualify=>:deep option
52
+ to do deep qualification of expressions, allowing qualification
53
+ of subexpressions in the expression tree. This can allow you
54
+ to do things like:
55
+
56
+ DB[:a].join(:b, {:c.cast(Integer)=>:d.cast(Integer)},
57
+ :qualify=>:deep)
58
+ # SELECT * FROM a INNER JOIN b
59
+ # ON (CAST(b.c AS INTEGER) = CAST(a.d AS INTEGER))
60
+
61
+ For backwards compatibility, by default Sequel will only do
62
+ automatic qualification if the arguments are simple symbols.
63
+ This may change in a future version, if automatic qualification
64
+ of only symbols is desired, switch to using :qualify=>:symbol.
65
+
66
+ You can also choose to do no automatic qualification using the
67
+ :qualify=>false option.
68
+
69
+ * All of Sequel's model associations now work with key expressions
70
+ that are not simple column references, without creating a fully
71
+ custom association. So you can create associations where the
72
+ primary/foreign key values are stored in PostgreSQL array or
73
+ hstore columns, for example.
74
+
75
+ * The pg_array extension has now been made more generic, so that it
76
+ is easy to support array types for any scalar type that is
77
+ currently supported. All scalar types that Sequel's postgres
78
+ adapter supports now have corresponding array types supported in
79
+ the pg_array extension. So if you load the pg_array extension and
80
+ return a date array column, the returned values will be arrays of
81
+ ruby Date objects.
82
+
83
+ Other pg_* extensions that add support for PostgreSQL-specific
84
+ scalar types now support array versions of those types if the
85
+ pg_array extension is loaded first.
86
+
87
+ * A pg_range extension has been added, making it easy to deal
88
+ with PostgreSQL 9.2+'s range types. As ruby's Range class does
89
+ not support all PostgreSQL range type values (such as empty ranges,
90
+ unbounded ranges, or ranges with an exlusive beginning), range
91
+ types are returned as instances of Sequel::Postgres::PGRange, which
92
+ has an API similar to Range. You can turn a PGRange into a Range
93
+ using PGRange#to_range, assuming that the range type value does not
94
+ use features that are incompatible with ruby's Range class.
95
+
96
+ The pg_range extension supports all range types supported by
97
+ default in PostgreSQL 9.2, and makes it easy to support custom
98
+ range types.
99
+
100
+ * A pg_range_ops extension has been added, which adds DSL support for
101
+ PostgreSQL range operators and functions, similar to the
102
+ pg_array_ops and pg_hstore_ops extensions.
103
+
104
+ * A pg_interval extension has been added, which makes Sequel return
105
+ PostgreSQL interval types as instances of ActiveSupport::Duration.
106
+ This is useful if you want to take the interval value and use it in
107
+ calculations in ruby (assuming you load the appropriate parts of
108
+ ActiveSupport).
109
+
110
+ * A split_array_nil extension has been added, which changes how Sequel
111
+ compiles IN/NOT IN expressions with arrays with nil values.
112
+
113
+ where(:col=>[1, nil])
114
+ # Default:
115
+ # WHERE (col IN (1, NULL))
116
+ # with split_array_nil extension:
117
+ # WHERE ((col IN (1)) OR (col IS NULL))
118
+
119
+ exclude(:col=>[1, nil])
120
+ # Default:
121
+ # WHERE (col NOT IN (1, NULL))
122
+ # with split_array_nil extension:
123
+ # WHERE ((col NOT IN (1)) AND (col IS NOT NULL))
124
+
125
+ * The nested_attributes plugin now allows the :fields option to
126
+ be a proc, which is called with the associated object and should
127
+ return an array of allowable fields.
128
+
129
+ * You can now specify the graph alias base when using eager_graph on
130
+ a per-call basis. Previously, it could only be set on a per
131
+ association basis. This is helpful if you have multiple
132
+ associations to the same class, and are cascading the eager graph to
133
+ dependent associations of that class for both of the associations.
134
+ Previously, there was no way to manually give descriptive names to
135
+ the tables in the cascaded associations, but you can now do so
136
+ by passing the association as an Sequel::SQL::AliasedExpression
137
+ instance instead of a plain Symbol. Here's a usage example:
138
+
139
+ ds = Game.eager_graph(:winner=>:players.as(:winning_players),
140
+ :loser=>:players.as(:losing_players)).
141
+ where(:winning_players__name=>'A',
142
+ :losing_players__name=>'B')
143
+
144
+ * many_through_many associations now differentiate between column
145
+ references and method references, by supporting the
146
+ :left_primary_key_column and :right_primary_key_method options that
147
+ many_to_many associations support.
148
+
149
+ * Custom :eager_loader procs that accept a single hash argument now
150
+ have an additional entry passed in the hash, :id_map, which is
151
+ easier to use than the :key_hash entry (which is still present for
152
+ backwards compatibility). Anyone with custom :eager_loader procs is
153
+ encouraged to switch from using :key_hash to :id_map.
154
+
155
+ * You can now override the create_table/alter_table schema generators
156
+ per database/adapter. This allows for database specific generator
157
+ subclasses, which have methods for unique features for that
158
+ database.
159
+
160
+ * You can now setup exclusion constraints on PostgreSQL using the
161
+ create_table and alter_table schema generators:
162
+
163
+ DB.create_table(:t) do
164
+ ...
165
+ exclusion_constraint([[:col1, '&&'], [:col2, '=']])
166
+ # EXCLUDE USING gist (col1 WITH &&, col2 WITH =)
167
+ end
168
+
169
+ One common use for exclusion constraints is to make sure that no two
170
+ rows have overlapping values/ranges/circles.
171
+
172
+ * When adding foreign key constraints to an existing table on
173
+ PostgreSQL, you can use the :not_valid option to mark the constraint
174
+ as not yet valid. This will make it so that future changes to the
175
+ table need to respect the foreign key constraint, but existing rows
176
+ do not. After cleaning up the existing data, you can then use the
177
+ alter_table validate_constraint method to mark the constraint as
178
+ valid.
179
+
180
+ * An eval_inspect extension has been added that attempts to do
181
+ do the following for Sequel::SQL::Expression instances:
182
+
183
+ eval(obj.inspect) == obj # => true
184
+
185
+ There are a lot of cases that this extension does not handle, but
186
+ it does a decent job in most cases. This is currently only used
187
+ internally in a specific case in the schema_dumper extension.
188
+
189
+ = Other Improvements
190
+
191
+ * The filter by associations support now respects the method
192
+ reference vs column reference distinction that other parts of the
193
+ association code have respected since 3.32.0.
194
+
195
+ * In the nested_attributes plugin, new one_to_one associated
196
+ values are saved once instead of twice. Previously it attempted to
197
+ save them before they were associated to the current model object,
198
+ which can violate some validations/constraints.
199
+
200
+ * When saving an associated object in the one_to_one association
201
+ setter method, Sequel no longer adds an unnecessary filter
202
+ condition when nullifying the foreign key for existing rows
203
+ in the associated table.
204
+
205
+ * The list plugin's before_create method now calls super, which
206
+ fixes usage when other plugins that define before_create are loaded
207
+ before it.
208
+
209
+ * In the pg_array extension, when typecasting an Array to PGArray,
210
+ a recursive map is done on the input array to convert each value
211
+ in the input array to the expected type, using the typecasting
212
+ method that would be used for the scalar value. For example, for
213
+ model objects, where ids is an integer array column:
214
+
215
+ model.set(:ids=>['1', '2']).ids.to_a # => [1, 2]
216
+
217
+ * The pg_array extension now correctly handles bytea arrays used
218
+ in bound variables.
219
+
220
+ * The pg_array extension no longer uses the JSON-based parser for
221
+ floating point types, since it doesn't handle NaN and Infinity
222
+ values correctly.
223
+
224
+ * When typecasting in the pg_array extension, PGArray values are
225
+ only returned verbatim if they have a matching database type.
226
+ Otherwise, the underlying array is rewrapped in a new PGArray
227
+ value with the correct database type.
228
+
229
+ * H2 clob types are now recognized as strings instead of blobs.
230
+ Previously the code attempted to do this, but it didn't do so
231
+ correctly.
232
+
233
+ * The jdbc/postgres adapter now converts scalar values of
234
+ the array to the appropriate type. Previously, if you retrieved
235
+ a date array, you got back a ruby array of JavaSQL::SQL::Date
236
+ instances. Now, you get back a ruby array of ruby Date instances.
237
+
238
+ * The schema_dumper extension now dumps migrations as change
239
+ migrations, instead of separate up/down migrations, resulting in
240
+ simpler code.
241
+
242
+ * When dumping non-integer foreign keys in the schema dumper, an
243
+ explicit type is now used. Previously, the column would have been
244
+ dumped as an integer column.
245
+
246
+ * When dumping unsigned integer columns in the schema dumper, add a
247
+ column > 0 constraint in the dumped migration.
248
+
249
+ * On Microsoft SQL Server, when updating a dataset with a limit,
250
+ the limit is now respected.
251
+
252
+ * When emulating offset using the ROW_NUMBER window function,
253
+ do not require that the dataset be ordered. If an order is
254
+ not provided, default to ordering on all of the columns in
255
+ the dataset. If you want to override the default order used
256
+ in such a case, you need to override the default_offset_order
257
+ method for the dataset.
258
+
259
+ * On SQLite, casting to Date/Time/DateTime now calls an SQLite
260
+ date/datetime function instead of using a cast, as SQLite treats
261
+ such a cast as a cast to integer.
262
+
263
+ * When using JRuby 1.6 in ruby 1.9 mode and typecasting a time
264
+ column, workaround a bug where Time#nsec is 0 even though
265
+ Time#usec is not.
266
+
267
+ * The odbc/mssql adapter now correctly handles the case where
268
+ SCOPE_IDENTITY returns NULL after an insert.
269
+
270
+ * bin/sequel now accepts multiple -l options for logging to multiple
271
+ output files.
272
+
273
+ * In addition to Sequel's rigorous pre-push testing, Sequel now
274
+ also uses TravisCI for continuous integration testing across
275
+ a wider range of ruby implementations.
276
+
277
+ = Backwards Compatibility
278
+
279
+ * The keys in the :key_hash entry passed to the :eager_loader proc
280
+ are now method references instead of column references. For most
281
+ associations, they are the same thing, but for associations using
282
+ the :key_column/:primary_key_column/:left_primary_key_column
283
+ options, the values could be different. If you were using one
284
+ of those options and had a custom eager_loader, you should switch
285
+ from indexing into the :key_hash option to just using the :id_map
286
+ option.
287
+
288
+ * The :key_hash entry passed to the :eager_loader proc is now no
289
+ longer guaranteed to contain key maps for associations other than
290
+ the one currently being eagerly loaded. Previously, it contained
291
+ key maps for all associations that were being eagerly loaded. If
292
+ you have a custom :eager_loader proc that accessed a key map for
293
+ a separate association that was being loaded concurrently, you'll
294
+ now have to build the key map manually if it doesn't exist.
295
+
296
+ * If you previously explicitly specified an :eager_loader_key option
297
+ when defining an association, you may need to change it so that it
298
+ is a method reference instead of a column reference, or possibly
299
+ just omit the option.
300
+
301
+ * If you have a custom :eager_loader proc for an association where
302
+ the default :eager_loader_key option references a method that
303
+ the model does not respond to (or raises an exception), you may
304
+ need to specify the :eager_loader_key=>nil option.
305
+
306
+ * In the pg_auto_parameterize extension, String values are no longer
307
+ automatically casted to text. This is because the default type of
308
+ a string literal in PostgreSQL is unknown, not text. This makes it
309
+ much less likely to require manual casts, but has the potential to
310
+ break existing code relying on the automatic cast to text. As a
311
+ work around, any query that can no longer be automatically
312
+ parameterized after this query just needs to add manual casting
313
+ to text.
314
+
315
+ * Sequel now raises an exception if you attempt to clone associations
316
+ with different types, except if one type is one_to_many and the
317
+ other is one_to_one. Cloning from other types was usually a bug,
318
+ and raising an exception early will make it much easier to track
319
+ such bugs down.
320
+
321
+ * When running the plugin/extension and PostgreSQL adapter specs,
322
+ a json library is now required.
323
+
324
+ * The json/postgres adapter array typecasting internals have been
325
+ modified, if you were relying on the internals, you may need to
326
+ update your code.
327
+
328
+ * The pg_array extension internals changed significantly. PGArray
329
+ no longer has any subclasses by default, as parsing is now done
330
+ in separate objects. Anyone relying on the pg_array internals
331
+ will need to update their code.
332
+
333
+ * The postgres adapter no longer sets up type conversion of int2vector
334
+ and money types, since in both cases the conversion was incorrect in
335
+ most cases. These types will now be returned as strings. If you are
336
+ relying on the conversion, you'll need to add your own custom type
337
+ procs.
338
+