sequel 3.29.0 → 3.30.0

Sign up to get free protection for your applications and to get access to all the features.
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)