colincasey-sequel 2.10.0 → 2.10.1
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +7 -1
- data/doc/advanced_associations.rdoc +614 -0
- data/doc/cheat_sheet.rdoc +223 -0
- data/doc/dataset_filtering.rdoc +158 -0
- data/doc/prepared_statements.rdoc +104 -0
- 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.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/doc/schema.rdoc +29 -0
- data/doc/sharding.rdoc +113 -0
- data/lib/sequel.rb +1 -0
- data/lib/sequel_core/adapters/ado.rb +89 -0
- data/lib/sequel_core/adapters/db2.rb +143 -0
- data/lib/sequel_core/adapters/dbi.rb +112 -0
- data/lib/sequel_core/adapters/do/mysql.rb +38 -0
- data/lib/sequel_core/adapters/do/postgres.rb +92 -0
- data/lib/sequel_core/adapters/do/sqlite.rb +31 -0
- data/lib/sequel_core/adapters/do.rb +205 -0
- data/lib/sequel_core/adapters/firebird.rb +298 -0
- data/lib/sequel_core/adapters/informix.rb +85 -0
- data/lib/sequel_core/adapters/jdbc/h2.rb +69 -0
- data/lib/sequel_core/adapters/jdbc/mysql.rb +66 -0
- data/lib/sequel_core/adapters/jdbc/oracle.rb +23 -0
- data/lib/sequel_core/adapters/jdbc/postgresql.rb +113 -0
- data/lib/sequel_core/adapters/jdbc/sqlite.rb +43 -0
- data/lib/sequel_core/adapters/jdbc.rb +491 -0
- data/lib/sequel_core/adapters/mysql.rb +369 -0
- data/lib/sequel_core/adapters/odbc.rb +174 -0
- data/lib/sequel_core/adapters/openbase.rb +68 -0
- data/lib/sequel_core/adapters/oracle.rb +107 -0
- data/lib/sequel_core/adapters/postgres.rb +456 -0
- data/lib/sequel_core/adapters/shared/ms_access.rb +110 -0
- data/lib/sequel_core/adapters/shared/mssql.rb +102 -0
- data/lib/sequel_core/adapters/shared/mysql.rb +325 -0
- data/lib/sequel_core/adapters/shared/oracle.rb +61 -0
- data/lib/sequel_core/adapters/shared/postgres.rb +715 -0
- data/lib/sequel_core/adapters/shared/progress.rb +31 -0
- data/lib/sequel_core/adapters/shared/sqlite.rb +265 -0
- data/lib/sequel_core/adapters/sqlite.rb +248 -0
- data/lib/sequel_core/connection_pool.rb +258 -0
- data/lib/sequel_core/core_ext.rb +217 -0
- data/lib/sequel_core/core_sql.rb +202 -0
- data/lib/sequel_core/database/schema.rb +164 -0
- data/lib/sequel_core/database.rb +691 -0
- data/lib/sequel_core/dataset/callback.rb +13 -0
- data/lib/sequel_core/dataset/convenience.rb +237 -0
- data/lib/sequel_core/dataset/pagination.rb +96 -0
- data/lib/sequel_core/dataset/prepared_statements.rb +220 -0
- data/lib/sequel_core/dataset/query.rb +41 -0
- data/lib/sequel_core/dataset/schema.rb +15 -0
- data/lib/sequel_core/dataset/sql.rb +1010 -0
- data/lib/sequel_core/dataset/stored_procedures.rb +75 -0
- data/lib/sequel_core/dataset/unsupported.rb +43 -0
- data/lib/sequel_core/dataset.rb +511 -0
- data/lib/sequel_core/deprecated.rb +26 -0
- data/lib/sequel_core/exceptions.rb +44 -0
- data/lib/sequel_core/migration.rb +212 -0
- data/lib/sequel_core/object_graph.rb +230 -0
- data/lib/sequel_core/pretty_table.rb +71 -0
- data/lib/sequel_core/schema/generator.rb +320 -0
- data/lib/sequel_core/schema/sql.rb +325 -0
- data/lib/sequel_core/schema.rb +2 -0
- data/lib/sequel_core/sql.rb +887 -0
- data/lib/sequel_core/version.rb +11 -0
- data/lib/sequel_core.rb +172 -0
- data/lib/sequel_model/association_reflection.rb +267 -0
- data/lib/sequel_model/associations.rb +499 -0
- data/lib/sequel_model/base.rb +523 -0
- data/lib/sequel_model/caching.rb +82 -0
- data/lib/sequel_model/dataset_methods.rb +26 -0
- data/lib/sequel_model/eager_loading.rb +370 -0
- data/lib/sequel_model/exceptions.rb +7 -0
- data/lib/sequel_model/hooks.rb +101 -0
- data/lib/sequel_model/inflector.rb +281 -0
- data/lib/sequel_model/plugins.rb +62 -0
- data/lib/sequel_model/record.rb +568 -0
- data/lib/sequel_model/schema.rb +49 -0
- data/lib/sequel_model/validations.rb +429 -0
- data/lib/sequel_model.rb +91 -0
- data/spec/adapters/ado_spec.rb +46 -0
- data/spec/adapters/firebird_spec.rb +376 -0
- data/spec/adapters/informix_spec.rb +96 -0
- data/spec/adapters/mysql_spec.rb +881 -0
- data/spec/adapters/oracle_spec.rb +244 -0
- data/spec/adapters/postgres_spec.rb +687 -0
- data/spec/adapters/spec_helper.rb +10 -0
- data/spec/adapters/sqlite_spec.rb +555 -0
- data/spec/integration/dataset_test.rb +134 -0
- data/spec/integration/eager_loader_test.rb +696 -0
- data/spec/integration/prepared_statement_test.rb +130 -0
- data/spec/integration/schema_test.rb +180 -0
- data/spec/integration/spec_helper.rb +58 -0
- data/spec/integration/type_test.rb +96 -0
- data/spec/rcov.opts +6 -0
- data/spec/sequel_core/connection_pool_spec.rb +526 -0
- data/spec/sequel_core/core_ext_spec.rb +156 -0
- data/spec/sequel_core/core_sql_spec.rb +522 -0
- data/spec/sequel_core/database_spec.rb +1188 -0
- data/spec/sequel_core/dataset_spec.rb +3481 -0
- data/spec/sequel_core/expression_filters_spec.rb +363 -0
- data/spec/sequel_core/migration_spec.rb +261 -0
- data/spec/sequel_core/object_graph_spec.rb +272 -0
- data/spec/sequel_core/pretty_table_spec.rb +58 -0
- data/spec/sequel_core/schema_generator_spec.rb +167 -0
- data/spec/sequel_core/schema_spec.rb +780 -0
- data/spec/sequel_core/spec_helper.rb +55 -0
- data/spec/sequel_core/version_spec.rb +7 -0
- data/spec/sequel_model/association_reflection_spec.rb +93 -0
- data/spec/sequel_model/associations_spec.rb +1767 -0
- data/spec/sequel_model/base_spec.rb +419 -0
- data/spec/sequel_model/caching_spec.rb +215 -0
- data/spec/sequel_model/dataset_methods_spec.rb +78 -0
- data/spec/sequel_model/eager_loading_spec.rb +1165 -0
- data/spec/sequel_model/hooks_spec.rb +485 -0
- data/spec/sequel_model/inflector_spec.rb +119 -0
- data/spec/sequel_model/model_spec.rb +588 -0
- data/spec/sequel_model/plugins_spec.rb +80 -0
- data/spec/sequel_model/record_spec.rb +1184 -0
- data/spec/sequel_model/schema_spec.rb +90 -0
- data/spec/sequel_model/spec_helper.rb +78 -0
- data/spec/sequel_model/validations_spec.rb +1067 -0
- data/spec/spec.opts +0 -0
- data/spec/spec_config.rb.example +10 -0
- metadata +177 -3
@@ -0,0 +1,101 @@
|
|
1
|
+
=== Better model associations
|
2
|
+
|
3
|
+
The latest release of sequel_model includes a new associations
|
4
|
+
functionality written by Jeremy Evans which replaces the old relations
|
5
|
+
code in previous versions. Please note that this version is not
|
6
|
+
completely backward-compatible and you should therefore upgrade with
|
7
|
+
caution.
|
8
|
+
|
9
|
+
The new implementation supports three kinds of relations: one_to_many,
|
10
|
+
many_to_one and many_to_many, which correspond to has_many, belongs_to
|
11
|
+
and has_and_belongs_to_many relations in ActiveRecord. In fact, the
|
12
|
+
new implementation includes aliases for ActiveRecord assocation macros
|
13
|
+
and is basically compatible with ActiveRecord conventions. It also
|
14
|
+
supports DRY implicit class name references. Here's a simple example:
|
15
|
+
|
16
|
+
class Author < Sequel::Model
|
17
|
+
has_many :books # equivalent to one_to_many
|
18
|
+
end
|
19
|
+
|
20
|
+
class Book < Sequel::Model
|
21
|
+
belongs_to :author # equivalent to many_to_one
|
22
|
+
has_and_belongs_to_many :categories # equivalent to many_to_many
|
23
|
+
end
|
24
|
+
|
25
|
+
class Category < Sequel::Model
|
26
|
+
has_and_belongs_to_many :books
|
27
|
+
end
|
28
|
+
|
29
|
+
These macros will create the following methods:
|
30
|
+
|
31
|
+
* Author#books, Author#add_book, Author#remove_book
|
32
|
+
* Book#author, Book#categories, Book#add_category,
|
33
|
+
Book#remove_category
|
34
|
+
* Category#books, Category#add_book, Category#remove_book
|
35
|
+
|
36
|
+
Unlike ActiveRecord, one_to_many and many_to_many association methods
|
37
|
+
return a dataset:
|
38
|
+
|
39
|
+
a = Author[1234]
|
40
|
+
a.books.sql #=> 'SELECT * FROM books WHERE (author_id = 1234)'
|
41
|
+
|
42
|
+
You can also tell Sequel to cache the association result set and
|
43
|
+
return it as an array:
|
44
|
+
|
45
|
+
class Author < Sequel::Model
|
46
|
+
has_many :books, :cache => true
|
47
|
+
end
|
48
|
+
|
49
|
+
Author[1234].books.class #=> Array
|
50
|
+
|
51
|
+
You can of course bypass the defaults and specify class names and key
|
52
|
+
names:
|
53
|
+
|
54
|
+
class Node < Sequel::Model
|
55
|
+
belongs_to :parent, :class => Node
|
56
|
+
belongs_to :session, :key => :producer_id
|
57
|
+
end
|
58
|
+
|
59
|
+
Another useful option is :order, which sets the order for the
|
60
|
+
association dataset:
|
61
|
+
|
62
|
+
class Author < Sequel::Model
|
63
|
+
has_many :books, :order => :title
|
64
|
+
end
|
65
|
+
|
66
|
+
Author[1234].books.sql #=> 'SELECT * FROM books WHERE (author_id =
|
67
|
+
1234) ORDER BY title'
|
68
|
+
|
69
|
+
More information about associations can be found in the Sequel
|
70
|
+
documentation.
|
71
|
+
|
72
|
+
=== Other changes
|
73
|
+
|
74
|
+
* Added configuration file for running specs (#186).
|
75
|
+
|
76
|
+
* Changed Database#drop_index to accept fixed arity (#173).
|
77
|
+
|
78
|
+
* Changed column definition sql to put UNSIGNED constraint before
|
79
|
+
unique in order to satisfy MySQL (#171).
|
80
|
+
|
81
|
+
* Enhanced MySQL adapter to support load data local infile_, added
|
82
|
+
compress option for mysql connection by default (#172).
|
83
|
+
|
84
|
+
* Fixed bug when inserting hashes in array tuples mode.
|
85
|
+
|
86
|
+
* Changed SQLite adapter to catch RuntimeError raised when executing a
|
87
|
+
statement and raise Error::InvalidStatement with the offending SQL and
|
88
|
+
error message (#188).
|
89
|
+
|
90
|
+
* Fixed Dataset#reverse to not raise for unordered dataset (#189).
|
91
|
+
|
92
|
+
* Added Dataset#unordered method and changed #order to remove order if
|
93
|
+
nil is specified (#190).
|
94
|
+
|
95
|
+
* Fixed reversing order of ASC expression (#164).
|
96
|
+
|
97
|
+
* Added support for :null => true option when defining table columns
|
98
|
+
(#192).
|
99
|
+
|
100
|
+
* Fixed Symbol#method_missing to accept variable arity (#185).
|
101
|
+
|
@@ -0,0 +1,53 @@
|
|
1
|
+
Eager loading for all types of associations:
|
2
|
+
|
3
|
+
Artist.eager(:albums).all
|
4
|
+
Album.eager(:artist, :genre, :tracks).all
|
5
|
+
Album.eager(:artist).eager(:genre).eager(:tracks).all
|
6
|
+
Album.filter(:year=>2008).eager(:artist).all
|
7
|
+
|
8
|
+
Eager loading supports cascading to an unlimited depth, and doesn't have
|
9
|
+
any aliasing issues:
|
10
|
+
|
11
|
+
Artist.eager(:albums=>:tracks).all
|
12
|
+
Artist.eager(:albums=>{:tracks=>:genre}).all
|
13
|
+
|
14
|
+
Unfortunately, eager loading comes at the expense of a small amount of
|
15
|
+
backward compatibility. If you were using uncached associations (the
|
16
|
+
default in sequel_model 0.5), they no longer work the same way. Now,
|
17
|
+
all associations act as if :cache=>true (which is now set for all
|
18
|
+
associations, so if you wrote a tool that worked with both cached and
|
19
|
+
uncached associations, it should still work).
|
20
|
+
|
21
|
+
One to many associations now populate the corresponding many to one
|
22
|
+
instance variable (even when eagerly loaded):
|
23
|
+
|
24
|
+
# Assuming: Album.one_to_many :tracks
|
25
|
+
album = Album.first
|
26
|
+
# This following code is only one query,
|
27
|
+
# not a query for the album and one for each track
|
28
|
+
album.tracks.each{|t| puts t.album.name}
|
29
|
+
|
30
|
+
ActiveRecord style has_many :through associations are now supported via
|
31
|
+
many_to_many. many_to_many will no longer select the entire result set,
|
32
|
+
just the columns of the associated table (and not the join table), so it
|
33
|
+
works for both has_and_belongs_to_many (simple join table) and has_many
|
34
|
+
:through (join table model) scenarios. If you want to include all or
|
35
|
+
part of the join table attributes, see the :select option for
|
36
|
+
many_to_many associations.
|
37
|
+
|
38
|
+
We reduced the number of gems from three (sequel, sequel_core,
|
39
|
+
sequel_model) to two (sequel, sequel_core). Basically, sequel_model is
|
40
|
+
now just sequel, and the old sequel gem metapackage is no longer. There
|
41
|
+
isn't a reason to have a gem metapackage for two gems when one
|
42
|
+
(sequel_model) depends on the other (sequel_core). This required a
|
43
|
+
version bump for the model part of sequel from 0.5.0.2 to 1.4.0 (since
|
44
|
+
the previous sequel gem version was 1.3).
|
45
|
+
|
46
|
+
Sequel 1.4.0 has fixes for 11 trackers issues, including fixes to the
|
47
|
+
MySQL and PostgreSQL adapters.
|
48
|
+
|
49
|
+
We have switched the source control repository for Sequel from Google
|
50
|
+
Code (which uses subversion) to github (which uses git). If you would
|
51
|
+
like to contribute to Sequel, please fork the github repository, make
|
52
|
+
your changes, and send a pull request. As before, posting patches on
|
53
|
+
the Google Code issue tracker is fine as well.
|
@@ -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
|
+
|