sequel 2.10.0 → 2.11.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 +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
|
+
|