Skip to content

Commit 45b7f37

Browse files
committed
Make Dataset#get and #first without argument not create intermediate datasets if receiver uses raw SQL
There's no reason for a dataset clone in this case, as the limit and select settings will be ignored. This also fixes use of Dataset#get without argument when using the implicit_subquery extension. Previously, it would try to use a subquery in an unhelpful way: DB['SELECT a FROM b WHERE c = 1'].extension(:implicit_subquery).get # SELECT NULL AS v FROM (SELECT a FROM b WHERE c = 1) AS t1 LIMIT 1 Now, it runs the query directly and returns the first value.
1 parent 26a2243 commit 45b7f37

File tree

3 files changed

+20
-2
lines changed

3 files changed

+20
-2
lines changed

CHANGELOG

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
=== master
22

3+
* Make Dataset#get and #first without argument not create intermediate datasets if receiver uses raw SQL (jeremyevans)
4+
35
* Add dataset_run extension, for building SQL using datasets, and running with Database#run (jeremyevans)
46

57
* Switch default connection pool to timed_queue on Ruby 3.2+ (jeremyevans)

lib/sequel/dataset/actions.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,7 @@ def first(*args, &block)
217217
case args.length
218218
when 0
219219
unless block
220-
return single_record
220+
return(@opts[:sql] ? single_record! : single_record)
221221
end
222222
when 1
223223
arg = args[0]
@@ -282,13 +282,21 @@ def first!(*args, &block)
282282
#
283283
# DB[:table].get{[sum(id).as(sum), name]} # SELECT sum(id) AS sum, name FROM table LIMIT 1
284284
# # => [6, 'foo']
285+
#
286+
# If called on a dataset with raw SQL, returns the
287+
# first value in the dataset without changing the selection or setting a limit:
288+
#
289+
# DB["SELECT id FROM table"].get # SELECT id FROM table
290+
# # => 3
285291
def get(column=(no_arg=true; nil), &block)
286292
ds = naked
287293
if block
288294
raise(Error, 'Must call Dataset#get with an argument or a block, not both') unless no_arg
289295
ds = ds.select(&block)
290296
column = ds.opts[:select]
291297
column = nil if column.is_a?(Array) && column.length < 2
298+
elsif no_arg && opts[:sql]
299+
return ds.single_value!
292300
else
293301
case column
294302
when Array

spec/core/dataset_spec.rb

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3035,6 +3035,12 @@ def supports_cte_in_subselect?; false end
30353035
Sequel.mock[:t].first.must_be_nil
30363036
end
30373037

3038+
it "should return first record in query when using raw SQL" do
3039+
db = Sequel.mock(:fetch=>{:v=>1})
3040+
db['SELECT 1'].first.must_equal(:v=>1)
3041+
db.sqls.must_equal ['SELECT 1']
3042+
end
3043+
30383044
it "#last should raise if no order is given" do
30393045
proc {@d.last}.must_raise(Sequel::Error)
30403046
proc {@d.last(2)}.must_raise(Sequel::Error)
@@ -3375,7 +3381,9 @@ def supports_cte_in_subselect?; false end
33753381
@d.with_sql('SELECT foo').get(:name).must_equal "SELECT foo"
33763382
@d = @d.with_fetch(:name=>1, :abc=>2)
33773383
@d.with_sql('SELECT foo').get{[name, n[abc]]}.must_equal [1, 2]
3378-
@d.db.sqls.must_equal ['SELECT foo'] * 2
3384+
@d = @d.with_fetch(:name=>1)
3385+
@d.with_sql('SELECT foo').get.must_equal 1
3386+
@d.db.sqls.must_equal ['SELECT foo'] * 3
33793387
end
33803388

33813389
it "should handle cases where no rows are returned" do

0 commit comments

Comments
 (0)