sequel 4.1.1 → 4.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG +32 -0
- data/doc/opening_databases.rdoc +4 -0
- data/doc/release_notes/4.2.0.txt +129 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +5 -0
- data/lib/sequel/adapters/mysql2.rb +2 -1
- data/lib/sequel/adapters/postgres.rb +8 -4
- data/lib/sequel/adapters/shared/db2.rb +5 -0
- data/lib/sequel/adapters/shared/mssql.rb +15 -4
- data/lib/sequel/adapters/shared/mysql.rb +1 -0
- data/lib/sequel/adapters/shared/oracle.rb +1 -1
- data/lib/sequel/adapters/shared/postgres.rb +10 -0
- data/lib/sequel/adapters/shared/sqlite.rb +5 -0
- data/lib/sequel/database/features.rb +6 -1
- data/lib/sequel/database/schema_methods.rb +3 -7
- data/lib/sequel/dataset/actions.rb +3 -4
- data/lib/sequel/dataset/features.rb +5 -0
- data/lib/sequel/dataset/misc.rb +28 -3
- data/lib/sequel/dataset/mutation.rb +37 -11
- data/lib/sequel/dataset/prepared_statements.rb +1 -3
- data/lib/sequel/dataset/query.rb +12 -3
- data/lib/sequel/dataset/sql.rb +12 -6
- data/lib/sequel/deprecated.rb +1 -1
- data/lib/sequel/extensions/columns_introspection.rb +1 -1
- data/lib/sequel/extensions/core_extensions.rb +0 -2
- data/lib/sequel/extensions/empty_array_ignore_nulls.rb +1 -1
- data/lib/sequel/extensions/filter_having.rb +1 -1
- data/lib/sequel/extensions/from_block.rb +31 -0
- data/lib/sequel/extensions/graph_each.rb +1 -1
- data/lib/sequel/extensions/hash_aliases.rb +1 -1
- data/lib/sequel/extensions/mssql_emulate_lateral_with_apply.rb +78 -0
- data/lib/sequel/extensions/pagination.rb +1 -1
- data/lib/sequel/extensions/pg_loose_count.rb +32 -0
- data/lib/sequel/extensions/pg_static_cache_updater.rb +133 -0
- data/lib/sequel/extensions/pretty_table.rb +1 -1
- data/lib/sequel/extensions/query.rb +3 -1
- data/lib/sequel/extensions/query_literals.rb +1 -1
- data/lib/sequel/extensions/select_remove.rb +1 -1
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +1 -1
- data/lib/sequel/extensions/set_overrides.rb +1 -1
- data/lib/sequel/model.rb +1 -1
- data/lib/sequel/model/base.rb +20 -6
- data/lib/sequel/model/exceptions.rb +1 -1
- data/lib/sequel/plugins/composition.rb +9 -0
- data/lib/sequel/plugins/dirty.rb +19 -8
- data/lib/sequel/plugins/instance_filters.rb +9 -0
- data/lib/sequel/plugins/serialization.rb +9 -0
- data/lib/sequel/plugins/serialization_modification_detection.rb +9 -0
- data/lib/sequel/plugins/static_cache.rb +96 -28
- data/lib/sequel/version.rb +2 -2
- data/spec/adapters/mssql_spec.rb +1 -1
- data/spec/adapters/postgres_spec.rb +70 -0
- data/spec/core/dataset_spec.rb +58 -1
- data/spec/core/deprecated_spec.rb +1 -1
- data/spec/core/schema_spec.rb +18 -0
- data/spec/extensions/composition_spec.rb +7 -0
- data/spec/extensions/dirty_spec.rb +9 -0
- data/spec/extensions/from_block_spec.rb +21 -0
- data/spec/extensions/instance_filters_spec.rb +6 -0
- data/spec/extensions/pg_loose_count_spec.rb +17 -0
- data/spec/extensions/pg_static_cache_updater_spec.rb +80 -0
- data/spec/extensions/query_spec.rb +8 -0
- data/spec/extensions/serialization_modification_detection_spec.rb +9 -0
- data/spec/extensions/serialization_spec.rb +7 -0
- data/spec/extensions/set_overrides_spec.rb +12 -0
- data/spec/extensions/static_cache_spec.rb +314 -154
- data/spec/integration/dataset_test.rb +12 -2
- data/spec/integration/schema_test.rb +13 -0
- data/spec/model/record_spec.rb +74 -0
- metadata +13 -3
data/lib/sequel/version.rb
CHANGED
@@ -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 =
|
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 =
|
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('.')
|
data/spec/adapters/mssql_spec.rb
CHANGED
@@ -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 => :
|
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
|
data/spec/core/dataset_spec.rb
CHANGED
@@ -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
|
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
|
data/spec/core/schema_spec.rb
CHANGED
@@ -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
|