Skip to content

Commit

Permalink
Deprecate ParseTree filters, allow expression (blockless) filters ins…
Browse files Browse the repository at this point in the history
…ide blocks, default to ParseTree filters

ParseTree filters are now officially deprecated and are scheduled for
removal in Sequel 2.2.  They are still the default even though they
are deprecated in order to not immediately break legacy code.

To use the expression (blockless) filters inside blocks, either
set the SEQUEL_NO_PARSE_TREE constant before requiring sequel,
or use Sequel.use_parse_tree = false after requiring it.
  • Loading branch information
jeremyevans committed Jun 15, 2008
1 parent 8a592a4 commit b94bf8e
Show file tree
Hide file tree
Showing 9 changed files with 53 additions and 36 deletions.
4 changes: 1 addition & 3 deletions sequel/spec/model_spec.rb
Expand Up @@ -199,8 +199,7 @@ def d.first
end

describe Sequel::Model, ".subset" do

before(:each) do
before do
MODEL_DB.reset

@c = Class.new(Sequel::Model(:items))
Expand All @@ -219,7 +218,6 @@ def d.first
@c.pricey.sql.should == "SELECT * FROM items WHERE (price > 100)"
@c.dataset.pricey.sql.should == "SELECT * FROM items WHERE (price > 100)"

# check if subsets are composable
@c.pricey.new_only.sql.should == "SELECT * FROM items WHERE ((price > 100) AND (age = 'new'))"
@c.new_only.pricey.sql.should == "SELECT * FROM items WHERE ((age = 'new') AND (price > 100))"
end
Expand Down
2 changes: 2 additions & 0 deletions sequel_core/CHANGELOG
@@ -1,5 +1,7 @@
=== HEAD

* ParseTree support is now officially deprecated, use Sequel.use_parse_tree = false to use the expression (blockless) filters inside blocks (jeremyevans)

* Remove :pool_reuse_connections ConnectionPool/Database option, MySQL users need to be careful with nested queries (jeremyevans)

* Allow Dataset#graph :select option to take an array of columns to select (jeremyevans)
Expand Down
9 changes: 8 additions & 1 deletion sequel_core/doc/dataset_filtering.rdoc
Expand Up @@ -175,7 +175,14 @@ Array#sql_string_join also takes a join argument:

Most SQL expressions that you can can create with expressions you can also express inside blocks. This was previously the only way to specify expressions using ruby code. Filtering with blocks requires that you install ParseTree, ruby2ruby, and their dependencies. It's slower than using the equivalent expression without a block, and the syntax inside the block is different in some cases. Because it requires ParseTree, it can only be used with MRI (Matz's Ruby Interpreter) 1.8.*, as ParseTree doesn't run on any other ruby implementation (blockless filters should work on other ruby implementations).

In general, filtering with a block should only be used with legacy code. While it is not officially deprecated, usage of blocks when filtering is discouraged.
In general, filtering with a block should only be used with legacy code. ParseTree filters are currently deprecated, and support for them will be removed in Sequel 2.2. To use the expression filtering syntax inside blocks, set:

Sequel.use_parse_tree = false
# or
SEQUEL_NO_PARSE_TREE = true
require 'sequel'

These will become no-ops in Sequel 2.2, as the expression syntax inside blocks will be the only supported behavior.

To filter with a block, supply a block to filter with the appropriate ruby code:

Expand Down
14 changes: 13 additions & 1 deletion sequel_core/lib/sequel_core.rb
Expand Up @@ -2,7 +2,7 @@
require f
end
%w"core_ext sql core_sql connection_pool exceptions pretty_table
dataset migration schema database worker object_graph".each do |f|
dataset migration schema database worker object_graph deprecated".each do |f|
require "sequel_core/#{f}"
end

Expand All @@ -26,9 +26,21 @@
# database. It defaults to Time. To change it to DateTime, use:
#
# Sequel.datetime_class = DateTime
#
# Sequel can either use ParseTree for block filters (deprecated but works),
# or it can use the block filter syntax inside block filters (which will
# be the only behavior allowed in Sequel 2.2). To set it not to use
# ParseTree filters:
#
# Sequel.use_parse_tree = false
module Sequel
@datetime_class = Time
@use_parse_tree = true

metaattr_accessor :datetime_class
metaattr_accessor :use_parse_tree

Deprecation.deprecation_message_stream = $stderr

# Creates a new database object based on the supplied connection string
# and optional arguments. The specified scheme determines the database
Expand Down
8 changes: 3 additions & 5 deletions sequel_core/lib/sequel_core/dataset/sequelizer.rb
@@ -1,8 +1,10 @@
begin
raise LoadError if defined?(SEQUEL_NO_PARSE_TREE)
require 'parse_tree'
require 'sequel_core/dataset/parse_tree_sequelizer'
class Proc
def to_sql(dataset, opts = {})
Sequel::Deprecation.deprecate("ParseTree filters are deprecated and will be removed in Sequel 2.2")
dataset.send(:pt_expr, to_sexp[2], self.binding, opts)
end
end
Expand Down Expand Up @@ -43,9 +45,5 @@ def to_sexp
end
end
rescue LoadError
class Proc
def to_sql(*args)
raise Sequel::Error, "You must have the ParseTree gem installed in order to use block filters."
end
end
Sequel.use_parse_tree = false
end
2 changes: 1 addition & 1 deletion sequel_core/lib/sequel_core/dataset/sql.rb
Expand Up @@ -767,7 +767,7 @@ def filter_expr(expr)
SQL::BooleanExpression.from_value_pairs(expr)
end
when Proc
expr.to_sql(self).lit
Sequel.use_parse_tree ? expr.to_sql(self).lit : filter_expr(expr.call)
when SQL::NumericExpression, SQL::StringExpression
raise(Error, "Invalid SQL Expression type: #{expr.inspect}")
when Symbol, SQL::Expression
Expand Down
6 changes: 0 additions & 6 deletions sequel_core/lib/sequel_core/deprecated.rb
Expand Up @@ -22,11 +22,5 @@ def self.deprecate(message)
caller.each{|c| @dms.puts(c)} if @pt
end
end

# Formats the message with a message that it will be removed in Sequel 2.0.
# This is the method that is added to the classes that include Sequel::Deprecation.
def deprecate(meth, message = nil)
::Sequel::Deprecation.deprecate("#{meth} is deprecated, and will be removed in Sequel 2.0.#{" #{message}." if message}")
end
end
end
19 changes: 17 additions & 2 deletions sequel_core/spec/blockless_filters_spec.rb
Expand Up @@ -5,13 +5,21 @@
db = Sequel::Database.new
db.quote_identifiers = false
@d = db[:items]
def @d.l(*args)
literal(filter_expr(*args))
def @d.l(*args, &block)
if block_given?
literal(filter_expr(Proc.new(&block)))
else
literal(filter_expr(*args))
end
end
def @d.lit(*args)
literal(*args)
end
end

after do
Sequel.use_parse_tree = true
end

it "should support boolean columns directly" do
@d.l(:x).should == 'x'
Expand Down Expand Up @@ -294,4 +302,11 @@ def @d.lit(*args)
@d.lit([:x].sql_string_join + :y).should == '((x) || y)'
@d.lit([:x, :z].sql_string_join(' ') + :y).should == "((x || ' ' || z) || y)"
end

it "should be supported inside blocks if Sequel.use_parse_tree = false" do
@d.l{[[:x, nil], [:y, [1,2,3]]].sql_or}.should == '((x IS NULL) OR (y IN (1, 2, 3)))'
@d.l{~[[:x, nil], [:y, [1,2,3]]]}.should == '((x IS NOT NULL) OR (y NOT IN (1, 2, 3)))'
@d.l{~(((('x'.lit - :y)/(:x + :y))*:z) <= 100)}.should == '((((x - y) / (x + y)) * z) > 100)'
@d.l{{:x => :a} & {:y => :z}}.should == '((x = a) AND (y = z))'
end
end
25 changes: 8 additions & 17 deletions sequel_core/spec/sequelizer_spec.rb
Expand Up @@ -2,30 +2,21 @@

context "Sequelizer without ParseTree" do
setup do
module Kernel
alias_method :orig_sq_require, :require
def require(*args); raise LoadError; end
end
old_verbose = $VERBOSE
$VERBOSE = nil
load(File.join(File.dirname(__FILE__), '../lib/sequel_core/dataset/sequelizer.rb'))
$VERBOSE = old_verbose
Sequel.use_parse_tree = false
@db = Sequel::Database.new
@ds = @db[:items]
end

teardown do
module Kernel
alias_method :require, :orig_sq_require
end
old_verbose = $VERBOSE
$VERBOSE = nil
load(File.join(File.dirname(__FILE__), '../lib/sequel_core/dataset/sequelizer.rb'))
$VERBOSE = old_verbose
Sequel.use_parse_tree = true
end

specify "should raise error when converting proc to SQL" do
proc {proc {:x > 1}.to_sql(@ds)}.should raise_error(Sequel::Error)
specify "should raise error when converting ParseTree proc to SQL" do
proc {@ds.filter{:x == 1}}.should raise_error(Sequel::Error)
end

specify "should allow expression syntax inside block raise error when converting ParseTree proc to SQL" do
proc {@ds.filter{:x > 1}}.should_not raise_error(Sequel::Error)
end
end

Expand Down

0 comments on commit b94bf8e

Please sign in to comment.