sequel 4.1.1 → 4.2.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.
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