sequel 2.10.0 → 2.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +51 -1
- data/README.rdoc +2 -2
- data/Rakefile +2 -2
- data/doc/advanced_associations.rdoc +6 -18
- data/doc/release_notes/1.0.txt +38 -0
- data/doc/release_notes/1.1.txt +143 -0
- data/doc/release_notes/1.3.txt +101 -0
- data/doc/release_notes/1.4.0.txt +53 -0
- data/doc/release_notes/1.5.0.txt +155 -0
- data/doc/release_notes/2.0.0.txt +298 -0
- data/doc/release_notes/2.1.0.txt +271 -0
- data/doc/release_notes/2.10.0.txt +328 -0
- data/doc/release_notes/2.11.0.txt +215 -0
- data/doc/release_notes/2.2.0.txt +253 -0
- data/doc/release_notes/2.3.0.txt +88 -0
- data/doc/release_notes/2.4.0.txt +106 -0
- data/doc/release_notes/2.5.0.txt +137 -0
- data/doc/release_notes/2.6.0.txt +157 -0
- data/doc/release_notes/2.7.0.txt +166 -0
- data/doc/release_notes/2.8.0.txt +171 -0
- data/doc/release_notes/2.9.0.txt +97 -0
- data/lib/sequel_core/adapters/ado.rb +3 -0
- data/lib/sequel_core/adapters/db2.rb +0 -11
- data/lib/sequel_core/adapters/dbi.rb +0 -11
- data/lib/sequel_core/adapters/do.rb +0 -12
- data/lib/sequel_core/adapters/firebird.rb +21 -16
- data/lib/sequel_core/adapters/informix.rb +1 -11
- data/lib/sequel_core/adapters/jdbc.rb +1 -13
- data/lib/sequel_core/adapters/jdbc/h2.rb +3 -11
- data/lib/sequel_core/adapters/jdbc/mysql.rb +0 -17
- data/lib/sequel_core/adapters/jdbc/postgresql.rb +3 -15
- data/lib/sequel_core/adapters/mysql.rb +31 -27
- data/lib/sequel_core/adapters/odbc.rb +34 -28
- data/lib/sequel_core/adapters/openbase.rb +0 -11
- data/lib/sequel_core/adapters/oracle.rb +11 -9
- data/lib/sequel_core/adapters/postgres.rb +14 -17
- data/lib/sequel_core/adapters/shared/mssql.rb +6 -15
- data/lib/sequel_core/adapters/shared/mysql.rb +29 -14
- data/lib/sequel_core/adapters/shared/oracle.rb +4 -0
- data/lib/sequel_core/adapters/shared/postgres.rb +30 -35
- data/lib/sequel_core/adapters/shared/progress.rb +4 -0
- data/lib/sequel_core/adapters/shared/sqlite.rb +73 -13
- data/lib/sequel_core/adapters/sqlite.rb +8 -18
- data/lib/sequel_core/adapters/utils/date_format.rb +21 -0
- data/lib/sequel_core/{dataset → adapters/utils}/stored_procedures.rb +0 -0
- data/lib/sequel_core/{dataset → adapters/utils}/unsupported.rb +0 -0
- data/lib/sequel_core/core_ext.rb +1 -1
- data/lib/sequel_core/core_sql.rb +9 -4
- data/lib/sequel_core/database.rb +63 -62
- data/lib/sequel_core/dataset.rb +9 -4
- data/lib/sequel_core/dataset/convenience.rb +10 -9
- data/lib/sequel_core/dataset/prepared_statements.rb +1 -1
- data/lib/sequel_core/dataset/sql.rb +130 -36
- data/lib/sequel_core/schema/sql.rb +2 -2
- data/lib/sequel_core/sql.rb +44 -51
- data/lib/sequel_core/version.rb +1 -1
- data/lib/sequel_model/associations.rb +25 -17
- data/lib/sequel_model/base.rb +35 -7
- data/lib/sequel_model/caching.rb +1 -6
- data/lib/sequel_model/record.rb +23 -5
- data/lib/sequel_model/validations.rb +20 -5
- data/spec/adapters/firebird_spec.rb +6 -1
- data/spec/adapters/mysql_spec.rb +12 -0
- data/spec/adapters/postgres_spec.rb +2 -2
- data/spec/adapters/sqlite_spec.rb +81 -2
- data/spec/integration/dataset_test.rb +2 -2
- data/spec/integration/type_test.rb +12 -2
- data/spec/sequel_core/core_sql_spec.rb +46 -12
- data/spec/sequel_core/database_spec.rb +24 -12
- data/spec/sequel_core/dataset_spec.rb +82 -32
- data/spec/sequel_core/schema_spec.rb +16 -0
- data/spec/sequel_model/associations_spec.rb +89 -0
- data/spec/sequel_model/base_spec.rb +66 -0
- data/spec/sequel_model/eager_loading_spec.rb +32 -0
- data/spec/sequel_model/record_spec.rb +9 -9
- data/spec/sequel_model/spec_helper.rb +3 -0
- data/spec/sequel_model/validations_spec.rb +63 -3
- metadata +41 -4
@@ -0,0 +1,155 @@
|
|
1
|
+
You can now graph a dataset and have the result split into component
|
2
|
+
tables:
|
3
|
+
|
4
|
+
DB[:artists].graph(:albums, :artist_id=>:id).first
|
5
|
+
# => {:artists=>{:id=>artists.id, :name=>artists.name}, \
|
6
|
+
# :albums=>{:id=>albums.id, :name=>albums.name,
|
7
|
+
:artist_id=>albums.artist_id}}
|
8
|
+
|
9
|
+
This aliases columns if necessary so they don't stomp on each other,
|
10
|
+
which
|
11
|
+
is what usually happens if you just join the tables:
|
12
|
+
|
13
|
+
DB[:artists].left_outer_join(:albums, :artist_id=>:id).first
|
14
|
+
# => {:id=>(albums.id||artists.id),
|
15
|
+
:name=>(albums.name||artist.names), \
|
16
|
+
:artist_id=>albums.artist_id}
|
17
|
+
|
18
|
+
Models can use graph as well, in which case the values will be model
|
19
|
+
objects:
|
20
|
+
|
21
|
+
Artist.graph(Album, :artist_id=>:id)
|
22
|
+
# => {:artists=>#<Artist...>, :albums=>#<Album...>}
|
23
|
+
|
24
|
+
Models can now eager load via .eager_graph, which will load all the
|
25
|
+
results
|
26
|
+
and all associations in a single query. This is necessary if you want
|
27
|
+
to
|
28
|
+
filter on columns in associated tables. It works exactly the same way
|
29
|
+
as
|
30
|
+
.eager, and supports cascading of associations as well:
|
31
|
+
|
32
|
+
# Artist.one_to_many :albums
|
33
|
+
# Album.one_to_many :tracks
|
34
|
+
# Track.many_to_one :genre
|
35
|
+
Artist.eager_graph(:albums=>{:tracks=>:genre}).filter( \
|
36
|
+
:tracks_name=>"Firewire").all
|
37
|
+
|
38
|
+
This will give you all artists have have an album with a track named
|
39
|
+
"Firewire", and calling .albums on one of those artists will only return
|
40
|
+
albums that have a track named "Firewire", and calling .tracks on one of
|
41
|
+
those albums will return only the track(s) named "Firewire".
|
42
|
+
|
43
|
+
You can use set_graph_aliases to select specific columns:
|
44
|
+
|
45
|
+
DB[:artists].graph(:albums, :artist_id=>:id).set_graph_aliases( \
|
46
|
+
:artist_name=>[:artists, :name], :album_name=>[:albums,
|
47
|
+
:name]).first
|
48
|
+
# => {:artists=>{:name=>artists.name}, :albums=>{:name=>albums.name}}
|
49
|
+
|
50
|
+
You can use eager_graph with set_graph_aliases to have eager loading
|
51
|
+
with
|
52
|
+
control over the SELECT clause.
|
53
|
+
|
54
|
+
All associations now update their reciprocal associations whenever the
|
55
|
+
association methods are used, so you don't need to refresh the
|
56
|
+
association or model to have the reciprocal association updated:
|
57
|
+
|
58
|
+
Album.many_to_one :band
|
59
|
+
Band.one_to_many :albums
|
60
|
+
|
61
|
+
# Note that all of these associations are cached,
|
62
|
+
# so after the first access there are no additional
|
63
|
+
# database queries to fetch associated records.
|
64
|
+
|
65
|
+
# many_to_one setter adds to reciprocal association
|
66
|
+
band1.albums # => []
|
67
|
+
album1.band = band1
|
68
|
+
band1.albums # => [album1]
|
69
|
+
band2.albums # => []
|
70
|
+
album1.band = band2
|
71
|
+
band1.albums # => []
|
72
|
+
band2.albums # => [album1]
|
73
|
+
album1.band = band2
|
74
|
+
band2.albums # => [album1]
|
75
|
+
album1.band = nil
|
76
|
+
band2.albums # => []
|
77
|
+
|
78
|
+
# one_to_many add_* method sets reciprocal association
|
79
|
+
# one_to_many remove_* method removes reciprocal association
|
80
|
+
album1.band # => nil
|
81
|
+
band1.add_album(album1)
|
82
|
+
album1.band # => band1
|
83
|
+
band2.add_album(album1)
|
84
|
+
album1.band # => band2
|
85
|
+
band2.remove_album(album1)
|
86
|
+
album1.band # => nil
|
87
|
+
|
88
|
+
Post.many_to_many :tags
|
89
|
+
Tag.many_to_many :posts
|
90
|
+
|
91
|
+
# many_to_many add_* method adds to reciprocal association
|
92
|
+
# many_to_many remove_* method removes from reciprocal association
|
93
|
+
post1.tags # => []
|
94
|
+
tag1.posts # => []
|
95
|
+
tag1.add_post(post1)
|
96
|
+
post1.tags # => [tag1]
|
97
|
+
tag1.posts # => [post1]
|
98
|
+
tag1.remove_post(post1)
|
99
|
+
post1.tags # => []
|
100
|
+
tag1.posts # => []
|
101
|
+
post1.add_tag(tag1)
|
102
|
+
post1.tags # => [tag1]
|
103
|
+
tag1.posts # => [post1]
|
104
|
+
post1.remove_tag(tag1)
|
105
|
+
post1.tags # => []
|
106
|
+
tag1.posts # => []
|
107
|
+
|
108
|
+
The MySQL and PostgreSQL adapters now support index types:
|
109
|
+
|
110
|
+
index :some_column, :type => :hash # or :spatial, :full_text, :rtree,
|
111
|
+
etc.
|
112
|
+
|
113
|
+
Starting in Sequel 1.5.0, some methods are deprecated. These methods
|
114
|
+
will be
|
115
|
+
removed in Sequel 2.0.0. The deprecation framework is fairly flexible.
|
116
|
+
You
|
117
|
+
can choose where the messages get sent:
|
118
|
+
|
119
|
+
Sequel::Deprecation.deprecation_message_stream = STDERR # the default
|
120
|
+
Sequel::Deprecation.deprecation_message_stream = \
|
121
|
+
File.new('deprecation.txt', 'wb') # A file
|
122
|
+
Sequel::Deprecation.deprecation_message_stream = nil # ignore the
|
123
|
+
messages
|
124
|
+
|
125
|
+
You can even have all deprecation messages accompanied by a traceback,
|
126
|
+
so you
|
127
|
+
can see exactly where in your code you are using a deprecated method:
|
128
|
+
|
129
|
+
Sequel::Deprecation.print_tracebacks = true
|
130
|
+
|
131
|
+
All deprecation methods come with an message telling you what
|
132
|
+
alternative code
|
133
|
+
will work.
|
134
|
+
|
135
|
+
In addition to deprecating some methods, we removed the ability to have
|
136
|
+
arrays returned instead of hashes. The array code still had debugging
|
137
|
+
messages
|
138
|
+
left it in, and we are not aware of anyone using it. Hashes have been
|
139
|
+
returned
|
140
|
+
by default since Sequel 0.3.
|
141
|
+
|
142
|
+
We have also removed the Numeric date/time extensions (e.g. 3.days.ago).
|
143
|
+
The
|
144
|
+
existing extensions were incomplete, better ones are provided elsewhere,
|
145
|
+
and the extensions were not really related to Sequel's purpose.
|
146
|
+
|
147
|
+
Sequel no longer depends on ParseTree, RubyInline, or ruby2ruby. They
|
148
|
+
are
|
149
|
+
still required to use the block filters. Sequel's only gem dependency
|
150
|
+
is on
|
151
|
+
the tiny metaid.
|
152
|
+
|
153
|
+
Sequel 1.5.0 has fixes for 12 tracker issues, including fixes to the
|
154
|
+
Informix,
|
155
|
+
MySQL, ODBC, ADO, JDBC, Postgres, and SQLite adapters.
|
@@ -0,0 +1,298 @@
|
|
1
|
+
Blockless Filter Expressions
|
2
|
+
----------------------------
|
3
|
+
|
4
|
+
Before 2.0.0, in order to specify complex SQL expressions, you
|
5
|
+
either had to resort to writing the SQL yourself in a string or
|
6
|
+
using an expression inside a block that was parsed by ParseTree.
|
7
|
+
Because ParseTree was required, only ruby 1.8.* was supported, and
|
8
|
+
supporting other ruby versions (ruby 1.9, JRuby, Rubinius) would
|
9
|
+
never be possible.
|
10
|
+
|
11
|
+
With 2.0.0, you no longer need to use a block to write complex SQL
|
12
|
+
expressions. The basics of the blockless filters are the usual
|
13
|
+
arithmetic, inequality, and binary operators:
|
14
|
+
|
15
|
+
+ = addition
|
16
|
+
- = subtraction
|
17
|
+
* = multiplication
|
18
|
+
/ = division
|
19
|
+
> = greater than
|
20
|
+
< = less than
|
21
|
+
>= = greater than or equal to
|
22
|
+
<= = less than or equal to
|
23
|
+
~ = negation
|
24
|
+
& = AND
|
25
|
+
| = OR
|
26
|
+
|
27
|
+
You can use these operators on Symbols, LiteralStrings, and other
|
28
|
+
Sequel::SQL::Expressions. Note that there is no equal operator or
|
29
|
+
not equal operator, to specify those, you use a Hash.
|
30
|
+
|
31
|
+
Here are some examples:
|
32
|
+
|
33
|
+
# Ruby code => SQL WHERE clause
|
34
|
+
:active => active
|
35
|
+
~:active => NOT active
|
36
|
+
~~:active => active
|
37
|
+
~~~:active => NOT active
|
38
|
+
:is_true[] => is_true()
|
39
|
+
~:is_true[] => NOT is_true()
|
40
|
+
:x > 100 => (x > 100)
|
41
|
+
:x < 100.01 => (x < 100.01)
|
42
|
+
:x <= 0 => (x <= 0)
|
43
|
+
:x >= 1 => (x >= 1)
|
44
|
+
~(:x > 100) => (x <= 100)
|
45
|
+
{:x => 100} => (x = 100)
|
46
|
+
{:x => 'a'} => (x = 'a')
|
47
|
+
{:x => nil} => (x IS NULL)
|
48
|
+
~{:x => 100} => (x != 100)
|
49
|
+
~{:x => 'a'} => (x != 'a')
|
50
|
+
~{:x => nil} => (x IS NOT NULL)
|
51
|
+
{:x => /a/} => (x ~ 'blah') # Default, MySQL different
|
52
|
+
~{:x => /a/} => (x !~ 'blah') # Default, MySQL different
|
53
|
+
:x.like('a') => (x LIKE 'a')
|
54
|
+
~:x.like('a') => (x NOT LIKE 'a')
|
55
|
+
:x.like(/a/) => (x ~ 'a') # Default, MySQL different
|
56
|
+
~:x.like('a', /b/) => ((x NOT LIKE 'a') AND (x !~ 'b')) # Default
|
57
|
+
~{:x => 1..5} => ((x < 1) OR (x > 5))
|
58
|
+
~{:x => DB[:items].select(:i)} => (x NOT IN (SELECT i FROM items))
|
59
|
+
~{:x => [1,2,3]} => (x NOT IN (1, 2, 3))
|
60
|
+
:x + 1 > 100 => ((x + 1) > 100)
|
61
|
+
(:x * :y) < 100.01 => ((x * y) < 100.01)
|
62
|
+
(:x - :y/2) >= 100 => ((x - (y / 2)) >= 100)
|
63
|
+
(((:x - :y)/(:x + :y))*:z) <= 100 => ((((x - y) / (x + y)) * z) <=
|
64
|
+
100)
|
65
|
+
~((((:x - :y)/(:x + :y))*:z) <= 100) => ((((x - y) / (x + y)) * z) >
|
66
|
+
100)
|
67
|
+
:x & :y => (x AND y)
|
68
|
+
:x & :y & :z => ((x AND y) AND z)
|
69
|
+
:x & {:y => :z} => (x AND (y = z))
|
70
|
+
{:y => :z} & :x => ((y = z) AND x)
|
71
|
+
{:x => :a} & {:y => :z} => ((x = a) AND (y = z))
|
72
|
+
(:x > 200) & (:y < 200) => ((x > 200) AND (y < 200))
|
73
|
+
:x | :y => (x OR y)
|
74
|
+
:x | :y | :z => ((x OR y) OR z)
|
75
|
+
:x | {:y => :z} => (x OR (y = z))
|
76
|
+
{:y => :z} | :x => ((y = z) OR x)
|
77
|
+
{:x => :a} | {:y => :z} => ((x = a) OR (y = z))
|
78
|
+
(:x > 200) | (:y < 200) => ((x > 200) OR (y < 200))
|
79
|
+
(:x | :y) & :z => ((x OR y) AND z)
|
80
|
+
:x | (:y & :z) => (x OR (y AND z))
|
81
|
+
(:x & :w) | (:y & :z) => ((x AND w) OR (y AND z))
|
82
|
+
~((:x | :y) & :z) => ((NOT x AND NOT y) OR NOT z)
|
83
|
+
~((:x & :w) | (:y & :z)) => ((NOT x OR NOT w) AND (NOT y OR NOT z))
|
84
|
+
~((:x > 200) | (:y & :z)) => ((x <= 200) AND (NOT y OR NOT z))
|
85
|
+
~('x'.lit + 1 > 100) => ((x + 1) <= 100)
|
86
|
+
'x'.lit.like(/a/) => (x ~ 'a') # (x ~ \'a\')
|
87
|
+
|
88
|
+
None of these require blocks, you can use any directly in a call to
|
89
|
+
filter:
|
90
|
+
|
91
|
+
DB[:items].filter((:price * :tax) - :discount > 100)
|
92
|
+
# => SELECT * FROM items WHERE (((price * tax) - discount) > 100)
|
93
|
+
DB[:items].filter(:active & ~:archived)
|
94
|
+
# => SELECT * FROM items WHERE (active AND NOT archived)
|
95
|
+
|
96
|
+
SQL String Concatenation
|
97
|
+
------------------------
|
98
|
+
|
99
|
+
Sequel now has support for expressing SQL string concatenation in an
|
100
|
+
easy way:
|
101
|
+
|
102
|
+
[:name, :title].sql_string_join(" - ")
|
103
|
+
# SQL: name || ' - ' || title
|
104
|
+
|
105
|
+
You can use this in selecting columns, creating filters, ordering
|
106
|
+
datasets, and possibly elsewhere.
|
107
|
+
|
108
|
+
Schema Reflection Support/Typecasting on Assignment
|
109
|
+
---------------------------------------------------
|
110
|
+
|
111
|
+
When used with PostgreSQL, MySQL, or SQLite, Sequel now has the
|
112
|
+
ability to get information from the database's schema in regards
|
113
|
+
to column types:
|
114
|
+
|
115
|
+
DB.schema(:artist)
|
116
|
+
=> [[:id, {:type=>:integer, :db_type=>"integer", :max_chars=>0
|
117
|
+
:numeric_precision=>32, :allow_null=>false,
|
118
|
+
:default=>"nextval('artist_id_seq'::regclass)"}], [:name,
|
119
|
+
{:type=>:string, :default=>nil, :db_type=>"text",
|
120
|
+
:numeric_precision=>0, :allow_null=>true, :max_chars=>0}]]
|
121
|
+
|
122
|
+
Models now use this information to typecast values on attribute
|
123
|
+
assignment. For example, if you have an integer column named number
|
124
|
+
and a text (e.g. varchar) column named title:
|
125
|
+
|
126
|
+
1.5.1:
|
127
|
+
model.number = '1'
|
128
|
+
model.number # => '1'
|
129
|
+
model.title = 1
|
130
|
+
model.title # => 1
|
131
|
+
2.0.0:
|
132
|
+
model.number = '1'
|
133
|
+
model.number # => 1
|
134
|
+
model.title = 1
|
135
|
+
model.title # => '1'
|
136
|
+
|
137
|
+
Typecasting can be turned off on a global, per class, and per object
|
138
|
+
basis:
|
139
|
+
|
140
|
+
Sequel::Model.typecast_on_assignment = false # Global
|
141
|
+
Album.typecast_on_assignment = false # Per Class
|
142
|
+
Album.new.typecast_on_assignment = false # Per Object
|
143
|
+
|
144
|
+
Typecasting is somewhat strict, it does not allow obviously bogus
|
145
|
+
data to be used:
|
146
|
+
|
147
|
+
model.number = 'a' # Raises error
|
148
|
+
|
149
|
+
This is in contrast to how some other ORMs handle the situation:
|
150
|
+
|
151
|
+
model.number = 'a'
|
152
|
+
model.number # => 0
|
153
|
+
|
154
|
+
If Sequel is being used with a web framework and you want to display
|
155
|
+
friendly error messages to the user, you should probably turn
|
156
|
+
typecasting off and set up the necessary validations in your models.
|
157
|
+
|
158
|
+
Model Association Improvements
|
159
|
+
------------------------------
|
160
|
+
|
161
|
+
Associations can now be eagerly loaded even if they have a block,
|
162
|
+
though the block should not rely on being evaluated in the context
|
163
|
+
of an instance. This allows you filter on associations when eagerly
|
164
|
+
loading:
|
165
|
+
|
166
|
+
Artist.one_to_many :albums_with_10_tracks, :class=>:Album do |ds|
|
167
|
+
ds.filter(:num_tracks => 10)
|
168
|
+
end
|
169
|
+
Artist.filter(:name.like('A%)).eager(:albums_with_10_tracks).all
|
170
|
+
# SELECT * FROM artists WHERE (name LIKE 'A%')
|
171
|
+
# SELECT albums.* FROM albums WHERE ((artist_id IN (...)) AND
|
172
|
+
# (num_tracks = 10))
|
173
|
+
|
174
|
+
Associations now have a remove_all_ method for removing all
|
175
|
+
associated objects in a single query:
|
176
|
+
|
177
|
+
Artist.many_to_many :albums
|
178
|
+
Artist[1].remove_all_albums
|
179
|
+
# DELETE FROM albums_artists WHERE artist_id = 1
|
180
|
+
|
181
|
+
Artist.one_to_many :albums
|
182
|
+
Artist[1].remove_all_albums
|
183
|
+
# UPDATE albums SET artist_id = NULL WHERE artist_id = 1
|
184
|
+
|
185
|
+
All associations can specify a :select option to change which columns
|
186
|
+
are selected. Previously only many to many associations suppported
|
187
|
+
this.
|
188
|
+
|
189
|
+
The SQL used when eagerly loading through eager_graph can be
|
190
|
+
modified via the :graph_join_type, :graph_conditions, and
|
191
|
+
:graph_join_conditions options.
|
192
|
+
|
193
|
+
:graph_join_type changes the join type from the default of
|
194
|
+
:left_outer. This can be useful if you do not want any
|
195
|
+
albums that don't have an artist in the result set:
|
196
|
+
|
197
|
+
Album.many_to_one :artist, :graph_join_type=>:inner
|
198
|
+
Album.eager_graph(:artist).sql
|
199
|
+
# SELECT ... FROM albums INNER JOIN artists ...
|
200
|
+
|
201
|
+
:graph_conditions adds conditions on the join to the table you are
|
202
|
+
joining, the eager_graph equivalent of an association block argument
|
203
|
+
in eager. It takes either a hash or an array where all elements
|
204
|
+
are arrays of length two, similar to join_table, where key symbols
|
205
|
+
specify columns in the joined table and value symbols specify
|
206
|
+
columns in the last joined or primary table:
|
207
|
+
|
208
|
+
Album.many_to_one :artist, :graph_conditions=>{:active=>true}
|
209
|
+
Album.eager_graph(:artist).sql
|
210
|
+
# SELECT ... FROM albums LEFT OUTER JOIN artists ON ((artists.id =
|
211
|
+
# albums.artist_id) AND (artists.active = 't'))
|
212
|
+
|
213
|
+
:graph_join_table_conditions exists for many to many associations only,
|
214
|
+
and operates the same as :graph_conditions, except it specifies a
|
215
|
+
condition on the many to many join table instead of the associated
|
216
|
+
model's table. This is necessary if the join table is also model
|
217
|
+
table with other columns on which you may want to filter:
|
218
|
+
|
219
|
+
Album.many_to_many :genres, :join_table=>:ag, \
|
220
|
+
:graph_join_table_conditions=>{:active=>true}
|
221
|
+
Album.eager_graph(:genres).sql
|
222
|
+
# SELECT ... FROM albums LEFT OUTER JOIN ag ON ((ag.album_id =
|
223
|
+
albums.id) AND (ag.active = 't')) LEFT OUTER JOIN genres ON
|
224
|
+
(genres.id = ag.genre_id)
|
225
|
+
|
226
|
+
Other Small Improvements
|
227
|
+
------------------------
|
228
|
+
|
229
|
+
* Dataset#invert returns a dataset that matches all records not
|
230
|
+
matching the current filter.
|
231
|
+
* Dataset#unfiltered returns a dataset that has any filters removed.
|
232
|
+
* Dataset#last_page? and Dataset#first_page? for paginated datasets.
|
233
|
+
* The sequel command line tool now support an -E or --echo argument
|
234
|
+
that logs all SQL to the standard output. It also can take a path
|
235
|
+
to a yaml file with database connection options, in addition to a
|
236
|
+
database URL.
|
237
|
+
* Databases can now have multiple SQL loggers, so you can log to the
|
238
|
+
standard output as well as a file.
|
239
|
+
* SQL identifiers (columns and tables) are now quoted by default (you
|
240
|
+
can turn this off via Sequel.quote_identifiers = false if need be).
|
241
|
+
* Sequel.connect now takes an optional block that will disconnect the
|
242
|
+
database when the block finishes.
|
243
|
+
* AlterTableGenerator now has add_primary_key and add_foreign_key
|
244
|
+
methods.
|
245
|
+
* Running the specs without ParseTree installed skips the specs that
|
246
|
+
require ParseTree.
|
247
|
+
* You can use an array of arrays instead of a hash when specifying
|
248
|
+
conditions, which may be necessary in certain situations where
|
249
|
+
you would be using the same hash key more than once.
|
250
|
+
* Almost all documentation for Sequel was updated for 2.0.0, so if you
|
251
|
+
found Sequel documentation lacking before, check out the new RDoc
|
252
|
+
pages.
|
253
|
+
* There have been many minor refactoring improvements, the code
|
254
|
+
should now be easier to read and follow.
|
255
|
+
* Sequel now has no external dependencies.
|
256
|
+
* Sequel::Models now have before_validation and after_validation
|
257
|
+
hooks.
|
258
|
+
* Sequel::Model hooks that return false cause the methods that call
|
259
|
+
them (such as save) to return false.
|
260
|
+
* Sequel::Models can now load their schema on first instantiation,
|
261
|
+
instead of when they are created, via
|
262
|
+
Sequel::Model.lazy_load_schema=. This is helpful for certain
|
263
|
+
web frameworks that reload all models on every request.
|
264
|
+
* Hook methods that use blocks can now include an optional tag,
|
265
|
+
which allows them to work well with web frameworks that load source
|
266
|
+
files every time they are modified.
|
267
|
+
|
268
|
+
The PostgreSQL adapter has been rewritten and now supports ruby-pg.
|
269
|
+
There have also been improvements in the following adapters: DBI,
|
270
|
+
MySQL, SQLite, Oracle, and MSSQL.
|
271
|
+
|
272
|
+
All of the methods that have been deprecated in 1.5.0 have now been
|
273
|
+
removed. If you are want to upgrade to Sequel 2.0.0 from version 1.4.0
|
274
|
+
or previous, upgrade to 1.5.1 first, fix all of the deprecation
|
275
|
+
warnings that show up, and then upgrade to 2.0.0.
|
276
|
+
|
277
|
+
There were some backwards incompatible changes made in 2.0.0 beyond the
|
278
|
+
removal of deprecated methods. These are:
|
279
|
+
|
280
|
+
* Inflector is no longer used, the inflection methods were moved
|
281
|
+
directly into String (where they belong because inflections only
|
282
|
+
make sense for strings). So to override singularization
|
283
|
+
or pluralization rules, use String.inflections instead of
|
284
|
+
Inflector.inflections.
|
285
|
+
* MySQL tinyints are now returned as boolean values instead of
|
286
|
+
integers. MySQL doesn't have a boolean type, and usually it
|
287
|
+
is recommended to use tinyint for a boolean column.
|
288
|
+
* You can no longer pass an array to Dataset#order or Dataset#select,
|
289
|
+
you need to pass each argument separately (the * operator is your
|
290
|
+
friend).
|
291
|
+
* You must use '?' instead of '(?)' when interpolating an array
|
292
|
+
argument into a string (e.g. filter('x IN ?', [1,2,3]))
|
293
|
+
* You must pass an explicit table alias argument to join_table and
|
294
|
+
related methods, you can no longer include the table alias
|
295
|
+
inside the table argument.
|
296
|
+
* sqlite:// URLs now operate the same as file:// URLs (2 slashes
|
297
|
+
for a relative path, 3 for an absolute path).
|
298
|
+
|