sequel 3.12.1 → 3.13.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +42 -0
- data/README.rdoc +137 -118
- data/Rakefile +21 -66
- data/doc/active_record.rdoc +9 -9
- data/doc/advanced_associations.rdoc +59 -188
- data/doc/association_basics.rdoc +15 -2
- data/doc/cheat_sheet.rdoc +38 -33
- data/doc/dataset_filtering.rdoc +16 -7
- data/doc/prepared_statements.rdoc +7 -7
- data/doc/querying.rdoc +5 -4
- data/doc/release_notes/3.13.0.txt +210 -0
- data/doc/sharding.rdoc +1 -1
- data/doc/sql.rdoc +5 -5
- data/doc/validations.rdoc +11 -11
- data/lib/sequel/adapters/ado.rb +1 -1
- data/lib/sequel/adapters/do.rb +3 -3
- data/lib/sequel/adapters/firebird.rb +3 -3
- data/lib/sequel/adapters/jdbc/h2.rb +39 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +5 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +3 -3
- data/lib/sequel/adapters/mysql.rb +7 -4
- data/lib/sequel/adapters/oracle.rb +3 -3
- data/lib/sequel/adapters/shared/mssql.rb +10 -1
- data/lib/sequel/adapters/shared/mysql.rb +63 -0
- data/lib/sequel/adapters/shared/postgres.rb +61 -3
- data/lib/sequel/adapters/sqlite.rb +105 -18
- data/lib/sequel/connection_pool.rb +31 -30
- data/lib/sequel/core.rb +58 -58
- data/lib/sequel/core_sql.rb +52 -43
- data/lib/sequel/database/misc.rb +11 -0
- data/lib/sequel/database/query.rb +55 -17
- data/lib/sequel/dataset/actions.rb +2 -1
- data/lib/sequel/dataset/query.rb +2 -3
- data/lib/sequel/dataset/sql.rb +24 -11
- data/lib/sequel/extensions/schema_dumper.rb +1 -1
- data/lib/sequel/metaprogramming.rb +4 -0
- data/lib/sequel/model.rb +37 -19
- data/lib/sequel/model/associations.rb +33 -25
- data/lib/sequel/model/base.rb +2 -2
- data/lib/sequel/model/plugins.rb +7 -2
- data/lib/sequel/plugins/active_model.rb +1 -1
- data/lib/sequel/plugins/association_pks.rb +2 -2
- data/lib/sequel/plugins/association_proxies.rb +1 -1
- data/lib/sequel/plugins/boolean_readers.rb +2 -2
- data/lib/sequel/plugins/class_table_inheritance.rb +10 -2
- data/lib/sequel/plugins/identity_map.rb +3 -3
- data/lib/sequel/plugins/instance_hooks.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +212 -0
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/list.rb +174 -0
- data/lib/sequel/plugins/many_through_many.rb +2 -2
- data/lib/sequel/plugins/rcte_tree.rb +6 -7
- data/lib/sequel/plugins/tree.rb +118 -0
- data/lib/sequel/plugins/xml_serializer.rb +321 -0
- data/lib/sequel/sql.rb +315 -206
- data/lib/sequel/timezones.rb +40 -17
- data/lib/sequel/version.rb +8 -2
- data/spec/adapters/firebird_spec.rb +2 -2
- data/spec/adapters/informix_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +2 -2
- data/spec/adapters/mysql_spec.rb +2 -2
- data/spec/adapters/oracle_spec.rb +1 -1
- data/spec/adapters/postgres_spec.rb +36 -6
- data/spec/adapters/spec_helper.rb +2 -2
- data/spec/adapters/sqlite_spec.rb +1 -1
- data/spec/core/connection_pool_spec.rb +3 -3
- data/spec/core/core_sql_spec.rb +31 -13
- data/spec/core/database_spec.rb +39 -2
- data/spec/core/dataset_spec.rb +24 -12
- data/spec/core/expression_filters_spec.rb +5 -1
- data/spec/core/object_graph_spec.rb +1 -1
- data/spec/core/schema_generator_spec.rb +1 -1
- data/spec/core/schema_spec.rb +1 -1
- data/spec/core/spec_helper.rb +1 -1
- data/spec/core/version_spec.rb +1 -1
- data/spec/extensions/active_model_spec.rb +82 -67
- data/spec/extensions/association_dependencies_spec.rb +1 -1
- data/spec/extensions/association_pks_spec.rb +1 -1
- data/spec/extensions/association_proxies_spec.rb +1 -1
- data/spec/extensions/blank_spec.rb +1 -1
- data/spec/extensions/boolean_readers_spec.rb +1 -1
- data/spec/extensions/caching_spec.rb +1 -1
- data/spec/extensions/class_table_inheritance_spec.rb +3 -2
- data/spec/extensions/composition_spec.rb +2 -5
- data/spec/extensions/force_encoding_spec.rb +3 -1
- data/spec/extensions/hook_class_methods_spec.rb +1 -1
- data/spec/extensions/identity_map_spec.rb +1 -1
- data/spec/extensions/inflector_spec.rb +1 -1
- data/spec/extensions/instance_filters_spec.rb +1 -1
- data/spec/extensions/instance_hooks_spec.rb +1 -1
- data/spec/extensions/json_serializer_spec.rb +154 -0
- data/spec/extensions/lazy_attributes_spec.rb +1 -2
- data/spec/extensions/list_spec.rb +251 -0
- data/spec/extensions/looser_typecasting_spec.rb +1 -1
- data/spec/extensions/many_through_many_spec.rb +3 -3
- data/spec/extensions/migration_spec.rb +1 -1
- data/spec/extensions/named_timezones_spec.rb +5 -6
- data/spec/extensions/nested_attributes_spec.rb +1 -1
- data/spec/extensions/optimistic_locking_spec.rb +1 -1
- data/spec/extensions/pagination_spec.rb +1 -1
- data/spec/extensions/pretty_table_spec.rb +1 -1
- data/spec/extensions/query_spec.rb +1 -1
- data/spec/extensions/rcte_tree_spec.rb +1 -1
- data/spec/extensions/schema_dumper_spec.rb +3 -2
- data/spec/extensions/schema_spec.rb +1 -1
- data/spec/extensions/serialization_spec.rb +6 -2
- data/spec/extensions/sharding_spec.rb +1 -1
- data/spec/extensions/single_table_inheritance_spec.rb +1 -1
- data/spec/extensions/skip_create_refresh_spec.rb +1 -1
- data/spec/extensions/spec_helper.rb +7 -3
- data/spec/extensions/sql_expr_spec.rb +1 -1
- data/spec/extensions/string_date_time_spec.rb +1 -1
- data/spec/extensions/string_stripper_spec.rb +1 -1
- data/spec/extensions/subclasses_spec.rb +1 -1
- data/spec/extensions/tactical_eager_loading_spec.rb +1 -1
- data/spec/extensions/thread_local_timezones_spec.rb +1 -1
- data/spec/extensions/timestamps_spec.rb +1 -1
- data/spec/extensions/touch_spec.rb +1 -1
- data/spec/extensions/tree_spec.rb +119 -0
- data/spec/extensions/typecast_on_load_spec.rb +1 -1
- data/spec/extensions/update_primary_key_spec.rb +1 -1
- data/spec/extensions/validation_class_methods_spec.rb +1 -1
- data/spec/extensions/validation_helpers_spec.rb +1 -1
- data/spec/extensions/xml_serializer_spec.rb +142 -0
- data/spec/integration/associations_test.rb +1 -1
- data/spec/integration/database_test.rb +1 -1
- data/spec/integration/dataset_test.rb +29 -14
- data/spec/integration/eager_loader_test.rb +1 -1
- data/spec/integration/migrator_test.rb +1 -1
- data/spec/integration/model_test.rb +1 -1
- data/spec/integration/plugin_test.rb +316 -1
- data/spec/integration/prepared_statement_test.rb +1 -1
- data/spec/integration/schema_test.rb +8 -8
- data/spec/integration/spec_helper.rb +1 -1
- data/spec/integration/timezone_test.rb +1 -1
- data/spec/integration/transaction_test.rb +35 -20
- data/spec/integration/type_test.rb +1 -1
- data/spec/model/association_reflection_spec.rb +1 -1
- data/spec/model/associations_spec.rb +49 -34
- data/spec/model/base_spec.rb +1 -1
- data/spec/model/dataset_methods_spec.rb +4 -4
- data/spec/model/eager_loading_spec.rb +1 -1
- data/spec/model/hooks_spec.rb +1 -1
- data/spec/model/inflector_spec.rb +1 -1
- data/spec/model/model_spec.rb +7 -1
- data/spec/model/plugins_spec.rb +1 -1
- data/spec/model/record_spec.rb +1 -3
- data/spec/model/spec_helper.rb +2 -2
- data/spec/model/validations_spec.rb +1 -1
- metadata +29 -5
data/doc/association_basics.rdoc
CHANGED
@@ -295,8 +295,8 @@ Examples:
|
|
295
295
|
|
296
296
|
== Dataset Method
|
297
297
|
|
298
|
-
In addition to the above methods, associations also add a
|
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
|
-
|
73
|
-
|
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{
|
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.
|
82
|
-
dataset[:name => 'abc']
|
87
|
+
dataset.where(:id=>other_dataset.select(:other_id))
|
83
88
|
|
84
|
-
|
85
|
-
dataset.filter{|o| o.price > dataset.select(o.avg(price) + 100)}
|
89
|
+
=== Subselects as scalar values
|
86
90
|
|
87
|
-
|
91
|
+
dataset.where('price > (SELECT avg(price) + 100 FROM table)')
|
92
|
+
dataset.filter{price > dataset.select(avg(price) + 100)}
|
88
93
|
|
89
|
-
|
90
|
-
#=> "SELECT * FROM items WHERE (price < 100)"
|
94
|
+
=== LIKE/Regexp
|
91
95
|
|
92
|
-
DB[:items].filter(:name.like('AL%'))
|
93
|
-
|
96
|
+
DB[:items].filter(:name.like('AL%'))
|
97
|
+
DB[:items].filter(:name => /^AL/)
|
94
98
|
|
95
|
-
|
99
|
+
=== AND/OR/NOT
|
96
100
|
|
97
|
-
DB[:items].filter{
|
98
|
-
|
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
|
-
|
105
|
+
# SELECT * FROM items WHERE (((x = 1) OR (y = 2)) AND (z != 3))
|
102
106
|
|
103
|
-
|
107
|
+
=== Mathematical operators
|
104
108
|
|
105
109
|
DB[:items].filter((:x + :y) > :z).sql
|
106
|
-
|
110
|
+
# SELECT * FROM items WHERE ((x + y) > z)
|
107
111
|
|
108
|
-
DB[:items].filter{
|
109
|
-
|
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
|
-
==
|
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
|
-
|
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
|
-
|
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
|
-
==
|
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
|
-
|
158
|
+
TrueClass :active, :default => true
|
154
159
|
foreign_key :category_id, :categories
|
155
|
-
|
160
|
+
DateTime :created_at
|
156
161
|
|
157
|
-
index :
|
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
|
-
#
|
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
|
215
|
-
dataset.delete_sql
|
216
|
-
dataset.where(:name => 'sequel').exists
|
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, ...}], ...]
|
data/doc/dataset_filtering.rdoc
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
= Dataset Filtering
|
2
2
|
|
3
|
-
Sequel
|
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
|
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
|
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
|
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{
|
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{
|
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
|
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
|
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
|
86
|
-
|
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,
|
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
|
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
|
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
|