sequel 4.1.1 → 4.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (70) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +32 -0
  3. data/doc/opening_databases.rdoc +4 -0
  4. data/doc/release_notes/4.2.0.txt +129 -0
  5. data/lib/sequel/adapters/jdbc/hsqldb.rb +5 -0
  6. data/lib/sequel/adapters/mysql2.rb +2 -1
  7. data/lib/sequel/adapters/postgres.rb +8 -4
  8. data/lib/sequel/adapters/shared/db2.rb +5 -0
  9. data/lib/sequel/adapters/shared/mssql.rb +15 -4
  10. data/lib/sequel/adapters/shared/mysql.rb +1 -0
  11. data/lib/sequel/adapters/shared/oracle.rb +1 -1
  12. data/lib/sequel/adapters/shared/postgres.rb +10 -0
  13. data/lib/sequel/adapters/shared/sqlite.rb +5 -0
  14. data/lib/sequel/database/features.rb +6 -1
  15. data/lib/sequel/database/schema_methods.rb +3 -7
  16. data/lib/sequel/dataset/actions.rb +3 -4
  17. data/lib/sequel/dataset/features.rb +5 -0
  18. data/lib/sequel/dataset/misc.rb +28 -3
  19. data/lib/sequel/dataset/mutation.rb +37 -11
  20. data/lib/sequel/dataset/prepared_statements.rb +1 -3
  21. data/lib/sequel/dataset/query.rb +12 -3
  22. data/lib/sequel/dataset/sql.rb +12 -6
  23. data/lib/sequel/deprecated.rb +1 -1
  24. data/lib/sequel/extensions/columns_introspection.rb +1 -1
  25. data/lib/sequel/extensions/core_extensions.rb +0 -2
  26. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +1 -1
  27. data/lib/sequel/extensions/filter_having.rb +1 -1
  28. data/lib/sequel/extensions/from_block.rb +31 -0
  29. data/lib/sequel/extensions/graph_each.rb +1 -1
  30. data/lib/sequel/extensions/hash_aliases.rb +1 -1
  31. data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +78 -0
  32. data/lib/sequel/extensions/pagination.rb +1 -1
  33. data/lib/sequel/extensions/pg_loose_count.rb +32 -0
  34. data/lib/sequel/extensions/pg_static_cache_updater.rb +133 -0
  35. data/lib/sequel/extensions/pretty_table.rb +1 -1
  36. data/lib/sequel/extensions/query.rb +3 -1
  37. data/lib/sequel/extensions/query_literals.rb +1 -1
  38. data/lib/sequel/extensions/select_remove.rb +1 -1
  39. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +1 -1
  40. data/lib/sequel/extensions/set_overrides.rb +1 -1
  41. data/lib/sequel/model.rb +1 -1
  42. data/lib/sequel/model/base.rb +20 -6
  43. data/lib/sequel/model/exceptions.rb +1 -1
  44. data/lib/sequel/plugins/composition.rb +9 -0
  45. data/lib/sequel/plugins/dirty.rb +19 -8
  46. data/lib/sequel/plugins/instance_filters.rb +9 -0
  47. data/lib/sequel/plugins/serialization.rb +9 -0
  48. data/lib/sequel/plugins/serialization_modification_detection.rb +9 -0
  49. data/lib/sequel/plugins/static_cache.rb +96 -28
  50. data/lib/sequel/version.rb +2 -2
  51. data/spec/adapters/mssql_spec.rb +1 -1
  52. data/spec/adapters/postgres_spec.rb +70 -0
  53. data/spec/core/dataset_spec.rb +58 -1
  54. data/spec/core/deprecated_spec.rb +1 -1
  55. data/spec/core/schema_spec.rb +18 -0
  56. data/spec/extensions/composition_spec.rb +7 -0
  57. data/spec/extensions/dirty_spec.rb +9 -0
  58. data/spec/extensions/from_block_spec.rb +21 -0
  59. data/spec/extensions/instance_filters_spec.rb +6 -0
  60. data/spec/extensions/pg_loose_count_spec.rb +17 -0
  61. data/spec/extensions/pg_static_cache_updater_spec.rb +80 -0
  62. data/spec/extensions/query_spec.rb +8 -0
  63. data/spec/extensions/serialization_modification_detection_spec.rb +9 -0
  64. data/spec/extensions/serialization_spec.rb +7 -0
  65. data/spec/extensions/set_overrides_spec.rb +12 -0
  66. data/spec/extensions/static_cache_spec.rb +314 -154
  67. data/spec/integration/dataset_test.rb +12 -2
  68. data/spec/integration/schema_test.rb +13 -0
  69. data/spec/model/record_spec.rb +74 -0
  70. metadata +13 -3
@@ -3,10 +3,10 @@ module Sequel
3
3
  MAJOR = 4
4
4
  # The minor version of Sequel. Bumped for every non-patch level
5
5
  # release, generally around once a month.
6
- MINOR = 1
6
+ MINOR = 2
7
7
  # The tiny version of Sequel. Usually 0, only bumped for bugfix
8
8
  # releases that fix regressions from previous versions.
9
- TINY = 1
9
+ TINY = 0
10
10
 
11
11
  # The version of Sequel you are using, as a string (e.g. "2.11.0")
12
12
  VERSION = [MAJOR, MINOR, TINY].join('.')
@@ -612,7 +612,7 @@ describe "Database#foreign_key_list" do
612
612
  DB.execute_ddl "drop schema vendor"
613
613
  end
614
614
  it "should support mixed schema bound tables" do
615
- DB.foreign_key_list(:vendor__mapping).sort_by{|h| h[:name].to_s}.should == [{:name => :fk_mapping_item, :table => :items, :columns => [:item_id], :key => [:id], :on_update => :no_action, :on_delete => :no_action }, {:name => :fk_mapping_vendor, :table => :vendor__vendors, :columns => [:vendor_id], :key => [:id], :on_update => :no_action, :on_delete => :no_action }]
615
+ DB.foreign_key_list(:vendor__mapping).sort_by{|h| h[:name].to_s}.should == [{:name => :fk_mapping_item, :table => :items, :columns => [:item_id], :key => [:id], :on_update => :no_action, :on_delete => :no_action }, {:name => :fk_mapping_vendor, :table => Sequel.qualify(:vendor, :vendors), :columns => [:vendor_id], :key => [:id], :on_update => :no_action, :on_delete => :no_action }]
616
616
  end
617
617
  end
618
618
  end
@@ -60,6 +60,18 @@ describe "PostgreSQL", '#create_table' do
60
60
  @db.create_table(:temp_unlogged_dolls, :temp => true, :unlogged => true){text :name}
61
61
  end.should raise_error(Sequel::Error, "can't provide both :temp and :unlogged to create_table")
62
62
  end
63
+
64
+ specify "should support pg_loose_count extension" do
65
+ @db.extension :pg_loose_count
66
+ @db.create_table(:tmp_dolls){text :name}
67
+ @db.loose_count(:tmp_dolls).should be_a_kind_of(Integer)
68
+ @db.loose_count(:tmp_dolls).should == 0
69
+ @db.loose_count(:public__tmp_dolls).should == 0
70
+ @db[:tmp_dolls].insert('a')
71
+ @db << 'VACUUM ANALYZE tmp_dolls'
72
+ @db.loose_count(:tmp_dolls).should == 1
73
+ @db.loose_count(:public__tmp_dolls).should == 1
74
+ end
63
75
  end
64
76
 
65
77
  describe "PostgreSQL views" do
@@ -1411,6 +1423,21 @@ if DB.adapter_scheme == :postgres
1411
1423
  end
1412
1424
  end
1413
1425
 
1426
+ specify "should respect the :cursor_name option" do
1427
+ one_rows = []
1428
+ two_rows = []
1429
+ @ds.order(:x).use_cursor(:cursor_name => 'cursor_one').each do |one|
1430
+ one_rows << one
1431
+ if one[:x] % 1000 == 500
1432
+ two_rows = []
1433
+ @ds.order(:x).use_cursor(:cursor_name => 'cursor_two').each do |two|
1434
+ two_rows << two
1435
+ end
1436
+ end
1437
+ end
1438
+ one_rows.should == two_rows
1439
+ end
1440
+
1414
1441
  specify "should handle returning inside block" do
1415
1442
  def @ds.check_return
1416
1443
  use_cursor.each{|r| return}
@@ -3135,3 +3162,46 @@ describe 'PostgreSQL row-valued/composite types' do
3135
3162
  end
3136
3163
  end
3137
3164
  end
3165
+
3166
+ describe 'pg_static_cache_updater extension' do
3167
+ before(:all) do
3168
+ @db = DB
3169
+ @db.extension :pg_static_cache_updater
3170
+ @db.drop_function(@db.default_static_cache_update_name, :cascade=>true, :if_exists=>true)
3171
+ @db.create_static_cache_update_function
3172
+
3173
+ @db.create_table!(:things) do
3174
+ primary_key :id
3175
+ String :name
3176
+ end
3177
+ @Thing = Class.new(Sequel::Model(:things))
3178
+ @Thing.plugin :static_cache
3179
+ @db.create_static_cache_update_trigger(:things)
3180
+ end
3181
+ after(:all) do
3182
+ @db.drop_table(:things)
3183
+ @db.drop_function(@db.default_static_cache_update_name)
3184
+ end
3185
+
3186
+ specify "should reload model static cache when underlying table changes" do
3187
+ @Thing.all.should == []
3188
+ q = Queue.new
3189
+ q1 = Queue.new
3190
+
3191
+ @db.listen_for_static_cache_updates(@Thing, :timeout=>0, :loop=>proc{q.push(nil); q1.pop.call})
3192
+ q.pop
3193
+ q1.push(proc{@db[:things].insert(1, 'A')})
3194
+ q.pop
3195
+ @Thing.all.should == [@Thing.load(:id=>1, :name=>'A')]
3196
+
3197
+ q1.push(proc{@db[:things].update(:name=>'B')})
3198
+ q.pop
3199
+ @Thing.all.should == [@Thing.load(:id=>1, :name=>'B')]
3200
+
3201
+ q1.push(proc{@db[:things].delete})
3202
+ q.pop
3203
+ @Thing.all.should == []
3204
+
3205
+ q1.push(proc{throw :stop})
3206
+ end
3207
+ end if DB.adapter_scheme == :postgres && SEQUEL_POSTGRES_USES_PG && DB.server_version >= 90000
@@ -421,7 +421,12 @@ describe "Dataset#where" do
421
421
  specify "should handle partial names" do
422
422
  @dataset.where('price < :price AND id = :p', :p=>2, :price=>100).select_sql.should == "SELECT * FROM test WHERE (price < 100 AND id = 2)"
423
423
  end
424
-
424
+
425
+ specify "should handle ::cast syntax when no parameters are supplied" do
426
+ @dataset.where('price::float = 10', {}).select_sql.should == "SELECT * FROM test WHERE (price::float = 10)"
427
+ @dataset.where('price::float ? 10', {}).select_sql.should == "SELECT * FROM test WHERE (price::float ? 10)"
428
+ end
429
+
425
430
  specify "should affect select, delete and update statements" do
426
431
  @d1.select_sql.should == "SELECT * FROM test WHERE (region = 'Asia')"
427
432
  @d1.delete_sql.should == "DELETE FROM test WHERE (region = 'Asia')"
@@ -1139,6 +1144,10 @@ describe "Dataset#from" do
1139
1144
  @dataset.from(:a, :b){[i, abc(de)]}.select_sql.should == "SELECT * FROM a, b, i, abc(de)"
1140
1145
  end
1141
1146
 
1147
+ specify "should handle LATERAL subqueries" do
1148
+ @dataset.from(:a, @dataset.from(:b).lateral).select_sql.should == "SELECT * FROM a, LATERAL (SELECT * FROM b) AS t1"
1149
+ end
1150
+
1142
1151
  specify "should accept :schema__table___alias symbol format" do
1143
1152
  @dataset.from(:abc__def).select_sql.should == "SELECT * FROM abc.def"
1144
1153
  @dataset.from(:a_b__c).select_sql.should == "SELECT * FROM a_b.c"
@@ -2039,6 +2048,12 @@ describe "Dataset#join_table" do
2039
2048
  specify "should support multiple joins" do
2040
2049
  @d.join_table(:inner, :b, :items_id=>:id).join_table(:left_outer, :c, :b_id => :b__id).sql.should == 'SELECT * FROM "items" INNER JOIN "b" ON ("b"."items_id" = "items"."id") LEFT OUTER JOIN "c" ON ("c"."b_id" = "b"."id")'
2041
2050
  end
2051
+
2052
+ specify "should handle LATERAL subqueries" do
2053
+ @d.join(@d.lateral, :a=>:b).select_sql.should == 'SELECT * FROM "items" INNER JOIN LATERAL (SELECT * FROM "items") AS "t1" ON ("t1"."a" = "items"."b")'
2054
+ @d.left_join(@d.lateral, :a=>:b).select_sql.should == 'SELECT * FROM "items" LEFT JOIN LATERAL (SELECT * FROM "items") AS "t1" ON ("t1"."a" = "items"."b")'
2055
+ @d.cross_join(@d.lateral).select_sql.should == 'SELECT * FROM "items" CROSS JOIN LATERAL (SELECT * FROM "items") AS "t1"'
2056
+ end
2042
2057
 
2043
2058
  specify "should support arbitrary join types" do
2044
2059
  @d.join_table(:magic, :categories, :category_id=>:id).sql.should == 'SELECT * FROM "items" MAGIC JOIN "categories" ON ("categories"."category_id" = "items"."id")'
@@ -4513,3 +4528,45 @@ describe "Dataset#supports_replace?" do
4513
4528
  Sequel::Dataset.new(nil).supports_replace?.should be_false
4514
4529
  end
4515
4530
  end
4531
+
4532
+ describe "Frozen Datasets" do
4533
+ before do
4534
+ @ds = Sequel.mock[:test].freeze
4535
+ end
4536
+
4537
+ it "should be returned by Dataset#freeze" do
4538
+ @ds.should be_frozen
4539
+ end
4540
+
4541
+ it "should have Dataset#freeze return receiver" do
4542
+ @ds = Sequel.mock[:test]
4543
+ @ds.freeze.should equal(@ds)
4544
+ end
4545
+
4546
+ it "should have Dataset#freeze be a no-op" do
4547
+ @ds.freeze.should equal(@ds)
4548
+ end
4549
+
4550
+ it "should have clones be frozen" do
4551
+ @ds.clone.should be_frozen
4552
+ end
4553
+
4554
+ it "should have dups not be frozen" do
4555
+ @ds.dup.should_not be_frozen
4556
+ end
4557
+
4558
+ it "should raise an error when calling mutation methods" do
4559
+ proc{@ds.select!(:a)}.should raise_error
4560
+ proc{@ds.identifier_input_method = :a}.should raise_error
4561
+ proc{@ds.identifier_output_method = :a}.should raise_error
4562
+ proc{@ds.quote_identifiers = false}.should raise_error
4563
+ proc{@ds.row_proc = proc{}}.should raise_error
4564
+ proc{@ds.extension! :query}.should raise_error
4565
+ proc{@ds.naked!}.should raise_error
4566
+ proc{@ds.from_self!}.should raise_error
4567
+ end
4568
+
4569
+ it "should not raise an error when calling query methods" do
4570
+ @ds.select(:a).sql.should == 'SELECT a FROM test'
4571
+ end
4572
+ end
@@ -27,7 +27,7 @@ describe "Sequel::Deprecated" do
27
27
 
28
28
  specify "should consider two arguments to be a method name and additional text" do
29
29
  @d.deprecate("foo", "Use bar instead")
30
- @output.should == ['foo is deprecated and will be removed in Sequel 4.0. Use bar instead.']
30
+ @output.should == ['foo is deprecated and will be removed in a future version of Sequel. Use bar instead.']
31
31
  end
32
32
 
33
33
  specify "should include a prefix if set" do
@@ -397,6 +397,24 @@ describe "DB#create_table" do
397
397
  @db.sqls.should == ["CREATE TABLE cats (name text, UNIQUE (name))"]
398
398
  end
399
399
 
400
+ specify "should accept partial index definitions" do
401
+ def @db.supports_partial_indexes?() true end
402
+ @db.create_table(:cats) do
403
+ integer :id
404
+ index :id, :where=>proc{id > 1}
405
+ end
406
+ @db.sqls.should == ["CREATE TABLE cats (id integer)", "CREATE INDEX cats_id_index ON cats (id) WHERE (id > 1)"]
407
+ end
408
+
409
+ specify "should raise an error if partial indexes are not supported" do
410
+ proc do
411
+ @db.create_table(:cats) do
412
+ integer :id
413
+ index :id, :where=>proc{id > 1}
414
+ end
415
+ end.should raise_error(Sequel::Error)
416
+ end
417
+
400
418
  specify "should not raise on index error for unsupported index definitions if ignore_index_errors is used" do
401
419
  proc {
402
420
  @db.create_table(:cats, :ignore_index_errors=>true) do
@@ -201,6 +201,13 @@ describe "Composition plugin" do
201
201
  proc{@o.date = Date.today}.should raise_error
202
202
  end
203
203
 
204
+ it "should have #dup duplicate compositions" do
205
+ @c.composition :date, :mapping=>[:year, :month, :day]
206
+ @o.date.should == Date.new(1, 2, 3)
207
+ @o.dup.compositions.should == @o.compositions
208
+ @o.dup.compositions.should_not equal(@o.compositions)
209
+ end
210
+
204
211
  it "should work correctly with subclasses" do
205
212
  @c.composition :date, :mapping=>[:year, :month, :day]
206
213
  c = Class.new(@c)
@@ -122,6 +122,15 @@ describe "Sequel::Plugins::Dirty" do
122
122
  @o.initial_value(:initial).should == 'i'
123
123
  proc{@o.initial = 'b'}.should raise_error
124
124
  end
125
+
126
+ it "should have #dup duplicate structures" do
127
+ @o.dup.initial_values.should == @o.initial_values
128
+ @o.dup.initial_values.should_not equal(@o.initial_values)
129
+ @o.dup.instance_variable_get(:@missing_initial_values).should == @o.instance_variable_get(:@missing_initial_values)
130
+ @o.dup.instance_variable_get(:@missing_initial_values).should_not equal(@o.instance_variable_get(:@missing_initial_values))
131
+ @o.dup.previous_changes.should == @o.previous_changes
132
+ @o.dup.previous_changes.should_not equal(@o.previous_changes) if @o.previous_changes
133
+ end
125
134
  end
126
135
 
127
136
  describe "with new instance" do
@@ -0,0 +1,21 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "from_block extension" do
4
+ before do
5
+ @db = Sequel.mock
6
+ @db.extension(:from_block)
7
+ end
8
+
9
+ specify "should make Database#from blocks apply to FROM" do
10
+ @db.from{f}.sql.should == 'SELECT * FROM f'
11
+ @db.from{[f, g(f)]}.sql.should == 'SELECT * FROM f, g(f)'
12
+ end
13
+
14
+ specify "should handle from blocks with method arguments" do
15
+ @db.from(:f){g(f)}.sql.should == 'SELECT * FROM f, g(f)'
16
+ end
17
+
18
+ specify "should handle from without block" do
19
+ @db.from(:f).sql.should == 'SELECT * FROM f'
20
+ end
21
+ end
@@ -70,4 +70,10 @@ describe "instance_filters plugin" do
70
70
  @p.freeze
71
71
  proc{@p.instance_filter(:name=>'Jim')}.should raise_error
72
72
  end
73
+
74
+ specify "should have dup duplicate internal structures" do
75
+ @p.instance_filter(:name=>'Joe')
76
+ @p.dup.send(:instance_filters).should == @p.send(:instance_filters)
77
+ @p.dup.send(:instance_filters).should_not equal(@p.send(:instance_filters))
78
+ end
73
79
  end
@@ -0,0 +1,17 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "pg_loose_count extension" do
4
+ before do
5
+ @db = Sequel.mock(:host=>'postgres', :fetch=>{:v=>1}).extension(:pg_loose_count)
6
+ end
7
+
8
+ specify "should add loose_count method getting fast count for entire table using table statistics" do
9
+ @db.loose_count(:a).should == 1
10
+ @db.sqls.should == ["SELECT CAST(reltuples AS integer) AS v FROM pg_class WHERE (oid = CAST(CAST('a' AS regclass) AS oid)) LIMIT 1"]
11
+ end
12
+
13
+ specify "should support schema qualified tables" do
14
+ @db.loose_count(:a__b).should == 1
15
+ @db.sqls.should == ["SELECT CAST(reltuples AS integer) AS v FROM pg_class WHERE (oid = CAST(CAST('a.b' AS regclass) AS oid)) LIMIT 1"]
16
+ end
17
+ end
@@ -0,0 +1,80 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "pg_static_cache_updater extension" do
4
+ before do
5
+ @db = Sequel.mock(:host=>'postgres')
6
+ def @db.listen(chan, opts={})
7
+ execute("LISTEN #{chan}")
8
+ yield(*opts[:yield])
9
+ end
10
+ @db.extension(:pg_static_cache_updater)
11
+ @model = Class.new(Sequel::Model(@db[:table]))
12
+ @model.plugin :static_cache
13
+ @db.sqls
14
+ end
15
+
16
+ specify "#create_static_cache_update_function should create a function in the database" do
17
+ @db.create_static_cache_update_function
18
+ @db.sqls.first.gsub(/\s+/, ' ').should == " CREATE FUNCTION sequel_static_cache_update() RETURNS trigger LANGUAGE plpgsql AS 'BEGIN PERFORM pg_notify(''sequel_static_cache_update'', TG_RELID::text); RETURN NULL; END ' "
19
+ end
20
+
21
+ specify "#create_static_cache_update_function should support :channel_name and :function_name options" do
22
+ @db.create_static_cache_update_function(:channel_name=>'foo', :function_name=>'bar')
23
+ @db.sqls.first.gsub(/\s+/, ' ').should == " CREATE FUNCTION bar() RETURNS trigger LANGUAGE plpgsql AS 'BEGIN PERFORM pg_notify(''foo'', TG_RELID::text); RETURN NULL; END ' "
24
+ end
25
+
26
+ specify "#create_static_cache_update_trigger should create a trigger for the database table" do
27
+ @db.create_static_cache_update_trigger(:tab)
28
+ @db.sqls.first.gsub(/\s+/, ' ').should == "CREATE TRIGGER sequel_static_cache_update AFTER INSERT OR UPDATE OR DELETE ON tab EXECUTE PROCEDURE sequel_static_cache_update()"
29
+ end
30
+
31
+ specify "#create_static_cache_update_trigger should support :trigger_name and :function_name options" do
32
+ @db.create_static_cache_update_trigger(:tab, :trigger_name=>'foo', :function_name=>'bar')
33
+ @db.sqls.first.gsub(/\s+/, ' ').should == "CREATE TRIGGER foo AFTER INSERT OR UPDATE OR DELETE ON tab EXECUTE PROCEDURE bar()"
34
+ end
35
+
36
+ specify "#default_static_cache_update_name should return the default name for function, trigger, and channel" do
37
+ @db.default_static_cache_update_name.should == :sequel_static_cache_update
38
+ end
39
+
40
+ specify "#listen_for_static_cache_updates should listen for changes to model tables and reload model classes" do
41
+ @db.fetch = {:v=>1234}
42
+ @db.listen_for_static_cache_updates([@model], :yield=>[nil, nil, 1234]).join
43
+ @db.sqls.should == ["SELECT CAST(CAST('table' AS regclass) AS oid) AS v LIMIT 1", "LISTEN sequel_static_cache_update", "SELECT * FROM table"]
44
+ end
45
+
46
+ specify "#listen_for_static_cache_updates should not reload model classes if oid doesn't match" do
47
+ @db.fetch = {:v=>1234}
48
+ @db.listen_for_static_cache_updates([@model], :yield=>[nil, nil, 12345]).join
49
+ @db.sqls.should == ["SELECT CAST(CAST('table' AS regclass) AS oid) AS v LIMIT 1", "LISTEN sequel_static_cache_update"]
50
+ end
51
+
52
+ specify "#listen_for_static_cache_updates should support a single model argument" do
53
+ @db.fetch = {:v=>1234}
54
+ @db.listen_for_static_cache_updates(@model, :yield=>[nil, nil, 1234]).join
55
+ @db.sqls.should == ["SELECT CAST(CAST('table' AS regclass) AS oid) AS v LIMIT 1", "LISTEN sequel_static_cache_update", "SELECT * FROM table"]
56
+ end
57
+
58
+ specify "#listen_for_static_cache_updates should support the :channel_name option" do
59
+ @db.fetch = {:v=>1234}
60
+ @db.listen_for_static_cache_updates([@model], :yield=>[nil, nil, 12345], :channel_name=>:foo).join
61
+ @db.sqls.should == ["SELECT CAST(CAST('table' AS regclass) AS oid) AS v LIMIT 1", "LISTEN foo"]
62
+ end
63
+
64
+ specify "#listen_for_static_cache_updates should raise an error if given an empty array" do
65
+ @db.fetch = {:v=>1234}
66
+ proc{@db.listen_for_static_cache_updates([])}.should raise_error(Sequel::Error)
67
+ end
68
+
69
+ specify "#listen_for_static_cache_updates should raise an error if one of the models is not using the static cache plugin" do
70
+ @db.fetch = {:v=>1234}
71
+ proc{@db.listen_for_static_cache_updates(Class.new(Sequel::Model(@db[:table])))}.should raise_error(Sequel::Error)
72
+ end
73
+
74
+ specify "#listen_for_static_cache_updates should raise an error if the database doesn't respond to listen" do
75
+ @db = Sequel.mock(:host=>'postgres')
76
+ @db.extension(:pg_static_cache_updater)
77
+ @db.fetch = {:v=>1234}
78
+ proc{@db.listen_for_static_cache_updates(Class.new(Sequel::Model(@db[:table])))}.should raise_error(Sequel::Error)
79
+ end
80
+ end
@@ -87,6 +87,14 @@ describe "Dataset#query" do
87
87
  q.sql.should == "SELECT * FROM xyz"
88
88
  end
89
89
 
90
+ specify "should have an appropriate mutation method" do
91
+ @d.query! do
92
+ select :a, :b___mongo
93
+ from :yyy
94
+ end
95
+ @d.sql.should == "SELECT a, b AS mongo FROM yyy"
96
+ end
97
+
90
98
  specify "should raise on non-chainable method calls" do
91
99
  proc {@d.query {row_proc}}.should raise_error(Sequel::Error)
92
100
  proc {@d.query {all}}.should raise_error(Sequel::Error)
@@ -77,4 +77,13 @@ describe "serialization_modification_detection plugin" do
77
77
  @o1.h[1] = 2
78
78
  @o1.changed_columns.should == [:h]
79
79
  end
80
+
81
+ it "should work with frozen objects" do
82
+ @o2.changed_columns.should == []
83
+ o = @o2.dup
84
+ @o2.h.should == {}
85
+ @o2.h[1] = 2
86
+ @o2.changed_columns.should == [:h]
87
+ o.changed_columns.should == []
88
+ end
80
89
  end
@@ -293,4 +293,11 @@ describe "Serialization plugin" do
293
293
  proc{o.abc = 2}.should raise_error
294
294
  proc{o.def = 'h'}.should raise_error
295
295
  end
296
+
297
+ it "should have dup duplicate internal structures" do
298
+ @c.plugin :serialization, :yaml, :abc, :def
299
+ o = @c.new
300
+ o.dup.deserialized_values.should == o.deserialized_values
301
+ o.dup.deserialized_values.should_not equal(o.deserialized_values)
302
+ end
296
303
  end
@@ -24,6 +24,12 @@ describe "Sequel::Dataset #set_defaults" do
24
24
  specify "should not affect String update arguments" do
25
25
  @ds.update_sql('y = 2').should == "UPDATE items SET y = 2"
26
26
  end
27
+
28
+ specify "should have working mutation method" do
29
+ @ds = Sequel.mock.dataset.from(:items).extension(:set_overrides)
30
+ @ds.set_defaults!(:x=>1)
31
+ @ds.insert_sql.should == "INSERT INTO items (x) VALUES (1)"
32
+ end
27
33
  end
28
34
 
29
35
  describe "Sequel::Dataset #set_overrides" do
@@ -46,4 +52,10 @@ describe "Sequel::Dataset #set_overrides" do
46
52
  @ds.set_overrides(:y=>2).update_sql.should =~ /UPDATE items SET (x = 1|y = 2), (x = 1|y = 2)/
47
53
  @ds.set_overrides(:x=>2).update_sql.should == "UPDATE items SET x = 1"
48
54
  end
55
+
56
+ specify "should have working mutation method" do
57
+ @ds = Sequel.mock.dataset.from(:items).extension(:set_overrides)
58
+ @ds.set_overrides!(:x=>1)
59
+ @ds.insert_sql.should == "INSERT INTO items (x) VALUES (1)"
60
+ end
49
61
  end