sequel 3.29.0 → 3.30.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 (106) hide show
  1. data/CHANGELOG +35 -3
  2. data/Rakefile +2 -1
  3. data/doc/association_basics.rdoc +11 -0
  4. data/doc/opening_databases.rdoc +2 -0
  5. data/doc/release_notes/3.30.0.txt +135 -0
  6. data/doc/testing.rdoc +17 -3
  7. data/lib/sequel/adapters/amalgalite.rb +2 -2
  8. data/lib/sequel/adapters/do/mysql.rb +5 -2
  9. data/lib/sequel/adapters/ibmdb.rb +2 -2
  10. data/lib/sequel/adapters/jdbc.rb +126 -43
  11. data/lib/sequel/adapters/jdbc/as400.rb +11 -3
  12. data/lib/sequel/adapters/jdbc/db2.rb +2 -1
  13. data/lib/sequel/adapters/jdbc/derby.rb +44 -19
  14. data/lib/sequel/adapters/jdbc/h2.rb +32 -19
  15. data/lib/sequel/adapters/jdbc/hsqldb.rb +21 -17
  16. data/lib/sequel/adapters/jdbc/jtds.rb +9 -4
  17. data/lib/sequel/adapters/jdbc/mssql.rb +3 -1
  18. data/lib/sequel/adapters/jdbc/mysql.rb +2 -1
  19. data/lib/sequel/adapters/jdbc/oracle.rb +21 -7
  20. data/lib/sequel/adapters/jdbc/postgresql.rb +3 -2
  21. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -1
  22. data/lib/sequel/adapters/jdbc/sqlserver.rb +48 -18
  23. data/lib/sequel/adapters/mock.rb +2 -1
  24. data/lib/sequel/adapters/mysql.rb +4 -2
  25. data/lib/sequel/adapters/mysql2.rb +2 -2
  26. data/lib/sequel/adapters/odbc/mssql.rb +1 -1
  27. data/lib/sequel/adapters/openbase.rb +1 -1
  28. data/lib/sequel/adapters/oracle.rb +6 -6
  29. data/lib/sequel/adapters/postgres.rb +25 -12
  30. data/lib/sequel/adapters/shared/access.rb +14 -6
  31. data/lib/sequel/adapters/shared/db2.rb +36 -13
  32. data/lib/sequel/adapters/shared/firebird.rb +12 -5
  33. data/lib/sequel/adapters/shared/informix.rb +11 -3
  34. data/lib/sequel/adapters/shared/mssql.rb +94 -47
  35. data/lib/sequel/adapters/shared/mysql.rb +107 -49
  36. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +2 -2
  37. data/lib/sequel/adapters/shared/oracle.rb +54 -27
  38. data/lib/sequel/adapters/shared/postgres.rb +65 -26
  39. data/lib/sequel/adapters/shared/progress.rb +4 -1
  40. data/lib/sequel/adapters/shared/sqlite.rb +36 -20
  41. data/lib/sequel/adapters/sqlite.rb +2 -3
  42. data/lib/sequel/adapters/swift/mysql.rb +3 -2
  43. data/lib/sequel/adapters/swift/sqlite.rb +2 -2
  44. data/lib/sequel/adapters/tinytds.rb +14 -8
  45. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +7 -4
  46. data/lib/sequel/database/misc.rb +6 -2
  47. data/lib/sequel/dataset/graph.rb +33 -7
  48. data/lib/sequel/dataset/prepared_statements.rb +19 -5
  49. data/lib/sequel/dataset/sql.rb +611 -201
  50. data/lib/sequel/model/associations.rb +12 -5
  51. data/lib/sequel/model/base.rb +20 -5
  52. data/lib/sequel/plugins/sharding.rb +9 -29
  53. data/lib/sequel/sql.rb +2 -1
  54. data/lib/sequel/timezones.rb +14 -4
  55. data/lib/sequel/version.rb +1 -1
  56. data/spec/adapters/mysql_spec.rb +10 -0
  57. data/spec/adapters/oracle_spec.rb +1 -1
  58. data/spec/core/core_sql_spec.rb +3 -1
  59. data/spec/core/database_spec.rb +42 -0
  60. data/spec/core/dataset_spec.rb +10 -3
  61. data/spec/core/mock_adapter_spec.rb +4 -0
  62. data/spec/core/object_graph_spec.rb +38 -0
  63. data/spec/extensions/association_autoreloading_spec.rb +1 -10
  64. data/spec/extensions/association_dependencies_spec.rb +2 -12
  65. data/spec/extensions/association_pks_spec.rb +35 -39
  66. data/spec/extensions/caching_spec.rb +23 -50
  67. data/spec/extensions/class_table_inheritance_spec.rb +30 -82
  68. data/spec/extensions/composition_spec.rb +18 -13
  69. data/spec/extensions/hook_class_methods_spec.rb +65 -91
  70. data/spec/extensions/identity_map_spec.rb +33 -103
  71. data/spec/extensions/instance_filters_spec.rb +10 -21
  72. data/spec/extensions/instance_hooks_spec.rb +6 -24
  73. data/spec/extensions/json_serializer_spec.rb +4 -5
  74. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  75. data/spec/extensions/list_spec.rb +17 -39
  76. data/spec/extensions/many_through_many_spec.rb +135 -277
  77. data/spec/extensions/migration_spec.rb +18 -15
  78. data/spec/extensions/named_timezones_spec.rb +1 -1
  79. data/spec/extensions/nested_attributes_spec.rb +97 -92
  80. data/spec/extensions/optimistic_locking_spec.rb +9 -20
  81. data/spec/extensions/prepared_statements_associations_spec.rb +22 -37
  82. data/spec/extensions/prepared_statements_safe_spec.rb +9 -27
  83. data/spec/extensions/prepared_statements_spec.rb +11 -30
  84. data/spec/extensions/prepared_statements_with_pk_spec.rb +6 -13
  85. data/spec/extensions/pretty_table_spec.rb +1 -6
  86. data/spec/extensions/rcte_tree_spec.rb +41 -43
  87. data/spec/extensions/schema_dumper_spec.rb +3 -6
  88. data/spec/extensions/serialization_spec.rb +20 -32
  89. data/spec/extensions/sharding_spec.rb +66 -140
  90. data/spec/extensions/single_table_inheritance_spec.rb +14 -36
  91. data/spec/extensions/spec_helper.rb +10 -64
  92. data/spec/extensions/sql_expr_spec.rb +20 -60
  93. data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
  94. data/spec/extensions/timestamps_spec.rb +6 -6
  95. data/spec/extensions/to_dot_spec.rb +1 -2
  96. data/spec/extensions/touch_spec.rb +13 -14
  97. data/spec/extensions/tree_spec.rb +11 -26
  98. data/spec/extensions/update_primary_key_spec.rb +30 -24
  99. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  100. data/spec/extensions/validation_helpers_spec.rb +16 -35
  101. data/spec/integration/dataset_test.rb +16 -4
  102. data/spec/integration/prepared_statement_test.rb +4 -2
  103. data/spec/model/eager_loading_spec.rb +16 -0
  104. data/spec/model/model_spec.rb +15 -1
  105. data/spec/model/record_spec.rb +60 -0
  106. metadata +23 -40
@@ -3,9 +3,7 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
3
3
  describe Sequel::Model, "#sti_key" do
4
4
  before do
5
5
  class ::StiTest < Sequel::Model
6
- def kind; self[:kind]; end
7
- def kind=(x); self[:kind] = x; end
8
- def _refresh(x); end
6
+ columns :id, :kind, :blah
9
7
  plugin :single_table_inheritance, :kind
10
8
  end
11
9
  class ::StiTestSub1 < StiTest
@@ -22,7 +20,7 @@ describe Sequel::Model, "#sti_key" do
22
20
  end
23
21
 
24
22
  specify "should have simple_table = nil" do
25
- StiTest.simple_table.should == nil
23
+ StiTest.simple_table.should == "sti_tests"
26
24
  StiTestSub1.simple_table.should == nil
27
25
  end
28
26
 
@@ -30,15 +28,9 @@ describe Sequel::Model, "#sti_key" do
30
28
  StiTest.plugin :single_table_inheritance, :blah
31
29
  Object.send(:remove_const, :StiTestSub1)
32
30
  Object.send(:remove_const, :StiTestSub2)
33
- class ::StiTestSub1 < StiTest
34
- end
35
- class ::StiTestSub2 < StiTest
36
- end
37
- def @ds.fetch_rows(sql)
38
- yield({:blah=>'StiTest'})
39
- yield({:blah=>'StiTestSub1'})
40
- yield({:blah=>'StiTestSub2'})
41
- end
31
+ class ::StiTestSub1 < StiTest; end
32
+ class ::StiTestSub2 < StiTest; end
33
+ @ds._fetch = [{:blah=>'StiTest'}, {:blah=>'StiTestSub1'}, {:blah=>'StiTestSub2'}]
42
34
  StiTest.all.collect{|x| x.class}.should == [StiTest, StiTestSub1, StiTestSub2]
43
35
  StiTest.dataset.sql.should == "SELECT * FROM sti_tests"
44
36
  StiTestSub1.dataset.sql.should == "SELECT * FROM sti_tests WHERE (sti_tests.blah IN ('StiTestSub1'))"
@@ -46,29 +38,18 @@ describe Sequel::Model, "#sti_key" do
46
38
  end
47
39
 
48
40
  it "should return rows with the correct class based on the polymorphic_key value" do
49
- def @ds.fetch_rows(sql)
50
- yield({:kind=>'StiTest'})
51
- yield({:kind=>'StiTestSub1'})
52
- yield({:kind=>'StiTestSub2'})
53
- end
41
+ @ds._fetch = [{:kind=>'StiTest'}, {:kind=>'StiTestSub1'}, {:kind=>'StiTestSub2'}]
54
42
  StiTest.all.collect{|x| x.class}.should == [StiTest, StiTestSub1, StiTestSub2]
55
43
  end
56
44
 
57
45
  it "should return rows with the correct class for subclasses based on the polymorphic_key value" do
58
- class ::StiTestSub1Sub < StiTestSub1
59
- end
60
- ds = StiTestSub1.dataset
61
- def ds.fetch_rows(sql)
62
- yield({:kind=>'StiTestSub1'})
63
- yield({:kind=>'StiTestSub1Sub'})
64
- end
46
+ class ::StiTestSub1Sub < StiTestSub1; end
47
+ StiTestSub1.dataset._fetch = [{:kind=>'StiTestSub1'}, {:kind=>'StiTestSub1Sub'}]
65
48
  StiTestSub1.all.collect{|x| x.class}.should == [StiTestSub1, StiTestSub1Sub]
66
49
  end
67
50
 
68
51
  it "should fallback to the main class if the given class does not exist" do
69
- def @ds.fetch_rows(sql)
70
- yield({:kind=>'StiTestSub3'})
71
- end
52
+ @ds._fetch = {:kind=>'StiTestSub3'}
72
53
  StiTest.all.collect{|x| x.class}.should == [StiTest]
73
54
  end
74
55
 
@@ -79,10 +60,7 @@ describe Sequel::Model, "#sti_key" do
79
60
  Object
80
61
  end
81
62
  StiTest.plugin :single_table_inheritance, :kind
82
- def @ds.fetch_rows(sql)
83
- yield({:kind=>''})
84
- yield({:kind=>nil})
85
- end
63
+ @ds._fetch = [{:kind=>''}, {:kind=>nil}]
86
64
  StiTest.all.collect{|x| x.class}.should == [StiTest, StiTest]
87
65
  called.should == false
88
66
  end
@@ -91,19 +69,19 @@ describe Sequel::Model, "#sti_key" do
91
69
  StiTest.new.save
92
70
  StiTestSub1.new.save
93
71
  StiTestSub2.new.save
94
- MODEL_DB.sqls.should == ["INSERT INTO sti_tests (kind) VALUES ('StiTest')", "INSERT INTO sti_tests (kind) VALUES ('StiTestSub1')", "INSERT INTO sti_tests (kind) VALUES ('StiTestSub2')"]
72
+ MODEL_DB.sqls.should == ["INSERT INTO sti_tests (kind) VALUES ('StiTest')", "SELECT * FROM sti_tests WHERE (id = 10) LIMIT 1", "INSERT INTO sti_tests (kind) VALUES ('StiTestSub1')", "SELECT * FROM sti_tests WHERE ((sti_tests.kind IN ('StiTestSub1')) AND (id = 10)) LIMIT 1", "INSERT INTO sti_tests (kind) VALUES ('StiTestSub2')", "SELECT * FROM sti_tests WHERE ((sti_tests.kind IN ('StiTestSub2')) AND (id = 10)) LIMIT 1"]
95
73
  end
96
74
 
97
75
  it "should have the before_create hook not override an existing value" do
98
76
  StiTest.create(:kind=>'StiTestSub1')
99
- MODEL_DB.sqls.should == ["INSERT INTO sti_tests (kind) VALUES ('StiTestSub1')"]
77
+ MODEL_DB.sqls.should == ["INSERT INTO sti_tests (kind) VALUES ('StiTestSub1')", "SELECT * FROM sti_tests WHERE (id = 10) LIMIT 1"]
100
78
  end
101
79
 
102
80
  it "should have the before_create hook handle columns with the same name as existing method names" do
103
81
  StiTest.plugin :single_table_inheritance, :type
104
82
  StiTest.columns :id, :type
105
83
  StiTest.create
106
- MODEL_DB.sqls.should == ["INSERT INTO sti_tests (type) VALUES ('StiTest')"]
84
+ MODEL_DB.sqls.should == ["INSERT INTO sti_tests (type) VALUES ('StiTest')", "SELECT * FROM sti_tests WHERE (id = 10) LIMIT 1"]
107
85
  end
108
86
 
109
87
  it "should add a filter to model datasets inside subclasses hook to only retreive objects with the matching key" do
@@ -129,7 +107,7 @@ describe Sequel::Model, "#sti_key" do
129
107
  before do
130
108
  class ::StiTest2 < Sequel::Model
131
109
  columns :id, :kind
132
- def _refresh(x); end
110
+ def _save_refresh; end
133
111
  end
134
112
  end
135
113
  after do
@@ -17,70 +17,15 @@ def skip_warn(s)
17
17
  warn "Skipping test of #{s}" if ENV["SKIPPED_TEST_WARN"]
18
18
  end
19
19
 
20
- class MockDataset < Sequel::Dataset
21
- def insert(*args)
22
- @db.execute insert_sql(*args)
23
- end
24
-
25
- def update(*args)
26
- @db.execute update_sql(*args)
27
- 1
28
- end
29
-
30
- def delete(*args)
31
- @db.execute delete_sql(*args)
32
- 1
33
- end
34
-
35
- def fetch_rows(sql)
36
- return if sql =~ /information_schema/
37
- @db.execute(sql)
38
- yield({:id => 1, :x => 1})
39
- end
40
-
41
- def quoted_identifier(c)
42
- "\"#{c}\""
43
- end
44
- end
45
-
46
- class MockDatabase < Sequel::Database
47
- @@quote_identifiers = false
48
- self.identifier_input_method = nil
49
- self.identifier_output_method = nil
50
- attr_reader :sqls
51
-
52
- def connect(opts)
53
- Object.new
54
- end
55
-
56
- def execute(sql, opts={})
57
- @sqls ||= []
58
- @sqls << sql
59
- end
60
-
61
- def new_sqls
62
- s = sqls
63
- reset
64
- s
65
- end
66
-
67
- def reset
68
- @sqls = []
69
- end
70
-
71
- def schema(table_name, opts)
72
- [[:id, {:primary_key=>true}]]
73
- end
74
-
75
- def transaction(opts={}); yield; end
76
-
77
- def dataset(opts=nil); MockDataset.new(self, opts); end
78
- end
20
+ Sequel.quote_identifiers = false
21
+ Sequel.identifier_input_method = nil
22
+ Sequel.identifier_output_method = nil
79
23
 
80
24
  class << Sequel::Model
25
+ attr_writer :db_schema
81
26
  alias orig_columns columns
82
27
  def columns(*cols)
83
- return @columns if cols.empty?
28
+ return super if cols.empty?
84
29
  define_method(:columns){cols}
85
30
  @dataset.instance_variable_set(:@columns, cols) if @dataset
86
31
  def_column_accessor(*cols)
@@ -88,10 +33,11 @@ class << Sequel::Model
88
33
  @db_schema = {}
89
34
  cols.each{|c| @db_schema[c] = {}}
90
35
  end
91
- def simple_table
92
- nil
93
- end
94
36
  end
95
37
 
96
- Sequel::Model.db = MODEL_DB = MockDatabase.new
97
38
  Sequel::Model.use_transactions = false
39
+
40
+ db = Sequel.mock(:fetch=>{:id => 1, :x => 1}, :numrows=>1, :autoid=>proc{|sql| 10})
41
+ def db.schema(*) [[:id, {:primary_key=>true}]] end
42
+ def db.reset() sqls end
43
+ Sequel::Model.db = MODEL_DB = db
@@ -4,86 +4,46 @@ describe "Sequel sql_expr extension" do
4
4
  specify "Object#sql_expr should wrap the object in a GenericComplexExpression" do
5
5
  o = Object.new
6
6
  s = o.sql_expr
7
- s.should be_a_kind_of(Sequel::SQL::GenericComplexExpression)
8
- s.op.should == :NOOP
9
- s.args.should == [o]
10
- (s+1).should be_a_kind_of(Sequel::SQL::NumericExpression)
11
- (s & true).should be_a_kind_of(Sequel::SQL::BooleanExpression)
12
- (s < 1).should be_a_kind_of(Sequel::SQL::BooleanExpression)
13
- s.sql_subscript(1).should be_a_kind_of(Sequel::SQL::Subscript)
14
- s.like('a').should be_a_kind_of(Sequel::SQL::BooleanExpression)
15
- s.as(:a).should be_a_kind_of(Sequel::SQL::AliasedExpression)
16
- s.cast(Integer).should be_a_kind_of(Sequel::SQL::Cast)
17
- s.desc.should be_a_kind_of(Sequel::SQL::OrderedExpression)
18
- s.sql_string.should be_a_kind_of(Sequel::SQL::StringExpression)
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)
19
17
  end
20
18
 
21
19
  specify "Numeric#sql_expr should wrap the object in a NumericExpression" do
22
- [1, 2.0, 2^40, BigDecimal.new('1.0')].each do |o|
23
- s = o.sql_expr
24
- s.should be_a_kind_of(Sequel::SQL::NumericExpression)
25
- s.op.should == :NOOP
26
- s.args.should == [o]
20
+ [1, 2.0, 2^70, BigDecimal.new('1.0')].each do |o|
21
+ o.sql_expr.should == Sequel::SQL::NumericExpression.new(:NOOP, o)
27
22
  end
28
23
  end
29
24
 
30
25
  specify "String#sql_expr should wrap the object in a StringExpression" do
31
- o = ""
32
- s = o.sql_expr
33
- s.should be_a_kind_of(Sequel::SQL::StringExpression)
34
- s.op.should == :NOOP
35
- s.args.should == [o]
26
+ "".sql_expr.should == Sequel::SQL::StringExpression.new(:NOOP, "")
36
27
  end
37
28
 
38
29
  specify "NilClass, TrueClass, and FalseClass#sql_expr should wrap the object in a BooleanExpression" do
39
30
  [nil, true, false].each do |o|
40
- s = o.sql_expr
41
- s.should be_a_kind_of(Sequel::SQL::BooleanExpression)
42
- s.op.should == :NOOP
43
- s.args.should == [o]
31
+ o.sql_expr.should == Sequel::SQL::BooleanExpression.new(:NOOP, o)
44
32
  end
45
33
  end
46
34
 
47
35
  specify "Proc#sql_expr should should treat the object as a virtual row block" do
48
- s = proc{a}.sql_expr
49
- s.should be_a_kind_of(Sequel::SQL::Identifier)
50
- s.value.should == :a
51
-
52
- s = proc{a__b}.sql_expr
53
- s.should be_a_kind_of(Sequel::SQL::QualifiedIdentifier)
54
- s.table.should == "a"
55
- s.column.should == "b"
56
-
57
- s = proc{a(b)}.sql_expr
58
- s.should be_a_kind_of(Sequel::SQL::Function)
59
- s.f.should == :a
60
- s.args.length.should == 1
61
- s.args.first.should be_a_kind_of(Sequel::SQL::Identifier)
62
- s.args.first.value.should == :b
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))
63
39
  end
64
40
 
65
41
  specify "Proc#sql_expr should should wrap the object in a GenericComplexExpression if the object is not already an expression" do
66
- s = proc{1}.sql_expr
67
- s.should be_a_kind_of(Sequel::SQL::GenericComplexExpression)
68
- s.op.should == :NOOP
69
- s.args.should == [1]
42
+ proc{1}.sql_expr.should == Sequel::SQL::GenericComplexExpression.new(:NOOP, 1)
70
43
  end
71
44
 
72
45
  specify "Proc#sql_expr should should convert a hash or array of two element arrays to a BooleanExpression" do
73
- s = proc{{a=>b}}.sql_expr
74
- s.should be_a_kind_of(Sequel::SQL::BooleanExpression)
75
- s.op.should == :"="
76
- s.args.first.should be_a_kind_of(Sequel::SQL::Identifier)
77
- s.args.first.value.should == :a
78
- s.args.last.should be_a_kind_of(Sequel::SQL::Identifier)
79
- s.args.last.value.should == :b
80
-
81
- s = proc{[[a,b]]}.sql_expr
82
- s.should be_a_kind_of(Sequel::SQL::BooleanExpression)
83
- s.op.should == :"="
84
- s.args.first.should be_a_kind_of(Sequel::SQL::Identifier)
85
- s.args.first.value.should == :a
86
- s.args.last.should be_a_kind_of(Sequel::SQL::Identifier)
87
- s.args.last.value.should == :b
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))
88
48
  end
89
49
  end
@@ -7,23 +7,13 @@ describe "Sequel::Plugins::TacticalEagerLoading" do
7
7
  columns :id, :parent_id
8
8
  many_to_one :parent, :class=>self
9
9
  one_to_many :children, :class=>self, :key=>:parent_id
10
- ds = dataset
11
- def ds.fetch_rows(sql)
12
- execute(sql)
13
- where = @opts[:where]
14
- if !where
15
- yield(:id=>1, :parent_id=>101)
16
- yield(:id=>2, :parent_id=>102)
17
- yield(:id=>101, :parent_id=>nil)
18
- yield(:id=>102, :parent_id=>nil)
19
- elsif where.args.first.column == :id
20
- Array(where.args.last).each do |x|
21
- yield(:id=>x, :parent_id=>nil)
22
- end
23
- elsif where.args.first.column == :parent_id
24
- Array(where.args.last).each do |x|
25
- yield(:id=>x-100, :parent_id=>x) if x > 100
26
- end
10
+ dataset._fetch = proc do |sql|
11
+ if sql !~ /WHERE/
12
+ [{:id=>1, :parent_id=>101}, {:id=>2, :parent_id=>102}, {:id=>101, :parent_id=>nil}, {:id=>102, :parent_id=>nil}]
13
+ elsif sql =~ /WHERE.*\bid IN \(([\d, ]*)\)/
14
+ $1.split(', ').map{|x| {:id=>x.to_i, :parent_id=>nil}}
15
+ elsif sql =~ /WHERE.*\bparent_id IN \(([\d, ]*)\)/
16
+ $1.split(', ').map{|x| {:id=>x.to_i - 100, :parent_id=>x.to_i} if x.to_i > 100}.compact
27
17
  end
28
18
  end
29
19
  end
@@ -49,9 +39,9 @@ describe "Sequel::Plugins::TacticalEagerLoading" do
49
39
  ts = @c.all
50
40
  MODEL_DB.sqls.length.should == 1
51
41
  ts.map{|x| x.parent}.should == [ts[2], ts[3], nil, nil]
52
- MODEL_DB.sqls.length.should == 2
42
+ MODEL_DB.sqls.length.should == 1
53
43
  ts.map{|x| x.children}.should == [[], [], [ts[0]], [ts[1]]]
54
- MODEL_DB.sqls.length.should == 3
44
+ MODEL_DB.sqls.length.should == 1
55
45
  end
56
46
 
57
47
  it "association getter methods should not eagerly load the association if the association is cached" do
@@ -13,9 +13,10 @@ describe "Sequel::Plugins::Timestamps" do
13
13
  @c.class_eval do
14
14
  columns :id, :created_at, :updated_at
15
15
  plugin :timestamps
16
+ def _save_refresh(*) end
16
17
  db.reset
17
- def _refresh(ds); self end
18
18
  end
19
+ @c.dataset.autoid = nil
19
20
  end
20
21
  after do
21
22
  Sequel.datetime_class = Time
@@ -40,8 +41,9 @@ describe "Sequel::Plugins::Timestamps" do
40
41
  it "should use the same value for the creation and update timestamps when creating if the :update_on_create option is given" do
41
42
  @c.plugin :timestamps, :update_on_create=>true
42
43
  o = @c.create
43
- @c.db.sqls.length.should == 1
44
- @c.db.sqls.first.should =~ /INSERT INTO t \((creat|updat)ed_at, (creat|updat)ed_at\) VALUES \('2009-08-01', '2009-08-01'\)/
44
+ sqls = @c.db.sqls
45
+ sqls.shift.should =~ /INSERT INTO t \((creat|updat)ed_at, (creat|updat)ed_at\) VALUES \('2009-08-01', '2009-08-01'\)/
46
+ sqls.should == []
45
47
  o.created_at.should === o.updated_at
46
48
  end
47
49
 
@@ -50,8 +52,7 @@ describe "Sequel::Plugins::Timestamps" do
50
52
  c.class_eval do
51
53
  columns :id, :c
52
54
  plugin :timestamps, :create=>:c
53
- db.reset
54
- def _refresh(ds); self end
55
+ def _save_refresh(*) end
55
56
  end
56
57
  o = c.create
57
58
  c.db.sqls.should == ["INSERT INTO t (c) VALUES ('2009-08-01')"]
@@ -64,7 +65,6 @@ describe "Sequel::Plugins::Timestamps" do
64
65
  columns :id, :u
65
66
  plugin :timestamps, :update=>:u
66
67
  db.reset
67
- def _refresh(ds); self end
68
68
  end
69
69
  o = c.load(:id=>1).save
70
70
  c.db.sqls.should == ["UPDATE t SET u = '2009-08-01' WHERE (id = 1)"]
@@ -11,14 +11,13 @@ describe Sequel::Model, "to_dot extension" do
11
11
  end
12
12
 
13
13
  it "should output a string suitable for input to the graphviz dot program" do
14
- @ds.to_dot.should == (<<END
14
+ @ds.to_dot.should == (<<END).strip
15
15
  digraph G {
16
16
  0 [label="self"];
17
17
  0 -> 1 [label=""];
18
18
  1 [label="Dataset"];
19
19
  }
20
20
  END
21
- ).strip
22
21
  end
23
22
 
24
23
  it "should handle an empty dataset" do
@@ -2,9 +2,7 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe "Touch plugin" do
4
4
  before do
5
- @c = Class.new(Sequel::Model) do
6
- def _refresh(*); end
7
- end
5
+ @c = Class.new(Sequel::Model)
8
6
  p = proc{def touch_instance_value; touch_association_value; end}
9
7
  @Artist = Class.new(@c, &p).set_dataset(:artists)
10
8
  @Album = Class.new(@c, &p).set_dataset(:albums)
@@ -63,8 +61,9 @@ describe "Touch plugin" do
63
61
  specify "should be able to give an array to the :associations option specifying multiple associations" do
64
62
  @Album.plugin :touch, :associations=>[:artist, :followup_albums]
65
63
  @Album.load(:id=>4, :artist_id=>1).touch
66
- MODEL_DB.sqls.shift.should == "UPDATE albums SET updated_at = CURRENT_TIMESTAMP WHERE (id = 4)"
67
- MODEL_DB.sqls.sort.should == ["UPDATE albums SET updated_at = CURRENT_TIMESTAMP WHERE (albums.original_album_id = 4)",
64
+ sqls = MODEL_DB.sqls
65
+ sqls.shift.should == "UPDATE albums SET updated_at = CURRENT_TIMESTAMP WHERE (id = 4)"
66
+ sqls.sort.should == ["UPDATE albums SET updated_at = CURRENT_TIMESTAMP WHERE (albums.original_album_id = 4)",
68
67
  "UPDATE artists SET updated_at = CURRENT_TIMESTAMP WHERE (artists.id = 1)"]
69
68
  end
70
69
 
@@ -85,8 +84,9 @@ describe "Touch plugin" do
85
84
  specify "should allow the mixed use of symbols and hashes inside an array for the :associations option" do
86
85
  @Album.plugin :touch, :associations=>[:artist, {:followup_albums=>:modified_on}]
87
86
  @Album.load(:id=>4, :artist_id=>1).touch
88
- MODEL_DB.sqls.shift.should == "UPDATE albums SET updated_at = CURRENT_TIMESTAMP WHERE (id = 4)"
89
- MODEL_DB.sqls.sort.should == ["UPDATE albums SET modified_on = CURRENT_TIMESTAMP WHERE (albums.original_album_id = 4)",
87
+ sqls = MODEL_DB.sqls
88
+ sqls.shift.should == "UPDATE albums SET updated_at = CURRENT_TIMESTAMP WHERE (id = 4)"
89
+ sqls.sort.should == ["UPDATE albums SET modified_on = CURRENT_TIMESTAMP WHERE (albums.original_album_id = 4)",
90
90
  "UPDATE artists SET updated_at = CURRENT_TIMESTAMP WHERE (artists.id = 1)"]
91
91
  end
92
92
 
@@ -94,8 +94,9 @@ describe "Touch plugin" do
94
94
  @Album.plugin :touch
95
95
  @Album.touch_associations(:artist, {:followup_albums=>:modified_on})
96
96
  @Album.load(:id=>4, :artist_id=>1).touch
97
- MODEL_DB.sqls.shift.should == "UPDATE albums SET updated_at = CURRENT_TIMESTAMP WHERE (id = 4)"
98
- MODEL_DB.sqls.sort.should == ["UPDATE albums SET modified_on = CURRENT_TIMESTAMP WHERE (albums.original_album_id = 4)",
97
+ sqls = MODEL_DB.sqls
98
+ sqls.shift.should == "UPDATE albums SET updated_at = CURRENT_TIMESTAMP WHERE (id = 4)"
99
+ sqls.sort.should == ["UPDATE albums SET modified_on = CURRENT_TIMESTAMP WHERE (albums.original_album_id = 4)",
99
100
  "UPDATE artists SET updated_at = CURRENT_TIMESTAMP WHERE (artists.id = 1)"]
100
101
  end
101
102
 
@@ -103,8 +104,9 @@ describe "Touch plugin" do
103
104
  @Album.plugin :touch
104
105
  @Album.touch_associations(:artist, {:followup_albums=>:modified_on})
105
106
  @Album.load(:id=>4, :artist_id=>1).destroy
106
- MODEL_DB.sqls.shift.should == "DELETE FROM albums WHERE (id = 4)"
107
- MODEL_DB.sqls.sort.should == ["UPDATE albums SET modified_on = CURRENT_TIMESTAMP WHERE (albums.original_album_id = 4)",
107
+ sqls = MODEL_DB.sqls
108
+ sqls.shift.should == "DELETE FROM albums WHERE (id = 4)"
109
+ sqls.sort.should == ["UPDATE albums SET modified_on = CURRENT_TIMESTAMP WHERE (albums.original_album_id = 4)",
108
110
  "UPDATE artists SET updated_at = CURRENT_TIMESTAMP WHERE (artists.id = 1)"]
109
111
  end
110
112
 
@@ -133,18 +135,15 @@ describe "Touch plugin" do
133
135
  c1 = Class.new(@Artist)
134
136
  c1.load(:id=>4).touch
135
137
  MODEL_DB.sqls.should == ["UPDATE artists SET updated_at = CURRENT_TIMESTAMP WHERE (id = 4)"]
136
- MODEL_DB.reset
137
138
 
138
139
  c1.touch_column = :modified_on
139
140
  c1.touch_associations :albums
140
141
  c1.load(:id=>1).touch
141
142
  MODEL_DB.sqls.should == ["UPDATE artists SET modified_on = CURRENT_TIMESTAMP WHERE (id = 1)",
142
143
  "UPDATE albums SET modified_on = CURRENT_TIMESTAMP WHERE (albums.artist_id = 1)"]
143
- MODEL_DB.reset
144
144
 
145
145
  @a.touch
146
146
  MODEL_DB.sqls.should == ["UPDATE artists SET updated_at = CURRENT_TIMESTAMP WHERE (id = 1)"]
147
- MODEL_DB.reset
148
147
 
149
148
  @Artist.plugin :touch, :column=>:modified_on, :associations=>:albums
150
149
  c2 = Class.new(@Artist)