sequel 3.13.0 → 3.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/CHANGELOG +36 -0
  2. data/doc/release_notes/3.14.0.txt +118 -0
  3. data/lib/sequel/adapters/oracle.rb +7 -2
  4. data/lib/sequel/adapters/shared/mssql.rb +9 -3
  5. data/lib/sequel/connection_pool/sharded_threaded.rb +1 -1
  6. data/lib/sequel/connection_pool/threaded.rb +3 -3
  7. data/lib/sequel/database/connecting.rb +47 -11
  8. data/lib/sequel/database/dataset.rb +17 -6
  9. data/lib/sequel/database/dataset_defaults.rb +15 -3
  10. data/lib/sequel/database/logging.rb +4 -3
  11. data/lib/sequel/database/misc.rb +33 -21
  12. data/lib/sequel/database/query.rb +61 -22
  13. data/lib/sequel/database/schema_generator.rb +108 -45
  14. data/lib/sequel/database/schema_methods.rb +8 -5
  15. data/lib/sequel/dataset/actions.rb +194 -45
  16. data/lib/sequel/dataset/features.rb +1 -1
  17. data/lib/sequel/dataset/graph.rb +51 -43
  18. data/lib/sequel/dataset/misc.rb +29 -5
  19. data/lib/sequel/dataset/mutation.rb +0 -1
  20. data/lib/sequel/dataset/prepared_statements.rb +14 -2
  21. data/lib/sequel/dataset/query.rb +268 -125
  22. data/lib/sequel/dataset/sql.rb +33 -44
  23. data/lib/sequel/extensions/migration.rb +3 -2
  24. data/lib/sequel/extensions/pagination.rb +1 -1
  25. data/lib/sequel/model/associations.rb +89 -87
  26. data/lib/sequel/model/base.rb +386 -109
  27. data/lib/sequel/model/errors.rb +15 -1
  28. data/lib/sequel/model/exceptions.rb +3 -3
  29. data/lib/sequel/model/inflections.rb +2 -2
  30. data/lib/sequel/model/plugins.rb +9 -5
  31. data/lib/sequel/plugins/rcte_tree.rb +43 -15
  32. data/lib/sequel/plugins/schema.rb +6 -5
  33. data/lib/sequel/plugins/serialization.rb +1 -1
  34. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  35. data/lib/sequel/plugins/tree.rb +33 -1
  36. data/lib/sequel/timezones.rb +16 -10
  37. data/lib/sequel/version.rb +1 -1
  38. data/spec/adapters/mssql_spec.rb +36 -2
  39. data/spec/adapters/mysql_spec.rb +4 -4
  40. data/spec/adapters/postgres_spec.rb +1 -1
  41. data/spec/adapters/spec_helper.rb +2 -2
  42. data/spec/core/database_spec.rb +8 -1
  43. data/spec/core/dataset_spec.rb +36 -1
  44. data/spec/extensions/pagination_spec.rb +1 -1
  45. data/spec/extensions/rcte_tree_spec.rb +40 -8
  46. data/spec/extensions/schema_spec.rb +5 -0
  47. data/spec/extensions/serialization_spec.rb +4 -4
  48. data/spec/extensions/single_table_inheritance_spec.rb +7 -0
  49. data/spec/extensions/tree_spec.rb +36 -0
  50. data/spec/integration/dataset_test.rb +19 -0
  51. data/spec/integration/prepared_statement_test.rb +2 -2
  52. data/spec/integration/schema_test.rb +1 -1
  53. data/spec/integration/spec_helper.rb +4 -4
  54. data/spec/integration/timezone_test.rb +27 -21
  55. data/spec/model/associations_spec.rb +5 -5
  56. data/spec/model/dataset_methods_spec.rb +13 -0
  57. data/spec/model/hooks_spec.rb +31 -0
  58. data/spec/model/record_spec.rb +24 -7
  59. data/spec/model/validations_spec.rb +9 -4
  60. metadata +6 -4
data/CHANGELOG CHANGED
@@ -1,3 +1,39 @@
1
+ === 3.14.0 (2010-08-02)
2
+
3
+ * Handle OCIInvalidHandle errors when disconnecting in the Oracle adapter (jeremyevans)
4
+
5
+ * Allow calling Model.create_table, .create_table! and .create_table? with blocks containing the schema in the schema plugin (jfirebaugh)
6
+
7
+ * Fix handling of a :conditions options in the rcte plugin (mluu)
8
+
9
+ * Fix aggregate methods such as Dataset#sum and #avg on MSSQL on datasets with an order but no limit (mluu)
10
+
11
+ * Fix rename_table on MSSQL for case sensitive collations and schemas (mluu)
12
+
13
+ * Add a :single_root option to the tree plugin, for enforcing a single root value via a before_save hook (jfirebaugh)
14
+
15
+ * Add a Model#root? method to the tree plugin, for checking if the current node is a root (jfirebaugh)
16
+
17
+ * Add a :raise_on_failure option to Model#save to override the raise_on_save_failure setting (jfirebaugh)
18
+
19
+ * Handle class discriminator column names that are existing ruby method names in the single table inheritance plugin (jeremyevans)
20
+
21
+ * Fix times and datetimes when timezone support is used and you are loading a standard time when in daylight time or vice versa (gcampbell)
22
+
23
+ * Handle literalization of OCI8::CLOB objects in the native oracle adapter (jeremyevans)
24
+
25
+ * Raise a Sequel::Error instead of an ArgumentError if the migration current or target version does not exist (jeremyevans)
26
+
27
+ * Fix Database#schema on Oracle when the same table exists in multiple schemas (djwhitt)
28
+
29
+ * Fix Database#each_server when using a connection string to connect (jeremyevans)
30
+
31
+ * Make Model dataset's destroy method respect the model's use_transactions setting, instead of always using a transaction (jeremyevans)
32
+
33
+ * Add Database#adapter_scheme, for checking which adapter a Database uses (jeremyevans)
34
+
35
+ * Allow Dataset#grep to take :all_patterns, :all_columns, and :case_insensitive options (mighub, jeremyevans)
36
+
1
37
  === 3.13.0 (2010-07-01)
2
38
 
3
39
  * Allow Model.find_or_create to take a block which is yielded the object to be created, if no object is found (zaius, jeremyevans)
@@ -0,0 +1,118 @@
1
+ = New Features
2
+
3
+ * Dataset#grep now accepts :all_patterns, :all_columns, and
4
+ :case_insensitive options. Previously, grep would use a case
5
+ sensitive search where it would match if any pattern matched any
6
+ column. These three options give you more control over how the
7
+ pattern matching will work:
8
+
9
+ dataset.grep([:a, :b], %w'%test% foo')
10
+ # WHERE ((a LIKE '%test%') OR (a LIKE 'foo')
11
+ # OR (b LIKE '%test%') OR (b LIKE 'foo'))
12
+
13
+ dataset.grep([:a, :b], %w'%foo% %bar%', :all_patterns=>true)
14
+ # WHERE (((a LIKE '%foo%') OR (b LIKE '%foo%'))
15
+ # AND ((a LIKE '%bar%') OR (b LIKE '%bar%')))
16
+
17
+ dataset.grep([:a, :b], %w'%foo% %bar%', :all_columns=>true)
18
+ # WHERE (((a LIKE '%foo%') OR (a LIKE '%bar%'))
19
+ # AND ((b LIKE '%foo%') OR (b LIKE '%bar%')))
20
+
21
+ dataset.grep([:a, :b], %w'%foo% %bar%',
22
+ :all_patterns=>true,:all_columns=>true)
23
+ # WHERE ((a LIKE '%foo%') AND (b LIKE '%foo%')
24
+ # AND (a LIKE '%bar%') AND (b LIKE '%bar%'))
25
+
26
+ dataset.grep([:a, :b], %w'%test% foo', :case_insensitive=>true)
27
+ # WHERE ((a ILIKE '%test%') OR (a ILIKE 'foo')
28
+ # OR (b ILIKE '%test%') OR (b ILIKE 'foo'))
29
+
30
+ * When using the schema plugin, you can now provide a block to the
31
+ create_table methods to set the schema and create the table
32
+ in the same call:
33
+
34
+ class Artist < Sequel::Model
35
+ create_table do
36
+ primary_key :id
37
+ String :name
38
+ end
39
+ end
40
+
41
+ * The tree plugin now accepts a :single_root option, which uses a
42
+ before_save hook to attempt to ensure that there is only a single
43
+ root in the tree. It also adds a Model.root method to get the
44
+ single root of the tree.
45
+
46
+ * The tree plugin now adds a Model#root? instance method to check
47
+ if the current node is a root of the tree.
48
+
49
+ * Model#save now takes a :raise_on_failure option which will
50
+ override the object's raise_on_save_failure setting. This makes
51
+ it easier to get the desired behavior (raise or just return false)
52
+ in library code without using a begin/ensure block.
53
+
54
+ * The Database#adapter_scheme instance method was added, which
55
+ operates the same as the class method.
56
+
57
+ * Sequel now handles the literalization of OCI8::CLOB objects in
58
+ the Oracle adapter.
59
+
60
+ = Other Improvements
61
+
62
+ * When using the timezone support, Sequel will now correctly load
63
+ times and datetimes in standard time when the current timezone is
64
+ in daylight time, or vice versa. Previously, if you tried to
65
+ to load a time or datetime in December when in July in a timezone
66
+ that used daylight time, it would be off by an hour.
67
+
68
+ * The rcte_tree plugin now works correctly when a :conditions option
69
+ is used.
70
+
71
+ * The single_table_inheritance plugin now works correctly when the
72
+ class discriminator column has the same name as an existing ruby
73
+ method (such as type).
74
+
75
+ * Database#each_server now works correctly when a connection string
76
+ is used to connect, instead of an options hash.
77
+
78
+ * Model#destroy now respects the object's use_transactions setting,
79
+ instead of always using a transaction.
80
+
81
+ * Model#exists? now uses a simpler and faster query.
82
+
83
+ * Sequel now handles the aggregate methods such as count and sum
84
+ correctly on Microsoft SQL Server when using an ordered dataset
85
+ with a clause such as DISTINCT or GROUP and without a limit.
86
+
87
+ * Sequel now handles rename_table correctly on Microsoft SQL Server
88
+ when using a case sensitive collation, or when qualifying the
89
+ table with a schema.
90
+
91
+ * Sequel now parses the schema correctly on Oracle when the same
92
+ table name is used in multiple schemas.
93
+
94
+ * Sequel now handles OCIInvalidHandle errors when disconnecting
95
+ in the Oracle adapter.
96
+
97
+ * Sequel now raises a Sequel::Error instead of an ArgumentError
98
+ if the current or target migration version does not exist.
99
+
100
+ * When a mismatched number of composite keys are used in
101
+ associations, Sequel now uses a more detailed error message.
102
+
103
+ * Significant improvements were made to the Dataset and Model
104
+ RDoc documentation.
105
+
106
+ = Backwards Compatibility
107
+
108
+ * Model#valid? now must accept an optional options hash.
109
+
110
+ * The Model#save_failure private method was renamed to
111
+ raise_hook_failure.
112
+
113
+ * The LOCAL_DATETIME_OFFSET_SECS and LOCAL_DATETIME_OFFSET constants
114
+ have been removed from the Sequel module.
115
+
116
+ * Sequel now uses obj.to_json instead of JSON.generate(obj). This
117
+ shouldn't affect backwards compatibility, but did fix a bug in
118
+ certain cases.
@@ -34,9 +34,9 @@ module Sequel
34
34
  def schema_parse_table(table, opts={})
35
35
  ds = dataset
36
36
  ds.identifier_output_method = :downcase
37
- schema, table = schema_and_table(table)
37
+ schema_and_table = "#{"#{quote_identifier(opts[:schema])}." if opts[:schema]}#{quote_identifier(table)}"
38
38
  table_schema = []
39
- metadata = transaction(opts){|conn| conn.describe_table(table.to_s)}
39
+ metadata = transaction(opts){|conn| conn.describe_table(schema_and_table)}
40
40
  metadata.columns.each do |column|
41
41
  table_schema << [
42
42
  column.name.downcase.to_sym,
@@ -85,6 +85,8 @@ module Sequel
85
85
 
86
86
  def disconnect_connection(c)
87
87
  c.logoff
88
+ rescue OCIInvalidHandle
89
+ nil
88
90
  end
89
91
 
90
92
  def remove_transaction(conn)
@@ -122,6 +124,9 @@ module Sequel
122
124
  case v
123
125
  when OraDate
124
126
  literal(Sequel.database_to_application_timestamp(v))
127
+ when OCI8::CLOB
128
+ v.rewind
129
+ literal(v.read)
125
130
  else
126
131
  super
127
132
  end
@@ -67,7 +67,7 @@ module Sequel
67
67
  when :add_column
68
68
  "ALTER TABLE #{quote_schema_table(table)} ADD #{column_definition_sql(op)}"
69
69
  when :rename_column
70
- "SP_RENAME #{literal("#{quote_schema_table(table)}.#{quote_identifier(op[:name])}")}, #{literal(op[:new_name].to_s)}, 'COLUMN'"
70
+ "sp_rename #{literal("#{quote_schema_table(table)}.#{quote_identifier(op[:name])}")}, #{literal(op[:new_name].to_s)}, 'COLUMN'"
71
71
  when :set_column_type
72
72
  "ALTER TABLE #{quote_schema_table(table)} ALTER COLUMN #{quote_identifier(op[:name])} #{type_literal(op)}"
73
73
  when :set_column_null
@@ -124,9 +124,9 @@ module Sequel
124
124
  ds
125
125
  end
126
126
 
127
- # Use SP_RENAME to rename the table
127
+ # Use sp_rename to rename the table
128
128
  def rename_table_sql(name, new_name)
129
- "SP_RENAME #{quote_schema_table(name)}, #{quote_schema_table(new_name)}"
129
+ "sp_rename #{literal(quote_schema_table(name))}, #{quote_identifier(schema_and_table(new_name).pop)}"
130
130
  end
131
131
 
132
132
  # SQL to rollback to a savepoint
@@ -373,6 +373,12 @@ module Sequel
373
373
  def supports_window_functions?
374
374
  true
375
375
  end
376
+
377
+ protected
378
+ # MSSQL does not allow ordering in sub-clauses unless 'top' (limit) is specified
379
+ def aggregate_dataset
380
+ (options_overlap(Sequel::Dataset::COUNT_FROM_SELF_OPTS) && !options_overlap([:limit])) ? unordered.from_self : super
381
+ end
376
382
 
377
383
  private
378
384
 
@@ -56,7 +56,7 @@ class Sequel::ShardedThreadedConnectionPool < Sequel::ThreadedConnectionPool
56
56
  @allocated[server].length + @available_connections[server].length
57
57
  end
58
58
 
59
- # Removes all connection currently available on all servers, optionally
59
+ # Removes all connections currently available on all servers, optionally
60
60
  # yielding each connection to the given block. This method has the effect of
61
61
  # disconnecting from the database, assuming that no connections are currently
62
62
  # being used. If connections are being used, they are scheduled to be
@@ -1,4 +1,5 @@
1
1
  # A connection pool allowing multi-threaded access to a pool of connections.
2
+ # This is the default connection pool used by Sequel.
2
3
  class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
3
4
  # The maximum number of connections this pool will create (per shard/server
4
5
  # if sharding).
@@ -35,11 +36,10 @@ class Sequel::ThreadedConnectionPool < Sequel::ConnectionPool
35
36
  @allocated.length + @available_connections.length
36
37
  end
37
38
 
38
- # Removes all connection currently available on all servers, optionally
39
+ # Removes all connections currently available on all servers, optionally
39
40
  # yielding each connection to the given block. This method has the effect of
40
41
  # disconnecting from the database, assuming that no connections are currently
41
- # being used. If connections are being used, they are scheduled to be
42
- # disconnected as soon as they are returned to the pool.
42
+ # being used.
43
43
  #
44
44
  # Once a connection is requested using #hold, the connection pool
45
45
  # creates new connections to the database.
@@ -27,13 +27,13 @@ module Sequel
27
27
 
28
28
  # make sure we actually loaded the adapter
29
29
  unless klass = ADAPTER_MAP[scheme]
30
- raise AdapterNotFound, "Could not load #{scheme} adapter"
30
+ raise AdapterNotFound, "Could not load #{scheme} adapter: adapter class not registered in ADAPTER_MAP"
31
31
  end
32
32
  end
33
33
  klass
34
34
  end
35
35
 
36
- # Returns the scheme for the Database class.
36
+ # Returns the scheme symbol for the Database class.
37
37
  def self.adapter_scheme
38
38
  @scheme
39
39
  end
@@ -54,6 +54,7 @@ module Sequel
54
54
  uri.query.split('&').collect{|s| s.split('=')}.each{|k,v| uri_options[k.to_sym] = v if k && !k.empty?} unless uri.query.to_s.strip.empty?
55
55
  uri_options.entries.each{|k,v| uri_options[k] = URI.unescape(v) if v.is_a?(String)}
56
56
  opts = uri_options.merge(opts)
57
+ opts[:adapter] = scheme
57
58
  end
58
59
  when Hash
59
60
  opts = conn_string.merge(opts)
@@ -62,7 +63,7 @@ module Sequel
62
63
  raise Error, "Sequel::Database.connect takes either a Hash or a String, given: #{conn_string.inspect}"
63
64
  end
64
65
  # process opts a bit
65
- opts = opts.inject({}) do |m, kv| k, v = *kv
66
+ opts = opts.inject({}) do |m, (k,v)|
66
67
  k = :user if k.to_s == 'username'
67
68
  m[k.to_sym] = v
68
69
  m
@@ -104,9 +105,20 @@ module Sequel
104
105
  end
105
106
  private_class_method :set_adapter_scheme
106
107
 
107
- # The connection pool for this database
108
+ # The connection pool for this Database instance. All Database instances have
109
+ # their own connection pools.
108
110
  attr_reader :pool
109
111
 
112
+ # Returns the scheme symbol for this instance's class, which reflects which
113
+ # adapter is being used. In some cases, this can be the same as the
114
+ # +database_type+ (for native adapters), in others (i.e. adapters with
115
+ # subadapters), it will be different.
116
+ #
117
+ # Sequel.connect('jdbc:postgres://...').adapter_scheme # => :jdbc
118
+ def adapter_scheme
119
+ self.class.adapter_scheme
120
+ end
121
+
110
122
  # Dynamically add new servers or modify server options at runtime. Also adds new
111
123
  # servers to the connection pool. Intended for use with master/slave or shard
112
124
  # configurations where it is useful to add new server hosts at runtime.
@@ -115,7 +127,7 @@ module Sequel
115
127
  # proc values. If a servers key is already in use, it's value is overridden
116
128
  # with the value provided.
117
129
  #
118
- # DB.add_servers(:f=>{:host=>"hash_host_f"})
130
+ # DB.add_servers(:f=>{:host=>"hash_host_f"})
119
131
  def add_servers(servers)
120
132
  @opts[:servers] = @opts[:servers] ? @opts[:servers].merge(servers) : servers
121
133
  @pool.add_servers(servers.keys)
@@ -133,19 +145,27 @@ module Sequel
133
145
  # type. Even better, you can tell that two Database objects that are using
134
146
  # the same adapter are connecting to different database types (think JDBC or
135
147
  # DataObjects).
148
+ #
149
+ # Sequel.connect('jdbc:postgres://...').database_type # => :postgres
136
150
  def database_type
137
- self.class.adapter_scheme
151
+ adapter_scheme
138
152
  end
139
153
 
140
154
  # Disconnects all available connections from the connection pool. Any
141
155
  # connections currently in use will not be disconnected. Options:
142
156
  # * :servers - Should be a symbol specifing the server to disconnect from,
143
157
  # or an array of symbols to specify multiple servers.
158
+ #
159
+ # Example:
160
+ #
161
+ # DB.disconnect # All servers
162
+ # DB.disconnect(:servers=>:server1) # Single server
163
+ # DB.disconnect(:servers=>[:server1, :server2]) # Multiple servers
144
164
  def disconnect(opts = {})
145
165
  pool.disconnect(opts)
146
166
  end
147
167
 
148
- # Yield a new database object for every server in the connection pool.
168
+ # Yield a new Database instance for every server in the connection pool.
149
169
  # Intended for use in sharded environments where there is a need to make schema
150
170
  # modifications (DDL queries) on each shard.
151
171
  #
@@ -175,6 +195,9 @@ module Sequel
175
195
  end
176
196
 
177
197
  # An array of servers/shards for this Database object.
198
+ #
199
+ # DB.servers # Unsharded: => [:default]
200
+ # DB.servers # Sharded: => [:default, :server1, :server2]
178
201
  def servers
179
202
  pool.servers
180
203
  end
@@ -184,13 +207,27 @@ module Sequel
184
207
  @single_threaded
185
208
  end
186
209
 
187
- # Acquires a database connection, yielding it to the passed block.
210
+ # Acquires a database connection, yielding it to the passed block. This is
211
+ # useful if you want to make sure the same connection is used for all
212
+ # database queries in the block. It is also useful if you want to gain
213
+ # direct access to the underlying connection object if you need to do
214
+ # something Sequel does not natively support.
215
+ #
216
+ # If a server option is given, acquires a connection for that specific
217
+ # server, instead of the :default server.
218
+ #
219
+ #
220
+ # DB.synchronize do |conn|
221
+ # ...
222
+ # end
188
223
  def synchronize(server=nil, &block)
189
224
  @pool.hold(server || :default, &block)
190
225
  end
191
226
 
192
227
  # Attempts to acquire a database connection. Returns true if successful.
193
- # Will probably raise an error if unsuccessful.
228
+ # Will probably raise an Error if unsuccessful. If a server argument
229
+ # is given, attempts to acquire a database connection to the given
230
+ # server/shard.
194
231
  def test_connection(server=nil)
195
232
  synchronize(server){|conn|}
196
233
  true
@@ -207,7 +244,7 @@ module Sequel
207
244
  # options for all server with the specific options for the given
208
245
  # server specified in the :servers option.
209
246
  def server_opts(server)
210
- opts = if @opts[:servers] && server_options = @opts[:servers][server]
247
+ opts = if @opts[:servers] and server_options = @opts[:servers][server]
211
248
  case server_options
212
249
  when Hash
213
250
  @opts.merge(server_options)
@@ -222,6 +259,5 @@ module Sequel
222
259
  opts.delete(:servers)
223
260
  opts
224
261
  end
225
-
226
262
  end
227
263
  end
@@ -5,10 +5,11 @@ module Sequel
5
5
  # These methods all return instances of this database's dataset class.
6
6
  # ---------------------
7
7
 
8
- # Returns a dataset from the database. If the first argument is a string,
8
+ # Returns a dataset for the database. If the first argument is a string,
9
9
  # the method acts as an alias for Database#fetch, returning a dataset for
10
- # arbitrary SQL:
10
+ # arbitrary SQL, with or without placeholders:
11
11
  #
12
+ # DB['SELECT * FROM items'].all
12
13
  # DB['SELECT * FROM items WHERE name = ?', my_name].all
13
14
  #
14
15
  # Otherwise, acts as an alias for Database#from, setting the primary
@@ -19,7 +20,10 @@ module Sequel
19
20
  (String === args.first) ? fetch(*args) : from(*args)
20
21
  end
21
22
 
22
- # Returns a blank dataset for this database
23
+ # Returns a blank dataset for this database.
24
+ #
25
+ # DB.dataset # SELECT *
26
+ # DB.dataset.from(:items) # SELECT * FROM items
23
27
  def dataset
24
28
  ds = Sequel::Dataset.new(self)
25
29
  end
@@ -29,11 +33,11 @@ module Sequel
29
33
  #
30
34
  # DB.fetch('SELECT * FROM items'){|r| p r}
31
35
  #
32
- # The method returns a dataset instance:
36
+ # The +fetch+ method returns a dataset instance:
33
37
  #
34
38
  # DB.fetch('SELECT * FROM items').all
35
39
  #
36
- # Fetch can also perform parameterized queries for protection against SQL
40
+ # +fetch+ can also perform parameterized queries for protection against SQL
37
41
  # injection:
38
42
  #
39
43
  # DB.fetch('SELECT * FROM items WHERE name = ?', my_name).all
@@ -43,14 +47,21 @@ module Sequel
43
47
  ds
44
48
  end
45
49
 
46
- # Returns a new dataset with the from method invoked. If a block is given,
50
+ # Returns a new dataset with the +from+ method invoked. If a block is given,
47
51
  # it is used as a filter on the dataset.
52
+ #
53
+ # DB.from(:items) # SELECT * FROM items
54
+ # DB.from(:items){id > 2} # SELECT * FROM items WHERE (id > 2)
48
55
  def from(*args, &block)
49
56
  ds = dataset.from(*args)
50
57
  block ? ds.filter(&block) : ds
51
58
  end
52
59
 
53
60
  # Returns a new dataset with the select method invoked.
61
+ #
62
+ # DB.select(1) # SELECT 1
63
+ # DB.select{server_version{}} # SELECT server_version()
64
+ # DB.select(:id).from(:items) # SELECT id FROM items
54
65
  def select(*args, &block)
55
66
  dataset.select(*args, &block)
56
67
  end