删除数据集过滤器的一部分

时间:2013-11-08 17:06:05

标签: ruby sequel

如果应用了多个过滤器的Sequel Dataset,如何创建一个删除或覆盖其中一个现有过滤器的新数据集?

ds1 = DB[:x].filter(a:1, b:2)
#=> <Sequel::Dataset: "SELECT * FROM x WHERE ((a = 1) AND (b = 2))">

ds2 = ds1.filter(a:42) # I want to CHANGE a, not add another
#=> <Sequel::Dataset: "SELECT * FROM x WHERE ((a = 1) AND (b = 2) AND (a = 42))">

Sequel::Dataset#unfiltered方法会删除所有过滤器(例如,它会删除b=2)。虽然在上述简单的情况下很容易重新添加,但在我的实际情况下会导致代码重复。

2 个答案:

答案 0 :(得分:1)

您可以将选择规则存储在哈希中并重用哈希:

require 'sequel'

DB = Sequel.sqlite

selection = { a:  1, b: 2 }
ds1 = DB[:x].where( selection )

selection[:a] = 5  #change data
ds2a = ds1.unfiltered.filter(selection) # change selection
ds2b = DB[:x].where( selection ) #Alternative usage

puts ds1.sql  #SELECT * FROM `x` WHERE ((`a` = 1) AND (`b` = 2))
puts ds2a.sql #SELECT * FROM `x` WHERE ((`a` = 5) AND (`b` = 2))
puts ds2b.sql #SELECT * FROM `x` WHERE ((`a` = 5) AND (`b` = 2))

我发现可以使用新方法filter_exchangefilter_exchange!修改数据集。

require 'sequel'
DB = Sequel.sqlite

module Sequel
  class Dataset
    def filter_exchange!( filter )
      filter.each{|key, value|
        opts[:where].args.each{|arg|
          if arg.args.first == key
            arg.args.pop
            arg.args << value
          end
        }
      }
      self
    end
    def filter_exchange( filter )
      sel = self.unfiltered
      filter.each{|key, value|
        opts[:where].args.each{|arg|
          if arg.args.first == key
            sel = sel.filter(key => value)
          else
            sel = sel.filter(arg)
          end
        }
      }
      sel
    end
  end
end

ds1 = DB[:x].filter(a:1, b:2)
puts ds1.sql                        #SELECT * FROM `x` WHERE ((`a` = 1) AND (`b` = 2))
puts ds1.filter_exchange( a: 7).sql #SELECT * FROM `x` WHERE ((`a` = 7) AND (`b` = 2)
puts ds1.sql                        #SELECT * FROM `x` WHERE ((`a` = 1) AND (`b` = 2)
puts ds1.filter_exchange!( a: 7).sql#SELECT * FROM `x` WHERE ((`a` = 7) AND (`b` = 2)
puts ds1.sql                        #SELECT * FROM `x` WHERE ((`a` = 7) AND (`b` = 2)

filter_exchange!修改原始数据集命令!即使ds.dup.filter_exchange!也会更改您的原始选择。

使用filter_exchange,您将获得修改后的数据集。 (到目前为止测试不太好。)

答案 1 :(得分:1)

我想这不是他们的主要用例,你可能想要进行基准测试,但你可以使用bound variables

# initial args
ds1 = DB[:x].filter(a: :$a, b: :$b).bind(a: 1, b: 2)
ds1.call(:first)  # or :select, :update, et al.

# then later
ds2 = ds1.bind(a: 42)
ds2.call(:first)  # uses a = 42 and b = 2

# or pass the args directly into call()
ds2.call(:first, a: 42)

请注意,绑定变量仅在与callprepare一起使用时才会被识别,因此您不能仅使用,例如ds2.first