Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Documentation cleanup

Most of this is using the block argument provided by filter instead
of sql_string or sql_number.

This also moves the column references via symbols documentation from
the dataset filtering rdoc to the README.

Add info on the new database independent migrations to the schema
rdoc.
  • Loading branch information...
commit ce1c70fa0db143d2eaf37487e2b3745a38645bde 1 parent 392963a
Jeremy Evans authored January 30, 2009
128  README.rdoc
Source Rendered
@@ -76,7 +76,7 @@ You get an IRB session with the database object stored in DB.
76 76
 
77 77
 Sequel is designed to take the hassle away from connecting to databases and manipulating them. Sequel deals with all the boring stuff like maintaining connections, formatting SQL correctly and fetching records so you can concentrate on your application.
78 78
 
79  
-Sequel uses the concept of datasets to retrieve data. A Dataset object encapsulates an SQL query and supports chainability, letting you fetch data using a convenient Ruby DSL that is both concise and infinitely flexible.
  79
+Sequel uses the concept of datasets to retrieve data. A Dataset object encapsulates an SQL query and supports chainability, letting you fetch data using a convenient Ruby DSL that is both concise and flexible.
80 80
 
81 81
 For example, the following one-liner returns the average GDP for the five biggest countries in the middle east region:
82 82
 
@@ -89,7 +89,7 @@ Which is equivalent to:
89 89
 Since datasets retrieve records only when needed, they can be stored and later reused. Records are fetched as hashes (they can also be fetched as custom model objects), and are accessed using an Enumerable interface:
90 90
 
91 91
   middle_east = DB[:countries].filter(:region => 'Middle East')
92  
-  middle_east.order(:name).each {|r| puts r[:name]}
  92
+  middle_east.order(:name).each{|r| puts r[:name]}
93 93
   
94 94
 Sequel also offers convenience methods for extracting data from Datasets, such as an extended map method:
95 95
 
@@ -123,8 +123,8 @@ You can specify a block to connect, which will disconnect from the database afte
123 123
 
124 124
 === Arbitrary SQL queries
125 125
 
126  
-  DB.execute("create table t (a text, b text)")
127  
-  DB.execute("insert into t values ('a', 'b')")
  126
+  DB.execute_ddl("create table t (a text, b text)")
  127
+  DB.execute_insert("insert into t values ('a', 'b')")
128 128
 
129 129
 Or more succinctly:
130 130
 
@@ -143,6 +143,12 @@ You can also fetch records with raw SQL through the dataset:
143 143
     p row
144 144
   end
145 145
 
  146
+You can use placeholders in your SQL string as well:
  147
+
  148
+  DB['select * from items where name = ?', name].each do |row|
  149
+    p row
  150
+  end
  151
+
146 152
 === Getting Dataset Instances
147 153
 
148 154
 Dataset is the primary means through which records are retrieved and manipulated. You can create an blank dataset by using the dataset method:
@@ -198,13 +204,13 @@ You can also specify ranges:
198 204
 
199 205
   my_posts = posts.filter(:stamp => (Date.today - 14)..(Date.today - 7))
200 206
   
201  
-Or lists of values:
  207
+Or arrays of values:
202 208
 
203 209
   my_posts = posts.filter(:category => ['ruby', 'postgres', 'linux'])
204 210
   
205 211
 Sequel also accepts expressions:
206 212
   
207  
-  my_posts = posts.filter(:stamp.sql_number > Date.today << 1)
  213
+  my_posts = posts.filter{|o| o.stamp > Date.today << 1}
208 214
   
209 215
 Some adapters (like postgresql) will also let you specify Regexps:
210 216
 
@@ -222,7 +228,7 @@ You can also specify a custom WHERE clause using a string:
222 228
 You can use parameters in your string, as well (ActiveRecord style):
223 229
 
224 230
   posts.filter('(stamp < ?) AND (author != ?)', Date.today - 3, author_name)
225  
-  posts.filter((:stamp + 3 < Date.today) & ~(:author => author_name)) # same as above
  231
+  posts.filter{|o| (o.stamp < Date.today + 3) & ~{:author => author_name}} # same as above
226 232
 
227 233
 Datasets can also be used as subqueries:
228 234
 
@@ -251,11 +257,34 @@ Ordering datasets is simple:
251 257
 
252 258
   posts.order(:stamp) # ORDER BY stamp
253 259
   posts.order(:stamp, :name) # ORDER BY stamp, name
  260
+
  261
+Chaining order doesn't work the same as filter:
  262
+
  263
+  posts.order(:stamp).order(:name) # ORDER BY name
  264
+
  265
+The order_more method chains this way, though:
  266
+
  267
+  posts.order(:stamp).order_more(:name) # ORDER BY stamp, name
254 268
   
255 269
 You can also specify descending order
256 270
 
257 271
   posts.order(:stamp.desc) # ORDER BY stamp DESC
258 272
 
  273
+=== Selecting Columns
  274
+
  275
+Selecting specific columns to be returned is also simple:
  276
+
  277
+  posts.select(:stamp) # SELECT stamp FROM posts
  278
+  posts.select(:stamp, :name) # SELECT stamp, name FROM posts
  279
+
  280
+Chaining select works like order, not filter:
  281
+
  282
+  posts.select(:stamp).select(:name) # SELECT name FROM posts
  283
+
  284
+As you might expect, there is an order_more equivalent for select:
  285
+
  286
+  posts.select(:stamp).select_more(:name) # SELECT stamp, name FROM posts
  287
+  
259 288
 === Deleting Records
260 289
 
261 290
 Deleting records from the table is done with delete:
@@ -300,7 +329,7 @@ Which is equivalent to the SQL:
300 329
   
301 330
 === Graphing Datasets
302 331
 
303  
-When retrieving records from joined datasets, you get the results in a single hash, which is subject to clobbering:
  332
+When retrieving records from joined datasets, you get the results in a single hash, which is subject to clobbering if you have columns with the same name in multiple tables:
304 333
 
305 334
   DB[:items].join(:order_items, :item_id => :id).first
306 335
   => {:id=>(could be items.id or order_items.id), :item_id=>order_items.order_id}
@@ -310,6 +339,30 @@ Using graph, you can split the result hashes into subhashes, one per join:
310 339
   DB[:items].graph(:order_items, :item_id => :id).first
311 340
   => {:items=>{:id=>items.id}, :order_items=>{:id=>order_items.id, :item_id=>order_items.item_id}}
312 341
 
  342
+== An aside: column references in Sequel
  343
+
  344
+Sequel expects column names to be specified using symbols. In addition, returned hashes always use symbols as their keys. This allows you to freely mix literal values and column references. For example, the two following lines produce equivalent SQL:
  345
+
  346
+  items.filter(:x => 1) #=> "SELECT * FROM items WHERE (x = 1)" 
  347
+  items.filter(1 => :x) #=> "SELECT * FROM items WHERE (1 = x)" 
  348
+
  349
+=== Qualifying column names
  350
+
  351
+Column references can be qualified by using the double underscore special notation :table__column:
  352
+
  353
+  items.literal(:items__price) #=> "items.price"
  354
+
  355
+=== Column aliases
  356
+
  357
+You can also alias columns by using the triple undersecore special notation :column___alias or :table__column___alias:
  358
+
  359
+  items.literal(:price___p) #=> "price AS p"
  360
+  items.literal(:items__price___p) #=> "items.price AS p"
  361
+
  362
+Another way to alias columns is to use the #AS method:
  363
+
  364
+  items.literal(:price.as(:p)) #=> "price AS p"
  365
+
313 366
 == Sequel Models
314 367
 
315 368
 Models in Sequel are based on the Active Record pattern described by Martin Fowler (http://www.martinfowler.com/eaaCatalog/activeRecord.html). A model class corresponds to a table or a dataset, and an instance of that class wraps a single record in the model's underlying dataset.
@@ -357,17 +410,17 @@ You can also define a model class that does not have a primary key, but then you
357 410
 A model instance can also be fetched by specifying a condition:
358 411
 
359 412
   post = Post[:title => 'hello world']
360  
-  post = Post.find(:num_comments.sql_number < 10)
  413
+  post = Post.find{|o| o.num_comments < 10}
361 414
 
362 415
 === Iterating over records
363 416
 
364  
-A model class lets you iterate over specific records by acting as a proxy to the underlying dataset. This means that you can use the entire Dataset API to create customized queries that return model instances, e.g.:
  417
+A model class lets you iterate over subsets of records by proxying many methods to the underlying dataset. This means that you can use most of the Dataset API to create customized queries that return model instances, e.g.:
365 418
 
366 419
   Post.filter(:category => 'ruby').each{|post| p post}
367 420
 
368 421
 You can also manipulate the records in the dataset:
369 422
 
370  
-  Post.filter(:num_comments.sql_number < 7).delete
  423
+  Post.filter{|o| o.num_comments < 7}.delete
371 424
   Post.filter(:title.like(/ruby/)).update(:category => 'ruby')
372 425
 
373 426
 === Accessing record values
@@ -386,9 +439,9 @@ You can also change record values:
386 439
   post.title = 'hey there'
387 440
   post.save
388 441
 
389  
-Another way to change values by using the #update_with_params method:
  442
+Another way to change values by using the #update method:
390 443
 
391  
-  post.update_with_params(:title => 'hey there')
  444
+  post.update(:title => 'hey there')
392 445
 
393 446
 === Creating new records
394 447
 
@@ -404,7 +457,7 @@ Another way is to construct a new instance and save it:
404 457
 
405 458
 You can also supply a block to Model.new and Model.create:
406 459
 
407  
-  post = Post.create {|p| p.title = 'hello world'}
  460
+  post = Post.create{|p| p.title = 'hello world'}
408 461
 
409 462
   post = Post.new do |p|
410 463
     p.title = 'hello world'
@@ -453,14 +506,6 @@ Associations are used in order to specify relationships between model classes th
453 506
     many_to_many :tags
454 507
   end
455 508
 
456  
-You can also use the ActiveRecord names for these associations:
457  
-
458  
-  class Post < Sequel::Model
459  
-    belongs_to :author
460  
-    has_many :comments
461  
-    has_and_belongs_to_many :tags
462  
-  end
463  
-
464 509
 many_to_one creates a getter and setter for each model object:
465 510
 
466 511
   class Post < Sequel::Model
@@ -518,7 +563,7 @@ Associations can be eagerly loaded via .eager and the :eager association option.
518 563
   Post.eager(:person).all
519 564
 
520 565
   # eager is a dataset method, so it works with filters/orders/limits/etc.
521  
-  Post.filter(:topic.sql_string > 'M').order(:date).limit(5).eager(:person).all
  566
+  Post.filter{|o| o.topic > 'M'}.order(:date).limit(5).eager(:person).all
522 567
   
523 568
   person = Person.first
524 569
   # Eager loading via :eager (will eagerly load the tags for this person's posts)
@@ -562,7 +607,7 @@ The obvious way to add table-wide logic is to define class methods to the model
562 607
 
563 608
   class Post < Sequel::Model
564 609
     def self.posts_with_few_comments
565  
-      filter(:num_comments.sql_number < 30)
  610
+      filter{|o| o.num_comments < 30}
566 611
     end
567 612
 
568 613
     def self.clean_posts_with_few_comments
@@ -574,7 +619,7 @@ You can also implement table-wide logic by defining methods on the dataset:
574 619
 
575 620
   class Post < Sequel::Model
576 621
     def_dataset_method(:posts_with_few_comments) do
577  
-      filter(:num_comments.sql_number < 30)
  622
+      filter{|o| o.num_comments < 30}
578 623
     end
579 624
 
580 625
     def_dataset_method(:clean_posts_with_few_comments) do
@@ -584,48 +629,29 @@ You can also implement table-wide logic by defining methods on the dataset:
584 629
 
585 630
 This is the recommended way of implementing table-wide operations, and allows you to have access to your model API from filtered datasets as well:
586 631
 
587  
-  Post.filter(:category => 'ruby').clean_old_posts
  632
+  Post.filter(:category => 'ruby').clean_posts_with_few_comments
588 633
 
589 634
 Sequel models also provide a short hand notation for filters:
590 635
 
591 636
   class Post < Sequel::Model
592  
-    subset(:posts_with_few_comments, :num_comments.sql_number < 30)
593  
-    subset :invisible, :visible => false
594  
-  end
595  
-
596  
-=== Defining the underlying schema
597  
-
598  
-Model classes can also be used as a place to define your table schema and control it. The schema DSL is exactly the same provided by Sequel::Schema::Generator:
599  
-
600  
-  class Post < Sequel::Model
601  
-    set_schema do
602  
-      primary_key :id
603  
-      text :title
604  
-      text :category
605  
-      foreign_key :author_id, :table => :authors
606  
-    end
  637
+    subset(:posts_with_few_comments){|o| o.num_comments < 30}
  638
+    subset :invisible, ~:visible
607 639
   end
608 640
 
609  
-You can then create the underlying table, drop it, or recreate it:
610  
-
611  
-  Post.table_exists?
612  
-  Post.create_table
613  
-  Post.drop_table
614  
-  Post.create_table! # drops the table if it exists and then recreates it
615  
-
616 641
 === Basic Model Validations
617 642
 
618 643
 To assign default validations to a sequel model:
619 644
 
620 645
   class MyModel < Sequel::Model
621 646
     validates do
622  
-      format_of...
623  
-      presence_of...
624 647
       acceptance_of...
625 648
       confirmation_of...
  649
+      format_of...
  650
+      format_of...
  651
+      presence_of...
626 652
       length_of...
  653
+      not_string ...
627 654
       numericality_of...
628  
-      format_of...
629 655
       each...
630 656
     end
631 657
   end
22  doc/advanced_associations.rdoc
Source Rendered
@@ -16,7 +16,7 @@ a different block when eager loading via Dataset#eager. Association blocks are
16 16
 useful for things like:
17 17
 
18 18
   Artist.one_to_many :gold_albums, :class=>:Album do |ds|
19  
-    ds.filter(:copies_sold.sql_number > 500000)
  19
+    ds.filter{|o| o.copies_sold > 500000}
20 20
   end
21 21
 
22 22
 There are a whole bunch of options for changing how the association is eagerly
@@ -124,7 +124,7 @@ a swiss army chainsaw.
124 124
 Sequel supports the same callbacks that ActiveRecord does: :before_add,
125 125
 :before_remove, :after_add, and :after_remove. It also supports a
126 126
 callback that ActiveRecord does not, :after_load, which is called
127  
-after the association has been loaded (when lazy loading).
  127
+after the association has been loaded.
128 128
 
129 129
 Each of these options can be a Symbol specifying an instance method
130 130
 that takes one argument (the associated object), or a Proc that takes
@@ -150,7 +150,7 @@ otherwise modified:
150 150
   class Author < Sequel::Model
151 151
     one_to_many :authorships
152 152
   end
153  
-  Author.first.authorships_dataset.filter(:number.sql_number < 10).first
  153
+  Author.first.authorships_dataset.filter{|o| o.number < 10}.first
154 154
  
155 155
 You can extend a dataset with a module easily with :extend:
156 156
 
@@ -180,18 +180,6 @@ model object, you'll have to use a closure:
180 180
   end
181 181
   Author.first.authorships_dataset.find_or_create_by_name('Bob')
182 182
 
183  
-You can cheat if you want to:
184  
-
185  
-  module FindOrCreate
186  
-    def find_or_create(vals)
187  
-      # Exploits the fact that Sequel filters are ruby objects that
188  
-      # can be introspected.
189  
-      author_id = @opts[:where].args[1]
190  
-      first(vals) || \
191  
-        @opts[:models][nil].create(vals.merge(:author_id=>author_id))
192  
-    end 
193  
-  end
194  
-
195 183
 ===has_many :through associations
196 184
 
197 185
 many_to_many handles the usual case of a has_many :through with a belongs_to in
@@ -310,7 +298,7 @@ Sequel::Model:
310 298
   Firm.find(:first).invoices
311 299
 
312 300
 It is significantly more code in Sequel Model, but quite a bit of it is setting
313  
-the intermediate associate record (the client) and the reciprocal association
  301
+the intermediate associated record (the client) and the reciprocal association
314 302
 in the associations cache for each object, which ActiveRecord won't do for you.
315 303
 The reason you would want to do this is that then firm.invoices.first.firm or
316 304
 firm.invoices.first.client doesn't do another query to get the firm/client.
@@ -551,7 +539,7 @@ node.children.  You can even eager load the relationship up to a certain depth:
551 539
   # Eager load three generations of generations of children for a given node 
552 540
   Node.filter(:id=>1).eager(:children=>{:children=>:children}).all.first
553 541
   # Load parents and grandparents for a group of nodes
554  
-  Node.filter(:id.sql_number < 10).eager(:parent=>:parent).all
  542
+  Node.filter{|o| o.id < 10}.eager(:parent=>:parent).all
555 543
 
556 544
 What if you want to get all ancestors up to the root node, or all descendents,
557 545
 without knowing the depth of the tree?
30  doc/cheat_sheet.rdoc
Source Rendered
@@ -29,7 +29,7 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
29 29
   DB.fetch("SELECT name FROM users") do |row|
30 30
     p r[:name]
31 31
   end
32  
-  dataset = DB["SELECT age FROM users"]
  32
+  dataset = DB["SELECT age FROM users WHERE name = ?", name]
33 33
   dataset.print
34 34
   dataset.map(:age)
35 35
 
@@ -70,17 +70,17 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
70 70
   dataset.map {|r| r[:name]}
71 71
   dataset.map(:name) # same effect as above
72 72
 
73  
-  dataset.inject {|sum, r| sum + r[:value]}
  73
+  dataset.inject(0){|sum, r| sum + r[:value]}
74 74
 
75 75
 == Filtering (see also doc/dataset_filtering.rdoc)
76 76
 
77 77
   dataset.filter(:name => 'abc')
78 78
   dataset.filter('name = ?', 'abc')
79  
-  dataset.filter(:value.sql_number > 100)
80  
-  dataset.exclude(:value.sql_number <= 100)
  79
+  dataset.filter{|o| o.value > 100}
  80
+  dataset.exclude{|o| o.value <= 100}
81 81
 
82 82
   dataset.filter(:value => 50..100)
83  
-  dataset.where((:value.sql_number >= 50) & (:value.sql_number <= 100))
  83
+  dataset.where{|o| (o.value >= 50) & (o.value <= 100)}
84 84
 
85 85
   dataset.where('value IN ?', [50,75,100])
86 86
 
@@ -91,11 +91,9 @@ Without a filename argument, the sqlite adapter will setup a new sqlite database
91 91
   # Filter using a subquery
92 92
   dataset.filter('price > ?', dataset.select('AVG(price) + 100'))
93 93
 
94  
-=== Advanced filtering using ruby expressions without blocks
  94
+=== Advanced filtering using ruby expressions
95 95
 
96  
-Available as of Sequel 2.0:
97  
-
98  
-  DB[:items].filter(:price.sql_number < 100).sql 
  96
+  DB[:items].filter{|o| o.price < 100}.sql 
99 97
   #=> "SELECT * FROM items WHERE (price < 100)" 
100 98
 
101 99
   DB[:items].filter(:name.like('AL%')).sql 
@@ -103,7 +101,7 @@ Available as of Sequel 2.0:
103 101
 
104 102
 There's support for nested expressions with AND, OR and NOT:
105 103
 
106  
-  DB[:items].filter((:x.sql_number > 5) & (:y.sql_number > 10)).sql 
  104
+  DB[:items].filter{|o| (o.x > 5) & (o.y > 10)}.sql 
107 105
   #=> "SELECT * FROM items WHERE ((x > 5) AND (y > 10))" 
108 106
 
109 107
   DB[:items].filter({:x => 1, :y => 2}.sql_or & ~{:z => 3}).sql 
@@ -114,7 +112,7 @@ You can use arithmetic operators and specify SQL functions:
114 112
   DB[:items].filter((:x + :y) > :z).sql 
115 113
   #=> "SELECT * FROM items WHERE ((x + y) > z)" 
116 114
 
117  
-  DB[:items].filter(:price - 100 < :AVG.sql_function(:price)).sql 
  115
+  DB[:items].filter{|o| :price - 100 < o.AVG(:price)}.sql 
118 116
   #=> "SELECT * FROM items WHERE ((price - 100) < AVG(price))" 
119 117
 
120 118
 == Ordering
@@ -165,9 +163,10 @@ You can use arithmetic operators and specify SQL functions:
165 163
 
166 164
   DB.create_table :items do
167 165
     primary_key :id
168  
-    text :name, :unique => true, :null => false
  166
+    String :name, :unique => true, :null => false
169 167
     boolean :active, :default => true
170 168
     foreign_key :category_id, :categories
  169
+    Time :created_at
171 170
     
172 171
     index :grade
173 172
   end
@@ -175,14 +174,13 @@ You can use arithmetic operators and specify SQL functions:
175 174
   DB.drop_table :items
176 175
 
177 176
   DB.create_table :test do
178  
-    varchar :zipcode, :size => 10
  177
+    String :zipcode, :size => 10
179 178
     enum :system, :elements => ['mac', 'linux', 'windows']
180 179
   end
181 180
 
182 181
 == Aliasing
183 182
 
184 183
   DB[:items].select(:name.as(:item_name))
185  
-  DB[:items].select(:name => :item_name)
186 184
   DB[:items].select(:name___item_name)
187 185
   DB[:items___items_table].select(:items_table__name___item_name)
188 186
   # => "SELECT items_table.name AS item_name FROM items AS items_table"
@@ -221,5 +219,5 @@ Miscellaneous:
221 219
   dataset.where(:name => 'sequel').exists #=> "EXISTS ( SELECT 1 FROM items WHERE name = 'sequel' )"
222 220
   dataset.print #=> pretty table print to $stdout
223 221
   dataset.columns #=> array of columns in the result set, does a SELECT
224  
-  DB.schema_for_table(:items) => [[:id, {:type=>:integer, ...}], [:name, {:type=>:string, ...}], ...]
225  
-                                 # Works on PostgreSQL, MySQL, SQLite, and possibly elsewhere
  222
+  DB.schema(:items) => [[:id, {:type=>:integer, ...}], [:name, {:type=>:string, ...}], ...]
  223
+                       # Works on PostgreSQL, MySQL, SQLite, and JDBC
36  doc/dataset_filtering.rdoc
Source Rendered
@@ -14,33 +14,9 @@ In order to prevent SQL injection, you can replace literal values with question
14 14
   items.filter('category = ?', 'ruby').sql
15 15
   #=> "SELECT * FROM items WHERE category = 'ruby'"
16 16
 
17  
-== An aside: column references in Sequel
18  
-
19  
-Sequel expects column names to be specified using symbols. In addition, tuples always use symbols as their keys. This allows you to freely mix literal values and column references. For example, the two following lines produce equivalent SQL:
20  
-
21  
-  items.filter(:x => 1) #=> "SELECT * FROM items WHERE (x = 1)"
22  
-  items.filter(1 => :x) #=> "SELECT * FROM items WHERE (1 = x)"
23  
-
24  
-=== Qualifying column names
25  
-
26  
-Column references can be qualified by using the double underscore special notation :table__column:
27  
-
28  
-  items.literal(:items__price) #=> "items.price"
29  
-
30  
-=== Column aliases
31  
-
32  
-You can also alias columns by using the triple undersecore special notation :column___alias or :table__column___alias:
33  
-
34  
-  items.literal(:price___p) #=> "price AS p"
35  
-  items.literal(:items__price___p) #=> "items.price AS p"
36  
-
37  
-Another way to alias columns is to use the #AS method:
38  
-
39  
-  items.literal(:price.as(:p)) #=> "price AS p"
40  
-
41 17
 === Specifying SQL functions
42 18
 
43  
-Sequel also allows you to specify functions by using the Symbol#[] method:
  19
+Sequel also allows you to specify functions by using the Symbol#sql_function method (and the Symbol#[] method on ruby 1.8):
44 20
 
45 21
   items.literal(:avg.sql_function(:price)) #=> "avg(price)"
46 22
 
@@ -76,10 +52,10 @@ Ranges (both inclusive and exclusive) can also be used:
76 52
 
77 53
 == Filtering using expressions
78 54
 
79  
-New in Sequel 2.0 is the ability to use ruby expressions directly in the call to filter, without using a block:
  55
+Sequel allows you to use ruby expressions directly in the call to filter, without using a block:
80 56
 
81  
-  items.filter(:price.sql_number < 100).sql
82  
-  #=> "SELECT * FROM items WHERE (price < 100) 
  57
+  items.filter(:price * 2 < 50).sql
  58
+  #=> "SELECT * FROM items WHERE ((price * 2) < 50) 
83 59
 
84 60
 This works for the standard inequality and arithmetic operators:
85 61
 
@@ -133,12 +109,12 @@ You can use the negation operator (~) in most cases:
133 109
 
134 110
 You can also compare against other columns:
135 111
 
136  
-  items.filter(:credit.sql_number > :debit).sql
  112
+  items.filter{|o| o.credit > :debit}.sql
137 113
   #=> "SELECT * FROM items WHERE (credit > debit)
138 114
 
139 115
 Or against SQL functions:
140 116
 
141  
-  items.filter(:price - 100 < :max.sql_function(:price)).sql
  117
+  items.filter{|o| :price - 100 < o.max(:price)}.sql
142 118
   #=> "SELECT * FROM items WHERE ((price - 100) < max(price))"
143 119
 
144 120
 == String search functions
20  doc/schema.rdoc
Source Rendered
@@ -7,3 +7,23 @@ The recommended way to set up schema modifications in Sequel is through migratio
7 7
 The format of the individual migration files themselves is explained in the Sequel::Migration documentation.  Each migration file contains a single migration class.  The migration class acts a proxy for the related database (given on the command line if the sequel command line tool is used, or by the db argument to Sequel::Migration#apply if the API is used). The methods that can be used inside Sequel::Migration#up or Sequel::Migration#down are just Sequel::Database instance methods, such as create_table, drop_table, and alter_table.  Most database methods that alter the schema take regular arguments, but create_table and alter_table take a block.  The methods you can use inside the create_table block are documented in Sequel::Schema::Generator, and the methods you can use inside the alter_table block are documented in Sequel::Schema::AlterTableGenerator.
8 8
 
9 9
 Migrations are not required, you can just call the schema modification methods directly on the database object.  This is often done in test code and examples.  However, it is recommended that you use the migration framework unless the database schema will not be changing in the future, as it provides a way to easily handle modifications to existing database schema.
  10
+
  11
+Also, new in Sequel 2.10 is the ability to have database independent migrations using ruby classes as types.  When you use a ruby class as a type, Sequel translates it to the most comparable type in the database you are using.  Here's an example using all supported types:
  12
+
  13
+    DB.create_table(:cats) do
  14
+      primary_key :id, :type=>Integer # integer
  15
+      String :a                       # varchar(255)
  16
+      column :b, File                 # blob
  17
+      Fixnum :c                       # integer
  18
+      foreign_key :d, :other_table, :type=>Bignum # bigint
  19
+      Float :e                        # double precision
  20
+      BigDecimal :f                   # numeric
  21
+      Date :g                         # date
  22
+      DateTime :h                     # timestamp
  23
+      Time :i                         # timestamp
  24
+      Numeric :j                      # numeric
  25
+      TrueClass :k                    # boolean
  26
+      FalseClass :l                   # boolean
  27
+    end
  28
+
  29
+Basically, if you use one of the ruby classes above, it will translate into a database specific type.  If you use a lowercase method, symbol, or string to specify the type, Sequel won't attempt to translate it.
10  lib/sequel_core/dataset/convenience.rb
@@ -40,11 +40,11 @@ def empty?
40 40
     #   ds.first(:id=>2) => {:id=>2}
41 41
     #   ds.first("id = 3") => {:id=>3}
42 42
     #   ds.first("id = ?", 4) => {:id=>4}
43  
-    #   ds.first{:id.sql_number > 2} => {:id=>5}
44  
-    #   ds.order(:id).first{:id.sql_number > 2} => {:id=>3}
45  
-    #   ds.first{:id.sql_number > 2} => {:id=>5}
46  
-    #   ds.first("id > ?", 4){:id.sql_number < 6) => {:id=>5}
47  
-    #   ds.order(:id).first(2){:id.sql_number < 2} => [{:id=>1}]
  43
+    #   ds.first{|o| o.id > 2} => {:id=>5}
  44
+    #   ds.order(:id).first{|o| o.id > 2} => {:id=>3}
  45
+    #   ds.first{|o| o.id > 2} => {:id=>5}
  46
+    #   ds.first("id > ?", 4){|o| o.id < 6} => {:id=>5}
  47
+    #   ds.order(:id).first(2){|o| o.id < 2} => [{:id=>1}]
48 48
     def first(*args, &block)
49 49
       ds = block ? filter(&block) : self
50 50
 
4  lib/sequel_core/dataset/query.rb
@@ -5,13 +5,13 @@ class Dataset
5 5
     #
6 6
     #   dataset = DB[:items].query do
7 7
     #     select :x, :y, :z
8  
-    #     filter((:x.sql_number > 1) & (:y.sql_number > 2))
  8
+    #     filter{|o| (o.x > 1) & (o.y > 2)}
9 9
     #     order :z.desc
10 10
     #   end
11 11
     #
12 12
     # Which is the same as:
13 13
     #
14  
-    #  dataset = DB[:items].select(:x, :y, :z).filter((:x.sql_number > 1) & (:y.sql_number > 2)).order(:z.desc)
  14
+    #  dataset = DB[:items].select(:x, :y, :z).filter{|o| (o.x > 1) & (o.y > 2)}.order(:z.desc)
15 15
     #
16 16
     # Note that inside a call to query, you cannot call each, insert, update,
17 17
     # or delete (or any method that calls those), or Sequel will raise an
6  lib/sequel_core/dataset/sql.rb
@@ -76,7 +76,7 @@ def count
76 76
 
77 77
     # Formats a DELETE statement using the given options and dataset options.
78 78
     # 
79  
-    #   dataset.filter(:price.sql_number >= 100).delete_sql #=>
  79
+    #   dataset.filter{|o| o.price >= 100}.delete_sql #=>
80 80
     #     "DELETE FROM items WHERE (price >= 100)"
81 81
     def delete_sql(opts = nil)
82 82
       opts = opts ? @opts.merge(opts) : @opts
@@ -163,13 +163,13 @@ def exists(opts = nil)
163 163
     #     "SELECT * FROM items WHERE price < 100"
164 164
     #   dataset.filter(:active).sql #=>
165 165
     #     "SELECT * FROM items WHERE :active
166  
-    #   dataset.filter(:price.sql_number < 100).sql #=>
  166
+    #   dataset.filter{|o| o.price < 100}.sql #=>
167 167
     #     "SELECT * FROM items WHERE (price < 100)"
168 168
     # 
169 169
     # Multiple filter calls can be chained for scoping:
170 170
     #
171 171
     #   software = dataset.filter(:category => 'software')
172  
-    #   software.filter(price < 100).sql #=>
  172
+    #   software.filter{|o| o.price < 100}.sql #=>
173 173
     #     "SELECT * FROM items WHERE ((category = 'software') AND (price < 100))"
174 174
     #
175 175
     # See doc/dataset_filters.rdoc for more examples and details.
8  lib/sequel_core/migration.rb
@@ -6,9 +6,9 @@ module Sequel
6 6
   #     def up
7 7
   #       create_table :sessions do
8 8
   #         primary_key :id
9  
-  #         varchar   :session_id, :size => 32, :unique => true
10  
-  #         timestamp :created_at
11  
-  #         text      :data
  9
+  #         String :session_id, :size => 32, :unique => true
  10
+  #         DateTime :created_at
  11
+  #         text :data
12 12
   #       end
13 13
   #     end
14 14
   # 
@@ -21,7 +21,7 @@ module Sequel
21 21
   #   class AlterItems < Sequel::Migration
22 22
   #     def up
23 23
   #       alter_table :items do
24  
-  #         add_column :category, :text, :default => 'ruby'
  24
+  #         add_column :category, String, :default => 'ruby'
25 25
   #       end
26 26
   #     end
27 27
   # 

0 notes on commit ce1c70f

Please sign in to comment.
Something went wrong with that request. Please try again.