sequel 3.35.0 → 3.36.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (81) hide show
  1. data/CHANGELOG +78 -0
  2. data/Rakefile +3 -3
  3. data/bin/sequel +3 -1
  4. data/doc/advanced_associations.rdoc +154 -11
  5. data/doc/migration.rdoc +18 -0
  6. data/doc/object_model.rdoc +541 -0
  7. data/doc/opening_databases.rdoc +4 -1
  8. data/doc/release_notes/3.36.0.txt +245 -0
  9. data/doc/schema_modification.rdoc +0 -6
  10. data/lib/sequel/adapters/do/mysql.rb +7 -0
  11. data/lib/sequel/adapters/jdbc.rb +11 -3
  12. data/lib/sequel/adapters/jdbc/mysql.rb +3 -5
  13. data/lib/sequel/adapters/jdbc/postgresql.rb +10 -8
  14. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  15. data/lib/sequel/adapters/mock.rb +2 -6
  16. data/lib/sequel/adapters/mysql.rb +3 -9
  17. data/lib/sequel/adapters/mysql2.rb +12 -11
  18. data/lib/sequel/adapters/postgres.rb +32 -40
  19. data/lib/sequel/adapters/shared/mssql.rb +15 -11
  20. data/lib/sequel/adapters/shared/mysql.rb +28 -3
  21. data/lib/sequel/adapters/shared/oracle.rb +5 -0
  22. data/lib/sequel/adapters/shared/postgres.rb +59 -5
  23. data/lib/sequel/adapters/shared/sqlite.rb +3 -13
  24. data/lib/sequel/adapters/sqlite.rb +0 -7
  25. data/lib/sequel/adapters/swift/mysql.rb +2 -5
  26. data/lib/sequel/adapters/tinytds.rb +1 -2
  27. data/lib/sequel/connection_pool/sharded_threaded.rb +5 -1
  28. data/lib/sequel/connection_pool/threaded.rb +9 -1
  29. data/lib/sequel/database/dataset_defaults.rb +3 -1
  30. data/lib/sequel/database/misc.rb +7 -1
  31. data/lib/sequel/database/query.rb +11 -3
  32. data/lib/sequel/database/schema_generator.rb +40 -9
  33. data/lib/sequel/database/schema_methods.rb +6 -1
  34. data/lib/sequel/dataset/actions.rb +5 -5
  35. data/lib/sequel/dataset/prepared_statements.rb +3 -1
  36. data/lib/sequel/dataset/query.rb +1 -1
  37. data/lib/sequel/extensions/migration.rb +28 -0
  38. data/lib/sequel/extensions/pg_auto_parameterize.rb +0 -9
  39. data/lib/sequel/extensions/pg_inet.rb +89 -0
  40. data/lib/sequel/extensions/pg_json.rb +178 -0
  41. data/lib/sequel/extensions/schema_dumper.rb +24 -6
  42. data/lib/sequel/model/associations.rb +19 -15
  43. data/lib/sequel/model/base.rb +11 -12
  44. data/lib/sequel/plugins/composition.rb +1 -2
  45. data/lib/sequel/plugins/eager_each.rb +59 -0
  46. data/lib/sequel/plugins/json_serializer.rb +41 -4
  47. data/lib/sequel/plugins/nested_attributes.rb +72 -52
  48. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  49. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  50. data/lib/sequel/version.rb +1 -1
  51. data/spec/adapters/postgres_spec.rb +271 -1
  52. data/spec/adapters/sqlite_spec.rb +11 -0
  53. data/spec/core/connection_pool_spec.rb +26 -1
  54. data/spec/core/database_spec.rb +19 -0
  55. data/spec/core/dataset_spec.rb +45 -5
  56. data/spec/core/expression_filters_spec.rb +31 -67
  57. data/spec/core/mock_adapter_spec.rb +4 -0
  58. data/spec/extensions/core_extensions_spec.rb +83 -0
  59. data/spec/extensions/eager_each_spec.rb +34 -0
  60. data/spec/extensions/inflector_spec.rb +0 -4
  61. data/spec/extensions/json_serializer_spec.rb +32 -1
  62. data/spec/extensions/migration_spec.rb +28 -0
  63. data/spec/extensions/nested_attributes_spec.rb +134 -1
  64. data/spec/extensions/optimistic_locking_spec.rb +15 -1
  65. data/spec/extensions/pg_hstore_spec.rb +1 -1
  66. data/spec/extensions/pg_inet_spec.rb +44 -0
  67. data/spec/extensions/pg_json_spec.rb +101 -0
  68. data/spec/extensions/prepared_statements_spec.rb +30 -0
  69. data/spec/extensions/rcte_tree_spec.rb +9 -0
  70. data/spec/extensions/schema_dumper_spec.rb +195 -7
  71. data/spec/extensions/serialization_spec.rb +4 -0
  72. data/spec/extensions/spec_helper.rb +9 -1
  73. data/spec/extensions/tactical_eager_loading_spec.rb +8 -0
  74. data/spec/integration/database_test.rb +5 -1
  75. data/spec/integration/prepared_statement_test.rb +20 -2
  76. data/spec/model/associations_spec.rb +27 -0
  77. data/spec/model/base_spec.rb +54 -0
  78. data/spec/model/model_spec.rb +6 -0
  79. data/spec/model/record_spec.rb +18 -0
  80. data/spec/rcov.opts +2 -0
  81. metadata +14 -3
data/CHANGELOG CHANGED
@@ -1,3 +1,81 @@
1
+ === 3.36.0 (2012-06-01)
2
+
3
+ * Use Bignum generic type when dumping unsigned integer types that could potentially overflow 32-bit signed integer values (stu314)
4
+
5
+ * Support :transform option in the nested_attributes plugin, for automatically preprocessing input hashes (chanks)
6
+
7
+ * Support :unmatched_pk option in the nested_attributes plugin, can be set to :create for associated objects with natural keys (chanks)
8
+
9
+ * Support composite primary keys in the nested_attributes plugin (chanks)
10
+
11
+ * Allow Model#from_json in the json_serializer plugin to use set_fields if a :fields option is given (jeremyevans)
12
+
13
+ * Support :using option to set_column_type on PostgreSQL, to force a specific conversion from the old value to the new value (jeremyevans)
14
+
15
+ * Drop indexes in the reverse order that they were added in the schema dumper (jeremyevans)
16
+
17
+ * Add :index_names option to schema dumper method, can be set to false or :namespace (stu314, jeremyevans)
18
+
19
+ * Add Database#global_index_namespace? for checking if index namespace is global or per table (jeremyevans)
20
+
21
+ * Fix typecasting of time columns on jdbc/postgres, before could be off by a millisecond (jeremyevans)
22
+
23
+ * Add document explaining Sequel's object model (jeremyevans)
24
+
25
+ * Attempt to detect more disconnect errors in the mysql2 adapter (jeremyevans)
26
+
27
+ * Add is_current? and check_current to the migrators, for checking/raising if there are unapplied migrations (pvh, jeremyevans) (#487)
28
+
29
+ * Add a jdbc subadapter for the Progress database (Michael Gliwinski, jeremyevans)
30
+
31
+ * Add pg_inet extension, for working with PostgreSQL inet and cidr types (jeremyevans)
32
+
33
+ * Fix bug in model column setters when passing an object that raises an exception for ==('') (jeremyevans)
34
+
35
+ * Add eager_each plugin, which makes each on an eagerly loaded dataset do eager loading (jeremyevans)
36
+
37
+ * Fix bugs when parsing foreign keys for tables with explicit schema on PostgreSQL (jeremyevans)
38
+
39
+ * Remove Database#case_sensitive_like on SQLite (jeremyevans)
40
+
41
+ * Remove Database#single_value in the native sqlite adapter (jeremyevans)
42
+
43
+ * Make Dataset#get work with nil and false arguments (jeremyevans)
44
+
45
+ * Make json_serializer plugin respect :root=>:collection and :root=>:instance options (jeremyevans)
46
+
47
+ * Support savepoints in prepared transactions on MySQL 5.5.23+ (jeremyevans)
48
+
49
+ * Add pg_json extension, for working with PostgreSQL 9.2's new json type (jeremyevans)
50
+
51
+ * In the optimistic locking plugin, make refresh and save after a failed save work correctly (jeremyevans)
52
+
53
+ * Support partial indexes on Microsoft SQL Server 2008 (jeremyevans)
54
+
55
+ * Make Database#call pass blocks (jeremyevans)
56
+
57
+ * Support :each when preparing statements, useful for iterating over large datasets (jeremyevans)
58
+
59
+ * Support :if_exists and :cascade options when dropping indexes on PostgreSQL (jeremyevans)
60
+
61
+ * Support :concurrently option when adding and dropping indexes on PostgreSQL (jeremyevans)
62
+
63
+ * Make Database#transaction on PostgreSQL recognize :synchronous, :read_only, and :deferrable options (jeremyevans)
64
+
65
+ * Support :sql_mode option when connecting to MySQL (jeremyevans)
66
+
67
+ * Apply :timeout MySQL connection setting on do, jdbc, and swift adapters (jeremyevans)
68
+
69
+ * Don't set Sequel::Model.db automatically when creating an anonymous class with an associated database object (jeremyevans)
70
+
71
+ * Add :connection_handling=>:queue option to the threaded connection pools, may reduce chance of stale connections (jeremyevans) (#481)
72
+
73
+ * Handle JRuby 1.7 exception handling changes when connecting in the jdbc adapter (jeremyevans) (#477)
74
+
75
+ * Make *_to_one association setters be noops if you pass a value that is the same as the cached value (jeremyevans)
76
+
77
+ * Make Model#refresh return self when using dirty plugin (jeremyevans)
78
+
1
79
  === 3.35.0 (2012-05-01)
2
80
 
3
81
  * Correctly handle parsing schema for tables in other databases on MySQL (jeremyevans)
data/Rakefile CHANGED
@@ -128,15 +128,15 @@ begin
128
128
  end
129
129
 
130
130
  task :default => [:spec]
131
- spec_with_cov.call("spec", Dir["spec/{core,model}/*_spec.rb"], "Run core and model specs"){|t| t.rcov_opts.concat(%w'--exclude "lib/sequel/adapters/([a-ln-z]|m[a-np-z])"')}
131
+ spec_with_cov.call("spec", Dir["spec/{core,model}/*_spec.rb"], "Run core and model specs"){|t| t.rcov_opts.concat(%w'--exclude "lib/sequel/(adapters/([a-ln-z]|m[a-np-z])|extensions/core_extensions)"')}
132
132
  spec.call("spec_core", Dir["spec/core/*_spec.rb"], "Run core specs")
133
133
  spec.call("spec_model", Dir["spec/model/*_spec.rb"], "Run model specs")
134
134
  spec.call("_spec_model_no_assoc", Dir["spec/model/*_spec.rb"].delete_if{|f| f =~ /association|eager_loading/}, '')
135
- spec_with_cov.call("spec_plugin", Dir["spec/extensions/*_spec.rb"], "Run extension/plugin specs")
135
+ spec_with_cov.call("spec_plugin", Dir["spec/extensions/*_spec.rb"], "Run extension/plugin specs"){|t| t.rcov_opts.concat(%w'--exclude "lib/sequel/([a-z_]+\.rb|adapters|connection_pool|database|dataset|model)"')}
136
136
  spec_with_cov.call("spec_integration", Dir["spec/integration/*_test.rb"], "Run integration tests")
137
137
 
138
138
  %w'postgres sqlite mysql informix oracle firebird mssql db2'.each do |adapter|
139
- spec_with_cov.call("spec_#{adapter}", ["spec/adapters/#{adapter}_spec.rb"] + Dir["spec/integration/*_test.rb"], "Run #{adapter} specs")
139
+ spec_with_cov.call("spec_#{adapter}", ["spec/adapters/#{adapter}_spec.rb"] + Dir["spec/integration/*_test.rb"], "Run #{adapter} specs"){|t| t.rcov_opts.concat(%w'--exclude "lib/sequel/([a-z_]+\.rb|connection_pool|database|dataset|model|extensions|plugins)"')}
140
140
  end
141
141
 
142
142
  desc "Run model specs without the associations code"
data/bin/sequel CHANGED
@@ -162,10 +162,12 @@ begin
162
162
  start_time = Time.now
163
163
  TO_DB = connect_proc[db2]
164
164
  same_db = DB.database_type==TO_DB.database_type
165
+ index_opts = {:same_db=>same_db}
166
+ index_opts[:index_names] = :namespace if !DB.global_index_namespace? && TO_DB.global_index_namespace?
165
167
 
166
168
  puts "Databases connections successful"
167
169
  schema_migration = eval(DB.dump_schema_migration(:indexes=>false, :same_db=>same_db))
168
- index_migration = eval(DB.dump_indexes_migration(:same_db=>same_db))
170
+ index_migration = eval(DB.dump_indexes_migration(index_opts))
169
171
  fk_migration = eval(DB.dump_foreign_key_migration(:same_db=>same_db))
170
172
  puts "Migrations dumped successfully"
171
173
 
@@ -96,25 +96,168 @@ necessary for polymorphic associations). Inside the <tt>:eager_loader</tt>
96
96
  proc, you should get the related objects and populate the
97
97
  associations cache for all objects in the array of records. The hash
98
98
  of dependent associations is available for you to cascade the eager
99
- loading down multiple levels, but it is up to you to use it. The
100
- key_hash is a performance enhancement that is used by the default
99
+ loading down multiple levels, but it is up to you to use it.
100
+
101
+ The key_hash is a performance enhancement that is used by the default
101
102
  association loaders and is also available to you. It is a hash with keys being
102
103
  foreign/primary key symbols in the current table, and the values
103
104
  being hashes where the key is foreign/primary key values and values
104
105
  being arrays of current model objects having the foreign/primary key
105
106
  value associated with the key. This is hard to visualize, so I'll
106
- give an example:
107
-
108
- album1 = Album.load(:id=>1, :artist_id=>2)
109
- album2 = Album.load(:id=>3, :artist_id=>2)
107
+ give an example. Let's say you have the following associations
108
+
110
109
  Album.many_to_one :artist
111
110
  Album.one_to_many :tracks
112
- Album.eager(:band, :tracks).all
113
- # The key_hash provided to the :eager_loader proc would be:
114
- {:id=>{1=>[album1], 3=>[album2]}, :artist_id=>{2=>[album1, album2]}}
111
+
112
+ and the following two albums in the database:
113
+
114
+ album1 = Album.create(:artist_id=>3) # id: 1
115
+ album2 = Album.create(:artist_id=>3) # id: 2
116
+
117
+ If you try to eager load this dataset:
118
+
119
+ Album.eager(:artist, :tracks).all
120
+
121
+ Then the key_hash provided to the :eager_loader proc would be:
122
+
123
+ {:id=>{1=>[album1], 2=>[album2]}, :artist_id=>{3=>[album1, album2]}}
124
+
125
+ Let's break down the reason for the makeup of this key_hash. The hash has keys for
126
+ each of foreign/primary keys used in the association. In this case, the artist
127
+ association needs the artist_id foreign key (since it is a many_to_one), and the
128
+ tracks association needs the id primary key (since it is a one_to_many).
129
+
130
+ If you only eagerly loaded the artist association:
131
+
132
+ Album.eager(:artist).all
133
+
134
+ Then the key_hash would only contain artist_id information:
115
135
 
116
- Using these options, you can build associations that Sequel doesn't natively support,
117
- and still be able to use the same eager loading features that you are used to.
136
+ {:artist_id=>{3=>[album1, album2]}}
137
+
138
+ Likewise, if you only eagerly loaded the tracks association:
139
+
140
+ Album.eager(:tracks).all
141
+
142
+ Then the key_hash would only contain id information:
143
+
144
+ {:id=>{1=>[album1], 2=>[album2]}}
145
+
146
+ Now, the eager loader for the artist association is only going to care about the
147
+ value of the artist_id key in the hash, so it's going to do the equivalent of:
148
+
149
+ artist_id_map = key_hash[:artist_id] # {3=>[album1, album2]}
150
+
151
+ The artist_id_map contains a mapping of artist_id values to arrays of
152
+ album objects. Since it only has a single entry with a key of 3, when eagerly
153
+ loading the artists, you only need to look for artists that have an id of 3.
154
+
155
+ artists = Artist.where(:id=>artist_id_map.keys).all
156
+
157
+ When the artists are retrieved, you can iterate over them, find entries
158
+ with matching keys, and manually associate them to the albums:
159
+
160
+ artists.each do |artist|
161
+ # Find related albums using the artist_id_map
162
+ if albums = artist_id_map[artist.id]
163
+ # Iterate over the albums
164
+ albums.each do |album|
165
+ # Manually set the artist association for each album
166
+ album.associations[:artist] = artist
167
+ end
168
+ end
169
+ end
170
+
171
+ Similarly, the eager loader for the tracks association is only going to care about the
172
+ value of the id key in the hash:
173
+
174
+ id_map = key_hash[:id] # {1=>[album1], 2=>[album2]}
175
+
176
+ Now the id_map contains a mapping of id values to arrays of album objects (in this
177
+ case each array only has a single object, because id is the primary key). So when
178
+ looking for tracks to eagerly load, you only need to look for ones that have an
179
+ album_id of 1 or 2:
180
+
181
+ tracks = Track.where(:album_id=>id_map.keys).all
182
+
183
+ When the tracks are retrieved, you can iterate over them, find entries with matching
184
+ keys, and manually associate them to the albums:
185
+
186
+ tracks.each do |track|
187
+ if albums = id_map[track.album_id]
188
+ albums.each do |album|
189
+ album.associations[:tracks] << track
190
+ end
191
+ end
192
+ end
193
+
194
+ === Two basic example eager loaders
195
+
196
+ Putting the code in the above examples together, you almost have enough for a basic
197
+ working eager loader. The main important thing that is missing is you need to set
198
+ initial values for the eagerly loaded associations. For the artist association, you
199
+ need to initial the values to nil:
200
+
201
+ # rows here is the :rows entry in the hash passed to the eager loader
202
+ rows.each{|album| album.associations[:artist] = nil}
203
+
204
+ For the tracks association, you set the initial value to an empty array:
205
+
206
+ rows.each{|album| album.associations[:track] = []}
207
+
208
+ These are done so that if an album currently being loaded doesn't have an associated
209
+ artist or any associated tracks, the lack of them will be cached, so calling the
210
+ artist or tracks method on the album will not do another database lookup.
211
+
212
+ So putting everything together, the artist eager loader looks like:
213
+
214
+ :eager_loader=>(proc do |eo_opts|
215
+ eo_opts[:rows].each{|album| album.associations[:artist] = nil}
216
+ artist_id_map = eo_opts[:key_hash][:artist_id]
217
+ Artist.where(:id=>artist_id_map.keys).all do |artist|
218
+ if albums = artist_id_map[artist.id]
219
+ albums.each do |album|
220
+ album.associations[:artist] = artist
221
+ end
222
+ end
223
+ end
224
+ end)
225
+
226
+ and the tracks eager loader looks like:
227
+
228
+ :eager_loader=>(proc do |eo_opts|
229
+ eo_opts[:rows].each{|album| album.associations[:tracks] = []}
230
+ id_map = eo_opts[:key_hash][:id]
231
+ Track.where(:id=>id_map.keys).all do |tracks|
232
+ if albums = id_map[track.album_id]
233
+ albums.each do |album|
234
+ album.associations[:tracks] << track
235
+ end
236
+ end
237
+ end
238
+ end)
239
+
240
+ Now, these are both overly simplistic eager loaders that don't respect cascaded
241
+ associations or any of the association options. But hopefully they both
242
+ provide simple examples that you can more easily build and learn from, as
243
+ the custom eager loaders described later in this page are more complex.
244
+
245
+ Basically, the eager loading steps can be broken down into:
246
+
247
+ 1. Set default association values (nil/[]) for each of the current objects
248
+ 2. Build a custom key map mapping foreign/primary key values to arrays of
249
+ current objects (using the key_hash)
250
+ 3. Return just related associated objects by filtering the associated class
251
+ to include only matching values
252
+ 4. Iterating over the returned associated objects, indexing into the custom key
253
+ map using the foreign/primary key value in the associated object to get
254
+ current values associated to that specific object.
255
+ 5. For each of those current values, updating the cached association value to
256
+ include that specific object.
257
+
258
+ Using the :eager_loader proc, you should be able to eagerly load all associations
259
+ that can be eagerly loaded, even if Sequel doesn't natively support such eager
260
+ loading.
118
261
 
119
262
  == ActiveRecord associations
120
263
 
data/doc/migration.rdoc CHANGED
@@ -534,6 +534,24 @@ with an empty database, and attempt to recreate the schema using:
534
534
 
535
535
  sequel -m db/migrations postgres://host/database
536
536
 
537
+ == Checking for Current Migrations
538
+
539
+ In your application code, you may want to check that you are up to date in
540
+ regards to migrations (i.e. you don't have any unapplied migrations). Sequel
541
+ offers two separate methods to do that. The first is Sequel::Migrator.check_current.
542
+ This method raises an exception if there are outstanding migrations that need to
543
+ be run. The second is Sequel::Migrator.is_current?, which returns true if there
544
+ are no outstanding migrations, and false if there are outstanding migrations.
545
+
546
+ If you want to ensure that your application code is up to date, you may want to
547
+ add the following code after connecting to your database:
548
+
549
+ Sequel.extension :migration
550
+ Sequel::Migrator.check_current(DB, '/path/to/migrations')
551
+
552
+ This will cause your application to raise an error when you start it if you have
553
+ any outstanding migrations.
554
+
537
555
  == Old-style migration classes
538
556
 
539
557
  Before the <tt>Sequel.migration</tt> DSL was introduced, Sequel used classes
@@ -0,0 +1,541 @@
1
+ = The Sequel Object Model
2
+
3
+ Sequel's dataset layer is mostly structured as an DSL, so it often obscures
4
+ what actual objects are being used. For example, you don't usually create
5
+ Sequel objects by calling #new on the object's class (other than Sequel::Model
6
+ subclasses). However, just as almost everything in ruby is an object, all
7
+ the methods you call in Sequel deal with objects behind the scenes.
8
+
9
+ There are five main types of Sequel-specific objects that you deal with in
10
+ Sequel:
11
+
12
+ * Sequel::Database
13
+ * Sequel::Dataset
14
+ * Sequel::Model
15
+ * Standard Ruby Types
16
+ * Sequel::SQL::Expression (and subclasses)
17
+
18
+ == Sequel::Database
19
+
20
+ Sequel::Database is the main Sequel object that you deal with. It's usually
21
+ created by the Sequel.connect method:
22
+
23
+ DB = Sequel.connect('postgres://host/database')
24
+
25
+ A Sequel::Database object represents the database you are connecting to.
26
+ Sequel::Database handles things like Sequel::Dataset creation,
27
+
28
+ dataset = DB[:table]
29
+
30
+ schema modification,
31
+
32
+ DB.create_table(:table) do
33
+ primary_key :id
34
+ String :name
35
+ end
36
+
37
+ and transactions:
38
+
39
+ DB.transaction do
40
+ DB[:table].insert(:column=>value)
41
+ end
42
+
43
+ Sequel::Database#literal can be used to take any object that Sequel handles
44
+ and literalize the object to an SQL string fragment:
45
+
46
+ DB.literal(DB[:table]) # (SELECT * FROM "table")
47
+
48
+ == Sequel::Dataset
49
+
50
+ Sequel::Dataset objects represent SQL queries, or more generally, they represent
51
+ abstract collections of rows in the database. They are usually created from
52
+ a Sequel::Database object:
53
+
54
+ dataset = DB[:table] # SELECT * FROM "table"
55
+ dataset = DB.from(table) # SELECT * FROM "table"
56
+ dataset = DB.select(:column) # SELECT "column"
57
+
58
+ Most Sequel::Dataset methods return modified copies of the receiver, and the
59
+ general way to build queries in Sequel is via a method chain:
60
+
61
+ dataset = DB[:test].
62
+ select(:column1, :column2).
63
+ where(:column3 => 4).
64
+ order(:column5)
65
+
66
+ Such a method chain is a more direct way of doing:
67
+
68
+ dataset = DB[:test]
69
+ dataset = dataset.select(:column1, :column2)
70
+ dataset = dataset.where(:column3 => 4)
71
+ dataset = dataset.order(:column5)
72
+
73
+ When you are ready to execute your query, you call one of the Sequel::Dataset
74
+ action methods. For returning rows, you can do:
75
+
76
+ dataset.first
77
+ dataset.all
78
+ dataset.each{|row| row}
79
+
80
+ For inserting, updating, or deleting rows, you can do:
81
+
82
+ dataset.insert(:column=>value)
83
+ dataset.update(:column=>value)
84
+ dataset.delete
85
+
86
+ All datasets are related to their database object, which you can access via
87
+ the Sequel::Dataset#db method:
88
+
89
+ dataset.db # => DB
90
+
91
+ == Sequel::Model
92
+
93
+ Sequel::Model objects are wrappers around a particular Sequel::Dataset object that
94
+ add custom behavior, both custom behavior for the entire set of rows in the dataset
95
+ (the model's class methods), custom behavior for a subset of rows in the dataset
96
+ (the model's dataset methods), and custom behavior for single rows in the dataset
97
+ (the model's instance methods).
98
+
99
+ Unlike most other Sequel objects, Sequel::Model classes and instances are
100
+ generally created by the user using standard ruby syntax:
101
+
102
+ class Album < Sequel::Model
103
+ end
104
+ album = Album.new
105
+
106
+ All model classes are related to their Sequel::Dataset object, which you
107
+ can access via the Sequel::Model.dataset method:
108
+
109
+ Album.dataset # SELECT * FROM "albums"
110
+
111
+ Additionally, all model classes are related to their dataset's Sequel::Database
112
+ object, which you can access via the Sequel::Model.db method:
113
+
114
+ Album.db # => DB
115
+
116
+ == Standard Ruby Types
117
+
118
+ Where possible, Sequel uses ruby's standard types to represent SQL concepts.
119
+ In the examples here, the text to the right side of the # sign is the output
120
+ if you pass the left side to Sequel::Database#literal.
121
+
122
+ === Symbol
123
+
124
+ For example, ruby symbols represent SQL identifiers (tables, columns, schemas):
125
+
126
+ :table # "table"
127
+ :column # "column"
128
+
129
+ However, they can also represent qualified identifiers by including a double
130
+ underscore inside a symbol:
131
+
132
+ :table__column # "table"."column"
133
+
134
+ They can also represent an aliased identifier by including a triple underscore
135
+ inside a symbol:
136
+
137
+ :column___alias # "column" AS "alias"
138
+
139
+ You can combine both qualification and aliasing by using a double underscore
140
+ and a triple underscore:
141
+
142
+ :table__column___alias # "table"."column" AS "alias"
143
+
144
+ === Integer, Float, BigDecimal, String, Date, Time, DateTime
145
+
146
+ Ruby's Integer, Float, BigDecimal, String, Date, Time, and DateTime classes
147
+ represent similar types in SQL:
148
+
149
+ 1 # 1
150
+ 1.0 # 1.0
151
+ BigDecimal.new('1.0') # 1.0
152
+ "string" # 'string'
153
+ Date.new(2012, 5, 6) # '2012-05-06'
154
+ Time.now # '2012-05-06 10:20:30'
155
+ DateTime.now # '2012-05-06 10:20:30'
156
+
157
+ === Hash
158
+
159
+ Sequel generally uses hash objects to represent equality:
160
+
161
+ {:column => 1} # ("column" = 1)
162
+
163
+ However, if you use in array as the hash value, it will usually be used to represent inclusion:
164
+
165
+ {:column => [1, 2, 3]} # ("column" IN (1, 2, 3))
166
+
167
+ You can also use a Sequel::Dataset instance as the hash value, which will be used to
168
+ represent inclusion in the subselect:
169
+
170
+ {:column => DB[:table].select(:column)} # ("column" IN (SELECT "column" FROM "table"))
171
+
172
+ If you pass true, false, or nil as the hash value, it will be used to represent identity:
173
+
174
+ {:column => nil} # ("column" IS NULL)
175
+
176
+ If you pass a Range object, it will be used as the bounds for a greater than and less than
177
+ operation:
178
+
179
+ {:column => 1..2} # (("column" >= 1) AND ("column" <= 2))
180
+ {:column => 1...3} # (("column" >= 1) AND ("column" < 3))
181
+
182
+ If you pass a Regexp object as the value, it will be used as a regular expression
183
+ operation (only supported on PostgreSQL and MySQL currently):
184
+
185
+ {:column => /a.*b/} # ("column" ~ 'a.*b')
186
+
187
+ === Array
188
+
189
+ Sequel generally treats arrays as an SQL value list:
190
+
191
+ [1, 2, 3] # (1, 2, 3)
192
+
193
+ However, if all members of the array are arrays with two members, then the array is treated like
194
+ a hash:
195
+
196
+ [[:column, 1]] # ("column" = 1)
197
+
198
+ The advantage of using an array over a hash for such a case is that a hash cannot include
199
+ multiple objects with the same key, while the array can.
200
+
201
+ == Sequel::SQL::Expression (and subclasses)
202
+
203
+ If Sequel needs to represent an SQL concept that does not map directly to an existing
204
+ ruby class, it will generally use a Sequel::SQL::Expression subclass to represent that
205
+ concept.
206
+
207
+ === Sequel::LiteralString
208
+
209
+ Sequel::LiteralString is not actually a Sequel::SQL::Expression subclass. It is
210
+ a subclass of String, but it is treated specially by Sequel, in that it is treated
211
+ as literal SQL code, instead of as an SQL string that needs to be escaped:
212
+
213
+ Sequel::LiteralString.new("co'de") # co'de
214
+
215
+ The following shortcuts exist for creating Sequel::LiteralString objects:
216
+
217
+ Sequel.lit("co'de")
218
+ "co'de".lit
219
+
220
+ === Sequel::SQL::Blob
221
+
222
+ Sequel::SQL::Blob is also a String subclass, but it is treated as an SQL blob
223
+ instead of an SQL string, as SQL blobs often have different literalization rules
224
+ than SQL strings do:
225
+
226
+ Sequel::SQL::Blob.new("blob")
227
+
228
+ The following shortcuts exist for creating Sequel::SQL::Blob objects:
229
+
230
+ Sequel.blob("blob")
231
+ "blob".to_sequel_blob
232
+
233
+ === Sequel::SQLTime
234
+
235
+ Sequel::SQLTime is a Time subclass. However, it is treated specially by Sequel
236
+ in that only the time component is literalized, not the date part. This type
237
+ is used to represent SQL time types, which do not contain date information.
238
+
239
+ Sequel::SQLTime.create(10, 20, 30) # "10:20:30"
240
+
241
+ === Sequel::SQL::ValueList
242
+
243
+ Sequel::SQL::ValueList objects always represent SQL value lists. Most ruby arrays
244
+ represent value lists in SQL, except that arrays of two-element arrays are treated
245
+ similar to hashes. Such arrays can be wrapped in this class to ensure they are
246
+ treated as value lists. This is important when doing a composite key IN lookup,
247
+ which some databases support. Sequel::SQL::ValueList is an ::Array subclass with
248
+ no additional behavior, so it can be instantiated like a normal array:
249
+
250
+ Sequel::SQL::ValueList.new([[1, 2], [3, 4]]) # ((1, 2), (3, 4))
251
+
252
+ In old versions of Sequel, these objects often needed to be created manually,
253
+ but in newer versions of Sequel, they are created automatically in most cases
254
+ where they are required.
255
+
256
+ The following shortcuts exist for creating Sequel::SQL::ValueList objects:
257
+
258
+ Sequel.value_list([[1, 2], [3, 4]])
259
+ [[1, 2], [3, 4]].sql_value_list
260
+
261
+ === Sequel::SQL::Identifier
262
+
263
+ Sequel::SQL::Identifier objects represent single identifiers. The main reason for
264
+ their existance is that they are not checked for double or triple underscores, so no
265
+ automatic qualification or aliasing happens for them:
266
+
267
+ Sequel::SQL::Identifier.new(:col__umn) # "col__umn"
268
+
269
+ The following shortcuts exist for creating Sequel::SQL::Identifier objects:
270
+
271
+ Sequel.identifier(:col__umn)
272
+ :col__umn.identifier
273
+
274
+ === Sequel::SQL::QualifiedIdentifier
275
+
276
+ Sequel::SQL::QualifiedIdentifier objects represent qualified identifiers:
277
+
278
+ Sequel::SQL::QualifiedIdentifier.new(:table, :column) # "table"."column"
279
+
280
+ The following shortcuts exist for creating Sequel::SQL::QualifiedIdentifier objects:
281
+
282
+ Sequel.qualify(:table, :column)
283
+ :column.qualify(:table)
284
+
285
+ === Sequel::SQL::AliasedExpression
286
+
287
+ Sequel::SQL::AliasedExpression objects represent aliased expressions in SQL. The alias
288
+ is treated as an identifier, but the expression can be an arbitrary Sequel expression:
289
+
290
+ Sequel::SQL::AliasedExpression.new(:column, :alias) # "column" AS "alias"
291
+
292
+ The following shortcuts exist for creating Sequel::SQL::AliasedExpression objects:
293
+
294
+ Sequel.as(:column, :alias)
295
+ :column.as(:alias)
296
+
297
+ === Sequel::SQL::ComplexExpression
298
+
299
+ Sequel::SQL::ComplexExpression objects mostly represent SQL operations with arguments.
300
+ There are separate subclasses for representing boolean operations such as AND and OR
301
+ (Sequel::SQL::BooleanExpression), mathematical operations such as + and -
302
+ (Sequel::SQL::NumericExpression), and string operations such as || and LIKE
303
+ (Sequel::SQL::StringExpression).
304
+
305
+ Sequel::SQL::BooleanExpression.new(:OR, :col1, :col2) # ("col1" OR "col2")
306
+ Sequel::SQL::NumericExpression.new(:+, :column, 2) # ("column" + 2)
307
+ Sequel::SQL::StringExpression.new(:"||", :column, "b") # ("column" || 'b')
308
+
309
+ There are many shortcuts for creating Sequel::SQL::ComplexExpression objects:
310
+
311
+ Sequel.or(:col1, :col2)
312
+ :col1 | :col2
313
+
314
+ Sequel.+(:column, 2)
315
+ :column + 2
316
+
317
+ Sequel.join([:column, 'b'])
318
+ :column + 'b'
319
+
320
+ === Sequel::SQL::CaseExpression
321
+
322
+ Sequel::SQL::CaseExpression objects represent SQL CASE expressions, which represent
323
+ branches in the database, similar to ruby case expressions. Like ruby's case
324
+ expressions, these case expressions can have a implicit value you are comparing
325
+ against:
326
+
327
+ Sequel::SQL::CaseExpression.new({2=>1}, 0, :a) # CASE "a" WHEN 2 THEN 1 ELSE 0 END
328
+
329
+ Or they can treat each condition separately:
330
+
331
+ Sequel::SQL::CaseExpression.new({{:a=>2}=>1}, 0) # CASE WHEN ("a" = 2) THEN 1 ELSE 0 END
332
+
333
+ In addition to providing a hash, you can also provide an array of two-element arrays:
334
+
335
+ Sequel::SQL::CaseExpression.new([[2, 1]], 0, :a) # CASE "a" WHEN 2 THEN 1 ELSE 0 END
336
+
337
+ The following shortcuts exist for creating Sequel::SQL::CaseExpression objects:
338
+
339
+ Sequel.case({2=>1}, 0, :a)
340
+ Sequel.case({{:a=>2}=>1}, 0)
341
+
342
+ {2=>1}.case(0, :a)
343
+ {{:a=>2}=>1}.case(0)
344
+
345
+ === Sequel::SQL::Cast
346
+
347
+ Sequel::SQL::Cast objects represent CAST expressions in SQL, which does explicit
348
+ typecasting in the database. With Sequel, you provide the expression to typecast
349
+ as well as the type to cast to. The type can either be a generic type, given as
350
+ a ruby class:
351
+
352
+ Sequel::SQL::Cast.new(:a, String) # (CAST "a" AS text)
353
+
354
+ or a specific type, given as a symbol or string:
355
+
356
+ Sequel::SQL::Cast.new(:a, :int4) # (CAST "a" AS int4)
357
+
358
+ The following shortcuts exist for creating Sequel::SQL::Cast objects:
359
+
360
+ Sequel.cast(:a, String)
361
+ Sequel.cast(:a, :int4)
362
+
363
+ :a.cast(String)
364
+ :a.cast(:int4)
365
+
366
+ === Sequel::SQL::ColumnAll
367
+
368
+ Sequel::SQL::ColumnAll objects represent the selection of all columns from a
369
+ table. They are pretty much only used as arguments to one of the Dataset select
370
+ methods, and are not used much anymore since Dataset#select_all was expanded to
371
+ take arguments. Still, it's possible they are still useful in some code:
372
+
373
+ Sequel::SQL::ColumnAll.new(:table) # "table".*
374
+
375
+ The following shortcut exists for creating Sequel::SQL::Cast objects:
376
+
377
+ :table.*
378
+
379
+ === Sequel::SQL::Constant
380
+
381
+ Sequel::SQL::Constant objects represent constants or psuedo-constants in SQL,
382
+ such as TRUE, NULL, and CURRENT_TIMESTAMP. These are not designed to be created
383
+ or used by the end user, but some existing values are predefined under the
384
+ Sequel namespace:
385
+
386
+ Sequel::CURRENT_TIMESTAMP # CURRENT_TIMESTAMP
387
+
388
+ These objects are usually used as values in queries:
389
+
390
+ DB[:table].insert(:time=>Sequel::CURRENT_TIMESTAMP)
391
+
392
+ === Sequel::SQL::Function
393
+
394
+ Sequel::SQL::Function objects represents database function calls, which take a function
395
+ name and any arguments:
396
+
397
+ Sequel::SQL::Function.new(:func, :a, 2) # func("a", 2)
398
+
399
+ The following shortcuts exist for creating Sequel::SQL::Function objects:
400
+
401
+ Sequel.function(:func, :a, 2)
402
+ :func.sql_function(:a, 2)
403
+
404
+ === Sequel::SQL::JoinClause
405
+
406
+ Sequel::SQL::JoinClause objects represent SQL JOIN clauses. They are usually
407
+ not created manually, as the Dataset join methods create them automatically.
408
+
409
+ === Sequel::SQL::PlaceholderLiteralString
410
+
411
+ Sequel::SQL::PlaceholderLiteralString objects represent a literal SQL string
412
+ with placeholders for variables. There are three types of these objects.
413
+ The first type uses question marks with multiple placeholder value objects:
414
+
415
+ Sequel::SQL::PlaceholderLiteralString.new('? = ?', [:a, 1]) # "a" = 1
416
+
417
+ The second uses named placeholders with colons and a hash of placeholder
418
+ value objects:
419
+
420
+ Sequel::SQL::PlaceholderLiteralString.new(':b = :v', [{:b=>:a, :v=>1}]) # "a" = 1
421
+
422
+ The third uses an array instead of a string, with multiple placeholder
423
+ objects, each one going in between the members of the array:
424
+
425
+ Sequel::SQL::PlaceholderLiteralString.new(['', ' = '], [:a, 1]) # "a" = 1
426
+
427
+ For any of these three forms, you can also include a third argument for whether
428
+ to include parentheses around the string:
429
+
430
+ Sequel::SQL::PlaceholderLiteralString.new('? = ?', [:a, 1], true) # ("a" = 1)
431
+
432
+ The following shortcuts exist for creating Sequel::SQL::PlaceholderLiteralString
433
+ objects:
434
+
435
+ Sequel.lit('? = ?', :a, 1)
436
+ Sequel.lit(':b = :v', :b=>:a, :v=>1)
437
+ Sequel.lit(['', ' = '], :a, 1)
438
+
439
+ '? = ?'.lit(:a, 1)
440
+ ':b = :v'.lit(:b=>:a, :v=>1)
441
+
442
+ === Sequel::SQL::OrderedExpression
443
+
444
+ Sequel::SQL::OrderedExpression objects represent ascending or descending sorts,
445
+ used by the Dataset order methods. They take an expression, and whether to sort
446
+ it ascending or descending:
447
+
448
+ Sequel::SQL::OrderedExpression.new(:a) # "a" DESC
449
+ Sequel::SQL::OrderedExpression.new(:a, false) # "a" ASC
450
+
451
+ Additionally, they take an options hash, which can be used to specify how nulls
452
+ can be sorted:
453
+
454
+ Sequel::SQL::OrderedExpression.new(:a, true, :nulls=>:first) # "a" DESC NULLS FIRST
455
+ Sequel::SQL::OrderedExpression.new(:a, false, :nulls=>:last) # "a" ASC NULLS LAST
456
+
457
+ The following shortcuts exist for creating Sequel::SQL::OrderedExpression objects:
458
+
459
+ Sequel.asc(:a)
460
+ Sequel.desc(:a)
461
+ Sequel.asc(:a, :nulls=>:first)
462
+ Sequel.desc(:a, :nulls=>:last)
463
+
464
+ :a.asc
465
+ :a.desc
466
+ :a.asc(:nulls=>:first)
467
+ :a.desc(:nulls=>:last)
468
+
469
+ === Sequel::SQL::Subscript
470
+
471
+ Sequel::SQL::Subscript objects represent SQL database array access. They take an
472
+ expression and an array of indexes:
473
+
474
+ Sequel::SQL::Subscript.new(:a, [1]) # "a"[1]
475
+ Sequel::SQL::Subscript.new(:a, [1, 2]) # "a"[1, 2]
476
+
477
+ The following shortcuts exist for creating Sequel::SQL::Subscript objects:
478
+
479
+ Sequel.subscript(:a, 1)
480
+ Sequel.subscript(:a, 1, 2)
481
+
482
+ :a.sql_subscript(1)
483
+ :a.sql_subscript(1, 2)
484
+
485
+ === Sequel::SQL::VirtualRow
486
+
487
+ Sequel::SQL::VirtualRow is a BasicObject subclass that is the backbone behind the
488
+ block expression support:
489
+
490
+ DB[:table].filter{a < 1}
491
+
492
+ In the above code, the block is instance-evaled instead a VirtualRow instance.
493
+
494
+ These objects are usually not instantiated manually. See the
495
+ {Virtual Row Guide}[link:files/doc/virtual_rows_rdoc.html] for details.
496
+
497
+ === Sequel::SQL::Window
498
+
499
+ Sequel::SQL::Window objects represent the windows used by Sequel::SQL::WindowFunction.
500
+ They use a hash-based API, supporting the :frame, :order, :partition, and :window
501
+ options:
502
+
503
+ Sequel::SQL::Window.new(:order=>:a) # (ORDER BY "a")
504
+ Sequel::SQL::Window.new(:parition=>:a) # (PARTITION BY "a")
505
+
506
+ Sequel::SQL::Window.new(:parition=>:a, :frame=>:all)
507
+ # (PARTITION BY "a" ROWS BETWEEN UNBOUNDED PRECEDING AND UNBOUNDED FOLLOWING)
508
+
509
+ === Sequel::SQL::WindowFunction
510
+
511
+ Sequel::SQL::WindowFunction objects represent SQL window function calls. These
512
+ just combine a Sequel::SQL::Function with a Sequel::SQL::Window:
513
+
514
+ function = Sequel::SQL::Function.new(:f, 1)
515
+ window = Sequel::SQL::Window.new(:order=>:a)
516
+ Sequel::SQL::WindowFunction.new(function, window) # f(1) OVER (ORDER BY "a")
517
+
518
+ Virtual rows offer a shortcut for creating Sequel::SQL::Window objects.
519
+
520
+ === Sequel::SQL::Wrapper
521
+
522
+ Sequel::SQL::Wrapper objects wrap arbitrary objects so that they can be used
523
+ in Sequel expressions:
524
+
525
+ o = Object.new
526
+ def o.sql_literal(ds) "foo" end
527
+ Sequel::SQL::Wrapper.new(o) # foo
528
+
529
+ The advantage of wrapping the object is that you can the call Sequel methods
530
+ on the wrapper that would not be defined on the object itself:
531
+
532
+ Sequel::SQL::Wrapper.new(o) + 1 # (foo + 1)
533
+
534
+ You can use the Sequel.expr method to wrap any object:
535
+
536
+ Sequel.expr(o)
537
+
538
+ However, note that that does not necessarily return a Sequel::SQL::Wrapper
539
+ object, it may return a different class of object, such as a
540
+ Sequel::SQL::ComplexExpression subclass object.
541
+