sequel 3.12.1 → 3.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|