sequel 3.12.1 → 3.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. data/CHANGELOG +42 -0
  2. data/README.rdoc +137 -118
  3. data/Rakefile +21 -66
  4. data/doc/active_record.rdoc +9 -9
  5. data/doc/advanced_associations.rdoc +59 -188
  6. data/doc/association_basics.rdoc +15 -2
  7. data/doc/cheat_sheet.rdoc +38 -33
  8. data/doc/dataset_filtering.rdoc +16 -7
  9. data/doc/prepared_statements.rdoc +7 -7
  10. data/doc/querying.rdoc +5 -4
  11. data/doc/release_notes/3.13.0.txt +210 -0
  12. data/doc/sharding.rdoc +1 -1
  13. data/doc/sql.rdoc +5 -5
  14. data/doc/validations.rdoc +11 -11
  15. data/lib/sequel/adapters/ado.rb +1 -1
  16. data/lib/sequel/adapters/do.rb +3 -3
  17. data/lib/sequel/adapters/firebird.rb +3 -3
  18. data/lib/sequel/adapters/jdbc/h2.rb +39 -0
  19. data/lib/sequel/adapters/jdbc/mysql.rb +5 -0
  20. data/lib/sequel/adapters/jdbc/oracle.rb +3 -3
  21. data/lib/sequel/adapters/mysql.rb +7 -4
  22. data/lib/sequel/adapters/oracle.rb +3 -3
  23. data/lib/sequel/adapters/shared/mssql.rb +10 -1
  24. data/lib/sequel/adapters/shared/mysql.rb +63 -0
  25. data/lib/sequel/adapters/shared/postgres.rb +61 -3
  26. data/lib/sequel/adapters/sqlite.rb +105 -18
  27. data/lib/sequel/connection_pool.rb +31 -30
  28. data/lib/sequel/core.rb +58 -58
  29. data/lib/sequel/core_sql.rb +52 -43
  30. data/lib/sequel/database/misc.rb +11 -0
  31. data/lib/sequel/database/query.rb +55 -17
  32. data/lib/sequel/dataset/actions.rb +2 -1
  33. data/lib/sequel/dataset/query.rb +2 -3
  34. data/lib/sequel/dataset/sql.rb +24 -11
  35. data/lib/sequel/extensions/schema_dumper.rb +1 -1
  36. data/lib/sequel/metaprogramming.rb +4 -0
  37. data/lib/sequel/model.rb +37 -19
  38. data/lib/sequel/model/associations.rb +33 -25
  39. data/lib/sequel/model/base.rb +2 -2
  40. data/lib/sequel/model/plugins.rb +7 -2
  41. data/lib/sequel/plugins/active_model.rb +1 -1
  42. data/lib/sequel/plugins/association_pks.rb +2 -2
  43. data/lib/sequel/plugins/association_proxies.rb +1 -1
  44. data/lib/sequel/plugins/boolean_readers.rb +2 -2
  45. data/lib/sequel/plugins/class_table_inheritance.rb +10 -2
  46. data/lib/sequel/plugins/identity_map.rb +3 -3
  47. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  48. data/lib/sequel/plugins/json_serializer.rb +212 -0
  49. data/lib/sequel/plugins/lazy_attributes.rb +1 -1
  50. data/lib/sequel/plugins/list.rb +174 -0
  51. data/lib/sequel/plugins/many_through_many.rb +2 -2
  52. data/lib/sequel/plugins/rcte_tree.rb +6 -7
  53. data/lib/sequel/plugins/tree.rb +118 -0
  54. data/lib/sequel/plugins/xml_serializer.rb +321 -0
  55. data/lib/sequel/sql.rb +315 -206
  56. data/lib/sequel/timezones.rb +40 -17
  57. data/lib/sequel/version.rb +8 -2
  58. data/spec/adapters/firebird_spec.rb +2 -2
  59. data/spec/adapters/informix_spec.rb +1 -1
  60. data/spec/adapters/mssql_spec.rb +2 -2
  61. data/spec/adapters/mysql_spec.rb +2 -2
  62. data/spec/adapters/oracle_spec.rb +1 -1
  63. data/spec/adapters/postgres_spec.rb +36 -6
  64. data/spec/adapters/spec_helper.rb +2 -2
  65. data/spec/adapters/sqlite_spec.rb +1 -1
  66. data/spec/core/connection_pool_spec.rb +3 -3
  67. data/spec/core/core_sql_spec.rb +31 -13
  68. data/spec/core/database_spec.rb +39 -2
  69. data/spec/core/dataset_spec.rb +24 -12
  70. data/spec/core/expression_filters_spec.rb +5 -1
  71. data/spec/core/object_graph_spec.rb +1 -1
  72. data/spec/core/schema_generator_spec.rb +1 -1
  73. data/spec/core/schema_spec.rb +1 -1
  74. data/spec/core/spec_helper.rb +1 -1
  75. data/spec/core/version_spec.rb +1 -1
  76. data/spec/extensions/active_model_spec.rb +82 -67
  77. data/spec/extensions/association_dependencies_spec.rb +1 -1
  78. data/spec/extensions/association_pks_spec.rb +1 -1
  79. data/spec/extensions/association_proxies_spec.rb +1 -1
  80. data/spec/extensions/blank_spec.rb +1 -1
  81. data/spec/extensions/boolean_readers_spec.rb +1 -1
  82. data/spec/extensions/caching_spec.rb +1 -1
  83. data/spec/extensions/class_table_inheritance_spec.rb +3 -2
  84. data/spec/extensions/composition_spec.rb +2 -5
  85. data/spec/extensions/force_encoding_spec.rb +3 -1
  86. data/spec/extensions/hook_class_methods_spec.rb +1 -1
  87. data/spec/extensions/identity_map_spec.rb +1 -1
  88. data/spec/extensions/inflector_spec.rb +1 -1
  89. data/spec/extensions/instance_filters_spec.rb +1 -1
  90. data/spec/extensions/instance_hooks_spec.rb +1 -1
  91. data/spec/extensions/json_serializer_spec.rb +154 -0
  92. data/spec/extensions/lazy_attributes_spec.rb +1 -2
  93. data/spec/extensions/list_spec.rb +251 -0
  94. data/spec/extensions/looser_typecasting_spec.rb +1 -1
  95. data/spec/extensions/many_through_many_spec.rb +3 -3
  96. data/spec/extensions/migration_spec.rb +1 -1
  97. data/spec/extensions/named_timezones_spec.rb +5 -6
  98. data/spec/extensions/nested_attributes_spec.rb +1 -1
  99. data/spec/extensions/optimistic_locking_spec.rb +1 -1
  100. data/spec/extensions/pagination_spec.rb +1 -1
  101. data/spec/extensions/pretty_table_spec.rb +1 -1
  102. data/spec/extensions/query_spec.rb +1 -1
  103. data/spec/extensions/rcte_tree_spec.rb +1 -1
  104. data/spec/extensions/schema_dumper_spec.rb +3 -2
  105. data/spec/extensions/schema_spec.rb +1 -1
  106. data/spec/extensions/serialization_spec.rb +6 -2
  107. data/spec/extensions/sharding_spec.rb +1 -1
  108. data/spec/extensions/single_table_inheritance_spec.rb +1 -1
  109. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  110. data/spec/extensions/spec_helper.rb +7 -3
  111. data/spec/extensions/sql_expr_spec.rb +1 -1
  112. data/spec/extensions/string_date_time_spec.rb +1 -1
  113. data/spec/extensions/string_stripper_spec.rb +1 -1
  114. data/spec/extensions/subclasses_spec.rb +1 -1
  115. data/spec/extensions/tactical_eager_loading_spec.rb +1 -1
  116. data/spec/extensions/thread_local_timezones_spec.rb +1 -1
  117. data/spec/extensions/timestamps_spec.rb +1 -1
  118. data/spec/extensions/touch_spec.rb +1 -1
  119. data/spec/extensions/tree_spec.rb +119 -0
  120. data/spec/extensions/typecast_on_load_spec.rb +1 -1
  121. data/spec/extensions/update_primary_key_spec.rb +1 -1
  122. data/spec/extensions/validation_class_methods_spec.rb +1 -1
  123. data/spec/extensions/validation_helpers_spec.rb +1 -1
  124. data/spec/extensions/xml_serializer_spec.rb +142 -0
  125. data/spec/integration/associations_test.rb +1 -1
  126. data/spec/integration/database_test.rb +1 -1
  127. data/spec/integration/dataset_test.rb +29 -14
  128. data/spec/integration/eager_loader_test.rb +1 -1
  129. data/spec/integration/migrator_test.rb +1 -1
  130. data/spec/integration/model_test.rb +1 -1
  131. data/spec/integration/plugin_test.rb +316 -1
  132. data/spec/integration/prepared_statement_test.rb +1 -1
  133. data/spec/integration/schema_test.rb +8 -8
  134. data/spec/integration/spec_helper.rb +1 -1
  135. data/spec/integration/timezone_test.rb +1 -1
  136. data/spec/integration/transaction_test.rb +35 -20
  137. data/spec/integration/type_test.rb +1 -1
  138. data/spec/model/association_reflection_spec.rb +1 -1
  139. data/spec/model/associations_spec.rb +49 -34
  140. data/spec/model/base_spec.rb +1 -1
  141. data/spec/model/dataset_methods_spec.rb +4 -4
  142. data/spec/model/eager_loading_spec.rb +1 -1
  143. data/spec/model/hooks_spec.rb +1 -1
  144. data/spec/model/inflector_spec.rb +1 -1
  145. data/spec/model/model_spec.rb +7 -1
  146. data/spec/model/plugins_spec.rb +1 -1
  147. data/spec/model/record_spec.rb +1 -3
  148. data/spec/model/spec_helper.rb +2 -2
  149. data/spec/model/validations_spec.rb +1 -1
  150. metadata +29 -5
@@ -295,8 +295,8 @@ Examples:
295
295
 
296
296
  == Dataset Method
297
297
 
298
- In addition to the above methods, associations also add a dataset method
299
- that returns a dataset representing the objects in the associated table:
298
+ In addition to the above methods, associations also add a instance method
299
+ ending in +_dataset+ that returns a dataset representing the objects in the associated table:
300
300
 
301
301
  @album.artist_id
302
302
  # 10
@@ -1386,3 +1386,16 @@ a one_to_one association that can actually return more than one row
1386
1386
  a many_to_many association where there is a unique index in the join table
1387
1387
  so that you know only one object will ever be associated through the
1388
1388
  association.
1389
+
1390
+ ==== :methods_module
1391
+
1392
+ The module that the methods created by the association will be placed
1393
+ into. Defaults to the module containing the model's columns. This
1394
+ is not included in the model's class, so you are responsible for doing
1395
+ that manually.
1396
+
1397
+ This is only useful in rare cases, such as when a plugin that adds
1398
+ associations depends on another plugin that defines instance methods of
1399
+ the same name. In that case, the instance methods of the dependent
1400
+ plugin would override the association methods created by the main
1401
+ plugin.
data/doc/cheat_sheet.rdoc CHANGED
@@ -48,8 +48,8 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
48
48
  == Retrieve rows
49
49
 
50
50
  dataset.each{|r| p r}
51
- dataset.all #=> [{...}, {...}, ...]
52
- dataset.first
51
+ dataset.all # => [{...}, {...}, ...]
52
+ dataset.first # => {...}
53
53
 
54
54
  == Update/Delete rows
55
55
 
@@ -66,47 +66,51 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
66
66
 
67
67
  == Filtering (see also doc/dataset_filtering.rdoc)
68
68
 
69
+ === Equality
70
+
69
71
  dataset.filter(:name => 'abc')
70
72
  dataset.filter('name = ?', 'abc')
71
73
 
72
- dataset.filter{|o| o.value > 100}
73
- dataset.exclude{|o| o.value <= 100}
74
+ === Inequality
75
+
76
+ dataset.filter{value > 100}
77
+ dataset.exclude{value <= 100}
78
+
79
+ === Inclusion
74
80
 
75
81
  dataset.filter(:value => 50..100)
76
- dataset.where{|o| (o.value >= 50) & (o.value <= 100)}
82
+ dataset.where{(value >= 50) & (value <= 100)}
77
83
 
78
84
  dataset.where('value IN ?', [50,75,100])
79
85
  dataset.where(:value=>[50,75,100])
80
86
 
81
- dataset.filter(:name => 'abc').first
82
- dataset[:name => 'abc']
87
+ dataset.where(:id=>other_dataset.select(:other_id))
83
88
 
84
- dataset.where('price > (SELECT avg(price) + 100 FROM table)')
85
- dataset.filter{|o| o.price > dataset.select(o.avg(price) + 100)}
89
+ === Subselects as scalar values
86
90
 
87
- === Advanced filtering using ruby expressions
91
+ dataset.where('price > (SELECT avg(price) + 100 FROM table)')
92
+ dataset.filter{price > dataset.select(avg(price) + 100)}
88
93
 
89
- DB[:items].filter{|o| o.price < 100}.sql
90
- #=> "SELECT * FROM items WHERE (price < 100)"
94
+ === LIKE/Regexp
91
95
 
92
- DB[:items].filter(:name.like('AL%')).sql
93
- #=> "SELECT * FROM items WHERE (name LIKE 'AL%')"
96
+ DB[:items].filter(:name.like('AL%'))
97
+ DB[:items].filter(:name => /^AL/)
94
98
 
95
- There's support for nested expressions with AND, OR and NOT:
99
+ === AND/OR/NOT
96
100
 
97
- DB[:items].filter{|o| (o.x > 5) & (o.y > 10)}.sql
98
- #=> "SELECT * FROM items WHERE ((x > 5) AND (y > 10))"
101
+ DB[:items].filter{(x > 5) & (y > 10)}.sql
102
+ # SELECT * FROM items WHERE ((x > 5) AND (y > 10))
99
103
 
100
104
  DB[:items].filter({:x => 1, :y => 2}.sql_or & ~{:z => 3}).sql
101
- #=> "SELECT * FROM items WHERE (((x = 1) OR (y = 2)) AND (z != 3))"
105
+ # SELECT * FROM items WHERE (((x = 1) OR (y = 2)) AND (z != 3))
102
106
 
103
- You can use arithmetic operators and specify SQL functions:
107
+ === Mathematical operators
104
108
 
105
109
  DB[:items].filter((:x + :y) > :z).sql
106
- #=> "SELECT * FROM items WHERE ((x + y) > z)"
110
+ # SELECT * FROM items WHERE ((x + y) > z)
107
111
 
108
- DB[:items].filter{|o| :price - 100 < o.avg(:price)}.sql
109
- #=> "SELECT * FROM items WHERE ((price - 100) < avg(price))"
112
+ DB[:items].filter{price - 100 < avg(price)}.sql
113
+ # SELECT * FROM items WHERE ((price - 100) < avg(price))
110
114
 
111
115
  == Ordering
112
116
 
@@ -114,7 +118,7 @@ You can use arithmetic operators and specify SQL functions:
114
118
  dataset.reverse_order(:kind)
115
119
  dataset.order(:kind.desc, :name)
116
120
 
117
- == Row ranges
121
+ == Limit/Offset
118
122
 
119
123
  dataset.limit(30) # LIMIT 30
120
124
  dataset.limit(30, 10) # LIMIT 30 OFFSET 10
@@ -122,12 +126,12 @@ You can use arithmetic operators and specify SQL functions:
122
126
  == Joins
123
127
 
124
128
  DB[:items].left_outer_join(:categories, :id => :category_id).sql
125
- #=> "SELECT * FROM items LEFT OUTER JOIN categories ON categories.id = items.category_id"
129
+ # SELECT * FROM items LEFT OUTER JOIN categories ON categories.id = items.category_id
126
130
 
127
131
  DB[:items].join(:categories, :id => :category_id).join(:groups, :id => :items__group_id)
128
- #=> "SELECT * FROM items INNER JOIN categories ON categories.id = items.category_id INNER JOIN groups ON groups.id = items.group_id"
132
+ # SELECT * FROM items INNER JOIN categories ON categories.id = items.category_id INNER JOIN groups ON groups.id = items.group_id
129
133
 
130
- == Summarizing
134
+ == Aggregate functions methods
131
135
 
132
136
  dataset.count #=> record count
133
137
  dataset.max(:price)
@@ -135,6 +139,7 @@ You can use arithmetic operators and specify SQL functions:
135
139
  dataset.avg(:price)
136
140
  dataset.sum(:stock)
137
141
 
142
+ dataset.group_and_count(:category)
138
143
  dataset.group(:category).select(:category, :AVG.sql_function(:price))
139
144
 
140
145
  == SQL Functions / Literals
@@ -150,11 +155,11 @@ You can use arithmetic operators and specify SQL functions:
150
155
  DB.create_table :items do
151
156
  primary_key :id
152
157
  String :name, :unique => true, :null => false
153
- boolean :active, :default => true
158
+ TrueClass :active, :default => true
154
159
  foreign_key :category_id, :categories
155
- Time :created_at
160
+ DateTime :created_at
156
161
 
157
- index :grade
162
+ index :created_at
158
163
  end
159
164
 
160
165
  DB.drop_table :items
@@ -169,7 +174,7 @@ You can use arithmetic operators and specify SQL functions:
169
174
  DB[:items].select(:name.as(:item_name))
170
175
  DB[:items].select(:name___item_name)
171
176
  DB[:items___items_table].select(:items_table__name___item_name)
172
- # => "SELECT items_table.name AS item_name FROM items AS items_table"
177
+ # SELECT items_table.name AS item_name FROM items AS items_table
173
178
 
174
179
  == Transactions
175
180
 
@@ -211,8 +216,8 @@ Savepoints can be used if the database supports it:
211
216
 
212
217
  == Miscellaneous:
213
218
 
214
- dataset.sql #=> "SELECT * FROM items"
215
- dataset.delete_sql #=> "DELETE FROM items"
216
- dataset.where(:name => 'sequel').exists #=> "EXISTS ( SELECT * FROM items WHERE name = 'sequel' )"
219
+ dataset.sql # "SELECT * FROM items"
220
+ dataset.delete_sql # "DELETE FROM items"
221
+ dataset.where(:name => 'sequel').exists # "EXISTS ( SELECT * FROM items WHERE name = 'sequel' )"
217
222
  dataset.columns #=> array of columns in the result set, does a SELECT
218
223
  DB.schema(:items) => [[:id, {:type=>:integer, ...}], [:name, {:type=>:string, ...}], ...]
@@ -1,6 +1,6 @@
1
1
  = Dataset Filtering
2
2
 
3
- Sequel offers unparalleled flexibility when it comes to filtering records. You can specify your conditions as a custom string, as a string with parameters, as a hash of values to compare against, or as ruby code that Sequel translates into SQL expressions.
3
+ Sequel is very flexibile when it comes to filtering records. You can specify your conditions as a custom string, as a string with parameters, as a hash of values to compare against, or as ruby code that Sequel translates into SQL expressions.
4
4
 
5
5
  == Filtering using a custom filter string
6
6
 
@@ -14,12 +14,21 @@ In order to prevent SQL injection, you can replace literal values with question
14
14
  items.filter('category = ?', 'ruby').sql
15
15
  #=> "SELECT * FROM items WHERE category = 'ruby'"
16
16
 
17
+ You can also use placeholders with :placeholder and a hash of placeholder values:
18
+
19
+ items.filter('category = :category', :category=>'ruby').sql
20
+ #=> "SELECT * FROM items WHERE category = 'ruby'"
21
+
17
22
  === Specifying SQL functions
18
23
 
19
- Sequel also allows you to specify functions by using the Symbol#sql_function method (and the Symbol#[] method on ruby 1.8):
24
+ Sequel also allows you to specify functions by using the Symbol#sql_function method:
20
25
 
21
26
  items.literal(:avg.sql_function(:price)) #=> "avg(price)"
22
27
 
28
+ If you are specifying a filter/selection/order, you can use a virtual row block:
29
+
30
+ items.select{avg(price)}
31
+
23
32
  == Filtering using a hash
24
33
 
25
34
  If you just need to compare records against values, you can supply a hash:
@@ -57,7 +66,7 @@ Sequel allows you to use ruby expressions directly in the call to filter:
57
66
  items.filter(:price * 2 < 50).sql
58
67
  #=> "SELECT * FROM items WHERE ((price * 2) < 50)
59
68
 
60
- This works for the standard inequality and arithmetic operators (though you can't use the inequality operators directly on a symbol in ruby 1.9):
69
+ This works for the standard inequality and arithmetic operators (though you can't use the inequality operators directly on a symbol):
61
70
 
62
71
  items.filter(:price + 100 < 200).sql
63
72
  #=> "SELECT * FROM items WHERE ((price + 100) < 200)
@@ -94,7 +103,7 @@ This works with other hash values, such as arrays and ranges:
94
103
 
95
104
  === Negating conditions
96
105
 
97
- You can use the negation operator (~) in most cases:
106
+ You can use the inversion operator (~) in most cases:
98
107
 
99
108
  items.filter(~{:category => 'ruby'}).sql
100
109
  #=> "SELECT * FROM items WHERE (category != 'ruby')"
@@ -109,12 +118,12 @@ You can use the negation operator (~) in most cases:
109
118
 
110
119
  You can also compare against other columns:
111
120
 
112
- items.filter{|o| o.credit > :debit}.sql
121
+ items.filter{credit > debit}.sql
113
122
  #=> "SELECT * FROM items WHERE (credit > debit)
114
123
 
115
124
  Or against SQL functions:
116
125
 
117
- items.filter{|o| :price - 100 < o.max(:price)}.sql
126
+ items.filter{price - 100 < max(price)}.sql
118
127
  #=> "SELECT * FROM items WHERE ((price - 100) < max(price))"
119
128
 
120
129
  == String search functions
@@ -155,4 +164,4 @@ One of the best features of Sequel is the ability to use datasets as sub-queries
155
164
  consumers.filter(:id => refs).sql
156
165
  #=> "SELECT * FROM consumers WHERE (id IN (SELECT consumer_id FROM consumer_refs WHERE logged_in))"
157
166
 
158
- Note that if you compare against a sub-query, you must select a single column in the sub-query.
167
+ Note that if you are checking for the inclusion of a single column in a subselect, the subselect should only select a single column.
@@ -8,7 +8,7 @@ the following databases:
8
8
  * PostgreSQL (using the pg driver, requires type specifiers)
9
9
  * MySQL (prepared statements only, as the ruby mysql driver doesn't support
10
10
  bound variables)
11
- * SQLite (a new native prepared statement is used for each call, though)
11
+ * SQLite
12
12
  * JDBC
13
13
 
14
14
  Support on other databases is emulated via string interpolation.
@@ -31,7 +31,7 @@ Using bound variables for this query is simple:
31
31
  ds.call(:select, :n=>'Jim')
32
32
 
33
33
  This will do the equivalent of selecting records that have the name 'Jim'. It
34
- returns all records, and can take a block that is passed to Dataset#all.
34
+ returns all records, and can take a block that is passed to <tt>Dataset#all</tt>.
35
35
 
36
36
  Deleting or returning the first record works similarly:
37
37
 
@@ -49,16 +49,16 @@ may itself contain placeholders:
49
49
  == Prepared Statements
50
50
 
51
51
  Prepared statement support is similar to bound variable support, but you
52
- use Dataset#prepare with a name, and Dataset#call or Database#call later with the values:
52
+ use <tt>Dataset#prepare</tt> with a name, and <tt>Dataset#call</tt> or <tt>Database#call</tt> later with the values:
53
53
 
54
54
  ds = DB[:items].filter(:name=>:$n)
55
55
  ps = ds.prepare(:select, :select_by_name)
56
56
  ps.call(:n=>'Jim')
57
57
  DB.call(:select_by_name, :n=>'Jim') # same as above
58
58
 
59
- The Dataset#prepare method returns a prepared statement, and also stores a
59
+ The <tt>Dataset#prepare</tt> method returns a prepared statement, and also stores a
60
60
  copy of the prepared statement in the database for later use. For insert
61
- and update queries, the hash to insert/update is passed to prepare:
61
+ and update queries, the hash to insert/update is passed to +prepare+:
62
62
 
63
63
  ps1 = DB[:items].prepare(:insert, :insert_with_name, :name=>:$n)
64
64
  ps1.call(:n=>'Jim')
@@ -82,8 +82,8 @@ in the SQL). Prepared statements are always server side.
82
82
 
83
83
  === SQLite
84
84
 
85
- SQLite supports bound variables and prepared statements exactly the same, since
86
- a new native prepared statement is created and executed for each call.
85
+ SQLite supports both prepared statements and bound variables. Prepared
86
+ statements are cached per connection.
87
87
 
88
88
  === MySQL
89
89
 
data/doc/querying.rdoc CHANGED
@@ -92,7 +92,7 @@ in the dataset unless you give the dataset an unambiguous order.
92
92
 
93
93
  ==== Retrieving a Single Column Value
94
94
 
95
- Sometimes, intead of wanting an entire row, you only want the value of
95
+ Sometimes, instead of wanting an entire row, you only want the value of
96
96
  a specific column. For this <tt>Sequel::Dataset#get</tt> is the method
97
97
  you want:
98
98
 
@@ -102,7 +102,7 @@ you want:
102
102
 
103
103
  === Retrieving Multiple Objects
104
104
 
105
- ==== As a Array of Hashes or Model Objects
105
+ ==== As an Array of Hashes or Model Objects
106
106
 
107
107
  In many cases, you want an array of all of the rows associated with the
108
108
  dataset, in which case <tt>Sequel::Dataset#all</tt> is the method you
@@ -141,7 +141,7 @@ given column. So the previous example can be handled more easily with:
141
141
  # SELECT * FROM artists
142
142
  => ["YJM", "AS"]
143
143
 
144
- One difference between these two ways of return an array of values is
144
+ One difference between these two ways of returning an array of values is
145
145
  that providing +map+ with an argument is really doing:
146
146
 
147
147
  artist_names = Artist.map{|x| x[:name]} # not x.name
@@ -172,7 +172,8 @@ using the +to_hash+ method:
172
172
  => {"YJM"=>1, "AS"=>2}
173
173
 
174
174
  As you can see, the +to_hash+ method uses the first symbol as the key
175
- and the second symbol as the value. So if you swap the two arguments:
175
+ and the second symbol as the value. So if you swap the two arguments the hash
176
+ will have its keys and values transposed:
176
177
 
177
178
  artist_names = Artist.to_hash(:id, :name)
178
179
  # SELECT * FROM artists
@@ -0,0 +1,210 @@
1
+ = New Plugins
2
+
3
+ * A json_serializer plugin was added that allows you to serialize
4
+ model instances or datasets to JSON using to_json. It requires
5
+ the json library. The API was modeled on ActiveRecord's JSON
6
+ serialization support. You can use :only and :except options
7
+ to specify the columns included, :include to specify associations
8
+ to include, as well pass options to nested associations using a
9
+ hash. In addition to serializing to JSON, it also adds support
10
+ for parsing JSON to model objects via JSON.parse or #from_json.
11
+
12
+ * An xml_serializer plugin was added that allows you to serialize
13
+ model instances or datasets to XML. It requries the nokogiri
14
+ library. It has a similar API to the json_serializer plugin, using
15
+ to_xml instead of to_json, and the from_xml class method instead
16
+ of JSON.parse.
17
+
18
+ * A tree plugin was added that allows you to treat Sequel::Model
19
+ objects as being part of a tree. It provides similar features to
20
+ rcte_tree, but works on databases that don't support recursive
21
+ common table expressions. In addition to the standard parent
22
+ and children associations, it provides instance methods to get
23
+ the ancestors, descendants, and siblings of the given tree node,
24
+ and class methods to get the roots of the tree.
25
+
26
+ * A list plugin was added that allows you to treat Sequel::Model
27
+ objects as being part of a list. This adds instance methods to
28
+ get the next and prev items in the list, or to move the item
29
+ to a specific place in the list. You can specify that all rows
30
+ in the table belong to the same list, or specify arbitrary scopes
31
+ so that the same table can contain many separate lists.
32
+
33
+ = Other New Features
34
+
35
+ * Sequel is now compatible with Ruby 1.9.2pre3.
36
+
37
+ * Sequel now supports prepared transactions/two-phase commit on
38
+ PostgreSQL, MySQL, and H2. You can specify that you want to
39
+ use prepared transactions using the :prepare option which
40
+ should be some transaction id string:
41
+
42
+ DB.transaction(:prepare=>'some string') do ... end
43
+
44
+ Assuming that no exceptions are raised in the transaction block,
45
+ Sequel will prepare the transaction. You can then commit the
46
+ transaction later:
47
+
48
+ DB.commit_prepared_transaction('some string')
49
+
50
+ If you need to rollback the prepared transaction, you can do
51
+ so as well:
52
+
53
+ DB.rollback_prepared_transaction('some string')
54
+
55
+ * Sequel now supports customizable transaction isolation levels on
56
+ PostgreSQL, MySQL, and Microsoft SQL Server. You can specify the
57
+ transaction isolation level to use for any transaction using the
58
+ :isolation option with an :uncommitted, :committed, :repeatable,
59
+ or :serializable value:
60
+
61
+ DB.transaction(:isolation=>:serializable) do ... end
62
+
63
+ You can also set the default isolation level for transactions via
64
+ the transaction_isolation_level Database attribute:
65
+
66
+ DB.transaction_isolation_level = :committed
67
+
68
+ If you are connecting to Microsoft SQL Server, it is recommended
69
+ that you set a default transaction isolation level if you plan
70
+ on using this feature.
71
+
72
+ * You can specify a NULLS FIRST/LAST ordering by using the
73
+ :nulls=>:first/:last option to asc and desc:
74
+
75
+ Album.filter(:release_date.desc(:nulls=>:first),
76
+ :name.asc(:nulls=>:last))
77
+ # ORDER BY release_date DESC NULLS FIRST,
78
+ # name ASC NULLS LAST
79
+
80
+ This syntax is supported by PostgreSQL 8.3+, Firebird 1.5+,
81
+ Oracle, and probably some other databases as well, and makes it
82
+ possible for the user to specify whether NULL values should sort
83
+ before or after other values.
84
+
85
+ * Sequel::Model.find_or_create now accepts a block that is a yielded
86
+ a new model object to be created if an existing model object is
87
+ not found.
88
+
89
+ Node.find_or_create(:name=>'A'){|i| i.parent_id = 4}
90
+
91
+ * The :frame option for windows and window functions can now be a
92
+ string that is used literally in the SQL. This is necessary if you
93
+ want to specify a custom frame, such as one that uses a specific
94
+ number of rows preceding or following.
95
+
96
+ * Savepoints are now supported on H2.
97
+
98
+ * A :methods_module association option was added, allowing you to
99
+ specify the module into which association instance methods are
100
+ placed. By default, it uses the module containing the column
101
+ accessor methods.
102
+
103
+ = Other Improvements
104
+
105
+ * The :encoding option for the native MySQL adapter should now work
106
+ correctly in all cases. This fix was included in 3.12.1.
107
+
108
+ * Sequel now handles arrays of two element arrays automatically when
109
+ using them as the value of a filter hash:
110
+
111
+ DB[a].filter([:a, :b]=>[[1, 2], [3, 4]])
112
+
113
+ Previously, you had to call .sql_array on the array in order to
114
+ tell Sequel that it was a value list and not a conditions
115
+ specifier.
116
+
117
+ * Sequel no longer attempts to use class polymorphism in the
118
+ class_table_inheritance plugin if you don't specify a cti_key.
119
+
120
+ * When using the native SQLite adapter, prepared statements are now
121
+ cached per connection for increased performance. Previously,
122
+ Sequel prepared a new statement for every query.
123
+
124
+ * tinyint(1) columns are now handled as booleans when connecting to
125
+ MySQL via JDBC.
126
+
127
+ * On PostgreSQL, if no :schema option is provided for
128
+ Database#tables, #table_exists?, or #schema, and no default_schema
129
+ is used, assume all schemas except the default non-public ones.
130
+ Previously, it assumed the public schema for tables and
131
+ table_exists?, but did not assume any schema for #schema.
132
+
133
+ This fixes issues if you use table names that overlap with table
134
+ names in the information_schema, such as domains. It's still
135
+ recommended that you specify a default_schema if you are using a
136
+ schema other than public.
137
+
138
+ * Unsigned integers are now handled correctly in the schema dumper.
139
+
140
+ * Sequel::SQL::PlaceholderLiteralString is now a GenericExpression
141
+ subclass, allowing you to treat it like most other Sequel
142
+ expression objects:
143
+
144
+ '(a || ?)'.lit(:b).like('Test%')
145
+ # ((a || b) LIKE 'Test%')
146
+
147
+ * Sequel now supports the bitwise shift operators (<< and >>) on
148
+ Microsoft SQL Server by emulating them.
149
+
150
+ * Sequel now supports most bitwise operators (&, |, ^, <<, >>) on H2
151
+ by emulating them. The bitwise complement operator is not yet
152
+ supported.
153
+
154
+ * Sequel now logs the SQL queries that are sent when connecting to
155
+ MySQL.
156
+
157
+ * If a plugin cannot be loaded, Sequel now gives a more detailed
158
+ error message.
159
+
160
+ = Backwards Compatibility
161
+
162
+ * Array#sql_array and the Sequel::SQL::SQLArray class are now
163
+ considered deprecated. Use the Array#sql_value_list and the
164
+ Sequel::SQL::ValueList class instead. SQLArray is now just
165
+ an alias for ValueList, but it now is an Array subclass instead
166
+ of a Sequel::SQL::Expression subclass.
167
+
168
+ * Using the ruby bitwise xor operator (^) on PostgreSQL now uses
169
+ PostgreSQL's bitwise xor operator (#) instead of PostgreSQL's
170
+ exponentiation operator (^). If you want exponentiation, use
171
+ the power function.
172
+
173
+ * Using the ruby bitwise complement operator (~) on MySQL now returns
174
+ a signed integer instead of an unsigned integer, for better
175
+ compatibility with other databases.
176
+
177
+ * Using nil as a case expression value (the 2nd argument to Hash#case
178
+ and Array#case) will now use NULL as the case expression value,
179
+ instead of omitting the case expression value:
180
+
181
+ # 3.12.0
182
+ {1=>2}.case(0, nil)
183
+ # CASE WHEN 1 THEN 2 ELSE 0 END
184
+
185
+ # 3.13.0
186
+ {1=>2}.case(0, nil)
187
+ # CASE NULL WHEN 1 THEN 2 ELSE 0 END
188
+
189
+ In general, you would never use nil explicitly, but the new
190
+ behavior makes more sense if you have a variable that might be nil:
191
+
192
+ parent_id = Node[1].parent_id
193
+ {1=>2}.case(0, parent_id)
194
+
195
+ If parent_id IS NULL/nil, then previously Sequel would have
196
+ generated unexpected SQL. If you don't want a case expression
197
+ value to be used, do not pass a second argument to #case.
198
+
199
+ * Some internal transaction methods now take an optional options
200
+ hash, so if you have a custom adapter, you will need to make
201
+ changes.
202
+
203
+ * Some internal association methods now take an optional options
204
+ hash.
205
+
206
+ * Some Rakefile task names were modified in the name of consistency:
207
+
208
+ spec_coverage -> spec_cov
209
+ integration -> spec_integration
210
+ integration_cov -> spec_integration_cov