sequel 3.31.0 → 3.32.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (56) hide show
  1. data/CHANGELOG +54 -0
  2. data/MIT-LICENSE +1 -1
  3. data/doc/advanced_associations.rdoc +17 -0
  4. data/doc/association_basics.rdoc +74 -30
  5. data/doc/release_notes/3.32.0.txt +202 -0
  6. data/doc/schema_modification.rdoc +1 -1
  7. data/lib/sequel/adapters/jdbc/db2.rb +7 -0
  8. data/lib/sequel/adapters/jdbc/derby.rb +13 -0
  9. data/lib/sequel/adapters/jdbc/h2.rb +10 -1
  10. data/lib/sequel/adapters/jdbc/hsqldb.rb +7 -0
  11. data/lib/sequel/adapters/jdbc/oracle.rb +7 -0
  12. data/lib/sequel/adapters/mock.rb +4 -0
  13. data/lib/sequel/adapters/mysql.rb +3 -0
  14. data/lib/sequel/adapters/oracle.rb +7 -3
  15. data/lib/sequel/adapters/shared/db2.rb +9 -2
  16. data/lib/sequel/adapters/shared/mssql.rb +48 -2
  17. data/lib/sequel/adapters/shared/mysql.rb +24 -4
  18. data/lib/sequel/adapters/shared/oracle.rb +7 -6
  19. data/lib/sequel/adapters/shared/progress.rb +1 -1
  20. data/lib/sequel/adapters/shared/sqlite.rb +16 -10
  21. data/lib/sequel/core.rb +22 -0
  22. data/lib/sequel/database/query.rb +13 -4
  23. data/lib/sequel/dataset/actions.rb +20 -11
  24. data/lib/sequel/dataset/mutation.rb +7 -1
  25. data/lib/sequel/dataset/prepared_statements.rb +11 -0
  26. data/lib/sequel/dataset/sql.rb +21 -24
  27. data/lib/sequel/extensions/query.rb +1 -1
  28. data/lib/sequel/model.rb +5 -2
  29. data/lib/sequel/model/associations.rb +70 -16
  30. data/lib/sequel/model/base.rb +11 -6
  31. data/lib/sequel/plugins/active_model.rb +13 -1
  32. data/lib/sequel/plugins/composition.rb +43 -10
  33. data/lib/sequel/plugins/many_through_many.rb +4 -1
  34. data/lib/sequel/plugins/nested_attributes.rb +65 -10
  35. data/lib/sequel/plugins/serialization.rb +13 -8
  36. data/lib/sequel/plugins/serialization_modification_detection.rb +22 -10
  37. data/lib/sequel/version.rb +1 -1
  38. data/spec/adapters/mssql_spec.rb +33 -10
  39. data/spec/adapters/mysql_spec.rb +111 -91
  40. data/spec/adapters/oracle_spec.rb +18 -0
  41. data/spec/core/database_spec.rb +1 -0
  42. data/spec/core/dataset_spec.rb +110 -15
  43. data/spec/extensions/active_model_spec.rb +13 -0
  44. data/spec/extensions/many_through_many_spec.rb +14 -14
  45. data/spec/extensions/query_spec.rb +6 -0
  46. data/spec/extensions/serialization_modification_detection_spec.rb +36 -1
  47. data/spec/extensions/serialization_spec.rb +9 -0
  48. data/spec/integration/associations_test.rb +278 -154
  49. data/spec/integration/dataset_test.rb +39 -2
  50. data/spec/integration/plugin_test.rb +63 -3
  51. data/spec/integration/prepared_statement_test.rb +10 -3
  52. data/spec/integration/schema_test.rb +61 -14
  53. data/spec/integration/transaction_test.rb +10 -0
  54. data/spec/model/associations_spec.rb +170 -80
  55. data/spec/model/hooks_spec.rb +40 -0
  56. metadata +4 -2
data/CHANGELOG CHANGED
@@ -1,3 +1,57 @@
1
+ === 3.32.0 (2012-02-01)
2
+
3
+ * Make serialization_modification_detection plugin work correctly with new objects and after saving existing objects (jeremyevans) (#432)
4
+
5
+ * Make refreshes after model creation clear the deserialized values in the serialization plugin (jeremyevans)
6
+
7
+ * Add Dataset#update_ignore on MySQL, for using UPDATE IGNORE in queries (danielb2) (#429)
8
+
9
+ * Allow select_map/select_order_map to take both a column argument and a block (jeremyevans)
10
+
11
+ * Fix virtual row block handling in select_map/select_order_map if block returns an array (jeremyevans) (#428)
12
+
13
+ * Add Sequel.empty_array_handle_nulls setting, can be set to false for possible better performance on some databases (jeremyevans)
14
+
15
+ * Change exclude(:b=>[]) to not return rows where b is NULL (jeremyevans) (#427)
16
+
17
+ * Support ActiveModel 3.2 in the active_model plugin, by adding support for to_partial_path (jeremyevans)
18
+
19
+ * Fix metadata methods (e.g. tables) on Oracle when custom identifier input methods are used (jeremyevans)
20
+
21
+ * Fix Database#indexes on DB2 (jeremyevans)
22
+
23
+ * Make DateTime/Time columns with Sequel::CURRENT_TIMESTAMP default values use timestamp column on MySQL (jeremyevans)
24
+
25
+ * Wrap column default values in extra parens on SQLite, fixes some cases (jeremyevans)
26
+
27
+ * Make Database#indexes not include primary key indexes on Derby, HSQLDB, Oracle, and DB2 using the jdbc adapter (jeremyevans)
28
+
29
+ * Support Database#indexes in shared MSSQL adapter (jeremyevans)
30
+
31
+ * Support :include option when creating indexes on MSSQL, for storing column values in the index (crawlik) (#426)
32
+
33
+ * Make set_column_type not modify defaults and NULL/NOT NULL setting on MSSQL, H2, and SQLite (jeremyevans)
34
+
35
+ * Qualify identifiers when filtering/excluding by associations (jeremyevans)
36
+
37
+ * Make table_exists? better handle tables where you don't have permissions for all columns (jeremyevans) (#422)
38
+
39
+ * Using new association options, support associations based on columns that clash with ruby method names (jeremyevans) (#417)
40
+
41
+ * Add use_after_commit_rollback setting to models, can be turned off to allow model usage with prepared transactions (jeremyevans)
42
+
43
+ * Fix alter table emulation on SQLite when foreign keys reference the table being altered (jeremyevans)
44
+
45
+ * Fix progress shared adapter, broken since the dataset literalization refactoring (jeremyevans) (#414)
46
+
47
+ * Support :map and :to_hash prepared statement types (jeremyevans)
48
+
49
+ * Make Dataset#naked! work correctly (jeremyevans)
50
+
51
+ * Remove Dataset#paginate!, as it was broken (jeremyevans)
52
+
53
+ * Fix query extension to not break usage of #clone without arguments (jeremyevans) (#413)
54
+
1
55
  === 3.31.0 (2012-01-03)
2
56
 
3
57
  * Dataset#from no longer handles :a__b__c___d as a.b.c AS d (jeremyevans)
data/MIT-LICENSE CHANGED
@@ -1,5 +1,5 @@
1
1
  Copyright (c) 2007-2008 Sharon Rosner
2
- Copyright (c) 2008-2011 Jeremy Evans
2
+ Copyright (c) 2008-2012 Jeremy Evans
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  of this software and associated documentation files (the "Software"), to
@@ -237,6 +237,23 @@ Sequel::Model:
237
237
 
238
238
  class Invoice < Sequel::Model
239
239
  many_to_one :client
240
+
241
+ # has_one :through equivalent 1
242
+ # eager load with :eager=>:firm option on :client association, and eager loading :client
243
+ def firm
244
+ client.firm if client
245
+ end
246
+
247
+ # has_one :through equivalent 2
248
+ # eager load the usual way
249
+ many_to_many :firms, :join_table=>:clients, :left_key=>:id, :left_primary_key=>:client_id, :right_key=>:firm_id
250
+ def firm
251
+ firms.first
252
+ end
253
+
254
+ # has_one :through equivalent 3
255
+ # eager loading requires custom :eager_loader proc
256
+ many_to_one :firm, :dataset=>proc{Firm.join(:clients, :firm_id=>:id, :id=>client_id).select_all(:firms)}
240
257
  end
241
258
 
242
259
  Firm.first.invoices
@@ -1430,6 +1430,78 @@ by the foreign/primary keys. This option causes the
1430
1430
  you want to replace the default foreign/primary key conditions that Sequel
1431
1431
  would use when eagerly graphing.
1432
1432
 
1433
+ === Column Naming Conflict Options
1434
+
1435
+ Sequel's association support historically called methods on model objects
1436
+ to get primary key or foreign key values instead of accessing the column
1437
+ values directly, in order to allow advanced features such as associations
1438
+ based on virtual column keys. Unfortunately, that causes issues if columns
1439
+ are used with names that clash with existing method names, which can happen
1440
+ if you want to name the association the same name as an existing column, or
1441
+ if the column has the same name as an already defined method such as
1442
+ <tt>object_id</tt>.
1443
+
1444
+ Sequel has added the following options that allow you to work around the
1445
+ issue by either specifying the column name symbol or the method name symbol
1446
+ to use. In most cases, these methods are designed to be used with column
1447
+ aliases defined with <tt>Model.def_column_alias</tt>:
1448
+
1449
+ # Example schema:
1450
+ # albums artists
1451
+ # :id /--> :id
1452
+ # :artist --/ :name
1453
+ # :name
1454
+ class Album < Sequel::Model
1455
+ def_column_alias(:artist_id, :artist)
1456
+ many_to_one :artist, :key=>:artist_id, :key_column=>:artist
1457
+ end
1458
+
1459
+ # Example schema:
1460
+ # things objs
1461
+ # :id /--> :id
1462
+ # :object_id --/ :name
1463
+ # :name
1464
+ class Thing < Sequel::Model
1465
+ def_column_alias(:obj_id, :object_id)
1466
+ end
1467
+ class Obj < Sequel::Model
1468
+ many_to_one :things, :key=>:object_id, :key_method=>:obj_id
1469
+ end
1470
+
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
+ ==== :key_column [+many_to_one+]
1476
+
1477
+ Like the :key option, but :key references the method name, while
1478
+ :key_column references the underlying column.
1479
+
1480
+ ==== :primary_key_method [+many_to_one+]
1481
+
1482
+ Like the :primary_key option, but :primary_key references the column
1483
+ name, while :primary_key_method references the method name.
1484
+
1485
+ ==== :primary_key_column [+one_to_many+, +one_to_one+]
1486
+
1487
+ Like the :primary_key option, but :primary_key references the method name, while
1488
+ :primary_key_column references the underlying column.
1489
+
1490
+ ==== :key_method [+one_to_many+, +one_to_one+]
1491
+
1492
+ Like the :key option, but :key references the column
1493
+ name, while :key_method references the method name.
1494
+
1495
+ ==== :left_primary_key_column [+many_to_many+]
1496
+
1497
+ Like the :left_primary_key option, but :left_primary_key references the method name, while
1498
+ :left_primary_key_column references the underlying column.
1499
+
1500
+ ==== :right_primary_key_method [+many_to_many+]
1501
+
1502
+ Like the :right_primary_key option, but :right_primary_key references the column
1503
+ name, while :right_primary_key_method references the method name.
1504
+
1433
1505
  === Advanced Options
1434
1506
 
1435
1507
  ==== :reciprocal
@@ -1483,34 +1555,6 @@ If the default modification methods would not do what you want, and you
1483
1555
  don't plan on overriding the internal modification methods to do what you
1484
1556
  want, it may be best to set this option to true.
1485
1557
 
1486
- ==== :key_column [+many_to_one+]
1487
-
1488
- This option exists to make it possible to create a +many_to_one+ association
1489
- with the same name as the foreign key it uses. Before this option was
1490
- introduced, this was problematic, since the :key option was used to refer
1491
- both to the model methods and the underlying database columns (which are
1492
- usually the same).
1493
-
1494
- If you have a legacy database with a foreign key that is the same as the name
1495
- of the association you would like to use, you should create a column alias
1496
- for the foreign key and use this option:
1497
-
1498
- # Example schema:
1499
- # albums artists
1500
- # :id /--> :id
1501
- # :artist --/ :name
1502
- # :name
1503
-
1504
- class Album < Sequel::Model
1505
- def_column_alias(:artist_id, :artist)
1506
- many_to_one :artist, :key_column=>:artist
1507
- end
1508
-
1509
- Note that if you have control over the database, it's better to just rename
1510
- the foreign key column than use this option. Similarly, if you can think
1511
- of another association name that will work, it's wiser to rename the
1512
- association than use this option. Think of this option as a last resort.
1513
-
1514
1558
  ==== :validate
1515
1559
 
1516
1560
  Set to false to not validate when implicitly saving any associated object.
@@ -1595,8 +1639,8 @@ strategies are:
1595
1639
  functions.
1596
1640
  :correlated_subquery :: Uses a correlated subquery to get the information.
1597
1641
  This is never used by default as if you aren't careful,
1598
- it can result in pathologically long running times
1599
- This will not work correctly for association where
1642
+ it can result in pathologically long running times.
1643
+ This will not work correctly for associations where
1600
1644
  the associated table has a composite primary key if
1601
1645
  the database doesn't support using IN
1602
1646
  with multiple columns. This will also not work on MySQL
@@ -0,0 +1,202 @@
1
+ = New Features
2
+
3
+ * Prepared statements now support :map and :to_hash prepared
4
+ statement types. The main reason for this is that certain
5
+ extensions (e.g. sequel_pg) optimize map/to_hash calls, and
6
+ there previously was not a way to use prepared statements
7
+ with the map/to_hash optimizations.
8
+
9
+ * Sequel.empty_array_handle_nulls has been added to change how
10
+ IN/NOT IN operations with an empty array are handled. See
11
+ the Backwards Compatibility section for details.
12
+
13
+ * 5 new association options have been added that allow you to
14
+ define associations where the underlying columns clash with
15
+ standard ruby method names:
16
+
17
+ many_to_one :primary_key_method
18
+ one_to_many :key_method
19
+ one_to_many :primary_key_column
20
+ many_to_many :left_primary_key_column
21
+ many_to_many :right_primary_key_method
22
+
23
+ Using these new options, you can now define associations
24
+ that work correctly when the underlying primary/foreign key
25
+ columns clash with existing ruby method names. See the RDoc
26
+ for details.
27
+
28
+ * A use_after_commit_rollback setting has been added to models.
29
+ This defaults to true, but can be set to false for performance
30
+ or to allow models to be used in prepared transactions
31
+ (which don't support after_commit/after_rollback).
32
+
33
+ * Dataset#update_ignore has been added when connecting to MySQL,
34
+ enabling use of the UPDATE IGNORE syntax to skip updating a row
35
+ if the update would cause a unique constraint to be violated.
36
+
37
+ * Database#indexes is now supported when connecting to Microsoft
38
+ SQL Server.
39
+
40
+ * On Microsoft SQL Server, the :include option is now supported
41
+ when creating indexes, for storing column values in the index,
42
+ which can be used by the query optimizer.
43
+
44
+ = Other Improvements
45
+
46
+ * The filtering/excluding by associations code now uses qualified
47
+ identifiers instead of unqualified identifiers, which allows it
48
+ to avoid ambiguous column names if you are doing your own joins.
49
+
50
+ * Virtual row blocks that return arrays are now handled correctly
51
+ in Dataset#select_map/select_order_map.
52
+
53
+ * Dataset#select_map/select_order_map can now take both a block
54
+ argument as well as a regular argument.
55
+
56
+ * Dataset#select_order_map now handles virtual row blocks that
57
+ return ordered expressions.
58
+
59
+ * Database#table_exists? should no longer generate false negatives
60
+ if you only have permission to retrieve some column values but
61
+ not all. Note that if you lack permission to SELECT from the
62
+ table itself, table_exists? can still generate false negatives.
63
+
64
+ * The active_model plugin now supports ActiveModel 3.2, by adding
65
+ support for to_partial_path.
66
+
67
+ * The serialization_modification_detection plugin now handles
68
+ changed_columns correctly both for new objects and after saving
69
+ objects.
70
+
71
+ * The serialization plugin now clears the deserialized values when
72
+ it does the automatic refresh after saving a new object, mostly for
73
+ consistency. You can use the skip_create_refresh plugin to skip
74
+ refreshing when creating a new model object.
75
+
76
+ * Column default values are now wrapped in parentheses on SQLite,
77
+ which fixes some cases such as when the default is an SQL function
78
+ call.
79
+
80
+ * Alter table emulation now works correctly on SQLite when foreign
81
+ keys reference the table being altered. The emulation requires
82
+ a renaming/deleting the existing table and creating a new table,
83
+ which can break foreign key references. Sequel now disables the
84
+ foreign key PRAGMA when altering tables, so SQLite won't track
85
+ the table renames and break the foreign key relationships.
86
+
87
+ * The set_column_type table alteration method no longer modifies
88
+ default values and NULL/NOT NULL settings on Microsoft SQL
89
+ Server, H2, and SQLite.
90
+
91
+ * On MySQL, Time/DateTime columns now use the timestamp type if the
92
+ default value is Sequel::CURRENT_TIMESTAMP, since it is currently
93
+ impossible for MySQL to have a non-constant default for a
94
+ datetime column (without using a workaround like a trigger).
95
+
96
+ * Metadata methods such as tables, views, and view_exists? are now
97
+ handled correctly on Oracle if custom identifier input methods
98
+ are used.
99
+
100
+ * Sequel now ignores errors that occur when attempting to get
101
+ information on column defaults in Oracle (which can happen if you
102
+ lack permission to the appropriate table). Previously, such errors
103
+ would cause the schema parser to raise an error, now, the schema
104
+ information is just returned without default information.
105
+
106
+ * Database#indexes now skips the primary key index when connecting to
107
+ DB2, Derby, HSQLDB, and Oracle via the jdbc adapter.
108
+
109
+ * Database#indexes now works correctly on DB2.
110
+
111
+ * The progress adapter has been fixed, it had been broken since the
112
+ dataset literalization refactoring.
113
+
114
+ * Dataset#naked! now works correctly. Previously, it just returned
115
+ the receiver unmodified.
116
+
117
+ * Dataset#paginate! has been removed, as it was broken.
118
+
119
+ * The query extension no longer breaks Dataset#clone if an argument
120
+ is not given.
121
+
122
+ * Transaction related queries are no longer logged twice in the mock
123
+ adapter.
124
+
125
+ = Backwards Compatibility
126
+
127
+ * Sequel's default handling of NOT IN operators with an empty array
128
+ of values has changed, which can change which rows are returned for
129
+ such queries.
130
+
131
+ Previously, Sequel was inconsistent in that it tried to handle NULL
132
+ values correctly in the IN case, but not in the NOT IN case. Now,
133
+ it defaults to handling NULL values correctly in both cases:
134
+
135
+ # 3.31.0
136
+ DB[:a].where(:b=>[])
137
+ # SELECT * FROM a WHERE (b != b)
138
+ DB[:a].exclude(:b=>[])
139
+ # SELECT * FROM a WHERE (1 = 1)
140
+
141
+ # 3.32.0
142
+ DB[:a].where(:b=>[])
143
+ # SELECT * FROM a WHERE (b != b)
144
+ DB[:a].exclude(:b=>[])
145
+ # SELECT * FROM a WHERE (b = b)
146
+
147
+ The important change in behavior is that in the NOT IN case, if
148
+ the left hand argument is NULL, the filter returns NULL instead
149
+ of true. This has the potential to change query results.
150
+
151
+ "Correct" here is really an opinion and not a fact, as there are
152
+ valid arguments for the alternative behavior:
153
+
154
+ DB[:a].where(:b=>[])
155
+ # SELECT * FROM a WHERE (1 = 0)
156
+ DB[:a].exclude(:b=>[])
157
+ # SELECT * FROM a WHERE (1 = 1)
158
+
159
+ The difference is that the "correct" NULL behavior is more
160
+ consistent with the non-empty array cases. For example, if b is
161
+ NULL:
162
+
163
+ # "Correct" NULL handling
164
+ # Empty array: where(:b=>[])
165
+ WHERE (b != b) # NULL
166
+ WHERE (b = b) # NULL
167
+ # Non-empty array: where(:b=>[1, 2])
168
+ WHERE (b IN (1, 2)) # NULL
169
+ WHERE (b NOT IN (1, 2)) # NULL
170
+
171
+ # Static boolean handling
172
+ # Empty array: where(:b=>[])
173
+ WHERE (1 = 0) # false
174
+ WHERE (1 = 1) # true
175
+ # Non-empty array: where(:b=>[1, 2])
176
+ WHERE (b IN (1, 2)) # NULL
177
+ WHERE (b NOT IN (1, 2)) # NULL
178
+
179
+ Sequel chooses to default to behavior consistent with the non-empty
180
+ array cases (similar to SQLAlchemy). However, there are two
181
+ downsides to this handling. The first is that some databases with
182
+ poor optimizers (e.g. MySQL) might do a full table scan with the
183
+ default syntax. The second is that the static boolean handling may
184
+ be generally perferable, if you believe that IN/NOT IN with an
185
+ empty array should always be true or false and never NULL even if
186
+ the left hand argument is NULL.
187
+
188
+ As there really isn't a truly correct answer in this case, Sequel
189
+ defaults to the "correct" NULL handling, and allows you to switch
190
+ to the static boolean handling via:
191
+
192
+ Sequel.empty_array_handle_nulls = false
193
+
194
+ This is currently a global setting, it may be made Database or
195
+ Dataset specific later if requested. Also, it is possible the
196
+ default will switch in the future, so if you care about a specific
197
+ handling, you should set your own default.
198
+
199
+ * Database#table_exists? now only rescues Sequel::DatabaseErrors
200
+ instead of StandardErrors, so it's possible it will raise errors
201
+ instead of returning false on custom adapters that don't wrap
202
+ their errors correctly.
@@ -515,7 +515,7 @@ mess up the migration.
515
515
  <tt>create_table?</tt> with a question mark only creates the table if it does
516
516
  not already exist, so:
517
517
 
518
- create_table!(:artists)
518
+ create_table?(:artists)
519
519
  primary_key :id
520
520
  end
521
521
 
@@ -16,6 +16,8 @@ module Sequel
16
16
  module DB2
17
17
  # Database instance methods for DB2 databases accessed via JDBC.
18
18
  module DatabaseMethods
19
+ PRIMARY_KEY_INDEX_RE = /\Asql\d+\z/i.freeze
20
+
19
21
  include Sequel::DB2::DatabaseMethods
20
22
  include Sequel::JDBC::Transactions
21
23
  IDENTITY_VAL_LOCAL = "SELECT IDENTITY_VAL_LOCAL() FROM SYSIBM.SYSDUMMY1".freeze
@@ -34,6 +36,11 @@ module Sequel
34
36
  rs.getInt(1)
35
37
  end
36
38
  end
39
+
40
+ # Primary key indexes appear to be named sqlNNNN on DB2
41
+ def primary_key_index_re
42
+ PRIMARY_KEY_INDEX_RE
43
+ end
37
44
  end
38
45
 
39
46
  # Dataset class for DB2 datasets accessed via JDBC.