sequel 3.11.0 → 3.12.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (136) hide show
  1. data/CHANGELOG +70 -0
  2. data/Rakefile +1 -1
  3. data/doc/active_record.rdoc +896 -0
  4. data/doc/advanced_associations.rdoc +46 -31
  5. data/doc/association_basics.rdoc +14 -9
  6. data/doc/dataset_basics.rdoc +3 -3
  7. data/doc/migration.rdoc +1011 -0
  8. data/doc/model_hooks.rdoc +198 -0
  9. data/doc/querying.rdoc +811 -86
  10. data/doc/release_notes/3.12.0.txt +304 -0
  11. data/doc/sharding.rdoc +17 -0
  12. data/doc/sql.rdoc +537 -0
  13. data/doc/validations.rdoc +501 -0
  14. data/lib/sequel/adapters/jdbc.rb +19 -27
  15. data/lib/sequel/adapters/jdbc/postgresql.rb +0 -7
  16. data/lib/sequel/adapters/mysql.rb +5 -4
  17. data/lib/sequel/adapters/odbc.rb +3 -2
  18. data/lib/sequel/adapters/shared/mssql.rb +7 -6
  19. data/lib/sequel/adapters/shared/mysql.rb +2 -7
  20. data/lib/sequel/adapters/shared/postgres.rb +2 -8
  21. data/lib/sequel/adapters/shared/sqlite.rb +2 -5
  22. data/lib/sequel/adapters/sqlite.rb +4 -4
  23. data/lib/sequel/core.rb +0 -1
  24. data/lib/sequel/database.rb +2 -1060
  25. data/lib/sequel/database/connecting.rb +227 -0
  26. data/lib/sequel/database/dataset.rb +58 -0
  27. data/lib/sequel/database/dataset_defaults.rb +127 -0
  28. data/lib/sequel/database/logging.rb +62 -0
  29. data/lib/sequel/database/misc.rb +246 -0
  30. data/lib/sequel/database/query.rb +390 -0
  31. data/lib/sequel/database/schema_generator.rb +7 -3
  32. data/lib/sequel/database/schema_methods.rb +351 -7
  33. data/lib/sequel/dataset/actions.rb +9 -2
  34. data/lib/sequel/dataset/misc.rb +6 -2
  35. data/lib/sequel/dataset/mutation.rb +3 -11
  36. data/lib/sequel/dataset/query.rb +49 -6
  37. data/lib/sequel/exceptions.rb +3 -0
  38. data/lib/sequel/extensions/migration.rb +395 -113
  39. data/lib/sequel/extensions/schema_dumper.rb +21 -13
  40. data/lib/sequel/model.rb +27 -25
  41. data/lib/sequel/model/associations.rb +72 -34
  42. data/lib/sequel/model/base.rb +74 -18
  43. data/lib/sequel/model/errors.rb +8 -1
  44. data/lib/sequel/plugins/active_model.rb +8 -0
  45. data/lib/sequel/plugins/association_pks.rb +87 -0
  46. data/lib/sequel/plugins/association_proxies.rb +8 -0
  47. data/lib/sequel/plugins/boolean_readers.rb +12 -6
  48. data/lib/sequel/plugins/caching.rb +14 -7
  49. data/lib/sequel/plugins/class_table_inheritance.rb +15 -9
  50. data/lib/sequel/plugins/composition.rb +2 -1
  51. data/lib/sequel/plugins/force_encoding.rb +10 -7
  52. data/lib/sequel/plugins/hook_class_methods.rb +12 -11
  53. data/lib/sequel/plugins/identity_map.rb +9 -0
  54. data/lib/sequel/plugins/instance_hooks.rb +23 -13
  55. data/lib/sequel/plugins/lazy_attributes.rb +4 -1
  56. data/lib/sequel/plugins/many_through_many.rb +18 -4
  57. data/lib/sequel/plugins/nested_attributes.rb +1 -0
  58. data/lib/sequel/plugins/optimistic_locking.rb +1 -1
  59. data/lib/sequel/plugins/rcte_tree.rb +9 -8
  60. data/lib/sequel/plugins/schema.rb +8 -0
  61. data/lib/sequel/plugins/serialization.rb +1 -3
  62. data/lib/sequel/plugins/sharding.rb +135 -0
  63. data/lib/sequel/plugins/single_table_inheritance.rb +117 -25
  64. data/lib/sequel/plugins/skip_create_refresh.rb +35 -0
  65. data/lib/sequel/plugins/string_stripper.rb +26 -0
  66. data/lib/sequel/plugins/tactical_eager_loading.rb +8 -0
  67. data/lib/sequel/plugins/timestamps.rb +15 -2
  68. data/lib/sequel/plugins/touch.rb +13 -0
  69. data/lib/sequel/plugins/update_primary_key.rb +48 -0
  70. data/lib/sequel/plugins/validation_class_methods.rb +8 -0
  71. data/lib/sequel/plugins/validation_helpers.rb +1 -1
  72. data/lib/sequel/sql.rb +17 -20
  73. data/lib/sequel/version.rb +1 -1
  74. data/spec/adapters/postgres_spec.rb +5 -5
  75. data/spec/core/core_sql_spec.rb +17 -1
  76. data/spec/core/database_spec.rb +17 -5
  77. data/spec/core/dataset_spec.rb +31 -8
  78. data/spec/core/schema_generator_spec.rb +8 -1
  79. data/spec/core/schema_spec.rb +13 -0
  80. data/spec/extensions/association_pks_spec.rb +85 -0
  81. data/spec/extensions/hook_class_methods_spec.rb +9 -9
  82. data/spec/extensions/migration_spec.rb +339 -219
  83. data/spec/extensions/schema_dumper_spec.rb +28 -17
  84. data/spec/extensions/sharding_spec.rb +272 -0
  85. data/spec/extensions/single_table_inheritance_spec.rb +92 -4
  86. data/spec/extensions/skip_create_refresh_spec.rb +17 -0
  87. data/spec/extensions/string_stripper_spec.rb +23 -0
  88. data/spec/extensions/update_primary_key_spec.rb +65 -0
  89. data/spec/extensions/validation_class_methods_spec.rb +5 -5
  90. data/spec/files/bad_down_migration/001_create_alt_basic.rb +4 -0
  91. data/spec/files/bad_down_migration/002_create_alt_advanced.rb +4 -0
  92. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +9 -0
  93. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +9 -0
  94. data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +3 -0
  95. data/spec/files/bad_up_migration/001_create_alt_basic.rb +4 -0
  96. data/spec/files/bad_up_migration/002_create_alt_advanced.rb +3 -0
  97. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +9 -0
  98. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +9 -0
  99. data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +4 -0
  100. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +9 -0
  101. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +9 -0
  102. data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +4 -0
  103. data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +4 -0
  104. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +9 -0
  105. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +9 -0
  106. data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +4 -0
  107. data/spec/files/integer_migrations/001_create_sessions.rb +9 -0
  108. data/spec/files/integer_migrations/002_create_nodes.rb +9 -0
  109. data/spec/files/integer_migrations/003_3_create_users.rb +4 -0
  110. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +9 -0
  111. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +9 -0
  112. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +9 -0
  113. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +9 -0
  114. data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +4 -0
  115. data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +4 -0
  116. data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +4 -0
  117. data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +9 -0
  118. data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +4 -0
  119. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +9 -0
  120. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +9 -0
  121. data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +4 -0
  122. data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +9 -0
  123. data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +9 -0
  124. data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +4 -0
  125. data/spec/integration/eager_loader_test.rb +20 -20
  126. data/spec/integration/migrator_test.rb +187 -0
  127. data/spec/integration/plugin_test.rb +150 -0
  128. data/spec/integration/schema_test.rb +13 -2
  129. data/spec/model/associations_spec.rb +41 -14
  130. data/spec/model/base_spec.rb +69 -0
  131. data/spec/model/eager_loading_spec.rb +7 -3
  132. data/spec/model/record_spec.rb +79 -4
  133. data/spec/model/validations_spec.rb +21 -9
  134. metadata +66 -5
  135. data/doc/schema.rdoc +0 -36
  136. data/lib/sequel/database/schema_sql.rb +0 -320
@@ -0,0 +1,26 @@
1
+ module Sequel
2
+ module Plugins
3
+ # StringStripper is a very simple plugin that strips all input strings
4
+ # when assigning to the model's values. Example:
5
+ #
6
+ # album = Album.new(:name=>' A ')
7
+ # album.name # => 'A'
8
+ #
9
+ # Usage:
10
+ #
11
+ # # Make all model subclass instances strip strings (called before loading subclasses)
12
+ # Sequel::Model.plugin :string_stripper
13
+ #
14
+ # # Make the Album class strip strings
15
+ # Album.plugin :string_stripper
16
+ module StringStripper
17
+ module InstanceMethods
18
+ # Strip value if it is a string, before attempting to assign
19
+ # it to the model's values.
20
+ def []=(k, v)
21
+ v.is_a?(String) ? super(k, v.strip) : super
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
@@ -17,6 +17,14 @@ module Sequel
17
17
  # Album.filter{id<100}.all do |a|
18
18
  # a.artists
19
19
  # end
20
+ #
21
+ # Usage:
22
+ #
23
+ # # Make all model subclass instances use tactical eager loading (called before loading subclasses)
24
+ # Sequel::Model.plugin :tactical_eager_loading
25
+ #
26
+ # # Make the Album class use tactical eager loading
27
+ # Album.plugin :tactical_eager_loading
20
28
  module TacticalEagerLoading
21
29
  module InstanceMethods
22
30
  # The dataset that retrieved this object, set if the object was
@@ -5,6 +5,19 @@ module Sequel
5
5
  # can also set whether to overwrite existing create timestamps (false
6
6
  # by default), or whether to set the update timestamp when creating (also
7
7
  # false by default).
8
+ #
9
+ # Usage:
10
+ #
11
+ # # Timestamp all model instances using +created_at+ and +updated_at+
12
+ # # (called before loading subclasses)
13
+ # Sequel::Model.plugin :timestamps
14
+ #
15
+ # # Timestamp Album instances, with custom column names
16
+ # Album.plugin :timestamps, :create=>:created_on, :update=>:updated_on
17
+ #
18
+ # # Timestamp Artist instances, forcing an overwrite of the create
19
+ # # timestamp, and setting the update timestamp when creating
20
+ # Album.plugin :timestamps, :force=>true, :update_on_create=>true
8
21
  module Timestamps
9
22
  # Configure the plugin by setting the avialable options. Note that
10
23
  # if this method is run more than once, previous settings are ignored,
@@ -51,14 +64,14 @@ module Sequel
51
64
  module InstanceMethods
52
65
  # Set the create timestamp when creating
53
66
  def before_create
54
- super
55
67
  set_create_timestamp
68
+ super
56
69
  end
57
70
 
58
71
  # Set the update timestamp when updating
59
72
  def before_update
60
- super
61
73
  set_update_timestamp
74
+ super
62
75
  end
63
76
 
64
77
  private
@@ -13,6 +13,19 @@ module Sequel
13
13
  # on datasets, so it updates all related rows in a single query, using
14
14
  # the SQL standard CURRENT_TIMESTAMP. Both of these can be overridden
15
15
  # easily if necessary.
16
+ #
17
+ # Usage:
18
+ #
19
+ # # Allow touching of all model instances (called before loading subclasses)
20
+ # Sequel::Model.plugin :touch
21
+ #
22
+ # # Allow touching of Album instances, with a custom column
23
+ # Album.plugin :touch, :column=>:updated_on
24
+ #
25
+ # # Allow touching of Artist instances, updating the albums and tags
26
+ # # associations when touching, touching the +updated_on+ column for
27
+ # # albums and the +updated_at+ column for tags
28
+ # Artist.plugin :touch, :associations=>[{:albums=>:updated_on}, :tags]
16
29
  module Touch
17
30
  # The default column to update when touching
18
31
  TOUCH_COLUMN_DEFAULT = :updated_at
@@ -0,0 +1,48 @@
1
+ module Sequel
2
+ module Plugins
3
+ # The update_primary_key plugin allows you to modify an objects
4
+ # primary key and then save the record. Sequel does not work
5
+ # correctly with primary key modifications by default. Sequel
6
+ # is designed to work with surrogate primary keys that never need to be
7
+ # modified, but this plugin makes it work correctly with natural
8
+ # primary keys that may need to be modified. Example:
9
+ #
10
+ # album = Album[1]
11
+ # album.id = 2
12
+ # album.save
13
+ #
14
+ # Usage:
15
+ #
16
+ # # Make all model subclasses support primary key updates
17
+ # # (called before loading subclasses)
18
+ # Sequel::Model.plugin :update_primary_key
19
+ #
20
+ # # Make the Album class support primary key updates
21
+ # Album.plugin :update_primary_key
22
+ module UpdatePrimaryKey
23
+ module ClassMethods
24
+ # Cache the pk_hash when loading records
25
+ def load(h)
26
+ r = super(h)
27
+ r.pk_hash
28
+ r
29
+ end
30
+ end
31
+
32
+ module InstanceMethods
33
+ # Clear the pk_hash and object dataset cache, and recache
34
+ # the pk_hash
35
+ def after_update
36
+ super
37
+ @pk_hash = nil
38
+ pk_hash
39
+ end
40
+
41
+ # Cache the pk_hash instead of generating it every time
42
+ def pk_hash
43
+ @pk_hash ||= super
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -7,6 +7,14 @@ module Sequel
7
7
  #
8
8
  # It is recommended to use the validation_helpers plugin instead of this one,
9
9
  # as it is less complex and more flexible.
10
+ #
11
+ # Usage:
12
+ #
13
+ # # Add the validation class methods to all model subclasses (called before loading subclasses)
14
+ # Sequel::Model.plugin :validation_class_methods
15
+ #
16
+ # # Add the validation class methods to the Album class
17
+ # Album.plugin :validation_class_methods
10
18
  module ValidationClassMethods
11
19
  # Setup the validations hash for the given model.
12
20
  def self.apply(model)
@@ -3,8 +3,8 @@ module Sequel
3
3
  # The validation_helpers plugin contains instance method equivalents for most of the legacy
4
4
  # class-level validations. The names and APIs are different, though. Example:
5
5
  #
6
+ # Sequel::Model.plugin :validation_helpers
6
7
  # class Album < Sequel::Model
7
- # plugin :validation_helpers
8
8
  # def validate
9
9
  # validates_min_length 1, :num_tracks
10
10
  # end
data/lib/sequel/sql.rb CHANGED
@@ -68,23 +68,32 @@ module Sequel
68
68
  end
69
69
  private_class_method :to_s_method
70
70
 
71
+ # Alias of eql?
72
+ def ==(other)
73
+ eql?(other)
74
+ end
75
+
76
+ # Returns true if the receiver is the same expression as the
77
+ # the +other+ expression.
78
+ def eql?(other)
79
+ other.is_a?(self.class) && !self.class.comparison_attrs.find {|a| send(a) != other.send(a)}
80
+ end
81
+
82
+ # Make sure that the hash value is the same if the attributes are the same.
83
+ def hash
84
+ ([self.class] + self.class.comparison_attrs.map{|x| send(x)}).hash
85
+ end
86
+
71
87
  # Returns self, because SQL::Expression already acts like
72
88
  # LiteralString.
73
89
  def lit
74
90
  self
75
91
  end
76
92
 
77
- # Alias for to_s
93
+ # Alias of to_s
78
94
  def sql_literal(ds)
79
95
  to_s(ds)
80
96
  end
81
-
82
- # Returns true if the receiver is the same expression as the
83
- # the +other+ expression.
84
- def eql?(other)
85
- other.is_a?(self.class) && !self.class.comparison_attrs.find {|a| send(a) != other.send(a)}
86
- end
87
- alias == eql?
88
97
  end
89
98
 
90
99
  # Represents a complex SQL expression, with a given operator and one
@@ -559,12 +568,6 @@ module Sequel
559
568
  @table = table
560
569
  end
561
570
 
562
- # ColumnAll expressions are considered equivalent if they
563
- # have the same class and string representation
564
- def ==(x)
565
- x.class == self.class and @table == x.table
566
- end
567
-
568
571
  to_s_method :column_all_sql
569
572
  end
570
573
 
@@ -626,12 +629,6 @@ module Sequel
626
629
  @f, @args = f, args
627
630
  end
628
631
 
629
- # Functions are considered equivalent if they
630
- # have the same class, function, and arguments.
631
- def ==(x)
632
- x.class == self.class && @f == x.f && @args == x.args
633
- end
634
-
635
632
  to_s_method :function_sql
636
633
  end
637
634
 
@@ -1,6 +1,6 @@
1
1
  module Sequel
2
2
  MAJOR = 3
3
- MINOR = 11
3
+ MINOR = 12
4
4
  TINY = 0
5
5
 
6
6
  VERSION = [MAJOR, MINOR, TINY].join('.')
@@ -541,7 +541,7 @@ context "Postgres::Database schema qualified tables" do
541
541
  after do
542
542
  POSTGRES_DB.quote_identifiers = false
543
543
  POSTGRES_DB << "DROP SCHEMA schema_test CASCADE"
544
- POSTGRES_DB.default_schema = :public
544
+ POSTGRES_DB.default_schema = nil
545
545
  end
546
546
 
547
547
  specify "should be able to create, drop, select and insert into tables in a given schema" do
@@ -914,7 +914,7 @@ context "Postgres::Database functions, languages, and triggers" do
914
914
  specify "#create_trigger and #drop_trigger should create and drop triggers" do
915
915
  @d.create_language(:plpgsql)
916
916
  @d.create_function(:tf, 'BEGIN IF NEW.value IS NULL THEN RAISE EXCEPTION \'Blah\'; END IF; RETURN NEW; END;', :language=>:plpgsql, :returns=>:trigger)
917
- @d.send(:create_trigger_sql, :test, :identity, :tf, :each_row=>true).should == 'CREATE TRIGGER identity BEFORE INSERT OR UPDATE OR DELETE ON public.test FOR EACH ROW EXECUTE PROCEDURE tf()'
917
+ @d.send(:create_trigger_sql, :test, :identity, :tf, :each_row=>true).should == 'CREATE TRIGGER identity BEFORE INSERT OR UPDATE OR DELETE ON test FOR EACH ROW EXECUTE PROCEDURE tf()'
918
918
  @d.create_table(:test){String :name; Integer :value}
919
919
  @d.create_trigger(:test, :identity, :tf, :each_row=>true)
920
920
  @d[:test].insert(:name=>'a', :value=>1)
@@ -923,10 +923,10 @@ context "Postgres::Database functions, languages, and triggers" do
923
923
  @d[:test].filter(:name=>'a').all.should == [{:name=>'a', :value=>1}]
924
924
  @d[:test].filter(:name=>'a').update(:value=>3)
925
925
  @d[:test].filter(:name=>'a').all.should == [{:name=>'a', :value=>3}]
926
- @d.send(:drop_trigger_sql, :test, :identity).should == 'DROP TRIGGER identity ON public.test'
926
+ @d.send(:drop_trigger_sql, :test, :identity).should == 'DROP TRIGGER identity ON test'
927
927
  @d.drop_trigger(:test, :identity)
928
- @d.send(:create_trigger_sql, :test, :identity, :tf, :after=>true, :events=>:insert, :args=>[1, 'a']).should == 'CREATE TRIGGER identity AFTER INSERT ON public.test EXECUTE PROCEDURE tf(1, \'a\')'
929
- @d.send(:drop_trigger_sql, :test, :identity, :if_exists=>true, :cascade=>true).should == 'DROP TRIGGER IF EXISTS identity ON public.test CASCADE'
928
+ @d.send(:create_trigger_sql, :test, :identity, :tf, :after=>true, :events=>:insert, :args=>[1, 'a']).should == 'CREATE TRIGGER identity AFTER INSERT ON test EXECUTE PROCEDURE tf(1, \'a\')'
929
+ @d.send(:drop_trigger_sql, :test, :identity, :if_exists=>true, :cascade=>true).should == 'DROP TRIGGER IF EXISTS identity ON test CASCADE'
930
930
  # Make sure if exists works
931
931
  @d.drop_trigger(:test, :identity, :if_exists=>true, :cascade=>true)
932
932
  end
@@ -410,8 +410,24 @@ context "Sequel::SQL::OrderedExpression" do
410
410
  end
411
411
 
412
412
  context "Expression" do
413
- specify "should ==" do
413
+ specify "should consider objects == only if they have the same attributes" do
414
414
  :column.qualify(:table).cast(:type).*(:numeric_column).asc.should == :column.qualify(:table).cast(:type).*(:numeric_column).asc
415
415
  :other_column.qualify(:table).cast(:type).*(:numeric_column).asc.should_not == :column.qualify(:table).cast(:type).*(:numeric_column).asc
416
+
417
+ :column.qualify(:table).cast(:type).*(:numeric_column).asc.should eql(:column.qualify(:table).cast(:type).*(:numeric_column).asc)
418
+ :other_column.qualify(:table).cast(:type).*(:numeric_column).asc.should_not eql(:column.qualify(:table).cast(:type).*(:numeric_column).asc)
419
+ end
420
+
421
+ specify "should use the same hash value for objects that have the same attributes" do
422
+ :column.qualify(:table).cast(:type).*(:numeric_column).asc.hash.should == :column.qualify(:table).cast(:type).*(:numeric_column).asc.hash
423
+ :other_column.qualify(:table).cast(:type).*(:numeric_column).asc.hash.should_not == :column.qualify(:table).cast(:type).*(:numeric_column).asc.hash
424
+
425
+ h = {}
426
+ a = :column.qualify(:table).cast(:type).*(:numeric_column).asc
427
+ b = :column.qualify(:table).cast(:type).*(:numeric_column).asc
428
+ h[a] = 1
429
+ h[b] = 2
430
+ h[a].should == 2
431
+ h[b].should == 2
416
432
  end
417
433
  end
@@ -204,8 +204,8 @@ context "Sequel.extension" do
204
204
  end
205
205
 
206
206
  context "Database#connect" do
207
- specify "should raise NotImplementedError" do
208
- proc {Sequel::Database.new.connect(:default)}.should raise_error(NotImplementedError)
207
+ specify "should raise Sequel::NotImplemented" do
208
+ proc {Sequel::Database.new.connect(:default)}.should raise_error(Sequel::NotImplemented)
209
209
  end
210
210
  end
211
211
 
@@ -363,9 +363,21 @@ context "Database#dataset" do
363
363
  end
364
364
 
365
365
  context "Database#execute" do
366
- specify "should raise NotImplementedError" do
367
- proc {Sequel::Database.new.execute('blah blah')}.should raise_error(NotImplementedError)
368
- proc {Sequel::Database.new << 'blah blah'}.should raise_error(NotImplementedError)
366
+ specify "should raise Sequel::NotImplemented" do
367
+ proc {Sequel::Database.new.execute('blah blah')}.should raise_error(Sequel::NotImplemented)
368
+ proc {Sequel::Database.new << 'blah blah'}.should raise_error(Sequel::NotImplemented)
369
+ end
370
+ end
371
+
372
+ context "Database#tables" do
373
+ specify "should raise Sequel::NotImplemented" do
374
+ proc {Sequel::Database.new.tables}.should raise_error(Sequel::NotImplemented)
375
+ end
376
+ end
377
+
378
+ context "Database#indexes" do
379
+ specify "should raise Sequel::NotImplemented" do
380
+ proc {Sequel::Database.new.indexes(:table)}.should raise_error(Sequel::NotImplemented)
369
381
  end
370
382
  end
371
383
 
@@ -1316,24 +1316,47 @@ context "Dataset#order_by" do
1316
1316
  end
1317
1317
  end
1318
1318
 
1319
- context "Dataset#order_more" do
1319
+ context "Dataset#order_more and order_append" do
1320
1320
  before do
1321
1321
  @dataset = Sequel::Dataset.new(nil).from(:test)
1322
1322
  end
1323
1323
 
1324
1324
  specify "should include an ORDER BY clause in the select statement" do
1325
- @dataset.order_more(:name).sql.should ==
1326
- 'SELECT * FROM test ORDER BY name'
1325
+ @dataset.order_more(:name).sql.should == 'SELECT * FROM test ORDER BY name'
1326
+ @dataset.order_append(:name).sql.should == 'SELECT * FROM test ORDER BY name'
1327
1327
  end
1328
1328
 
1329
- specify "should add to a previous ordering" do
1330
- @dataset.order(:name).order_more(:stamp.desc).sql.should ==
1331
- 'SELECT * FROM test ORDER BY name, stamp DESC'
1329
+ specify "should add to the end of a previous ordering" do
1330
+ @dataset.order(:name).order_more(:stamp.desc).sql.should == 'SELECT * FROM test ORDER BY name, stamp DESC'
1331
+ @dataset.order(:name).order_append(:stamp.desc).sql.should == 'SELECT * FROM test ORDER BY name, stamp DESC'
1332
1332
  end
1333
1333
 
1334
1334
  specify "should accept a block that yields a virtual row" do
1335
1335
  @dataset.order(:a).order_more{|o| o.b}.sql.should == 'SELECT * FROM test ORDER BY a, b'
1336
1336
  @dataset.order(:a, :b).order_more(:c, :d){[e, f(1, 2)]}.sql.should == 'SELECT * FROM test ORDER BY a, b, c, d, e, f(1, 2)'
1337
+ @dataset.order(:a).order_append{|o| o.b}.sql.should == 'SELECT * FROM test ORDER BY a, b'
1338
+ @dataset.order(:a, :b).order_append(:c, :d){[e, f(1, 2)]}.sql.should == 'SELECT * FROM test ORDER BY a, b, c, d, e, f(1, 2)'
1339
+ end
1340
+ end
1341
+
1342
+ context "Dataset#order_prepend" do
1343
+ before do
1344
+ @dataset = Sequel::Dataset.new(nil).from(:test)
1345
+ end
1346
+
1347
+ specify "should include an ORDER BY clause in the select statement" do
1348
+ @dataset.order_prepend(:name).sql.should ==
1349
+ 'SELECT * FROM test ORDER BY name'
1350
+ end
1351
+
1352
+ specify "should add to the beginning of a previous ordering" do
1353
+ @dataset.order(:name).order_prepend(:stamp.desc).sql.should ==
1354
+ 'SELECT * FROM test ORDER BY stamp DESC, name'
1355
+ end
1356
+
1357
+ specify "should accept a block that yields a virtual row" do
1358
+ @dataset.order(:a).order_prepend{|o| o.b}.sql.should == 'SELECT * FROM test ORDER BY b, a'
1359
+ @dataset.order(:a, :b).order_prepend(:c, :d){[e, f(1, 2)]}.sql.should == 'SELECT * FROM test ORDER BY c, d, e, f(1, 2), a, b'
1337
1360
  end
1338
1361
  end
1339
1362
 
@@ -3074,8 +3097,8 @@ context "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #exe
3074
3097
  @ds = @db[:items]
3075
3098
  end
3076
3099
 
3077
- specify "#fetch_rows should raise a NotImplementedError" do
3078
- proc{@ds.fetch_rows(''){}}.should raise_error(NotImplementedError)
3100
+ specify "#fetch_rows should raise a Sequel::NotImplemented" do
3101
+ proc{@ds.fetch_rows(''){}}.should raise_error(Sequel::NotImplemented)
3079
3102
  end
3080
3103
 
3081
3104
  specify "#delete should execute delete SQL" do
@@ -12,6 +12,7 @@ describe Sequel::Schema::Generator do
12
12
  index :title
13
13
  index [:title, :body], :unique => true
14
14
  foreign_key :node_id, :nodes
15
+ foreign_key :deferrable_node_id, :nodes, :deferrable => true
15
16
  primary_key [:title, :parent_id], :name => :cpk
16
17
  foreign_key [:node_id, :prop_id], :nodes_props, :name => :cfk
17
18
  end
@@ -26,7 +27,7 @@ describe Sequel::Schema::Generator do
26
27
  end
27
28
 
28
29
  it "counts definitions correctly" do
29
- @columns.size.should == 5
30
+ @columns.size.should == 6
30
31
  @indexes.size.should == 2
31
32
  @constraints.size.should == 4
32
33
  end
@@ -48,6 +49,12 @@ describe Sequel::Schema::Generator do
48
49
  @columns[4][:name].should == :node_id
49
50
  @columns[4][:type].should == Integer
50
51
  end
52
+
53
+ it "creates deferrable altered foreign key column" do
54
+ @columns[5][:name].should == :deferrable_node_id
55
+ @columns[5][:type].should == Integer
56
+ @columns[5][:deferrable].should == true
57
+ end
51
58
 
52
59
  it "uses table for foreign key columns, if specified" do
53
60
  @columns[3][:table].should == nil
@@ -23,6 +23,12 @@ context "DB#create_table" do
23
23
  proc{@db.create_table(:cats.as(:c)) {}}.should raise_error(Sequel::Error)
24
24
  end
25
25
 
26
+ specify "should remove cached schema entry" do
27
+ @db.instance_variable_set(:@schemas, {'cats'=>[]})
28
+ @db.create_table(:cats){Integer :a}
29
+ @db.instance_variable_get(:@schemas).should be_empty
30
+ end
31
+
26
32
  specify "should accept multiple columns" do
27
33
  @db.create_table(:cats) do
28
34
  column :id, :integer
@@ -268,6 +274,13 @@ context "DB#create_table" do
268
274
  @db.sqls.clear
269
275
  end
270
276
 
277
+ specify "should accept foreign keys with deferrable option" do
278
+ @db.create_table(:cats) do
279
+ foreign_key :project_id, :projects, :deferrable=>true
280
+ end
281
+ @db.sqls.should == ["CREATE TABLE cats (project_id integer REFERENCES projects DEFERRABLE INITIALLY DEFERRED)"]
282
+ end
283
+
271
284
  specify "should accept inline index definition" do
272
285
  @db.create_table(:cats) do
273
286
  integer :id, :index => true