Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add sql_expr extension, which adds the sql_expr to all objects, givin…
…g them easy access to Sequel's DSL The sql_expr extension adds the sql_expr method to every object, which returns an object that works nicely with Sequel's DSL. This is best shown by example: 1.sql_expr < :a # 1 < a false.sql_expr & :a # FALSE AND a true.sql_expr | :a # TRUE OR a ~nil.sql_expr # NOT NULL "a".sql_expr + "b" # 'a' || 'b' This isn't possible to do in Sequel by default. I generally refrain from modifying the core classes unless necessary, which is why this is an extension instead of being included in Sequel itself. This extension also allows you to do: o = Object.new o.sql_expr < :a Of course, for this to work, you'll need to add your own extension which literalizes the object properly. You'll need to modify Dataset#literal_other to recognize the object and literalize it correctly. I'm generally against parametized specs, but I did use them in a couple instances here, since the specs are small and the behavior is identical.
- Loading branch information
1 parent
1d7580e
commit bc59602
Showing
5 changed files
with
150 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
# The sql_expr extension adds the sql_expr method to every object, which | ||
# returns an object that works nicely with Sequel's DSL. This is | ||
# best shown by example: | ||
# | ||
# 1.sql_expr < :a # 1 < a | ||
# false.sql_expr & :a # FALSE AND a | ||
# true.sql_expr | :a # TRUE OR a | ||
# ~nil.sql_expr # NOT NULL | ||
# "a".sql_expr + "b" # 'a' || 'b' | ||
|
||
module Sequel | ||
module SQL | ||
# The GenericComplexExpression acts like a | ||
# GenericExpression in terms of methods, | ||
# but has an internal structure of a | ||
# ComplexExpression. It is used by Object#sql_expr. | ||
# Since we don't know what specific type of object | ||
# we are dealing with it, we treat it similarly to | ||
# how we treat symbols or literal strings, allowing | ||
# many different types of methods. | ||
class GenericComplexExpression < ComplexExpression | ||
include AliasMethods | ||
include BooleanMethods | ||
include CastMethods | ||
include ComplexExpressionMethods | ||
include InequalityMethods | ||
include NumericMethods | ||
include OrderMethods | ||
include StringMethods | ||
include SubscriptMethods | ||
end | ||
end | ||
end | ||
|
||
class Object | ||
# Return a copy of the object wrapped in a | ||
# Sequel::SQL::GenericComplexExpression. Allows easy use | ||
# of the Object with Sequel's DSL. You'll probably have | ||
# to make sure that Sequel knows how to literalize the | ||
# object properly, though. | ||
def sql_expr | ||
Sequel::SQL::GenericComplexExpression.new(:NOOP, self) | ||
end | ||
end | ||
|
||
class FalseClass | ||
# Returns a copy of the object wrapped in a | ||
# Sequel::SQL::BooleanExpression, allowing easy use | ||
# of Sequel's DSL: | ||
# | ||
# false.sql_expr & :a # FALSE AND a | ||
def sql_expr | ||
Sequel::SQL::BooleanExpression.new(:NOOP, self) | ||
end | ||
end | ||
|
||
class NilClass | ||
# Returns a copy of the object wrapped in a | ||
# Sequel::SQL::BooleanExpression, allowing easy use | ||
# of Sequel's DSL: | ||
# | ||
# ~nil.sql_expr # NOT NULL | ||
def sql_expr | ||
Sequel::SQL::BooleanExpression.new(:NOOP, self) | ||
end | ||
end | ||
|
||
class Numeric | ||
# Returns a copy of the object wrapped in a | ||
# Sequel::SQL::NumericExpression, allowing easy use | ||
# of Sequel's DSL: | ||
# | ||
# 1.sql_expr < :a # 1 < a | ||
def sql_expr | ||
Sequel::SQL::NumericExpression.new(:NOOP, self) | ||
end | ||
end | ||
|
||
class String | ||
# Returns a copy of the object wrapped in a | ||
# Sequel::SQL::StringExpression, allowing easy use | ||
# of Sequel's DSL: | ||
# | ||
# "a".sql_expr + :a # 'a' || a | ||
def sql_expr | ||
Sequel::SQL::StringExpression.new(:NOOP, self) | ||
end | ||
end | ||
|
||
class TrueClass | ||
# Returns a copy of the object wrapped in a | ||
# Sequel::SQL::BooleanExpression, allowing easy use | ||
# of Sequel's DSL: | ||
# | ||
# true.sql_expr | :a # TRUE OR a | ||
def sql_expr | ||
Sequel::SQL::BooleanExpression.new(:NOOP, self) | ||
end | ||
end | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
require File.join(File.dirname(__FILE__), 'spec_helper') | ||
|
||
context "Sequel sql_expr extension" do | ||
specify "Object#sql_expr should wrap the object in a GenericComplexExpression" do | ||
o = Object.new | ||
s = o.sql_expr | ||
s.should be_a_kind_of(Sequel::SQL::GenericComplexExpression) | ||
s.op.should == :NOOP | ||
s.args.should == [o] | ||
(s+1).should be_a_kind_of(Sequel::SQL::NumericExpression) | ||
(s & true).should be_a_kind_of(Sequel::SQL::BooleanExpression) | ||
(s < 1).should be_a_kind_of(Sequel::SQL::BooleanExpression) | ||
s.sql_subscript(1).should be_a_kind_of(Sequel::SQL::Subscript) | ||
s.like('a').should be_a_kind_of(Sequel::SQL::BooleanExpression) | ||
s.as(:a).should be_a_kind_of(Sequel::SQL::AliasedExpression) | ||
s.cast(Integer).should be_a_kind_of(Sequel::SQL::Cast) | ||
s.desc.should be_a_kind_of(Sequel::SQL::OrderedExpression) | ||
s.sql_string.should be_a_kind_of(Sequel::SQL::StringExpression) | ||
end | ||
|
||
specify "Numeric#sql_expr should wrap the object in a NumericExpression" do | ||
[1, 2.0, 2^40, BigDecimal.new('1.0')].each do |o| | ||
s = o.sql_expr | ||
s.should be_a_kind_of(Sequel::SQL::NumericExpression) | ||
s.op.should == :NOOP | ||
s.args.should == [o] | ||
end | ||
end | ||
|
||
specify "String#sql_expr should wrap the object in a StringExpression" do | ||
o = "" | ||
s = o.sql_expr | ||
s.should be_a_kind_of(Sequel::SQL::StringExpression) | ||
s.op.should == :NOOP | ||
s.args.should == [o] | ||
end | ||
|
||
specify "NilClass, TrueClass, and FalseClass#sql_expr should wrap the object in a BooleanExpression" do | ||
[nil, true, false].each do |o| | ||
s = o.sql_expr | ||
s.should be_a_kind_of(Sequel::SQL::BooleanExpression) | ||
s.op.should == :NOOP | ||
s.args.should == [o] | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters