sequel 0.3.3 → 0.3.4.1

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG CHANGED
@@ -1,3 +1,23 @@
1
+ === 0.3.4.1 (2007-11-10)
2
+
3
+ * Changed Dataset#select_sql to support queries without a FROM clause.
4
+
5
+ === 0.3.4 (2007-11-10)
6
+
7
+ * Fixed MySQL adapter to allow calling stored procedures (thanks Sebastian).
8
+
9
+ * Changed Dataset#each to always return self.
10
+
11
+ * Fixed SQL functions without arguments in block filters.
12
+
13
+ * Implemented super-cool Symbol#cast_as method.
14
+
15
+ * Fixed error message in command-line tool if failed to load adapter (#85).
16
+
17
+ * Refactored code relating to column references for better extendibility (#88).
18
+
19
+ * Tiny fix to Model#run_hooks.
20
+
1
21
  === 0.3.3 (2007-11-04)
2
22
 
3
23
  * Revised code to generate SQL statements without trailing semicolons.
data/README CHANGED
@@ -28,11 +28,13 @@ If you have any comments or suggestions please send an email to ciconia at gmail
28
28
 
29
29
  Sequel currently supports:
30
30
 
31
- * Postgresql
32
- * SQLite 3
31
+ * ADO (on Windows)
33
32
  * DBI
34
- * ODBC
35
33
  * MySQL
34
+ * ODBC
35
+ * Oracle
36
+ * PostgreSQL
37
+ * SQLite 3
36
38
 
37
39
  == The Sequel Console
38
40
 
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ require 'fileutils'
6
6
  include FileUtils
7
7
 
8
8
  NAME = "sequel"
9
- VERS = "0.3.3"
9
+ VERS = "0.3.4.1"
10
10
  CLEAN.include ['**/.*.sw?', 'pkg/*', '.config', 'doc/*', 'coverage/*']
11
11
  RDOC_OPTS = ['--quiet', '--title', "Sequel: Concise ORM for Ruby",
12
12
  "--opname", "index.html",
data/bin/sequel CHANGED
@@ -24,8 +24,8 @@ end
24
24
  begin
25
25
  scheme = URI.parse(db).scheme
26
26
  require File.join('sequel', scheme)
27
- rescue LoadError
28
- puts "Invalid adapter specified: #{scheme}"
27
+ rescue LoadError => e
28
+ puts "Failed to load #{scheme} adapter: #{e.message}"
29
29
  exit
30
30
  rescue => e
31
31
  puts e.message
@@ -1,7 +1,7 @@
1
1
  require 'metaid'
2
2
 
3
3
  files = %w[
4
- core_ext array_keys error connection_pool pretty_table
4
+ core_ext core_sql array_keys error connection_pool pretty_table
5
5
  dataset migration model schema database worker
6
6
  ]
7
7
  dir = File.join(File.dirname(__FILE__), 'sequel')
@@ -208,6 +208,7 @@ module ArrayKeys
208
208
  else
209
209
  fetch_rows(select_sql(opts)) {|r| block[@row_proc[transform_load(Array.from_hash(r))]]}
210
210
  end
211
+ self
211
212
  end
212
213
  end
213
214
  elsif @row_proc
@@ -218,18 +219,21 @@ module ArrayKeys
218
219
  else
219
220
  fetch_rows(select_sql(opts)) {|r| block[@row_proc[Array.from_hash(r)]]}
220
221
  end
222
+ self
221
223
  end
222
224
  end
223
225
  elsif @transform
224
226
  class << self
225
227
  def each(opts = nil, &block)
226
228
  fetch_rows(select_sql(opts)) {|r| block[transform_load(Array.from_hash(r))]}
229
+ self
227
230
  end
228
231
  end
229
232
  else
230
233
  class << self
231
234
  def each(opts = nil, &block)
232
235
  fetch_rows(select_sql(opts)) {|r| block[Array.from_hash(r)]}
236
+ self
233
237
  end
234
238
  end
235
239
  end
@@ -7,16 +7,6 @@ module Enumerable
7
7
  end
8
8
  end
9
9
 
10
- # Array extensions
11
- class Array
12
- # Concatenates an array of strings into an SQL string. ANSI SQL and C-style
13
- # comments are removed, as well as excessive white-space.
14
- def to_sql
15
- map {|l| (l =~ /^(.*)--/ ? $1 : l).chomp}.join(' '). \
16
- gsub(/\/\*.*\*\//, '').gsub(/\s+/, ' ').strip
17
- end
18
- end
19
-
20
10
  # Range extensions
21
11
  class Range
22
12
  # Returns the interval between the beginning and end of the range.
@@ -25,133 +15,11 @@ class Range
25
15
  end
26
16
  end
27
17
 
28
- module Sequel
29
- # LiteralString is used to represent literal SQL expressions. An
30
- # LiteralString is copied verbatim into an SQL statement. Instances of
31
- # LiteralString can be created by calling String#expr.
32
- class LiteralString < ::String
33
- end
34
- end
35
-
36
- # String extensions
37
- class String
38
- # Converts a string into an SQL string by removing comments.
39
- # See also Array#to_sql.
40
- def to_sql
41
- split($/).to_sql
42
- end
43
-
44
- # Splits a string into separate SQL statements, removing comments
45
- # and excessive white-space.
46
- def split_sql
47
- to_sql.split(';').map {|s| s.strip}
48
- end
49
-
50
- # Converts a string into an LiteralString, in order to override string
51
- # literalization, e.g.:
52
- #
53
- # DB[:items].filter(:abc => 'def').sql #=>
54
- # "SELECT * FROM items WHERE (abc = 'def')"
55
- #
56
- # DB[:items].filter(:abc => 'def'.lit).sql #=>
57
- # "SELECT * FROM items WHERE (abc = def)"
58
- #
59
- def lit
60
- Sequel::LiteralString.new(self)
61
- end
62
-
63
- alias_method :expr, :lit
64
-
65
- # Converts a string into a Time object.
66
- def to_time
67
- Time.parse(self)
68
- end
69
-
70
- # Converts a string into a column name.
71
- def to_field_name
72
- self
73
- end
74
- alias_method :to_column_name, :to_field_name
75
- end
76
-
77
- # Methods to format column names and associated constructs. This module is
78
- # included in String and Symbol.
79
- module ColumnCompositionMethods
80
- # Constructs a DESC clause for use in an ORDER BY clause.
81
- def DESC
82
- "#{to_column_name} DESC".lit
83
- end
84
-
85
- # Constructs an AS clause for column aliasing.
86
- def AS(target)
87
- "#{to_column_name} AS #{target}".lit
88
- end
89
-
90
- # Constructs a qualified wildcard (*) clause.
91
- def ALL
92
- "#{to_s}.*".lit
93
- end
94
-
95
- COLUMN_TITLE_RE1 = /^(.*)\sAS\s(.+)$/i.freeze
96
- COLUMN_TITLE_RE2 = /^([^\.]+)\.([^\.]+)$/.freeze
97
-
98
- # Returns the column name. If the column name is aliased, the alias is
99
- # returned.
100
- def field_title
101
- case s = to_column_name
102
- when COLUMN_TITLE_RE1, COLUMN_TITLE_RE2: $2
103
- else
104
- s
105
- end
106
- end
107
- alias_method :column_title, :field_title
108
- end
109
-
110
- # String extensions
111
- class String
112
- include ColumnCompositionMethods
113
- end
114
-
115
- # Symbol extensions
116
- class Symbol
117
- include ColumnCompositionMethods
118
-
119
-
120
- COLUMN_REF_RE1 = /^(\w+)__(\w+)___(\w+)/.freeze
121
- COLUMN_REF_RE2 = /^(\w+)___(\w+)$/.freeze
122
- COLUMN_REF_RE3 = /^(\w+)__(\w+)$/.freeze
123
-
124
- # Converts a symbol into a column name. This method supports underscore
125
- # notation in order to express qualified (two underscores) and aliased
126
- # (three underscores) columns:
127
- #
128
- # :abc.to_column_name #=> "abc"
129
- # :abc___a.to_column_name #=> "abc AS a"
130
- # :items__abc.to_column_name #=> "items.abc"
131
- # :items__abc___a.to_column_name #=> "items.abc AS a"
132
- #
133
- def to_field_name
134
- s = to_s
135
- case s
136
- when COLUMN_REF_RE1: "#{$1}.#{$2} AS #{$3}"
137
- when COLUMN_REF_RE2: "#{$1} AS #{$2}"
138
- when COLUMN_REF_RE3: "#{$1}.#{$2}"
139
- else
140
- s
141
- end
142
- end
143
- alias_method :to_column_name, :to_field_name
144
-
145
- # Converts missing method calls into functions on columns, if the
146
- # method name is made of all upper case letters.
147
- def method_missing(sym)
148
- ((s = sym.to_s) =~ /^([A-Z]+)$/) ? \
149
- "#{s.downcase}(#{to_column_name})".lit : super
150
- end
151
-
152
- # Formats an SQL function with optional parameters
153
- def [](*args)
154
- "#{to_s}(#{args.join(', ')})".lit
18
+ # Object extensions
19
+ class Object
20
+ def is_one_of?(*classes)
21
+ classes.each {|c| return c if is_a?(c)}
22
+ nil
155
23
  end
156
24
  end
157
25
 
@@ -0,0 +1,151 @@
1
+ # Array extensions
2
+ class Array
3
+ # Concatenates an array of strings into an SQL string. ANSI SQL and C-style
4
+ # comments are removed, as well as excessive white-space.
5
+ def to_sql
6
+ map {|l| (l =~ /^(.*)--/ ? $1 : l).chomp}.join(' '). \
7
+ gsub(/\/\*.*\*\//, '').gsub(/\s+/, ' ').strip
8
+ end
9
+ end
10
+
11
+ module Sequel
12
+ # LiteralString is used to represent literal SQL expressions. An
13
+ # LiteralString is copied verbatim into an SQL statement. Instances of
14
+ # LiteralString can be created by calling String#expr.
15
+ class LiteralString < ::String
16
+ end
17
+ end
18
+
19
+ # String extensions
20
+ class String
21
+ # Converts a string into an SQL string by removing comments.
22
+ # See also Array#to_sql.
23
+ def to_sql
24
+ split($/).to_sql
25
+ end
26
+
27
+ # Splits a string into separate SQL statements, removing comments
28
+ # and excessive white-space.
29
+ def split_sql
30
+ to_sql.split(';').map {|s| s.strip}
31
+ end
32
+
33
+ # Converts a string into an LiteralString, in order to override string
34
+ # literalization, e.g.:
35
+ #
36
+ # DB[:items].filter(:abc => 'def').sql #=>
37
+ # "SELECT * FROM items WHERE (abc = 'def')"
38
+ #
39
+ # DB[:items].filter(:abc => 'def'.lit).sql #=>
40
+ # "SELECT * FROM items WHERE (abc = def)"
41
+ #
42
+ def lit
43
+ Sequel::LiteralString.new(self)
44
+ end
45
+
46
+ alias_method :expr, :lit
47
+
48
+ # Converts a string into a Time object.
49
+ def to_time
50
+ Time.parse(self)
51
+ end
52
+ end
53
+
54
+
55
+ module Sequel
56
+ module SQL
57
+ class Expression
58
+ def lit; self; end
59
+ end
60
+
61
+ class ColumnExpr < Expression
62
+ def initialize(l, op, r = nil); @l, @op, @r = l, op, r; end
63
+
64
+ def to_s(ds)
65
+ @r ? \
66
+ "#{ds.literal(@l)} #{@op} #{ds.literal(@r)}" : \
67
+ "#{ds.literal(@l)} #{@op}"
68
+ end
69
+ end
70
+
71
+ class Function < Expression
72
+ def initialize(f, *args); @f, @args = f, args; end
73
+
74
+ def to_s(ds)
75
+ args = @args.empty? ? '' : ds.literal(@args)
76
+ "#{@f}(#{args})"
77
+ end
78
+ end
79
+
80
+ class ColumnAll < Expression
81
+ def initialize(t); @t = t; end
82
+ def to_s(ds); "#{@t}.*"; end
83
+ end
84
+
85
+ module ColumnMethods
86
+ AS = 'AS'.freeze
87
+ DESC = 'DESC'.freeze
88
+ ASC = 'ASC'.freeze
89
+
90
+ def as(a); ColumnExpr.new(self, AS, a); end
91
+ alias_method :AS, :as
92
+
93
+ def desc; ColumnExpr.new(self, DESC); end
94
+ alias_method :DESC, :desc
95
+
96
+ def asc; ColumnExpr.new(self, ASC); end
97
+ alias_method :ASC, :asc
98
+
99
+ def all; Sequel::SQL::ColumnAll.new(self); end
100
+ alias_method :ALL, :all
101
+
102
+ def cast_as(t)
103
+ if t.is_a?(Symbol)
104
+ t = t.to_s.lit
105
+ end
106
+ Sequel::SQL::Function.new(:cast, self.as(t))
107
+ end
108
+ end
109
+ end
110
+ end
111
+
112
+ class Object
113
+ include Sequel::SQL::ColumnMethods
114
+ end
115
+
116
+ class Symbol
117
+ def [](*args); Sequel::SQL::Function.new(self, *args); end
118
+
119
+ COLUMN_REF_RE1 = /^(\w+)__(\w+)___(\w+)/.freeze
120
+ COLUMN_REF_RE2 = /^(\w+)___(\w+)$/.freeze
121
+ COLUMN_REF_RE3 = /^(\w+)__(\w+)$/.freeze
122
+
123
+ # Converts a symbol into a column name. This method supports underscore
124
+ # notation in order to express qualified (two underscores) and aliased
125
+ # (three underscores) columns:
126
+ #
127
+ # ds = DB[:items]
128
+ # :abc.to_column_ref(ds) #=> "abc"
129
+ # :abc___a.to_column_ref(ds) #=> "abc AS a"
130
+ # :items__abc.to_column_ref(ds) #=> "items.abc"
131
+ # :items__abc___a.to_column_ref(ds) #=> "items.abc AS a"
132
+ #
133
+ def to_column_ref(ds)
134
+ case s = to_s
135
+ when COLUMN_REF_RE1: "#{$1}.#{ds.quote_column_ref($2)} AS #{ds.quote_column_ref($3)}"
136
+ when COLUMN_REF_RE2: "#{ds.quote_column_ref($1)} AS #{ds.quote_column_ref($2)}"
137
+ when COLUMN_REF_RE3: "#{$1}.#{ds.quote_column_ref($2)}"
138
+ else ds.quote_column_ref(s)
139
+ end
140
+ end
141
+
142
+ # Converts missing method calls into functions on columns, if the
143
+ # method name is made of all upper case letters.
144
+ def method_missing(sym)
145
+ if ((s = sym.to_s) =~ /^([A-Z]+)$/)
146
+ Sequel::SQL::Function.new(s.downcase, self)
147
+ else
148
+ super
149
+ end
150
+ end
151
+ end
@@ -161,6 +161,7 @@ module Sequel
161
161
  # Iterates over the records in the dataset
162
162
  def each(opts = nil, &block)
163
163
  fetch_rows(select_sql(opts), &block)
164
+ self
164
165
  end
165
166
 
166
167
  # Returns the the model classes associated with the dataset as a hash.
@@ -347,6 +348,7 @@ module Sequel
347
348
  else
348
349
  fetch_rows(select_sql(opts)) {|r| block[@row_proc[transform_load(r)]]}
349
350
  end
351
+ self
350
352
  end
351
353
  end
352
354
  elsif @row_proc
@@ -357,18 +359,21 @@ module Sequel
357
359
  else
358
360
  fetch_rows(select_sql(opts)) {|r| block[@row_proc[r]]}
359
361
  end
362
+ self
360
363
  end
361
364
  end
362
365
  elsif @transform
363
366
  class << self
364
367
  def each(opts = nil, &block)
365
368
  fetch_rows(select_sql(opts)) {|r| block[transform_load(r)]}
369
+ self
366
370
  end
367
371
  end
368
372
  else
369
373
  class << self
370
374
  def each(opts = nil, &block)
371
375
  fetch_rows(select_sql(opts), &block)
376
+ self
372
377
  end
373
378
  end
374
379
  end
@@ -108,7 +108,8 @@ class Sequel::Dataset
108
108
  when :>, :<, :>=, :<=
109
109
  l = eval_expr(e[1], b)
110
110
  r = eval_expr(e[3][1], b)
111
- if (Symbol === l) || (Sequel::LiteralString === l) || (Symbol === r) || (Sequel::LiteralString === r)
111
+ if l.is_one_of?(Symbol, Sequel::LiteralString, Sequel::SQL::Expression) || \
112
+ r.is_one_of?(Symbol, Sequel::LiteralString, Sequel::SQL::Expression)
112
113
  "(#{literal(l)} #{op} #{literal(r)})"
113
114
  else
114
115
  ext_expr(e, b)
@@ -124,7 +125,8 @@ class Sequel::Dataset
124
125
  when :+, :-, :*, :/, :%
125
126
  l = eval_expr(e[1], b)
126
127
  r = eval_expr(e[3][1], b)
127
- if (Symbol === l) || (Sequel::LiteralString === l) || (Symbol === r) || (Sequel::LiteralString === r)
128
+ if l.is_one_of?(Symbol, Sequel::LiteralString, Sequel::SQL::Expression) || \
129
+ r.is_one_of?(Symbol, Sequel::LiteralString, Sequel::SQL::Expression)
128
130
  "(#{literal(l)} #{op} #{literal(r)})".lit
129
131
  else
130
132
  ext_expr(e, b)
@@ -146,7 +148,11 @@ class Sequel::Dataset
146
148
  else
147
149
  if (op == :[]) && (e[1][0] == :lit) && (Symbol === e[1][1])
148
150
  # SQL Functions, e.g.: :sum[:x]
149
- e[1][1][*pt_expr(e[3], b)]
151
+ if e[3]
152
+ e[1][1][*eval_expr(e[3], b)]
153
+ else
154
+ e[1][1][]
155
+ end
150
156
  else
151
157
  # external code
152
158
  ext_expr(e, b)
@@ -3,26 +3,10 @@ module Sequel
3
3
  # The Dataset SQL module implements all the dataset methods concerned with
4
4
  # generating SQL statements for retrieving and manipulating records.
5
5
  module SQL
6
- # Returns a valid SQL column name as a string. Column names specified as
7
- # symbols can include double underscores to denote a dot separator, e.g.
8
- # :posts__id will be converted into posts.id.
9
- def column_name(column)
10
- case column
11
- when Symbol, String:
12
- quoted_column_name(column.to_column_name)
13
- when Hash:
14
- column.map {|f,a| "#{column_name(f)} AS #{column_name(a)}"}.join(COMMA_SEPARATOR)
15
- else
16
- column
17
- end
18
- end
19
-
20
6
  # Adds quoting to column references. This method is just a stub and can
21
7
  # be overriden in adapters in order to provide correct column quoting
22
8
  # behavior.
23
- def quoted_column_name(name)
24
- name
25
- end
9
+ def quote_column_ref(name); name.to_s; end
26
10
 
27
11
  ALIASED_REGEXP = /^(.*)\s(.*)$/.freeze
28
12
  QUALIFIED_REGEXP = /^(.*)\.(.*)$/.freeze
@@ -30,7 +14,7 @@ module Sequel
30
14
  # Returns a qualified column name (including a table name) if the column
31
15
  # name isn't already qualified.
32
16
  def qualified_column_name(column, table)
33
- column = column_name(column)
17
+ column = literal(column)
34
18
  if column =~ QUALIFIED_REGEXP
35
19
  # column is already qualified
36
20
  column
@@ -105,7 +89,8 @@ module Sequel
105
89
  when NilClass: NULL
106
90
  when TrueClass: TRUE
107
91
  when FalseClass: FALSE
108
- when Symbol: quoted_column_name(v.to_column_name)
92
+ when Symbol: v.to_column_ref(self)
93
+ when Sequel::SQL::Expression: v.to_s(self)
109
94
  when Array: v.empty? ? NULL : v.map {|i| literal(i)}.join(COMMA_SEPARATOR)
110
95
  when Time: v.strftime(TIMESTAMP_FORMAT)
111
96
  when Date: v.strftime(DATE_FORMAT)
@@ -170,20 +155,25 @@ module Sequel
170
155
  order(*invert_order(order.empty? ? @opts[:order] : order))
171
156
  end
172
157
 
173
- DESC_ORDER_REGEXP = /(.*)\sDESC/i.freeze
158
+ DESC_ORDER_REGEXP = /^(.*)\sDESC$/i.freeze
174
159
 
175
160
  # Inverts the given order by breaking it into a list of column references
176
161
  # and inverting them.
177
162
  #
178
- # dataset.invert_order('id DESC') #=> "id"
179
- # dataset.invert_order('category, price DESC') #=>
180
- # "category DESC, price"
163
+ # dataset.invert_order(['id DESC']) #=> ["id"]
164
+ # dataset.invert_order(['category, price DESC']) #=>
165
+ # ["category DESC, price"]
181
166
  def invert_order(order)
182
167
  new_order = []
183
168
  order.each do |f|
184
- f.to_s.split(',').map do |p|
185
- p.strip!
186
- new_order << ((p =~ DESC_ORDER_REGEXP ? $1 : p.to_sym.DESC).lit)
169
+ if f.is_a?(String)
170
+ f.split(',').each do |r|
171
+ r.strip!
172
+ new_order << ((r =~ DESC_ORDER_REGEXP ? $1 : r.to_sym.desc).lit)
173
+ end
174
+ else
175
+ r = literal(f).strip
176
+ new_order << ((r =~ DESC_ORDER_REGEXP ? $1 : r.to_sym.desc).lit)
187
177
  end
188
178
  end
189
179
  new_order
@@ -381,10 +371,13 @@ module Sequel
381
371
 
382
372
  columns = opts[:select]
383
373
  select_columns = columns ? column_list(columns) : WILDCARD
384
- select_source = source_list(opts[:from])
385
374
  sql = opts[:distinct] ? \
386
- "SELECT DISTINCT #{select_columns} FROM #{select_source}" : \
387
- "SELECT #{select_columns} FROM #{select_source}"
375
+ "SELECT DISTINCT #{select_columns}" : \
376
+ "SELECT #{select_columns}"
377
+
378
+ if opts[:from]
379
+ sql << " FROM #{source_list(opts[:from])}"
380
+ end
388
381
 
389
382
  if join = opts[:join]
390
383
  sql << join
@@ -460,7 +453,7 @@ module Sequel
460
453
  "INSERT INTO #{@opts[:from]} DEFAULT VALUES"
461
454
  else
462
455
  fl, vl = [], []
463
- values.each {|k, v| fl << column_name(k); vl << literal(v)}
456
+ values.each {|k, v| fl << literal(k); vl << literal(v)}
464
457
  "INSERT INTO #{@opts[:from]} (#{fl.join(COMMA_SEPARATOR)}) VALUES (#{vl.join(COMMA_SEPARATOR)})"
465
458
  end
466
459
  when Dataset
@@ -488,7 +481,7 @@ module Sequel
488
481
  values = values.to_hash
489
482
  end
490
483
  values = transform_save(values) if @transform
491
- set_list = values.map {|k, v| "#{column_name(k)} = #{literal(v)}"}.
484
+ set_list = values.map {|k, v| "#{literal(k)} = #{literal(v)}"}.
492
485
  join(COMMA_SEPARATOR)
493
486
  sql = "UPDATE #{@opts[:from]} SET #{set_list}"
494
487
 
@@ -116,7 +116,7 @@ module Sequel
116
116
 
117
117
  # Evaluates specified chain of Hooks through <tt>instance_eval</tt>.
118
118
  def run_hooks(key)
119
- model.hooks[key].each { |h| instance_eval &h }
119
+ model.hooks[key].each {|h| instance_eval(&h)}
120
120
  end
121
121
 
122
122
  def self.has_hooks?(key)
@@ -93,7 +93,7 @@ module Sequel
93
93
 
94
94
  def connect
95
95
  conn = Mysql.real_connect(@opts[:host], @opts[:user], @opts[:password],
96
- @opts[:database], @opts[:port])
96
+ @opts[:database], @opts[:port], nil, Mysql::CLIENT_MULTI_RESULTS)
97
97
  conn.query_with_result = false
98
98
  if encoding = @opts[:encoding] || @opts[:charset]
99
99
  conn.query("set character_set_connection = '#{encoding}'")
@@ -172,31 +172,14 @@ module Sequel
172
172
  end
173
173
 
174
174
  class Dataset < Sequel::Dataset
175
- UNQUOTABLE_COLUMN_RE = /^(`(.+)`)|\*$/.freeze
176
- def quote_column(f)
177
- (f.nil? || f.empty? || f =~ UNQUOTABLE_COLUMN_RE) ? f : "`#{f}`"
178
- end
179
-
180
- COLUMN_EXPR_RE = /^([^\(]+\()?([^\.]+\.)?([^\s\)]+)?(\))?(\sAS\s(.+))?$/i.freeze
181
- COLUMN_ORDER_RE = /^(.*) (DESC|ASC)$/i.freeze
182
- def quoted_column_name(name)
183
- case name
184
- when COLUMN_EXPR_RE:
185
- $6 ? \
186
- "#{$1}#{$2}#{quote_column($3)}#{$4} AS #{quote_column($6)}" : \
187
- "#{$1}#{$2}#{quote_column($3)}#{$4}"
188
- when COLUMN_ORDER_RE: "#{quote_column($1)} #{$2}"
189
- else
190
- quote_column(name)
191
- end
192
- end
175
+ def quote_column_ref(c); "`#{c}`"; end
193
176
 
194
177
  TRUE = '1'
195
178
  FALSE = '0'
196
179
 
197
180
  def literal(v)
198
181
  case v
199
- when LiteralString: quoted_column_name(v)
182
+ when LiteralString: v
200
183
  when String: "'#{v.gsub(/'|\\/, '\&\&')}'"
201
184
  when true: TRUE
202
185
  when false: FALSE
@@ -97,17 +97,29 @@ context "A MySQL dataset" do
97
97
  @d.order(:name.DESC).sql.should == \
98
98
  'SELECT * FROM items ORDER BY `name` DESC'
99
99
 
100
- @d.select('items.name AS item_name'.to_sym).sql.should == \
101
- 'SELECT items.`name` AS `item_name` FROM items'
100
+ @d.select('items.name AS item_name'.lit).sql.should == \
101
+ 'SELECT items.name AS item_name FROM items'
102
102
 
103
103
  @d.select('`name`'.lit).sql.should == \
104
104
  'SELECT `name` FROM items'
105
105
 
106
106
  @d.select('max(items.`name`) AS `max_name`'.lit).sql.should == \
107
107
  'SELECT max(items.`name`) AS `max_name` FROM items'
108
+
109
+ @d.select(:test[:abc, 'hello']).sql.should == \
110
+ "SELECT test(`abc`, 'hello') FROM items"
111
+
112
+ @d.select(:test[:abc__def, 'hello']).sql.should == \
113
+ "SELECT test(abc.`def`, 'hello') FROM items"
114
+
115
+ @d.select(:test[:abc__def, 'hello'].as(:x2)).sql.should == \
116
+ "SELECT test(abc.`def`, 'hello') AS `x2` FROM items"
108
117
 
109
118
  @d.insert_sql(:value => 333).should == \
110
119
  'INSERT INTO items (`value`) VALUES (333)'
120
+
121
+ @d.insert_sql(:x => :y).should == \
122
+ 'INSERT INTO items (`x`) VALUES (`y`)'
111
123
  end
112
124
 
113
125
  specify "should support ORDER clause in UPDATE statements" do
@@ -188,3 +200,37 @@ context "A MySQL dataset in array tuples mode" do
188
200
  a[:value].should == '123'
189
201
  end
190
202
  end
203
+
204
+ context "MySQL datasets" do
205
+ setup do
206
+ @d = MYSQL_DB[:orders]
207
+ end
208
+
209
+ specify "should correctly quote column references" do
210
+ market = 'ICE'
211
+ ack_stamp = Time.now - 15 * 60 # 15 minutes ago
212
+ @d.query do
213
+ select :market, :minute[:from_unixtime[:ack]].as(:minute)
214
+ where do
215
+ :ack > ack_stamp
216
+ :market == market
217
+ end
218
+ group_by :minute[:from_unixtime[:ack]]
219
+ end.sql.should == \
220
+ "SELECT `market`, minute(from_unixtime(`ack`)) AS `minute` FROM orders WHERE ((`ack` > #{@d.literal(ack_stamp)}) AND (`market` = 'ICE')) GROUP BY minute(from_unixtime(`ack`))"
221
+ end
222
+ end
223
+
224
+ context "Simple stored procedure test" do
225
+ setup do
226
+ # Create a simple stored procedure but drop it first if there
227
+ MYSQL_DB.execute("DROP PROCEDURE IF EXISTS sp_get_server_id;")
228
+ MYSQL_DB.execute("CREATE PROCEDURE sp_get_server_id() SQL SECURITY DEFINER SELECT @@SERVER_ID as server_id;")
229
+ end
230
+
231
+ specify "should return the server-id via a stored procedure call" do
232
+ @server_id = MYSQL_DB["SELECT @@SERVER_ID as server_id;"].first[:server_id] # grab the server_id via a simple query
233
+ @server_id_by_sp = MYSQL_DB["CALL sp_get_server_id();"].first[:server_id]
234
+ @server_id_by_sp.should == @server_id # compare it to output from stored procedure
235
+ end
236
+ end
@@ -8,92 +8,6 @@ context "Enumerable#send_each" do
8
8
  end
9
9
  end
10
10
 
11
- context "Array#to_sql" do
12
- specify "should concatenate multiple lines into a single string" do
13
- "SELECT * \r\nFROM items\r\n WHERE a = 1".split.to_sql. \
14
- should == 'SELECT * FROM items WHERE a = 1'
15
- end
16
-
17
- specify "should remove superfluous white space and line breaks" do
18
- "\tSELECT * \n FROM items ".split.to_sql. \
19
- should == 'SELECT * FROM items'
20
- end
21
-
22
- specify "should remove ANSI SQL comments" do
23
- "SELECT * --comment\r\n FROM items\r\n --comment".split.to_sql. \
24
- should == 'SELECT * FROM items'
25
- end
26
-
27
- specify "should remove C-style comments" do
28
- "SELECT * \r\n /* comment comment\r\n comment\r\n FROM items */\r\n FROM items\r\n--comment".split.to_sql. \
29
- should == 'SELECT * FROM items'
30
- end
31
- end
32
-
33
- context "String#to_sql" do
34
- specify "should concatenate multiple lines into a single string" do
35
- "SELECT * \r\nFROM items\r\nWHERE a = 1".to_sql. \
36
- should == 'SELECT * FROM items WHERE a = 1'
37
- end
38
-
39
- specify "should remove superfluous white space and line breaks" do
40
- "\tSELECT * \r\n FROM items ".to_sql. \
41
- should == 'SELECT * FROM items'
42
- end
43
-
44
- specify "should remove ANSI SQL comments" do
45
- "SELECT * --comment \r\n FROM items\r\n --comment".to_sql. \
46
- should == 'SELECT * FROM items'
47
- end
48
-
49
- specify "should remove C-style comments" do
50
- "SELECT * \r\n/* comment comment\r\ncomment\r\nFROM items */\r\nFROM items\r\n--comment".to_sql. \
51
- should == 'SELECT * FROM items'
52
- end
53
- end
54
-
55
- context "String#lit" do
56
- specify "should return an LiteralString object" do
57
- 'xyz'.lit.should be_a_kind_of(Sequel::LiteralString)
58
- 'xyz'.lit.to_s.should == 'xyz'
59
- end
60
-
61
- specify "should inhibit string literalization" do
62
- db = Sequel::Database.new
63
- ds = db[:t]
64
-
65
- ds.update_sql(:stamp => "NOW()".lit).should == \
66
- "UPDATE t SET stamp = NOW()"
67
- end
68
- end
69
-
70
- context "String#expr" do
71
- specify "should return an LiteralString object" do
72
- 'xyz'.expr.should be_a_kind_of(Sequel::LiteralString)
73
- 'xyz'.expr.to_s.should == 'xyz'
74
- end
75
-
76
- specify "should inhibit string literalization" do
77
- db = Sequel::Database.new
78
- ds = db[:t]
79
-
80
- ds.update_sql(:stamp => "NOW()".expr).should == \
81
- "UPDATE t SET stamp = NOW()"
82
- end
83
- end
84
-
85
- context "String#split_sql" do
86
- specify "should split a string containing multiple statements" do
87
- "DROP TABLE a; DROP TABLE c".split_sql.should == \
88
- ['DROP TABLE a', 'DROP TABLE c']
89
- end
90
-
91
- specify "should remove comments from the string" do
92
- "DROP TABLE a;/* DROP TABLE b; DROP TABLE c;*/DROP TABLE d".split_sql.should == \
93
- ['DROP TABLE a', 'DROP TABLE d']
94
- end
95
- end
96
-
97
11
  context "String#to_time" do
98
12
  specify "should convert the string into a Time object" do
99
13
  "2007-07-11".to_time.should == Time.parse("2007-07-11")
@@ -101,112 +15,6 @@ context "String#to_time" do
101
15
  end
102
16
  end
103
17
 
104
- context "Symbol#DESC" do
105
- specify "should append the symbol with DESC" do
106
- :hey.DESC.should == 'hey DESC'
107
- end
108
-
109
- specify "should support qualified symbol notation" do
110
- :abc__def.DESC.should == 'abc.def DESC'
111
- end
112
- end
113
-
114
- context "Symbol#AS" do
115
- specify "should append an AS clause" do
116
- :hey.AS(:ho).should == 'hey AS ho'
117
- end
118
-
119
- specify "should support qualified symbol notation" do
120
- :abc__def.AS(:x).should == 'abc.def AS x'
121
- end
122
- end
123
-
124
- context "Symbol#ALL" do
125
- specify "should format a qualified wildcard" do
126
- :xyz.ALL.should == 'xyz.*'
127
- end
128
- end
129
-
130
- context "Symbol#to_column_name" do
131
- specify "should convert qualified symbol notation into dot notation" do
132
- :abc__def.to_column_name.should == 'abc.def'
133
- end
134
-
135
- specify "should convert AS symbol notation into SQL AS notation" do
136
- :xyz___x.to_column_name.should == 'xyz AS x'
137
- :abc__def___x.to_column_name.should == 'abc.def AS x'
138
- end
139
-
140
- specify "should support names with digits" do
141
- :abc2.to_column_name.should == 'abc2'
142
- :xx__yy3.to_column_name.should == 'xx.yy3'
143
- :ab34__temp3_4ax.to_column_name.should == 'ab34.temp3_4ax'
144
- :x1___y2.to_column_name.should == 'x1 AS y2'
145
- :abc2__def3___ggg4.to_column_name.should == 'abc2.def3 AS ggg4'
146
- end
147
-
148
- specify "should support upper case and lower case" do
149
- :ABC.to_column_name.should == 'ABC'
150
- :Zvashtoy__aBcD.to_column_name.should == 'Zvashtoy.aBcD'
151
-
152
- end
153
- end
154
-
155
- context "ColumnCompositionMethods#column_title" do
156
- specify "should return the column name for non aliased columns" do
157
- :xyz.column_title.should == 'xyz'
158
- :abc__xyz.column_title.should == 'xyz'
159
-
160
- 'abc'.column_title.should == 'abc'
161
- 'abc.def'.column_title.should == 'def'
162
- end
163
-
164
- specify "should return the column alias for aliased columns" do
165
- :xyz___x.column_title.should == 'x'
166
- :abc__xyz___y.column_title.should == 'y'
167
-
168
- 'abc AS x'.column_title.should == 'x'
169
- 'abc as y'.column_title.should == 'y'
170
- 'abc.def AS d'.column_title.should == 'd'
171
- end
172
- end
173
-
174
- context "Symbol" do
175
- specify "should support MIN for specifying min function" do
176
- :abc__def.MIN.should == 'min(abc.def)'
177
- end
178
-
179
- specify "should support MAX for specifying max function" do
180
- :abc__def.MAX.should == 'max(abc.def)'
181
- end
182
-
183
- specify "should support SUM for specifying sum function" do
184
- :abc__def.SUM.should == 'sum(abc.def)'
185
- end
186
-
187
- specify "should support AVG for specifying avg function" do
188
- :abc__def.AVG.should == 'avg(abc.def)'
189
- end
190
-
191
- specify "should support COUNT for specifying count function" do
192
- :abc__def.COUNT.should == 'count(abc.def)'
193
- end
194
-
195
- specify "should support any other function using upper case letters" do
196
- :abc__def.DADA.should == 'dada(abc.def)'
197
- end
198
-
199
- specify "should support upper case outer functions" do
200
- :COUNT['1'].should == 'COUNT(1)'
201
- end
202
-
203
- specify "should inhibit string literalization" do
204
- db = Sequel::Database.new
205
- ds = db[:t]
206
- ds.select(:COUNT['1']).sql.should == "SELECT COUNT(1) FROM t"
207
- end
208
- end
209
-
210
18
  context "Range#interval" do
211
19
  specify "should return the interval between the beginning and end of the range" do
212
20
  (1..10).interval.should == 9
@@ -0,0 +1,279 @@
1
+ require File.join(File.dirname(__FILE__), 'spec_helper')
2
+
3
+ context "Array#to_sql" do
4
+ specify "should concatenate multiple lines into a single string" do
5
+ "SELECT * \r\nFROM items\r\n WHERE a = 1".split.to_sql. \
6
+ should == 'SELECT * FROM items WHERE a = 1'
7
+ end
8
+
9
+ specify "should remove superfluous white space and line breaks" do
10
+ "\tSELECT * \n FROM items ".split.to_sql. \
11
+ should == 'SELECT * FROM items'
12
+ end
13
+
14
+ specify "should remove ANSI SQL comments" do
15
+ "SELECT * --comment\r\n FROM items\r\n --comment".split.to_sql. \
16
+ should == 'SELECT * FROM items'
17
+ end
18
+
19
+ specify "should remove C-style comments" do
20
+ "SELECT * \r\n /* comment comment\r\n comment\r\n FROM items */\r\n FROM items\r\n--comment".split.to_sql. \
21
+ should == 'SELECT * FROM items'
22
+ end
23
+ end
24
+
25
+ context "String#to_sql" do
26
+ specify "should concatenate multiple lines into a single string" do
27
+ "SELECT * \r\nFROM items\r\nWHERE a = 1".to_sql. \
28
+ should == 'SELECT * FROM items WHERE a = 1'
29
+ end
30
+
31
+ specify "should remove superfluous white space and line breaks" do
32
+ "\tSELECT * \r\n FROM items ".to_sql. \
33
+ should == 'SELECT * FROM items'
34
+ end
35
+
36
+ specify "should remove ANSI SQL comments" do
37
+ "SELECT * --comment \r\n FROM items\r\n --comment".to_sql. \
38
+ should == 'SELECT * FROM items'
39
+ end
40
+
41
+ specify "should remove C-style comments" do
42
+ "SELECT * \r\n/* comment comment\r\ncomment\r\nFROM items */\r\nFROM items\r\n--comment".to_sql. \
43
+ should == 'SELECT * FROM items'
44
+ end
45
+ end
46
+
47
+ context "String#lit" do
48
+ specify "should return an LiteralString object" do
49
+ 'xyz'.lit.should be_a_kind_of(Sequel::LiteralString)
50
+ 'xyz'.lit.to_s.should == 'xyz'
51
+ end
52
+
53
+ specify "should inhibit string literalization" do
54
+ db = Sequel::Database.new
55
+ ds = db[:t]
56
+
57
+ ds.update_sql(:stamp => "NOW()".lit).should == \
58
+ "UPDATE t SET stamp = NOW()"
59
+ end
60
+ end
61
+
62
+ context "String#expr" do
63
+ specify "should return an LiteralString object" do
64
+ 'xyz'.expr.should be_a_kind_of(Sequel::LiteralString)
65
+ 'xyz'.expr.to_s.should == 'xyz'
66
+ end
67
+
68
+ specify "should inhibit string literalization" do
69
+ db = Sequel::Database.new
70
+ ds = db[:t]
71
+
72
+ ds.update_sql(:stamp => "NOW()".expr).should == \
73
+ "UPDATE t SET stamp = NOW()"
74
+ end
75
+ end
76
+
77
+ context "String#split_sql" do
78
+ specify "should split a string containing multiple statements" do
79
+ "DROP TABLE a; DROP TABLE c".split_sql.should == \
80
+ ['DROP TABLE a', 'DROP TABLE c']
81
+ end
82
+
83
+ specify "should remove comments from the string" do
84
+ "DROP TABLE a;/* DROP TABLE b; DROP TABLE c;*/DROP TABLE d".split_sql.should == \
85
+ ['DROP TABLE a', 'DROP TABLE d']
86
+ end
87
+ end
88
+
89
+ context "#DESC/#desc" do
90
+ setup do
91
+ @ds = Sequel::Dataset.new(nil)
92
+ end
93
+
94
+ specify "should format a DESC clause for a column ref" do
95
+ :test.DESC.to_s(@ds).should == 'test DESC'
96
+ :test.desc.to_s(@ds).should == 'test DESC'
97
+
98
+ :items__price.DESC.to_s(@ds).should == 'items.price DESC'
99
+ :items__price.desc.to_s(@ds).should == 'items.price DESC'
100
+ end
101
+
102
+ specify "should format a DESC clause for a function" do
103
+ :avg[:test].DESC.to_s(@ds).should == 'avg(test) DESC'
104
+ :avg[:test].desc.to_s(@ds).should == 'avg(test) DESC'
105
+ end
106
+
107
+ specify "should format a DESC clause for a literal value" do
108
+ 1.DESC.to_s(@ds).should == '1 DESC'
109
+ 'abc'.desc.to_s(@ds).should == "'abc' DESC"
110
+ end
111
+ end
112
+
113
+ context "#ASC/#asc" do
114
+ setup do
115
+ @ds = Sequel::Dataset.new(nil)
116
+ end
117
+
118
+ specify "should format a ASC clause for a column ref" do
119
+ :test.ASC.to_s(@ds).should == 'test ASC'
120
+ :test.asc.to_s(@ds).should == 'test ASC'
121
+
122
+ :items__price.ASC.to_s(@ds).should == 'items.price ASC'
123
+ :items__price.asc.to_s(@ds).should == 'items.price ASC'
124
+ end
125
+
126
+ specify "should format a ASC clause for a function" do
127
+ :avg[:test].ASC.to_s(@ds).should == 'avg(test) ASC'
128
+ :avg[:test].asc.to_s(@ds).should == 'avg(test) ASC'
129
+ end
130
+
131
+ specify "should format a ASC clause for a literal value" do
132
+ 1.ASC.to_s(@ds).should == '1 ASC'
133
+ 'abc'.asc.to_s(@ds).should == "'abc' ASC"
134
+ end
135
+ end
136
+
137
+ context "#AS/#as" do
138
+ setup do
139
+ @ds = Sequel::Dataset.new(nil)
140
+ end
141
+
142
+ specify "should format a AS clause for a column ref" do
143
+ :test.AS(:t).to_s(@ds).should == 'test AS t'
144
+ :test.as(:t).to_s(@ds).should == 'test AS t'
145
+
146
+ :items__price.AS(:p).to_s(@ds).should == 'items.price AS p'
147
+ :items__price.as(:p).to_s(@ds).should == 'items.price AS p'
148
+ end
149
+
150
+ specify "should format a AS clause for a function" do
151
+ :avg[:test].AS(:avg).to_s(@ds).should == 'avg(test) AS avg'
152
+ :avg[:test].as(:avg).to_s(@ds).should == 'avg(test) AS avg'
153
+ end
154
+
155
+ specify "should format a AS clause for a literal value" do
156
+ 1.AS(:one).to_s(@ds).should == '1 AS one'
157
+ 'abc'.as(:abc).to_s(@ds).should == "'abc' AS abc"
158
+ end
159
+ end
160
+
161
+ context "Column references" do
162
+ setup do
163
+ @c = Class.new(Sequel::Dataset) do
164
+ def quote_column_ref(c); "`#{c}`"; end
165
+ end
166
+ @ds = @c.new(nil)
167
+ end
168
+
169
+ specify "should be quoted properly" do
170
+ @ds.literal(:xyz).should == "`xyz`"
171
+ @ds.literal(:xyz__abc).should == "xyz.`abc`"
172
+
173
+ @ds.literal(:xyz.as(:x)).should == "`xyz` AS `x`"
174
+ @ds.literal(:xyz__abc.as(:x)).should == "xyz.`abc` AS `x`"
175
+
176
+ @ds.literal(:xyz___x).should == "`xyz` AS `x`"
177
+ @ds.literal(:xyz__abc___x).should == "xyz.`abc` AS `x`"
178
+ end
179
+
180
+ specify "should be quoted properly in SQL functions" do
181
+ @ds.literal(:avg[:xyz]).should == "avg(`xyz`)"
182
+ @ds.literal(:avg[:xyz, 1]).should == "avg(`xyz`, 1)"
183
+ @ds.literal(:avg[:xyz].as(:a)).should == "avg(`xyz`) AS `a`"
184
+ end
185
+
186
+ specify "should be quoted properly in ASC/DESC clauses" do
187
+ @ds.literal(:xyz.ASC).should == "`xyz` ASC"
188
+ @ds.literal(:avg[:xyz, 1].desc).should == "avg(`xyz`, 1) DESC"
189
+ end
190
+
191
+ specify "should be quoted properly in a cast function" do
192
+ @ds.literal(:x.cast_as(:integer)).should == "cast(`x` AS integer)"
193
+ @ds.literal(:x__y.cast_as(:varchar[20])).should == "cast(x.`y` AS varchar(20))"
194
+ end
195
+ end
196
+
197
+ context "Symbol#ALL/#all" do
198
+ setup do
199
+ @ds = Sequel::Dataset.new(nil)
200
+ end
201
+
202
+ specify "should format a qualified wildcard" do
203
+ :xyz.ALL.to_s(@ds).should == 'xyz.*'
204
+ :abc.all.to_s(@ds).should == 'abc.*'
205
+ end
206
+ end
207
+
208
+ context "Symbol#to_column_ref" do
209
+ setup do
210
+ @ds = Sequel::Dataset.new(nil)
211
+ end
212
+
213
+ specify "should convert qualified symbol notation into dot notation" do
214
+ :abc__def.to_column_ref(@ds).should == 'abc.def'
215
+ end
216
+
217
+ specify "should convert AS symbol notation into SQL AS notation" do
218
+ :xyz___x.to_column_ref(@ds).should == 'xyz AS x'
219
+ :abc__def___x.to_column_ref(@ds).should == 'abc.def AS x'
220
+ end
221
+
222
+ specify "should support names with digits" do
223
+ :abc2.to_column_ref(@ds).should == 'abc2'
224
+ :xx__yy3.to_column_ref(@ds).should == 'xx.yy3'
225
+ :ab34__temp3_4ax.to_column_ref(@ds).should == 'ab34.temp3_4ax'
226
+ :x1___y2.to_column_ref(@ds).should == 'x1 AS y2'
227
+ :abc2__def3___ggg4.to_column_ref(@ds).should == 'abc2.def3 AS ggg4'
228
+ end
229
+
230
+ specify "should support upper case and lower case" do
231
+ :ABC.to_column_ref(@ds).should == 'ABC'
232
+ :Zvashtoy__aBcD.to_column_ref(@ds).should == 'Zvashtoy.aBcD'
233
+ end
234
+ end
235
+
236
+ context "Symbol" do
237
+ setup do
238
+ @ds = Sequel::Dataset.new(nil)
239
+ end
240
+
241
+ specify "should support MIN for specifying min function" do
242
+ :abc__def.MIN.to_s(@ds).should == 'min(abc.def)'
243
+ end
244
+
245
+ specify "should support MAX for specifying max function" do
246
+ :abc__def.MAX.to_s(@ds).should == 'max(abc.def)'
247
+ end
248
+
249
+ specify "should support SUM for specifying sum function" do
250
+ :abc__def.SUM.to_s(@ds).should == 'sum(abc.def)'
251
+ end
252
+
253
+ specify "should support AVG for specifying avg function" do
254
+ :abc__def.AVG.to_s(@ds).should == 'avg(abc.def)'
255
+ end
256
+
257
+ specify "should support COUNT for specifying count function" do
258
+ :abc__def.COUNT.to_s(@ds).should == 'count(abc.def)'
259
+ end
260
+
261
+ specify "should support any other function using upper case letters" do
262
+ :abc__def.DADA.to_s(@ds).should == 'dada(abc.def)'
263
+ end
264
+
265
+ specify "should support upper case outer functions" do
266
+ :COUNT['1'].to_s(@ds).should == "COUNT('1')"
267
+ end
268
+
269
+ specify "should inhibit string literalization" do
270
+ db = Sequel::Database.new
271
+ ds = db[:t]
272
+ ds.select(:COUNT['1']).sql.should == "SELECT COUNT('1') FROM t"
273
+ end
274
+
275
+ specify "should support cast function" do
276
+ :abc.cast_as(:integer).to_s(@ds).should == "cast(abc AS integer)"
277
+ end
278
+ end
279
+
@@ -795,12 +795,12 @@ context "Dataset#qualified_column_name" do
795
795
  end
796
796
 
797
797
  specify "should return the same if already qualified" do
798
- @dataset.qualified_column_name('test.a', :items).should == 'test.a'
798
+ @dataset.qualified_column_name('test.a'.lit, :items).should == 'test.a'
799
799
  @dataset.qualified_column_name(:ccc__b, :items).should == 'ccc.b'
800
800
  end
801
801
 
802
802
  specify "should qualify the column with the supplied table name" do
803
- @dataset.qualified_column_name('a', :items).should == 'items.a'
803
+ @dataset.qualified_column_name('a'.lit, :items).should == 'items.a'
804
804
  @dataset.qualified_column_name(:b1, :items).should == 'items.b1'
805
805
  end
806
806
  end
@@ -1274,16 +1274,16 @@ context "Dataset#last" do
1274
1274
 
1275
1275
  specify "should invert the order" do
1276
1276
  @d.order(:a).last
1277
- @c.last_dataset.opts[:order].should == ['a DESC']
1277
+ @d.literal(@c.last_dataset.opts[:order]).should == @d.literal([:a.DESC])
1278
1278
 
1279
1279
  @d.order(:b.DESC).last
1280
- @c.last_dataset.opts[:order].should == ['b']
1280
+ @d.literal(@c.last_dataset.opts[:order]).should == @d.literal(:b)
1281
1281
 
1282
1282
  @d.order(:c, :d).last
1283
- @c.last_dataset.opts[:order].should == ['c DESC', 'd DESC']
1283
+ @d.literal(@c.last_dataset.opts[:order]).should == @d.literal([:c.DESC, :d.DESC])
1284
1284
 
1285
1285
  @d.order(:e.DESC, :f).last
1286
- @c.last_dataset.opts[:order].should == ['e', 'f DESC']
1286
+ @d.literal(@c.last_dataset.opts[:order]).should == @d.literal([:e, :f.DESC])
1287
1287
  end
1288
1288
 
1289
1289
  specify "should return the first matching record if a hash is specified" do
@@ -163,6 +163,13 @@ context "Proc#to_sql" do
163
163
  "(x(1, (SELECT z FROM y), 'a''b') > 100)"
164
164
  end
165
165
 
166
+ specify "should support SQL functions without arguments" do
167
+ proc {:abc[] > 100}.to_sql.should == "(abc() > 100)"
168
+
169
+ proc {:now[] - :last_stamp > 100}.to_sql.should == \
170
+ "((now() - last_stamp) > 100)"
171
+ end
172
+
166
173
  specify "should do stuff like..." do
167
174
  proc {:price < 100 || :category != 'ruby'}.to_sql.should == \
168
175
  "((price < 100) OR (NOT (category = 'ruby')))"
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: sequel
5
5
  version: !ruby/object:Gem::Version
6
- version: 0.3.3
7
- date: 2007-11-04 00:00:00 +02:00
6
+ version: 0.3.4.1
7
+ date: 2007-11-10 00:00:00 +02:00
8
8
  summary: Lightweight ORM library for Ruby
9
9
  require_paths:
10
10
  - lib
@@ -33,7 +33,6 @@ files:
33
33
  - README
34
34
  - Rakefile
35
35
  - bin/sequel
36
- - doc/rdoc
37
36
  - spec/adapters
38
37
  - spec/adapters/mysql_spec.rb
39
38
  - spec/adapters/oracle_spec.rb
@@ -42,6 +41,7 @@ files:
42
41
  - spec/array_keys_spec.rb
43
42
  - spec/connection_pool_spec.rb
44
43
  - spec/core_ext_spec.rb
44
+ - spec/core_sql_spec.rb
45
45
  - spec/database_spec.rb
46
46
  - spec/dataset_spec.rb
47
47
  - spec/migration_spec.rb
@@ -57,6 +57,7 @@ files:
57
57
  - lib/sequel/array_keys.rb
58
58
  - lib/sequel/connection_pool.rb
59
59
  - lib/sequel/core_ext.rb
60
+ - lib/sequel/core_sql.rb
60
61
  - lib/sequel/database.rb
61
62
  - lib/sequel/dataset
62
63
  - lib/sequel/dataset/convenience.rb