sequel_core 1.3 → 1.4.0

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,29 @@
1
+ === 1.4.0 (2008-04-08)
2
+
3
+ * Merge 3 mysql patches from the bugtracker (mvyver) (#200, #201, #202).
4
+
5
+ * Merge 2 postgresql patches from the bugtracker (a...@mellowtone.co.jp) (#211, 212).
6
+
7
+ * Allow overriding of default posgres spec database via ENV['SEQUEL_PG_SPEC_DB'] (jeremyevans).
8
+
9
+ * Allow using the Sequel::Model as the first argument in a dataset join selection (jeremyevans) (#170).
10
+
11
+ * Add simple callback mechanism to make model eager loading implementation easier (jeremyevans).
12
+
13
+ * Added Sequel::Error::InvalidOperation class for invalid operations (#198).
14
+
15
+ * Implemented MySQL::Database#server_version (#199).
16
+
17
+ * Added spec configuration for MySQL socket file.
18
+
19
+ * Fixed transform with array tuples in postgres adapter.
20
+
21
+ * Changed spec configuration to Database objects instead of URIs in order to support custom options for spec databases.
22
+
23
+ * Renamed schema files.
24
+
25
+ * Fixed Dataset#from to work correctly with SQL functions (#193).
26
+
1
27
  === 1.3 (2008-03-08)
2
28
 
3
29
  * Added configuration file for running specs (#186).
data/README CHANGED
@@ -7,18 +7,19 @@ Sequel makes it easy to deal with multiple records without having to break your
7
7
  == Resources
8
8
 
9
9
  * {Project page}[http://code.google.com/p/ruby-sequel/]
10
- * {Source code}[http://ruby-sequel.googlecode.com/svn/]
10
+ * {Source code}[http://github.com/jeremyevans/sequel]
11
11
  * {Bug tracking}[http://code.google.com/p/ruby-sequel/issues/list]
12
12
  * {Google group}[http://groups.google.com/group/sequel-talk]
13
13
  * {RubyForge page}[http://rubyforge.org/projects/sequel/]
14
+ * {API RDoc}[http://sequel.rubyforge.org]
14
15
 
15
16
  To check out the source code:
16
17
 
17
- svn co http://ruby-sequel.googlecode.com/svn/trunk
18
+ git clone git://github.com/jeremyevans/sequel.git
18
19
 
19
20
  === Contact
20
21
 
21
- If you have any comments or suggestions please send an email to ciconia at gmail.com and I'll get back to you.
22
+ If you have any comments or suggestions please post to the Google group.
22
23
 
23
24
  == Installation
24
25
 
@@ -208,7 +209,7 @@ Or calculate a sum:
208
209
 
209
210
  You can also specify descending order
210
211
 
211
- posts.order(:stamp.DESC)
212
+ posts.order(:stamp.desc)
212
213
 
213
214
  === Deleting Records
214
215
 
data/Rakefile CHANGED
@@ -9,7 +9,7 @@ include FileUtils
9
9
  # Configuration
10
10
  ##############################################################################
11
11
  NAME = "sequel_core"
12
- VERS = "1.3"
12
+ VERS = "1.4.0"
13
13
  CLEAN.include ["**/.*.sw?", "pkg/*", ".config", "doc/*", "coverage/*"]
14
14
  RDOC_OPTS = [
15
15
  "--quiet",
@@ -49,10 +49,10 @@ spec = Gem::Specification.new do |s|
49
49
  s.extra_rdoc_files = ["README", "CHANGELOG", "COPYING"]
50
50
  s.rdoc_options += RDOC_OPTS +
51
51
  ["--exclude", "^(examples|extras)\/", "--exclude", "lib/sequel_core.rb"]
52
- s.summary = "The Database Toolkit for Ruby"
52
+ s.summary = "The Database Toolkit for Ruby: Core Library and Adapters"
53
53
  s.description = s.summary
54
- s.author = "Sharon Rosner"
55
- s.email = "ciconia@gmail.com"
54
+ s.author = "Aman Gupta"
55
+ s.email = "themastermind1@gmail.com"
56
56
  s.homepage = "http://sequel.rubyforge.org"
57
57
  s.executables = ["sequel"]
58
58
  s.required_ruby_version = ">= 1.8.4"
@@ -99,14 +99,6 @@ task :uninstall => [:clean] do
99
99
  sh %{sudo gem uninstall #{NAME}}
100
100
  end
101
101
 
102
- task :tag do
103
- cwd = FileUtils.pwd
104
- sh %{rm -rf doc/*}
105
- sh %{rm -rf pkg/*}
106
- sh %{rm -rf coverage/*}
107
- sh %{cd ../.. && svn copy #{cwd} tags/#{NAME}-#{VERS} && svn commit -m "#{NAME}-#{VERS} tag." tags}
108
- end
109
-
110
102
  ##############################################################################
111
103
  # gem and rdoc release
112
104
  ##############################################################################
@@ -75,6 +75,17 @@ module Sequel
75
75
  class Database < Sequel::Database
76
76
  set_adapter_scheme :mysql
77
77
 
78
+ def server_version
79
+ @server_version ||= pool.hold do |conn|
80
+ if conn.respond_to?(:server_version)
81
+ pool.hold {|c| c.server_version}
82
+ else
83
+ get(:version[]) =~ /(\d+)\.(\d+)\.(\d+)/
84
+ ($1.to_i * 10000) + ($2.to_i * 100) + $3.to_i
85
+ end
86
+ end
87
+ end
88
+
78
89
  def serial_primary_key_options
79
90
  {:primary_key => true, :type => :integer, :auto_increment => true}
80
91
  end
@@ -213,8 +224,7 @@ module Sequel
213
224
  # Changes the database in use by issuing a USE statement.
214
225
  def use(db_name)
215
226
  disconnect
216
- @opts[:database] = db_name
217
- self << "USE #{db_name}"
227
+ @opts[:database] = db_name if self << "USE #{db_name}"
218
228
  self
219
229
  end
220
230
  end
@@ -225,6 +235,28 @@ module Sequel
225
235
  TRUE = '1'
226
236
  FALSE = '0'
227
237
 
238
+ # Join processing changed after MySQL v5.0.12. NATURAL
239
+ # joins are SQL:2003 consistent.
240
+ JOIN_TYPES = { :cross => 'INNER JOIN'.freeze,
241
+ :straight => 'STRAIGHT_JOIN'.freeze,
242
+ :natural_left => 'NATURAL LEFT JOIN'.freeze,
243
+ :natural_right => 'NATURAL RIGHT JOIN'.freeze,
244
+ :natural_left_outer => 'NATURAL LEFT OUTER JOIN'.freeze,
245
+ :natural_right_outer => 'NATURAL RIGHT OUTER JOIN'.freeze,
246
+ :left => 'LEFT JOIN'.freeze,
247
+ :right => 'RIGHT JOIN'.freeze,
248
+ :left_outer => 'LEFT OUTER JOIN'.freeze,
249
+ :right_outer => 'RIGHT OUTER JOIN'.freeze,
250
+ :natural_inner => 'NATURAL LEFT JOIN'.freeze,
251
+ # :full_outer => 'FULL OUTER JOIN'.freeze,
252
+ #
253
+ # A full outer join, nor a workaround implementation of
254
+ # :full_outer, is not yet possible in Sequel. See issue
255
+ # #195 which probably depends on issue #113 being
256
+ # resolved.
257
+ :inner => 'INNER JOIN'.freeze
258
+ }
259
+
228
260
  def literal(v)
229
261
  case v
230
262
  when LiteralString
@@ -240,6 +272,46 @@ module Sequel
240
272
  end
241
273
  end
242
274
 
275
+ # Returns a join clause based on the specified join type
276
+ # and condition. MySQL's NATURAL join is 'semantically
277
+ # equivalent to a JOIN with a USING clause that names all
278
+ # columns that exist in both tables. The constraint
279
+ # expression may be nil, so join expression can accept two
280
+ # arguments.
281
+ #
282
+ # === Note
283
+ # Full outer joins (:full_outer) are not implemented in
284
+ # MySQL (as of v6.0), nor is there currently a work around
285
+ # implementation in Sequel. Straight joins with 'ON
286
+ # <condition>' are not yet implemented.
287
+ #
288
+ # === Example
289
+ # @ds = MYSQL_DB[:nodes]
290
+ # @ds.join_expr(:natural_left_outer, :nodes)
291
+ # # 'NATURAL LEFT OUTER JOIN nodes'
292
+ #
293
+ def join_expr(type, table, expr = nil)
294
+ join_type = JOIN_TYPES[type || :inner]
295
+ unless join_type
296
+ raise Error::InvalidJoinType, "Invalid join type: #{type}"
297
+ end
298
+ @opts[:server_version] = @db.server_version unless @opts[:server_version]
299
+ type = :inner if type == :cross && !expr.nil?
300
+ if type.to_s =~ /natural|cross|straight/ && @opts[:server_version] >= 50014
301
+ tbl_factor = table.to_s
302
+ if table.is_a?(Dataset)
303
+ tbl_factor = table.sql << " AS t1"
304
+ end
305
+ if table.is_a?(Array)
306
+ tbl_factor = "( #{literal(table)} )"
307
+ end
308
+ join_string = "#{join_type} " << tbl_factor
309
+ return join_string
310
+ end
311
+
312
+ super
313
+ end
314
+
243
315
  def match_expr(l, r)
244
316
  case r
245
317
  when Regexp
@@ -452,4 +524,4 @@ module Sequel
452
524
  end
453
525
  end
454
526
  end
455
- end
527
+ end
@@ -2,8 +2,8 @@ require 'postgres'
2
2
 
3
3
  class PGconn
4
4
  # the pure-ruby postgres adapter does not have a quote method.
5
- TRUE = 't'.freeze
6
- FALSE = 'f'.freeze
5
+ TRUE = 'true'.freeze
6
+ FALSE = 'false'.freeze
7
7
  NULL = 'NULL'.freeze
8
8
 
9
9
  unless methods.include?('quote')
@@ -47,6 +47,10 @@ class PGconn
47
47
  alias_method :async_exec, :exec
48
48
  end
49
49
 
50
+ unless instance_methods.include?('async_query')
51
+ alias_method :async_query, :query
52
+ end
53
+
50
54
  def execute(sql, &block)
51
55
  q = nil
52
56
  begin
@@ -80,7 +84,7 @@ class PGconn
80
84
  end
81
85
  if seq = @table_sequences[table]
82
86
  r = async_query(SELECT_CURRVAL % seq)
83
- return r[0][0].to_i unless r.nil? || r.empty?
87
+ return r[0][0].to_i unless r.nil? || (r.respond_to?(:empty?) && r.empty?)
84
88
  end
85
89
  nil # primary key sequence not found
86
90
  end
@@ -126,17 +130,17 @@ class PGconn
126
130
 
127
131
  def pkey_and_sequence(table)
128
132
  r = async_query(SELECT_PK_AND_SERIAL_SEQUENCE % table)
129
- return [r[0].first, r[0].last] unless r.nil? or r.empty?
133
+ return [r[0].first, r[0].last] unless r.nil? || (r.respond_to?(:empty?) && r.empty?)
130
134
 
131
135
  r = async_query(SELECT_PK_AND_CUSTOM_SEQUENCE % table)
132
- return [r[0].first, r[0].last] unless r.nil? or r.empty?
136
+ return [r[0].first, r[0].last] unless r.nil? || (r.respond_to?(:empty?) && r.empty?)
133
137
  rescue
134
138
  nil
135
139
  end
136
140
 
137
141
  def primary_key(table)
138
142
  r = async_query(SELECT_PK % table)
139
- pkey = r[0].first unless r.nil? or r.empty?
143
+ pkey = r[0].first unless r.nil? || (r.respond_to?(:empty?) && r.empty?)
140
144
  return pkey.to_sym if pkey
141
145
  rescue
142
146
  nil
@@ -535,6 +539,23 @@ module Sequel
535
539
  end
536
540
  eval("lambda {|r| r.keys = columns; #{tr.join(';')}; r}")
537
541
  end
542
+
543
+ def array_tuples_transform_load(r)
544
+ a = []; a.keys = []
545
+ r.each_pair do |k, v|
546
+ a[k] = (tt = @transform[k]) ? tt[0][v] : v
547
+ end
548
+ a
549
+ end
550
+
551
+ # Applies the value transform for data saved to the database.
552
+ def array_tuples_transform_save(r)
553
+ a = []; a.keys = []
554
+ r.each_pair do |k, v|
555
+ a[k] = (tt = @transform[k]) ? tt[1][v] : v
556
+ end
557
+ a
558
+ end
538
559
  end
539
560
  end
540
561
  end
@@ -0,0 +1,19 @@
1
+ module Sequel
2
+ class Dataset
3
+ module Callback
4
+ # Add a symbol with the name of a method to the list of callbacks for name.
5
+ def add_callback(name, sym)
6
+ cbs = (@opts[:callbacks] ||= {})
7
+ cb = (cbs[name] ||= [])
8
+ cb.push(sym)
9
+ end
10
+
11
+ # Run all callbacks for name with the given args
12
+ def run_callback(name, *args)
13
+ return unless cbs = @opts[:callbacks]
14
+ return unless cb = cbs[name]
15
+ cb.each{|sym| send(sym, *args)}
16
+ end
17
+ end
18
+ end
19
+ end
@@ -42,23 +42,33 @@ module Sequel
42
42
  m.join(COMMA_SEPARATOR)
43
43
  end
44
44
  end
45
-
45
+
46
+ def table_ref(t)
47
+ case t
48
+ when Dataset
49
+ t.to_table_reference
50
+ when Hash
51
+ t.map {|k, v| "#{table_ref(k)} #{table_ref(v)}"}.join(COMMA_SEPARATOR)
52
+ when Symbol, String
53
+ t
54
+ else
55
+ literal(t)
56
+ end
57
+ end
58
+
46
59
  # Converts an array of sources names into into a comma separated list.
47
60
  def source_list(source)
48
61
  if source.nil? || source.empty?
49
62
  raise Error, 'No source specified for query'
50
63
  end
51
64
  auto_alias_count = 0
52
- m = source.map do |i|
53
- case i
65
+ m = source.map do |s|
66
+ case s
54
67
  when Dataset
55
68
  auto_alias_count += 1
56
- i.to_table_reference(auto_alias_count)
57
- when Hash
58
- i.map {|k, v| "#{k.is_a?(Dataset) ? k.to_table_reference : k} #{v}"}.
59
- join(COMMA_SEPARATOR)
69
+ s.to_table_reference(auto_alias_count)
60
70
  else
61
- i
71
+ table_ref(s)
62
72
  end
63
73
  end
64
74
  m.join(COMMA_SEPARATOR)
@@ -356,7 +366,7 @@ module Sequel
356
366
  # if the dataset has not been grouped. See also #filter
357
367
  def having(*cond, &block)
358
368
  unless @opts[:group]
359
- raise Error, "Can only specify a HAVING clause on a grouped dataset"
369
+ raise Error::InvalidOperation, "Can only specify a HAVING clause on a grouped dataset"
360
370
  else
361
371
  @opts[:having] = {}
362
372
  filter(*cond, &block)
@@ -402,6 +412,8 @@ module Sequel
402
412
  unless join_type
403
413
  raise Error::InvalidJoinType, "Invalid join type: #{type}"
404
414
  end
415
+
416
+ table = table.table_name if table.respond_to?(:table_name)
405
417
 
406
418
  join_conditions = {}
407
419
  expr.each do |k, v|
@@ -687,4 +699,4 @@ module Sequel
687
699
  end
688
700
  end
689
701
  end
690
- end
702
+ end
@@ -6,6 +6,7 @@ require 'base64'
6
6
  require File.join(File.dirname(__FILE__), 'dataset/sql')
7
7
  require File.join(File.dirname(__FILE__), 'dataset/sequelizer')
8
8
  require File.join(File.dirname(__FILE__), 'dataset/convenience')
9
+ require File.join(File.dirname(__FILE__), 'dataset/callback')
9
10
 
10
11
  module Sequel
11
12
  # A Dataset represents a view of a the data in a database, constrained by
@@ -69,6 +70,7 @@ module Sequel
69
70
  include Sequelizer
70
71
  include SQL
71
72
  include Convenience
73
+ include Callback
72
74
 
73
75
  attr_accessor :db
74
76
  attr_accessor :opts
@@ -80,6 +82,7 @@ module Sequel
80
82
  def all(opts = nil, &block)
81
83
  a = []
82
84
  each(opts) {|r| a << r}
85
+ run_callback(:post_load, a)
83
86
  a.each(&block) if block
84
87
  a
85
88
  end
@@ -14,6 +14,9 @@ module Sequel
14
14
 
15
15
  # Represents an Invalid transform.
16
16
  class InvalidTransform < Error ; end
17
+
18
+ # Raised on an invalid operation.
19
+ class InvalidOperation < Error; end
17
20
 
18
21
  # Represents an Invalid filter.
19
22
  class InvalidFilter < Error ; end
File without changes
@@ -3,6 +3,6 @@ module Sequel
3
3
  end
4
4
  end
5
5
 
6
- require File.join(File.dirname(__FILE__), 'schema/schema_sql')
7
- require File.join(File.dirname(__FILE__), 'schema/schema_generator')
6
+ require File.join(File.dirname(__FILE__), 'schema/sql')
7
+ require File.join(File.dirname(__FILE__), 'schema/generator')
8
8
 
@@ -1,9 +1,10 @@
1
1
  require File.join(File.dirname(__FILE__), '../../lib/sequel_core')
2
2
  require File.join(File.dirname(__FILE__), '../spec_helper.rb')
3
3
 
4
- unless defined?(INFORMIX_URL); INFORMIX_URL = 'informix://localhost/mydb' ;end
4
+ unless defined?(INFORMIX_DB)
5
+ INFORMIX_DB = Sequel('informix://localhost/mydb')
6
+ end
5
7
 
6
- INFORMIX_DB = Sequel(INFORMIX_URL)
7
8
  if INFORMIX_DB.table_exists?(:test)
8
9
  INFORMIX_DB.drop_table :test
9
10
  end
@@ -2,9 +2,17 @@ require File.join(File.dirname(__FILE__), '../../lib/sequel_core')
2
2
  require File.join(File.dirname(__FILE__), '../spec_helper.rb')
3
3
  require 'logger'
4
4
 
5
- unless defined?(MYSQL_URL); MYSQL_URL = 'mysql://root@localhost/sandbox' ;end
5
+ unless defined?(MYSQL_DB)
6
+ MYSQL_URL = 'mysql://root@localhost/sandbox' unless defined? MYSQL_URL
7
+ MYSQL_DB = Sequel(MYSQL_URL)
8
+ end
9
+ unless defined?(MYSQL_SOCKET_FILE)
10
+ MYSQL_SOCKET_FILE = '/tmp/mysql.sock'
11
+ end
12
+
13
+ MYSQL_URI = URI.parse(MYSQL_DB.uri)
14
+ MYSQL_DB_NAME = MYSQL_URI.path =~ /\/(.*)/ && $1
6
15
 
7
- MYSQL_DB = Sequel(MYSQL_URL)
8
16
  MYSQL_DB.drop_table(:items) if MYSQL_DB.table_exists?(:items)
9
17
  MYSQL_DB.drop_table(:test2) if MYSQL_DB.table_exists?(:test2)
10
18
  MYSQL_DB.create_table :items do
@@ -28,6 +36,10 @@ context "A MySQL database" do
28
36
  @db.pool.size.should == 0
29
37
  end
30
38
 
39
+ specify "should provide the server version" do
40
+ @db.server_version.should >= 40000
41
+ end
42
+
31
43
  specify "should support sequential primary keys" do
32
44
  @db.create_table!(:with_pk) {primary_key :id; text :name}
33
45
  @db[:with_pk] << {:name => 'abc'}
@@ -267,6 +279,53 @@ end
267
279
  # end
268
280
  # end
269
281
  #
282
+ context "MySQL join expressions" do
283
+ setup do
284
+ @ds = MYSQL_DB[:nodes]
285
+ @ds.db.meta_def(:server_version) {50014}
286
+ end
287
+
288
+ specify "should raise error for :full_outer join requests." do
289
+ lambda{@ds.join_expr(:full_outer, :nodes)}.should raise_error(Sequel::Error::InvalidJoinType)
290
+ end
291
+ specify "should support natural left joins" do
292
+ @ds.join_expr(:natural_left, :nodes).should == \
293
+ 'NATURAL LEFT JOIN nodes'
294
+ end
295
+ specify "should support natural right joins" do
296
+ @ds.join_expr(:natural_right, :nodes).should == \
297
+ 'NATURAL RIGHT JOIN nodes'
298
+ end
299
+ specify "should support natural left outer joins" do
300
+ @ds.join_expr(:natural_left_outer, :nodes).should == \
301
+ 'NATURAL LEFT OUTER JOIN nodes'
302
+ end
303
+ specify "should support natural right outer joins" do
304
+ @ds.join_expr(:natural_right_outer, :nodes).should == \
305
+ 'NATURAL RIGHT OUTER JOIN nodes'
306
+ end
307
+ specify "should support natural inner joins" do
308
+ @ds.join_expr(:natural_inner, :nodes).should == \
309
+ 'NATURAL LEFT JOIN nodes'
310
+ end
311
+ specify "should support cross joins (equivalent to inner join in MySQL, not in std SQL)" do
312
+ @ds.join_expr(:cross, :nodes).should == \
313
+ 'INNER JOIN nodes'
314
+ end
315
+ specify "should support straight joins (force left table to be read before right)" do
316
+ @ds.join_expr(:straight, :nodes).should == \
317
+ 'STRAIGHT_JOIN nodes'
318
+ end
319
+ specify "should support natural joins on multiple tables." do
320
+ @ds.join_expr(:natural_left_outer, [:nodes, :branches]).should == \
321
+ 'NATURAL LEFT OUTER JOIN ( `nodes`, `branches` )'
322
+ end
323
+ specify "should support straight joins on multiple tables." do
324
+ @ds.join_expr(:straight, [:nodes,:branches]).should == \
325
+ 'STRAIGHT_JOIN ( `nodes`, `branches` )'
326
+ end
327
+ end
328
+
270
329
  context "Joined MySQL dataset" do
271
330
  setup do
272
331
  @ds = MYSQL_DB[:nodes].join(:attributes, :node_id => :id)
@@ -391,17 +450,17 @@ end
391
450
 
392
451
  context "A MySQL database" do
393
452
  specify "should accept a socket option" do
394
- db = Sequel.mysql('sandbox', :host => 'localhost', :user => 'root', :socket => '/tmp/mysql.sock')
453
+ db = Sequel.mysql(MYSQL_DB_NAME, :host => 'localhost', :user => 'root', :socket => MYSQL_SOCKET_FILE)
395
454
  proc {db.test_connection}.should_not raise_error
396
455
  end
397
456
 
398
457
  specify "should accept a socket option without host option" do
399
- db = Sequel.mysql('sandbox', :user => 'root', :socket => '/tmp/mysql.sock')
458
+ db = Sequel.mysql(MYSQL_DB_NAME, :user => 'root', :socket => MYSQL_SOCKET_FILE)
400
459
  proc {db.test_connection}.should_not raise_error
401
460
  end
402
461
 
403
462
  specify "should fail to connect with invalid socket" do
404
- db = Sequel.mysql('sandbox', :host => 'localhost', :user => 'root', :socket => 'blah')
463
+ db = Sequel.mysql(MYSQL_DB_NAME, :host => 'localhost', :user => 'root', :socket => 'blah')
405
464
  proc {db.test_connection}.should raise_error
406
465
  end
407
466
  end
@@ -590,4 +649,4 @@ context "MySQL::Dataset#replace" do
590
649
  @d.replace(:id => 111, :value => 333)
591
650
  @d.all.should == [{:id => 111, :value => 333}]
592
651
  end
593
- end
652
+ end
@@ -1,9 +1,9 @@
1
1
  require File.join(File.dirname(__FILE__), '../../lib/sequel_core')
2
2
  require File.join(File.dirname(__FILE__), '../spec_helper.rb')
3
3
 
4
- unless defined?(ORACLE_URL); ORACLE_URL = 'oracle://hr:hr@localhost/XE' ;end
5
-
6
- ORACLE_DB = Sequel(ORACLE_URL)
4
+ unless defined?(ORACLE_DB)
5
+ ORACLE_DB = Sequel('oracle://hr:hr@localhost/XE')
6
+ end
7
7
 
8
8
  if ORACLE_DB.table_exists?(:items)
9
9
  ORACLE_DB.drop_table :items
@@ -1,25 +1,25 @@
1
1
  require File.join(File.dirname(__FILE__), '../../lib/sequel_core')
2
2
  require File.join(File.dirname(__FILE__), '../spec_helper.rb')
3
3
 
4
- unless defined?(POSTGRES_URL); POSTGRES_URL = 'postgres://postgres:postgres@localhost:5432/reality_spec' ;end
5
-
4
+ unless defined?(POSTGRES_DB)
5
+ POSTGRES_DB = Sequel(ENV['SEQUEL_PG_SPEC_DB']||'postgres://postgres:postgres@localhost:5432/reality_spec')
6
+ end
6
7
 
7
- PGSQL_DB = Sequel(POSTGRES_URL)
8
- PGSQL_DB.drop_table(:test) if PGSQL_DB.table_exists?(:test)
9
- PGSQL_DB.drop_table(:test2) if PGSQL_DB.table_exists?(:test2)
8
+ POSTGRES_DB.drop_table(:test) if POSTGRES_DB.table_exists?(:test)
9
+ POSTGRES_DB.drop_table(:test2) if POSTGRES_DB.table_exists?(:test2)
10
10
 
11
- PGSQL_DB.create_table :test do
11
+ POSTGRES_DB.create_table :test do
12
12
  text :name
13
13
  integer :value, :index => true
14
14
  end
15
- PGSQL_DB.create_table :test2 do
15
+ POSTGRES_DB.create_table :test2 do
16
16
  text :name
17
17
  integer :value
18
18
  end
19
19
 
20
20
  context "A PostgreSQL database" do
21
21
  setup do
22
- @db = PGSQL_DB
22
+ @db = POSTGRES_DB
23
23
  end
24
24
 
25
25
  specify "should provide disconnect functionality" do
@@ -36,7 +36,7 @@ end
36
36
 
37
37
  context "A PostgreSQL dataset" do
38
38
  setup do
39
- @d = PGSQL_DB[:test]
39
+ @d = POSTGRES_DB[:test]
40
40
  @d.delete # remove all records
41
41
  end
42
42
 
@@ -147,7 +147,7 @@ context "A PostgreSQL dataset" do
147
147
  end
148
148
 
149
149
  specify "should support transactions" do
150
- PGSQL_DB.transaction do
150
+ POSTGRES_DB.transaction do
151
151
  @d << {:name => 'abc', :value => 1}
152
152
  end
153
153
 
@@ -169,7 +169,7 @@ end
169
169
 
170
170
  context "A PostgreSQL dataset in array tuples mode" do
171
171
  setup do
172
- @d = PGSQL_DB[:test]
172
+ @d = POSTGRES_DB[:test]
173
173
  @d.delete # remove all records
174
174
  Sequel.use_array_tuples
175
175
  end
@@ -215,7 +215,7 @@ end
215
215
 
216
216
  context "A PostgreSQL database" do
217
217
  setup do
218
- @db = PGSQL_DB
218
+ @db = POSTGRES_DB
219
219
  end
220
220
 
221
221
  specify "should support add_column operations" do
@@ -259,44 +259,44 @@ context "A PostgreSQL database" do
259
259
  end
260
260
 
261
261
  specify "should support fulltext indexes" do
262
- g = Sequel::Schema::Generator.new(PGSQL_DB) do
262
+ g = Sequel::Schema::Generator.new(POSTGRES_DB) do
263
263
  text :title
264
264
  text :body
265
265
  full_text_index [:title, :body]
266
266
  end
267
- PGSQL_DB.create_table_sql_list(:posts, *g.create_info).should == [
267
+ POSTGRES_DB.create_table_sql_list(:posts, *g.create_info).should == [
268
268
  "CREATE TABLE posts (\"title\" text, \"body\" text)",
269
269
  "CREATE INDEX posts_title_body_index ON posts USING gin(to_tsvector(\"title\" || \"body\"))"
270
270
  ]
271
271
  end
272
272
 
273
273
  specify "should support fulltext indexes with a specific language" do
274
- g = Sequel::Schema::Generator.new(PGSQL_DB) do
274
+ g = Sequel::Schema::Generator.new(POSTGRES_DB) do
275
275
  text :title
276
276
  text :body
277
277
  full_text_index [:title, :body], :language => 'french'
278
278
  end
279
- PGSQL_DB.create_table_sql_list(:posts, *g.create_info).should == [
279
+ POSTGRES_DB.create_table_sql_list(:posts, *g.create_info).should == [
280
280
  "CREATE TABLE posts (\"title\" text, \"body\" text)",
281
281
  "CREATE INDEX posts_title_body_index ON posts USING gin(to_tsvector('french', \"title\" || \"body\"))"
282
282
  ]
283
283
  end
284
284
 
285
285
  specify "should support full_text_search" do
286
- PGSQL_DB[:posts].full_text_search(:title, 'ruby').sql.should ==
286
+ POSTGRES_DB[:posts].full_text_search(:title, 'ruby').sql.should ==
287
287
  "SELECT * FROM posts WHERE (to_tsvector(\"title\") @@ to_tsquery('ruby'))"
288
288
 
289
- PGSQL_DB[:posts].full_text_search([:title, :body], ['ruby', 'sequel']).sql.should ==
289
+ POSTGRES_DB[:posts].full_text_search([:title, :body], ['ruby', 'sequel']).sql.should ==
290
290
  "SELECT * FROM posts WHERE (to_tsvector(\"title\" || \"body\") @@ to_tsquery('ruby | sequel'))"
291
291
 
292
- PGSQL_DB[:posts].full_text_search(:title, 'ruby', :language => 'french').sql.should ==
292
+ POSTGRES_DB[:posts].full_text_search(:title, 'ruby', :language => 'french').sql.should ==
293
293
  "SELECT * FROM posts WHERE (to_tsvector('french', \"title\") @@ to_tsquery('french', 'ruby'))"
294
294
  end
295
295
  end
296
296
 
297
297
  context "Postgres::Dataset#multi_insert_sql / #import" do
298
298
  setup do
299
- @ds = PGSQL_DB[:test]
299
+ @ds = POSTGRES_DB[:test]
300
300
  end
301
301
 
302
302
  specify "should return separate insert statements if server_version < 80200" do
@@ -321,4 +321,4 @@ context "Postgres::Dataset#multi_insert_sql / #import" do
321
321
  'INSERT INTO test ("x", "y") VALUES (1, 2), (3, 4)'
322
322
  ]
323
323
  end
324
- end
324
+ end
@@ -1,9 +1,10 @@
1
1
  require File.join(File.dirname(__FILE__), '../../lib/sequel_core')
2
2
  require File.join(File.dirname(__FILE__), '../spec_helper.rb')
3
3
 
4
- unless defined?(SQLITE_URL); SQLITE_URL = 'sqlite:/' ;end
4
+ unless defined?(SQLITE_DB)
5
+ SQLITE_DB = Sequel('sqlite:/')
6
+ end
5
7
 
6
- SQLITE_DB = Sequel(SQLITE_URL)
7
8
  SQLITE_DB.create_table :items do
8
9
  integer :id, :primary_key => true, :auto_increment => true
9
10
  text :name
data/spec/dataset_spec.rb CHANGED
@@ -199,11 +199,11 @@ context "A dataset with multiple tables in its FROM clause" do
199
199
  end
200
200
 
201
201
  specify "should raise on #update_sql" do
202
- proc {@dataset.update_sql(:a=>1)}.should raise_error
202
+ proc {@dataset.update_sql(:a=>1)}.should raise_error(Sequel::Error::InvalidOperation)
203
203
  end
204
204
 
205
205
  specify "should raise on #delete_sql" do
206
- proc {@dataset.delete_sql}.should raise_error
206
+ proc {@dataset.delete_sql}.should raise_error(Sequel::Error::InvalidOperation)
207
207
  end
208
208
 
209
209
  specify "should generate a select query FROM all specified tables" do
@@ -508,7 +508,7 @@ context "Dataset#having" do
508
508
  end
509
509
 
510
510
  specify "should raise if the dataset is not grouped" do
511
- proc {@dataset.having('avg(gdp) > 10')}.should raise_error
511
+ proc {@dataset.having('avg(gdp) > 10')}.should raise_error(Sequel::Error::InvalidOperation)
512
512
  end
513
513
 
514
514
  specify "should affect select statements" do
@@ -665,6 +665,12 @@ context "Dataset#from" do
665
665
  @dataset.from(:a => :b).sql.should ==
666
666
  "SELECT * FROM a b"
667
667
 
668
+ @dataset.from(:a => 'b').sql.should ==
669
+ "SELECT * FROM a b"
670
+
671
+ @dataset.from(:a => :c[:d]).sql.should ==
672
+ "SELECT * FROM a c(d)"
673
+
668
674
  @dataset.from(@dataset.from(:a).group(:b) => :c).sql.should ==
669
675
  "SELECT * FROM (SELECT * FROM a GROUP BY b) c"
670
676
  end
@@ -677,6 +683,20 @@ context "Dataset#from" do
677
683
  specify "should raise if no source is given" do
678
684
  proc {@dataset.from(@dataset.from).select_sql}.should raise_error(Sequel::Error)
679
685
  end
686
+
687
+ specify "should accept sql functions" do
688
+ @dataset.from(:abc[:def]).select_sql.should ==
689
+ "SELECT * FROM abc(def)"
690
+
691
+ @dataset.from(:a|:i).select_sql.should ==
692
+ "SELECT * FROM a[i]"
693
+
694
+ @dataset.from(:generate_series[1, 2].as(:a[:i])).select_sql.should ==
695
+ "SELECT * FROM generate_series(1, 2) AS a(i)"
696
+
697
+ @dataset.from(:generate_series[1, 2] => :a[:i]).select_sql.should ==
698
+ "SELECT * FROM generate_series(1, 2) a(i)"
699
+ end
680
700
  end
681
701
 
682
702
  context "Dataset#select" do
@@ -1229,6 +1249,14 @@ context "Dataset#join_table" do
1229
1249
  @d.join_table(:left_outer, ds, :item_id => :id).sql.should ==
1230
1250
  'SELECT * FROM items LEFT OUTER JOIN (SELECT * FROM categories WHERE (active = \'t\')) t1 ON (t1.item_id = items.id)'
1231
1251
  end
1252
+
1253
+ specify "should support joining objects that respond to :table_name" do
1254
+ ds = Object.new
1255
+ def ds.table_name; :categories end
1256
+
1257
+ @d.join(ds, :item_id => :id).sql.should ==
1258
+ 'SELECT * FROM items INNER JOIN categories ON (categories.item_id = items.id)'
1259
+ end
1232
1260
  end
1233
1261
 
1234
1262
  context "Dataset#[]=" do
@@ -2943,4 +2971,4 @@ context "Dataset#grep" do
2943
2971
  @ds.grep(:title, [/^ruby/, 'ruby']).sql.should ==
2944
2972
  "SELECT * FROM posts WHERE ((title =~ '^ruby') OR (title LIKE 'ruby'))"
2945
2973
  end
2946
- end
2974
+ end
@@ -1,6 +1,7 @@
1
- # connection URL's for running adapter specs
2
- INFORMIX_URL = 'informix://localhost/mydb'
3
- MYSQL_URL = 'mysql://root@localhost/sandbox'
4
- ORACLE_URL = 'oracle://hr:hr@localhost/XE'
5
- POSTGRES_URL = 'postgres://postgres:postgres@localhost:5432/reality_spec'
6
- SQLITE_URL = 'sqlite:/'
1
+ # database objects for running adapter specs
2
+ # INFORMIX_DB = Sequel('informix://localhost/mydb')
3
+ # MYSQL_DB = Sequel('mysql://root@localhost/sandbox')
4
+ # MYSQL_SOCKET_FILE = '/tmp/mysql.sock'
5
+ # ORACLE_DB = Sequel('oracle://hr:hr@localhost/XE')
6
+ # POSTGRES_DB = Sequel('postgres://postgres:postgres@localhost:5432/reality_spec')
7
+ # SQLITE_DB = Sequel('sqlite:/')
metadata CHANGED
@@ -1,83 +1,39 @@
1
1
  --- !ruby/object:Gem::Specification
2
+ rubygems_version: 0.9.4
3
+ specification_version: 1
2
4
  name: sequel_core
3
5
  version: !ruby/object:Gem::Version
4
- version: "1.3"
5
- platform: ruby
6
- authors:
7
- - Sharon Rosner
6
+ version: 1.4.0
7
+ date: 2008-04-08 00:00:00 -07:00
8
+ summary: "The Database Toolkit for Ruby: Core Library and Adapters"
9
+ require_paths:
10
+ - lib
11
+ email: themastermind1@gmail.com
12
+ homepage: http://sequel.rubyforge.org
13
+ rubyforge_project: sequel
14
+ description: "The Database Toolkit for Ruby: Core Library and Adapters"
8
15
  autorequire:
9
- bindir: bin
10
- cert_chain: []
11
-
12
- date: 2008-03-08 00:00:00 +02:00
13
16
  default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: metaid
17
- version_requirement:
18
- version_requirements: !ruby/object:Gem::Requirement
19
- requirements:
20
- - - ">="
21
- - !ruby/object:Gem::Version
22
- version: "0"
23
- version:
24
- - !ruby/object:Gem::Dependency
25
- name: assistance
26
- version_requirement:
27
- version_requirements: !ruby/object:Gem::Requirement
28
- requirements:
29
- - - ">="
30
- - !ruby/object:Gem::Version
31
- version: "0.1"
32
- version:
33
- - !ruby/object:Gem::Dependency
34
- name: RubyInline
35
- version_requirement:
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: 3.6.6
41
- version:
42
- - !ruby/object:Gem::Dependency
43
- name: ParseTree
44
- version_requirement:
45
- version_requirements: !ruby/object:Gem::Requirement
46
- requirements:
47
- - - ">="
48
- - !ruby/object:Gem::Version
49
- version: 2.1.1
50
- version:
51
- - !ruby/object:Gem::Dependency
52
- name: ruby2ruby
53
- version_requirement:
54
- version_requirements: !ruby/object:Gem::Requirement
55
- requirements:
56
- - - ">="
57
- - !ruby/object:Gem::Version
58
- version: "0"
59
- version:
60
- description: The Database Toolkit for Ruby
61
- email: ciconia@gmail.com
62
- executables:
63
- - sequel
64
- extensions: []
65
-
66
- extra_rdoc_files:
67
- - README
68
- - CHANGELOG
69
- - COPYING
17
+ bindir: bin
18
+ has_rdoc: true
19
+ required_ruby_version: !ruby/object:Gem::Version::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.8.4
24
+ version:
25
+ platform: ruby
26
+ signing_key:
27
+ cert_chain:
28
+ post_install_message:
29
+ authors:
30
+ - Aman Gupta
70
31
  files:
71
32
  - COPYING
72
33
  - README
73
34
  - Rakefile
74
35
  - bin/sequel
75
36
  - spec/adapters
76
- - spec/adapters/informix_spec.rb
77
- - spec/adapters/mysql_spec.rb
78
- - spec/adapters/oracle_spec.rb
79
- - spec/adapters/postgres_spec.rb
80
- - spec/adapters/sqlite_spec.rb
81
37
  - spec/array_keys_spec.rb
82
38
  - spec/core_ext_spec.rb
83
39
  - spec/core_sql_spec.rb
@@ -93,8 +49,27 @@ files:
93
49
  - spec/spec_config.rb.example
94
50
  - spec/spec_helper.rb
95
51
  - spec/worker_spec.rb
52
+ - spec/adapters/informix_spec.rb
53
+ - spec/adapters/mysql_spec.rb
54
+ - spec/adapters/oracle_spec.rb
55
+ - spec/adapters/postgres_spec.rb
56
+ - spec/adapters/sqlite_spec.rb
57
+ - lib/sequel_core.rb
96
58
  - lib/sequel_core
97
59
  - lib/sequel_core/adapters
60
+ - lib/sequel_core/array_keys.rb
61
+ - lib/sequel_core/core_ext.rb
62
+ - lib/sequel_core/core_sql.rb
63
+ - lib/sequel_core/database.rb
64
+ - lib/sequel_core/dataset.rb
65
+ - lib/sequel_core/dataset
66
+ - lib/sequel_core/exceptions.rb
67
+ - lib/sequel_core/migration.rb
68
+ - lib/sequel_core/model.rb
69
+ - lib/sequel_core/pretty_table.rb
70
+ - lib/sequel_core/schema.rb
71
+ - lib/sequel_core/schema
72
+ - lib/sequel_core/worker.rb
98
73
  - lib/sequel_core/adapters/adapter_skeleton.rb
99
74
  - lib/sequel_core/adapters/ado.rb
100
75
  - lib/sequel_core/adapters/db2.rb
@@ -108,29 +83,15 @@ files:
108
83
  - lib/sequel_core/adapters/oracle.rb
109
84
  - lib/sequel_core/adapters/postgres.rb
110
85
  - lib/sequel_core/adapters/sqlite.rb
111
- - lib/sequel_core/array_keys.rb
112
- - lib/sequel_core/core_ext.rb
113
- - lib/sequel_core/core_sql.rb
114
- - lib/sequel_core/database.rb
115
- - lib/sequel_core/dataset
86
+ - lib/sequel_core/dataset/callback.rb
116
87
  - lib/sequel_core/dataset/convenience.rb
117
88
  - lib/sequel_core/dataset/sequelizer.rb
118
89
  - lib/sequel_core/dataset/sql.rb
119
- - lib/sequel_core/dataset.rb
120
- - lib/sequel_core/exceptions.rb
121
- - lib/sequel_core/migration.rb
122
- - lib/sequel_core/model.rb
123
- - lib/sequel_core/pretty_table.rb
124
- - lib/sequel_core/schema
125
- - lib/sequel_core/schema/schema_generator.rb
126
- - lib/sequel_core/schema/schema_sql.rb
127
- - lib/sequel_core/schema.rb
128
- - lib/sequel_core/worker.rb
129
- - lib/sequel_core.rb
90
+ - lib/sequel_core/schema/generator.rb
91
+ - lib/sequel_core/schema/sql.rb
130
92
  - CHANGELOG
131
- has_rdoc: true
132
- homepage: http://sequel.rubyforge.org
133
- post_install_message:
93
+ test_files: []
94
+
134
95
  rdoc_options:
135
96
  - --quiet
136
97
  - --title
@@ -145,26 +106,59 @@ rdoc_options:
145
106
  - ^(examples|extras)/
146
107
  - --exclude
147
108
  - lib/sequel_core.rb
148
- require_paths:
149
- - lib
150
- required_ruby_version: !ruby/object:Gem::Requirement
151
- requirements:
152
- - - ">="
153
- - !ruby/object:Gem::Version
154
- version: 1.8.4
155
- version:
156
- required_rubygems_version: !ruby/object:Gem::Requirement
157
- requirements:
158
- - - ">="
159
- - !ruby/object:Gem::Version
160
- version: "0"
161
- version:
162
- requirements: []
109
+ extra_rdoc_files:
110
+ - README
111
+ - CHANGELOG
112
+ - COPYING
113
+ executables:
114
+ - sequel
115
+ extensions: []
163
116
 
164
- rubyforge_project: sequel
165
- rubygems_version: 1.0.1
166
- signing_key:
167
- specification_version: 2
168
- summary: The Database Toolkit for Ruby
169
- test_files: []
117
+ requirements: []
170
118
 
119
+ dependencies:
120
+ - !ruby/object:Gem::Dependency
121
+ name: metaid
122
+ version_requirement:
123
+ version_requirements: !ruby/object:Gem::Version::Requirement
124
+ requirements:
125
+ - - ">"
126
+ - !ruby/object:Gem::Version
127
+ version: 0.0.0
128
+ version:
129
+ - !ruby/object:Gem::Dependency
130
+ name: assistance
131
+ version_requirement:
132
+ version_requirements: !ruby/object:Gem::Version::Requirement
133
+ requirements:
134
+ - - ">="
135
+ - !ruby/object:Gem::Version
136
+ version: "0.1"
137
+ version:
138
+ - !ruby/object:Gem::Dependency
139
+ name: RubyInline
140
+ version_requirement:
141
+ version_requirements: !ruby/object:Gem::Version::Requirement
142
+ requirements:
143
+ - - ">="
144
+ - !ruby/object:Gem::Version
145
+ version: 3.6.6
146
+ version:
147
+ - !ruby/object:Gem::Dependency
148
+ name: ParseTree
149
+ version_requirement:
150
+ version_requirements: !ruby/object:Gem::Version::Requirement
151
+ requirements:
152
+ - - ">="
153
+ - !ruby/object:Gem::Version
154
+ version: 2.1.1
155
+ version:
156
+ - !ruby/object:Gem::Dependency
157
+ name: ruby2ruby
158
+ version_requirement:
159
+ version_requirements: !ruby/object:Gem::Version::Requirement
160
+ requirements:
161
+ - - ">"
162
+ - !ruby/object:Gem::Version
163
+ version: 0.0.0
164
+ version: