sequel 0.3.3 → 0.3.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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