sequel 3.33.0 → 3.34.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 (152) hide show
  1. data/CHANGELOG +140 -0
  2. data/Rakefile +7 -0
  3. data/bin/sequel +22 -2
  4. data/doc/dataset_basics.rdoc +1 -1
  5. data/doc/mass_assignment.rdoc +3 -1
  6. data/doc/querying.rdoc +28 -4
  7. data/doc/reflection.rdoc +23 -3
  8. data/doc/release_notes/3.34.0.txt +671 -0
  9. data/doc/schema_modification.rdoc +18 -2
  10. data/doc/virtual_rows.rdoc +49 -0
  11. data/lib/sequel/adapters/do/mysql.rb +0 -5
  12. data/lib/sequel/adapters/ibmdb.rb +9 -4
  13. data/lib/sequel/adapters/jdbc.rb +9 -4
  14. data/lib/sequel/adapters/jdbc/h2.rb +8 -2
  15. data/lib/sequel/adapters/jdbc/mysql.rb +0 -5
  16. data/lib/sequel/adapters/jdbc/postgresql.rb +43 -0
  17. data/lib/sequel/adapters/jdbc/sqlite.rb +19 -0
  18. data/lib/sequel/adapters/mock.rb +24 -3
  19. data/lib/sequel/adapters/mysql.rb +29 -50
  20. data/lib/sequel/adapters/mysql2.rb +13 -28
  21. data/lib/sequel/adapters/oracle.rb +8 -2
  22. data/lib/sequel/adapters/postgres.rb +115 -20
  23. data/lib/sequel/adapters/shared/db2.rb +1 -1
  24. data/lib/sequel/adapters/shared/mssql.rb +14 -3
  25. data/lib/sequel/adapters/shared/mysql.rb +59 -11
  26. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +6 -0
  27. data/lib/sequel/adapters/shared/oracle.rb +1 -1
  28. data/lib/sequel/adapters/shared/postgres.rb +127 -30
  29. data/lib/sequel/adapters/shared/sqlite.rb +55 -38
  30. data/lib/sequel/adapters/sqlite.rb +9 -3
  31. data/lib/sequel/adapters/swift.rb +2 -2
  32. data/lib/sequel/adapters/swift/mysql.rb +0 -5
  33. data/lib/sequel/adapters/swift/postgres.rb +10 -0
  34. data/lib/sequel/ast_transformer.rb +4 -0
  35. data/lib/sequel/connection_pool.rb +8 -0
  36. data/lib/sequel/connection_pool/sharded_single.rb +5 -0
  37. data/lib/sequel/connection_pool/sharded_threaded.rb +17 -0
  38. data/lib/sequel/connection_pool/single.rb +5 -0
  39. data/lib/sequel/connection_pool/threaded.rb +14 -0
  40. data/lib/sequel/core.rb +24 -3
  41. data/lib/sequel/database/connecting.rb +24 -14
  42. data/lib/sequel/database/dataset_defaults.rb +1 -0
  43. data/lib/sequel/database/misc.rb +16 -25
  44. data/lib/sequel/database/query.rb +20 -2
  45. data/lib/sequel/database/schema_generator.rb +2 -2
  46. data/lib/sequel/database/schema_methods.rb +120 -23
  47. data/lib/sequel/dataset/actions.rb +91 -18
  48. data/lib/sequel/dataset/features.rb +5 -0
  49. data/lib/sequel/dataset/prepared_statements.rb +6 -2
  50. data/lib/sequel/dataset/sql.rb +68 -51
  51. data/lib/sequel/extensions/_pretty_table.rb +79 -0
  52. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +18 -13
  53. data/lib/sequel/extensions/migration.rb +4 -0
  54. data/lib/sequel/extensions/null_dataset.rb +90 -0
  55. data/lib/sequel/extensions/pg_array.rb +460 -0
  56. data/lib/sequel/extensions/pg_array_ops.rb +220 -0
  57. data/lib/sequel/extensions/pg_auto_parameterize.rb +174 -0
  58. data/lib/sequel/extensions/pg_hstore.rb +296 -0
  59. data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
  60. data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
  61. data/lib/sequel/extensions/pretty_table.rb +5 -71
  62. data/lib/sequel/extensions/query_literals.rb +79 -0
  63. data/lib/sequel/extensions/schema_caching.rb +76 -0
  64. data/lib/sequel/extensions/schema_dumper.rb +227 -31
  65. data/lib/sequel/extensions/select_remove.rb +35 -0
  66. data/lib/sequel/extensions/sql_expr.rb +4 -110
  67. data/lib/sequel/extensions/to_dot.rb +1 -1
  68. data/lib/sequel/model.rb +11 -2
  69. data/lib/sequel/model/associations.rb +35 -7
  70. data/lib/sequel/model/base.rb +159 -36
  71. data/lib/sequel/no_core_ext.rb +2 -0
  72. data/lib/sequel/plugins/caching.rb +25 -18
  73. data/lib/sequel/plugins/composition.rb +1 -1
  74. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  75. data/lib/sequel/plugins/identity_map.rb +11 -3
  76. data/lib/sequel/plugins/instance_filters.rb +10 -0
  77. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  78. data/lib/sequel/plugins/nested_attributes.rb +4 -3
  79. data/lib/sequel/plugins/prepared_statements.rb +3 -1
  80. data/lib/sequel/plugins/prepared_statements_associations.rb +5 -1
  81. data/lib/sequel/plugins/schema.rb +7 -2
  82. data/lib/sequel/plugins/single_table_inheritance.rb +1 -1
  83. data/lib/sequel/plugins/static_cache.rb +99 -0
  84. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  85. data/lib/sequel/sql.rb +417 -7
  86. data/lib/sequel/version.rb +1 -1
  87. data/spec/adapters/firebird_spec.rb +1 -1
  88. data/spec/adapters/mssql_spec.rb +12 -15
  89. data/spec/adapters/mysql_spec.rb +81 -23
  90. data/spec/adapters/postgres_spec.rb +444 -77
  91. data/spec/adapters/spec_helper.rb +2 -0
  92. data/spec/adapters/sqlite_spec.rb +8 -8
  93. data/spec/core/connection_pool_spec.rb +85 -0
  94. data/spec/core/database_spec.rb +29 -5
  95. data/spec/core/dataset_spec.rb +171 -3
  96. data/spec/core/expression_filters_spec.rb +364 -0
  97. data/spec/core/mock_adapter_spec.rb +17 -3
  98. data/spec/core/schema_spec.rb +133 -0
  99. data/spec/extensions/association_dependencies_spec.rb +13 -13
  100. data/spec/extensions/caching_spec.rb +26 -3
  101. data/spec/extensions/class_table_inheritance_spec.rb +2 -2
  102. data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +23 -94
  103. data/spec/extensions/force_encoding_spec.rb +4 -2
  104. data/spec/extensions/hook_class_methods_spec.rb +5 -2
  105. data/spec/extensions/identity_map_spec.rb +17 -0
  106. data/spec/extensions/instance_filters_spec.rb +1 -1
  107. data/spec/extensions/lazy_attributes_spec.rb +2 -2
  108. data/spec/extensions/list_spec.rb +4 -4
  109. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  110. data/spec/extensions/migration_spec.rb +6 -2
  111. data/spec/extensions/nested_attributes_spec.rb +20 -0
  112. data/spec/extensions/null_dataset_spec.rb +85 -0
  113. data/spec/extensions/optimistic_locking_spec.rb +2 -2
  114. data/spec/extensions/pg_array_ops_spec.rb +105 -0
  115. data/spec/extensions/pg_array_spec.rb +196 -0
  116. data/spec/extensions/pg_auto_parameterize_spec.rb +64 -0
  117. data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
  118. data/spec/extensions/pg_hstore_spec.rb +195 -0
  119. data/spec/extensions/pg_statement_cache_spec.rb +209 -0
  120. data/spec/extensions/prepared_statements_spec.rb +4 -0
  121. data/spec/extensions/pretty_table_spec.rb +6 -0
  122. data/spec/extensions/query_literals_spec.rb +168 -0
  123. data/spec/extensions/schema_caching_spec.rb +41 -0
  124. data/spec/extensions/schema_dumper_spec.rb +231 -11
  125. data/spec/extensions/schema_spec.rb +14 -2
  126. data/spec/extensions/select_remove_spec.rb +38 -0
  127. data/spec/extensions/sharding_spec.rb +6 -6
  128. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  129. data/spec/extensions/spec_helper.rb +2 -1
  130. data/spec/extensions/sql_expr_spec.rb +28 -19
  131. data/spec/extensions/static_cache_spec.rb +145 -0
  132. data/spec/extensions/touch_spec.rb +1 -1
  133. data/spec/extensions/typecast_on_load_spec.rb +9 -1
  134. data/spec/integration/associations_test.rb +6 -6
  135. data/spec/integration/database_test.rb +1 -1
  136. data/spec/integration/dataset_test.rb +89 -26
  137. data/spec/integration/migrator_test.rb +2 -3
  138. data/spec/integration/model_test.rb +3 -3
  139. data/spec/integration/plugin_test.rb +85 -22
  140. data/spec/integration/prepared_statement_test.rb +28 -8
  141. data/spec/integration/schema_test.rb +78 -7
  142. data/spec/integration/spec_helper.rb +1 -0
  143. data/spec/integration/timezone_test.rb +1 -1
  144. data/spec/integration/transaction_test.rb +4 -6
  145. data/spec/integration/type_test.rb +2 -2
  146. data/spec/model/associations_spec.rb +94 -8
  147. data/spec/model/base_spec.rb +4 -4
  148. data/spec/model/hooks_spec.rb +2 -2
  149. data/spec/model/model_spec.rb +19 -7
  150. data/spec/model/record_spec.rb +135 -58
  151. data/spec/model/spec_helper.rb +1 -0
  152. metadata +35 -7
@@ -86,12 +86,24 @@ describe Sequel::Model, "drop_table" do
86
86
  MODEL_DB.reset
87
87
  end
88
88
 
89
- it "should get the drop table SQL for the associated table and then execute the SQL." do
89
+ it "should drop the related table" do
90
90
  @model.drop_table
91
91
  MODEL_DB.sqls.should == ['DROP TABLE items']
92
92
  end
93
93
  end
94
94
 
95
+ describe Sequel::Model, "drop_table?" do
96
+ before do
97
+ @model = Class.new(Sequel::Model(:items))
98
+ MODEL_DB.reset
99
+ end
100
+
101
+ it "should drop the table if it exists" do
102
+ @model.drop_table?
103
+ MODEL_DB.sqls.should == ["SELECT NULL FROM items LIMIT 1", 'DROP TABLE items']
104
+ end
105
+ end
106
+
95
107
  describe Sequel::Model, "create_table!" do
96
108
  before do
97
109
  MODEL_DB.reset
@@ -100,7 +112,7 @@ describe Sequel::Model, "create_table!" do
100
112
 
101
113
  it "should drop table if it exists and then create the table" do
102
114
  @model.create_table!
103
- MODEL_DB.sqls.should == ['DROP TABLE items', 'CREATE TABLE items ()']
115
+ MODEL_DB.sqls.should == ["SELECT NULL FROM items LIMIT 1", 'DROP TABLE items', 'CREATE TABLE items ()']
104
116
  end
105
117
  end
106
118
 
@@ -0,0 +1,38 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "Dataset#select_remove" do
4
+ before do
5
+ @d = Sequel.mock.from(:test)
6
+ @d.columns :a, :b, :c
7
+ end
8
+
9
+ specify "should remove columns from the selected columns" do
10
+ @d.sql.should == 'SELECT * FROM test'
11
+ @d.select_remove(:a).sql.should == 'SELECT b, c FROM test'
12
+ @d.select_remove(:b).sql.should == 'SELECT a, c FROM test'
13
+ @d.select_remove(:c).sql.should == 'SELECT a, b FROM test'
14
+ end
15
+
16
+ specify "should work correctly if there are already columns selected" do
17
+ d = @d.select(:a, :b, :c)
18
+ d.columns :a, :b, :c
19
+ d.select_remove(:c).sql.should == 'SELECT a, b FROM test'
20
+ end
21
+
22
+ specify "should have no effect if the columns given are not currently selected" do
23
+ @d.select_remove(:d).sql.should == 'SELECT a, b, c FROM test'
24
+ end
25
+
26
+ specify "should handle expressions where Sequel can't determine the alias by itself" do
27
+ d = @d.select(:a, :b.sql_function, :c.as(:b))
28
+ d.columns :a, :"b()", :b
29
+ d.select_remove(:"b()").sql.should == 'SELECT a, c AS b FROM test'
30
+ end
31
+
32
+ specify "should remove expressions if given exact expressions" do
33
+ d = @d.select(:a, :b.sql_function, :c.as(:b))
34
+ d.columns :a, :"b()", :b
35
+ d.select_remove(:b.sql_function).sql.should == 'SELECT a, c AS b FROM test'
36
+ d.select_remove(:c.as(:b)).sql.should == 'SELECT a, b() FROM test'
37
+ end
38
+ end
@@ -5,19 +5,19 @@ describe "sharding plugin" do
5
5
  @db = Sequel.mock(:numrows=>1, :autoid=>proc{1}, :servers=>{:s1=>{}, :s2=>{}, :s3=>{}, :s4=>{}})
6
6
  @Artist = Class.new(Sequel::Model(@db[:artists]))
7
7
  @Artist.class_eval do
8
- dataset._fetch = {:id=>2, :name=>'YJM'}
8
+ instance_dataset._fetch = dataset._fetch = {:id=>2, :name=>'YJM'}
9
9
  columns :id, :name
10
10
  plugin :sharding
11
11
  end
12
12
  @Album = Class.new(Sequel::Model(@db[:albums]))
13
13
  @Album.class_eval do
14
- dataset._fetch = {:id=>1, :name=>'RF', :artist_id=>2}
14
+ instance_dataset._fetch = dataset._fetch = {:id=>1, :name=>'RF', :artist_id=>2}
15
15
  columns :id, :artist_id, :name
16
16
  plugin :sharding
17
17
  end
18
18
  @Tag = Class.new(Sequel::Model(@db[:tags]))
19
19
  @Tag.class_eval do
20
- dataset._fetch = {:id=>3, :name=>'M'}
20
+ instance_dataset._fetch = dataset._fetch = {:id=>3, :name=>'M'}
21
21
  columns :id, :name
22
22
  plugin :sharding
23
23
  end
@@ -67,7 +67,7 @@ describe "sharding plugin" do
67
67
  end
68
68
 
69
69
  specify "should not use current dataset's shard when eager loading if eagerly loaded dataset has its own shard" do
70
- @Artist.dataset.opts[:server] = :s2
70
+ @Artist.instance_dataset.opts[:server] = @Artist.dataset.opts[:server] = :s2
71
71
  albums = @Album.server(:s1).eager(:artist).all
72
72
  @db.sqls.should == ["SELECT * FROM albums -- s1", "SELECT * FROM artists WHERE (artists.id IN (2)) -- s2"]
73
73
  albums.length.should == 1
@@ -86,7 +86,7 @@ describe "sharding plugin" do
86
86
  end
87
87
 
88
88
  specify "should not use current dataset's shard when eager graphing if eagerly graphed dataset has its own shard" do
89
- @Artist.dataset.opts[:server] = :s2
89
+ @Artist.instance_dataset.opts[:server] = @Artist.dataset.opts[:server] = :s2
90
90
  ds = @Album.server(:s1).eager_graph(:artist)
91
91
  ds._fetch = {:id=>1, :artist_id=>2, :name=>'RF', :artist_id_0=>2, :artist_name=>'YJM'}
92
92
  albums = ds.all
@@ -97,7 +97,7 @@ describe "sharding plugin" do
97
97
  end
98
98
 
99
99
  specify "should use eagerly graphed dataset shard for eagerly graphed objects even if current dataset does not have a shard" do
100
- @Artist.dataset.opts[:server] = :s2
100
+ @Artist.instance_dataset.opts[:server] = @Artist.dataset.opts[:server] = :s2
101
101
  ds = @Album.eager_graph(:artist)
102
102
  ds._fetch = {:id=>1, :artist_id=>2, :name=>'RF', :artist_id_0=>2, :artist_name=>'YJM'}
103
103
  albums = ds.all
@@ -5,7 +5,7 @@ describe "Sequel::Plugins::SkipCreateRefresh" do
5
5
  c = Class.new(Sequel::Model(:a))
6
6
  c.columns :id, :x
7
7
  c.db.reset
8
- c.dataset.meta_def(:insert){|*a| super(*a); 2}
8
+ c.instance_dataset.meta_def(:insert){|*a| super(*a); 2}
9
9
  c.create(:x=>1)
10
10
  c.db.sqls.should == ['INSERT INTO a (x) VALUES (1)', 'SELECT * FROM a WHERE (id = 2) LIMIT 1']
11
11
 
@@ -8,7 +8,7 @@ unless Sequel.const_defined?('Model')
8
8
  require 'sequel/model'
9
9
  end
10
10
 
11
- Sequel.extension(*%w'string_date_time inflector pagination query pretty_table blank migration schema_dumper looser_typecasting sql_expr thread_local_timezones to_dot columns_introspection server_block arbitrary_servers')
11
+ Sequel.extension(*%w'string_date_time inflector pagination query pretty_table blank migration schema_dumper looser_typecasting sql_expr thread_local_timezones to_dot columns_introspection server_block arbitrary_servers pg_auto_parameterize pg_statement_cache pg_hstore pg_hstore_ops schema_caching null_dataset select_remove query_literals')
12
12
  {:hook_class_methods=>[], :schema=>[], :validation_class_methods=>[]}.each{|p, opts| Sequel::Model.plugin(p, *opts)}
13
13
 
14
14
  Sequel::Dataset.introspect_all_columns if ENV['SEQUEL_COLUMNS_INTROSPECTION']
@@ -36,6 +36,7 @@ class << Sequel::Model
36
36
  end
37
37
 
38
38
  Sequel::Model.use_transactions = false
39
+ Sequel::Model.cache_anonymous_models = false
39
40
 
40
41
  db = Sequel.mock(:fetch=>{:id => 1, :x => 1}, :numrows=>1, :autoid=>proc{|sql| 10})
41
42
  def db.schema(*) [[:id, {:primary_key=>true}]] end
@@ -1,49 +1,58 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
3
  describe "Sequel sql_expr extension" do
4
+ before do
5
+ @ds = Sequel.mock.dataset
6
+ end
7
+
4
8
  specify "Object#sql_expr should wrap the object in a GenericComplexExpression" do
5
9
  o = Object.new
10
+ def o.sql_literal(ds) 'foo' end
6
11
  s = o.sql_expr
7
- s.should == Sequel::SQL::GenericComplexExpression.new(:NOOP, o)
8
- (s+1).should == Sequel::SQL::NumericExpression.new(:+, s, 1)
9
- (s & true).should == Sequel::SQL::BooleanExpression.new(:AND, s, true)
10
- (s < 1).should == Sequel::SQL::BooleanExpression.new(:<, s, 1)
11
- s.sql_subscript(1).should == Sequel::SQL::Subscript.new(s, [1])
12
- s.like('a').should == Sequel::SQL::BooleanExpression.new(:LIKE, s, 'a')
13
- s.as(:a).should == Sequel::SQL::AliasedExpression.new(s, :a)
14
- s.cast(Integer).should == Sequel::SQL::Cast.new(s, Integer)
15
- s.desc.should == Sequel::SQL::OrderedExpression.new(s, true)
16
- s.sql_string.should == Sequel::SQL::StringExpression.new(:NOOP, s)
12
+ @ds.literal(s).should == "foo"
13
+ @ds.literal(s+1).should == "(foo + 1)"
14
+ @ds.literal(s & true).should == "(foo AND 't')"
15
+ @ds.literal(s < 1).should == "(foo < 1)"
16
+ @ds.literal(s.sql_subscript(1)).should == "foo[1]"
17
+ @ds.literal(s.like('a')).should == "(foo LIKE 'a')"
18
+ @ds.literal(s.as(:a)).should == "foo AS a"
19
+ @ds.literal(s.cast(Integer)).should == "CAST(foo AS integer)"
20
+ @ds.literal(s.desc).should == "foo DESC"
21
+ @ds.literal(s.sql_string + '1').should == "(foo || '1')"
17
22
  end
18
23
 
19
24
  specify "Numeric#sql_expr should wrap the object in a NumericExpression" do
20
25
  [1, 2.0, 2^70, BigDecimal.new('1.0')].each do |o|
21
- o.sql_expr.should == Sequel::SQL::NumericExpression.new(:NOOP, o)
26
+ @ds.literal(o.sql_expr).should == @ds.literal(o)
27
+ @ds.literal(o.sql_expr + 1).should == "(#{@ds.literal(o)} + 1)"
22
28
  end
23
29
  end
24
30
 
25
31
  specify "String#sql_expr should wrap the object in a StringExpression" do
26
- "".sql_expr.should == Sequel::SQL::StringExpression.new(:NOOP, "")
32
+ @ds.literal("".sql_expr).should == "''"
33
+ @ds.literal("".sql_expr + :a).should == "('' || a)"
27
34
  end
28
35
 
29
36
  specify "NilClass, TrueClass, and FalseClass#sql_expr should wrap the object in a BooleanExpression" do
30
37
  [nil, true, false].each do |o|
31
- o.sql_expr.should == Sequel::SQL::BooleanExpression.new(:NOOP, o)
38
+ @ds.literal(o.sql_expr).should == @ds.literal(o)
39
+ @ds.literal(o.sql_expr & :a).should == "(#{@ds.literal(o)} AND a)"
32
40
  end
33
41
  end
34
42
 
35
43
  specify "Proc#sql_expr should should treat the object as a virtual row block" do
36
- proc{a}.sql_expr.should == Sequel::SQL::Identifier.new(:a)
37
- proc{a__b}.sql_expr.should == Sequel::SQL::QualifiedIdentifier.new('a', 'b')
38
- proc{a(b)}.sql_expr.should == Sequel::SQL::Function.new(:a, Sequel::SQL::Identifier.new(:b))
44
+ @ds.literal(proc{a}.sql_expr).should == "a"
45
+ @ds.literal(proc{a__b}.sql_expr).should == "a.b"
46
+ @ds.literal(proc{a(b)}.sql_expr).should == "a(b)"
39
47
  end
40
48
 
41
49
  specify "Proc#sql_expr should should wrap the object in a GenericComplexExpression if the object is not already an expression" do
42
- proc{1}.sql_expr.should == Sequel::SQL::GenericComplexExpression.new(:NOOP, 1)
50
+ @ds.literal(proc{1}.sql_expr).should == "1"
51
+ @ds.literal(proc{1}.sql_expr + 2).should == "(1 + 2)"
43
52
  end
44
53
 
45
54
  specify "Proc#sql_expr should should convert a hash or array of two element arrays to a BooleanExpression" do
46
- proc{{a=>b}}.sql_expr.should == Sequel::SQL::BooleanExpression.new(:'=', Sequel::SQL::Identifier.new(:a), Sequel::SQL::Identifier.new(:b))
47
- proc{[[a,b]]}.sql_expr.should == Sequel::SQL::BooleanExpression.new(:'=', Sequel::SQL::Identifier.new(:a), Sequel::SQL::Identifier.new(:b))
55
+ @ds.literal(proc{{a=>b}}.sql_expr).should == "(a = b)"
56
+ @ds.literal(proc{[[a, b]]}.sql_expr & :a).should == "((a = b) AND a)"
48
57
  end
49
58
  end
@@ -0,0 +1,145 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "Sequel::Plugins::StaticCache" do
4
+ before do
5
+ @db = Sequel.mock
6
+ @db.fetch = [{:id=>1}, {:id=>2}]
7
+ @c = Class.new(Sequel::Model(@db[:t]))
8
+ @c.columns :id
9
+ @c.plugin :static_cache
10
+ @c1 = @c.cache[1]
11
+ @c2 = @c.cache[2]
12
+ @db.sqls
13
+ end
14
+
15
+ it "should use a ruby hash as a cache of all model instances" do
16
+ @c.cache.should == {1=>@c.load(:id=>1), 2=>@c.load(:id=>2)}
17
+ end
18
+
19
+ it "should work correctly with composite keys" do
20
+ @db.fetch = [{:id=>1, :id2=>1}, {:id=>2, :id2=>1}]
21
+ @c = Class.new(Sequel::Model(@db[:t]))
22
+ @c.columns :id, :id2
23
+ @c.set_primary_key([:id, :id2])
24
+ @c.plugin :static_cache
25
+ @db.sqls
26
+ @c1 = @c.cache[[1, 2]]
27
+ @c2 = @c.cache[[2, 1]]
28
+ @c[[1, 2]].should equal(@c1)
29
+ @c[[2, 1]].should equal(@c2)
30
+ @db.sqls.should == []
31
+ end
32
+
33
+ it "should make .[] method with primary key use the cache" do
34
+ @c[1].should equal(@c1)
35
+ @c[2].should equal(@c2)
36
+ @c[3].should be_nil
37
+ @c[[1, 2]].should be_nil
38
+ @c[nil].should be_nil
39
+ @c[].should be_nil
40
+ @db.sqls.should == []
41
+ end
42
+
43
+ it "should have .[] with a hash not use the cache" do
44
+ @db.fetch = {:id=>2}
45
+ @c[:id=>2].should == @c2
46
+ @db.sqls.should == ['SELECT * FROM t WHERE (id = 2) LIMIT 1']
47
+ end
48
+
49
+ it "should support cache_get_pk" do
50
+ @c.cache_get_pk(1).should equal(@c1)
51
+ @c.cache_get_pk(2).should equal(@c2)
52
+ @c.cache_get_pk(3).should be_nil
53
+ @db.sqls.should == []
54
+ end
55
+
56
+ it "should have each just iterate over the hash's values without sending a query" do
57
+ a = []
58
+ @c.each{|o| a << o}
59
+ a = a.sort_by{|o| o.id}
60
+ a.first.should equal(@c1)
61
+ a.last.should equal(@c2)
62
+ @db.sqls.should == []
63
+ end
64
+
65
+ it "should have map just iterate over the hash's values without sending a query if no argument is given" do
66
+ @c.map{|v| v.id}.sort.should == [1, 2]
67
+ @db.sqls.should == []
68
+ end
69
+
70
+ it "should have map send a query if given an argument" do
71
+ @c.map(:id).sort.should == [1, 2]
72
+ @db.sqls.should == ["SELECT * FROM t"]
73
+ end
74
+
75
+ it "should have map without a block or argument not raise an exception or issue a query" do
76
+ @c.map
77
+ @db.sqls.should == []
78
+ end
79
+
80
+ it "should have map without a block not return a frozen object" do
81
+ @c.map.frozen?.should be_false
82
+ end
83
+
84
+ it "should have other enumerable methods work without sending a query" do
85
+ a = @c.sort_by{|o| o.id}
86
+ a.first.should equal(@c1)
87
+ a.last.should equal(@c2)
88
+ @db.sqls.should == []
89
+ end
90
+
91
+ it "should have all just return the hashes' values" do
92
+ a = @c.all.sort_by{|o| o.id}
93
+ a.first.should equal(@c1)
94
+ a.last.should equal(@c2)
95
+ @db.sqls.should == []
96
+ end
97
+
98
+ it "should have all not return a frozen object" do
99
+ @c.all.frozen?.should be_false
100
+ end
101
+
102
+ it "should have all return things in dataset order" do
103
+ @c.all.should == [@c1, @c2]
104
+ end
105
+
106
+ it "should have to_hash without arguments return the cached objects without a query" do
107
+ a = @c.to_hash
108
+ a[1].should equal(@c1)
109
+ a[2].should equal(@c2)
110
+ @db.sqls.should == []
111
+ end
112
+
113
+ it "should have to_hash with any arguments use a query" do
114
+ @c.to_hash(:id).should == {1=>@c1, 2=>@c2}
115
+ @db.sqls.should == ['SELECT * FROM t']
116
+ @c.to_hash(:id, :id).should == {1=>1, 2=>2}
117
+ @db.sqls.should == ['SELECT * FROM t']
118
+ end
119
+
120
+ it "should have all not return a frozen object" do
121
+ @c.to_hash.frozen?.should be_false
122
+ end
123
+
124
+ it "all of the static cache values (model instances) should be frozen" do
125
+ @c.all.all?{|o| o.frozen?}.should be_true
126
+ end
127
+
128
+ it "subclasses should work correctly" do
129
+ c = Class.new(@c)
130
+ c.all.should == [c.load(:id=>1), c.load(:id=>2)]
131
+ c.to_hash.should == {1=>c.load(:id=>1), 2=>c.load(:id=>2)}
132
+ @db.sqls.should == ['SELECT * FROM t']
133
+ end
134
+
135
+ it "set_dataset should work correctly" do
136
+ ds = @c.dataset.from(:t2)
137
+ ds.instance_variable_set(:@columns, [:id])
138
+ ds._fetch = {:id=>3}
139
+ @c.dataset = ds
140
+ @c.all.should == [@c.load(:id=>3)]
141
+ @c.to_hash.should == {3=>@c.load(:id=>3)}
142
+ @c.to_hash[3].should equal(@c.all.first)
143
+ @db.sqls.should == ['SELECT * FROM t2']
144
+ end
145
+ end
@@ -105,7 +105,7 @@ describe "Touch plugin" do
105
105
  @Album.touch_associations(:artist, {:followup_albums=>:modified_on})
106
106
  @Album.load(:id=>4, :artist_id=>1).destroy
107
107
  sqls = MODEL_DB.sqls
108
- sqls.shift.should == "DELETE FROM albums WHERE (id = 4)"
108
+ sqls.shift.should == "DELETE FROM albums WHERE id = 4"
109
109
  sqls.sort.should == ["UPDATE albums SET modified_on = CURRENT_TIMESTAMP WHERE (albums.original_album_id = 4)",
110
110
  "UPDATE artists SET updated_at = CURRENT_TIMESTAMP WHERE (artists.id = 1)"]
111
111
  end
@@ -2,7 +2,7 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe Sequel::Model, "TypecastOnLoad plugin" do
4
4
  before do
5
- @db = Sequel.mock(:fetch=>{:id=>1, :b=>"1", :y=>"0"}, :columns=>[:id, :b, :y])
5
+ @db = Sequel.mock(:fetch=>{:id=>1, :b=>"1", :y=>"0"}, :columns=>[:id, :b, :y], :numrows=>1)
6
6
  def @db.schema(*args)
7
7
  [[:id, {}], [:y, {:type=>:boolean, :db_type=>'tinyint(1)'}], [:b, {:type=>:integer, :db_type=>'integer'}]]
8
8
  end
@@ -30,6 +30,14 @@ describe Sequel::Model, "TypecastOnLoad plugin" do
30
30
  o.bset.should == true
31
31
  end
32
32
 
33
+ specify "should call setter method with value when automatically reloading the object on creation via insert_select" do
34
+ @c.plugin :typecast_on_load, :b
35
+ @c.dataset.meta_def(:insert_select){|h| insert(h); first}
36
+ o = @c.new({:id=>1, :b=>"1", :y=>"0"}, true)
37
+ o.save.values.should == {:id=>1, :b=>1, :y=>"0"}
38
+ o.bset.should == true
39
+ end
40
+
33
41
  specify "should allowing setting columns separately via add_typecast_on_load_columns" do
34
42
  @c.plugin :typecast_on_load
35
43
  @c.load(:id=>1, :b=>"1", :y=>"0").values.should == {:id=>1, :b=>"1", :y=>"0"}
@@ -536,7 +536,7 @@ end
536
536
  describe "Sequel::Model Simple Associations" do
537
537
  before(:all) do
538
538
  @db = INTEGRATION_DB
539
- [:albums_tags, :tags, :albums, :artists].each{|t| @db.drop_table(t) rescue nil}
539
+ @db.drop_table?(:albums_tags, :tags, :albums, :artists)
540
540
  @db.create_table(:artists) do
541
541
  primary_key :id
542
542
  String :name
@@ -598,7 +598,7 @@ describe "Sequel::Model Simple Associations" do
598
598
  [:Tag, :Album, :Artist].each{|x| Object.send(:remove_const, x)}
599
599
  end
600
600
  after(:all) do
601
- @db.drop_table(:albums_tags, :tags, :albums, :artists)
601
+ @db.drop_table?(:albums_tags, :tags, :albums, :artists)
602
602
  end
603
603
 
604
604
  it_should_behave_like "regular and composite key associations"
@@ -733,7 +733,7 @@ end
733
733
  describe "Sequel::Model Composite Key Associations" do
734
734
  before(:all) do
735
735
  @db = INTEGRATION_DB
736
- [:albums_tags, :tags, :albums, :artists].each{|t| @db.drop_table(t) rescue nil}
736
+ @db.drop_table?(:albums_tags, :tags, :albums, :artists)
737
737
  @db.create_table(:artists) do
738
738
  Integer :id1
739
739
  Integer :id2
@@ -813,7 +813,7 @@ describe "Sequel::Model Composite Key Associations" do
813
813
  [:Tag, :Album, :Artist].each{|x| Object.send(:remove_const, x)}
814
814
  end
815
815
  after(:all) do
816
- @db.drop_table(:albums_tags, :tags, :albums, :artists)
816
+ @db.drop_table?(:albums_tags, :tags, :albums, :artists)
817
817
  end
818
818
 
819
819
  it_should_behave_like "regular and composite key associations"
@@ -868,7 +868,7 @@ end
868
868
  describe "Sequel::Model Associations with clashing column names" do
869
869
  before(:all) do
870
870
  @db = INTEGRATION_DB
871
- [:bars_foos, :bars, :foos].each{|t| @db.drop_table(t) rescue nil}
871
+ @db.drop_table?(:bars_foos, :bars, :foos)
872
872
  @db.create_table(:foos) do
873
873
  primary_key :id
874
874
  Integer :object_id
@@ -899,7 +899,7 @@ describe "Sequel::Model Associations with clashing column names" do
899
899
  @Foo.db[:bars_foos].insert(2, 2)
900
900
  end
901
901
  after(:all) do
902
- @db.drop_table(:bars_foos, :bars, :foos)
902
+ @db.drop_table?(:bars_foos, :bars, :foos)
903
903
  end
904
904
 
905
905
  it "should have working regular association methods" do