sequel 4.12.0 → 4.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (101) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +64 -0
  3. data/Rakefile +3 -1
  4. data/bin/sequel +13 -5
  5. data/doc/release_notes/4.13.0.txt +169 -0
  6. data/doc/sql.rdoc +3 -3
  7. data/lib/sequel/adapters/do.rb +11 -23
  8. data/lib/sequel/adapters/do/mysql.rb +8 -0
  9. data/lib/sequel/adapters/do/postgres.rb +8 -0
  10. data/lib/sequel/adapters/do/{sqlite.rb → sqlite3.rb} +9 -0
  11. data/lib/sequel/adapters/jdbc.rb +16 -139
  12. data/lib/sequel/adapters/jdbc/as400.rb +9 -0
  13. data/lib/sequel/adapters/jdbc/cubrid.rb +9 -0
  14. data/lib/sequel/adapters/jdbc/db2.rb +9 -0
  15. data/lib/sequel/adapters/jdbc/derby.rb +9 -0
  16. data/lib/sequel/adapters/jdbc/{firebird.rb → firebirdsql.rb} +9 -0
  17. data/lib/sequel/adapters/jdbc/h2.rb +10 -0
  18. data/lib/sequel/adapters/jdbc/hsqldb.rb +9 -0
  19. data/lib/sequel/adapters/jdbc/{informix.rb → informix-sqli.rb} +9 -0
  20. data/lib/sequel/adapters/jdbc/{progress.rb → jdbcprogress.rb} +9 -0
  21. data/lib/sequel/adapters/jdbc/jtds.rb +10 -0
  22. data/lib/sequel/adapters/jdbc/mysql.rb +14 -0
  23. data/lib/sequel/adapters/jdbc/oracle.rb +9 -0
  24. data/lib/sequel/adapters/jdbc/postgresql.rb +9 -0
  25. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +23 -0
  26. data/lib/sequel/adapters/jdbc/sqlite.rb +10 -0
  27. data/lib/sequel/adapters/jdbc/sqlserver.rb +10 -0
  28. data/lib/sequel/adapters/odbc.rb +6 -14
  29. data/lib/sequel/adapters/odbc/db2.rb +9 -0
  30. data/lib/sequel/adapters/odbc/mssql.rb +8 -0
  31. data/lib/sequel/adapters/odbc/progress.rb +8 -0
  32. data/lib/sequel/adapters/oracle.rb +1 -1
  33. data/lib/sequel/adapters/postgres.rb +1 -1
  34. data/lib/sequel/adapters/shared/firebird.rb +8 -1
  35. data/lib/sequel/adapters/shared/mssql.rb +68 -27
  36. data/lib/sequel/adapters/shared/mysql.rb +3 -5
  37. data/lib/sequel/adapters/shared/oracle.rb +17 -3
  38. data/lib/sequel/adapters/shared/postgres.rb +9 -4
  39. data/lib/sequel/adapters/shared/sqlanywhere.rb +6 -6
  40. data/lib/sequel/database/connecting.rb +38 -17
  41. data/lib/sequel/dataset/actions.rb +6 -2
  42. data/lib/sequel/dataset/graph.rb +18 -20
  43. data/lib/sequel/dataset/misc.rb +37 -0
  44. data/lib/sequel/dataset/prepared_statements.rb +1 -2
  45. data/lib/sequel/dataset/query.rb +1 -0
  46. data/lib/sequel/dataset/sql.rb +17 -10
  47. data/lib/sequel/extensions/dataset_source_alias.rb +90 -0
  48. data/lib/sequel/extensions/pg_array.rb +14 -10
  49. data/lib/sequel/extensions/pg_enum.rb +135 -0
  50. data/lib/sequel/extensions/pg_hstore.rb +4 -6
  51. data/lib/sequel/extensions/pg_inet.rb +4 -5
  52. data/lib/sequel/extensions/pg_interval.rb +3 -3
  53. data/lib/sequel/extensions/pg_json.rb +16 -12
  54. data/lib/sequel/extensions/pg_range.rb +5 -3
  55. data/lib/sequel/extensions/pg_row.rb +2 -2
  56. data/lib/sequel/extensions/round_timestamps.rb +52 -0
  57. data/lib/sequel/model.rb +5 -2
  58. data/lib/sequel/model/associations.rb +29 -3
  59. data/lib/sequel/model/base.rb +68 -29
  60. data/lib/sequel/plugins/class_table_inheritance.rb +25 -16
  61. data/lib/sequel/plugins/column_select.rb +57 -0
  62. data/lib/sequel/plugins/composition.rb +14 -16
  63. data/lib/sequel/plugins/dirty.rb +9 -11
  64. data/lib/sequel/plugins/insert_returning_select.rb +70 -0
  65. data/lib/sequel/plugins/instance_filters.rb +7 -9
  66. data/lib/sequel/plugins/lazy_attributes.rb +16 -4
  67. data/lib/sequel/plugins/list.rb +9 -0
  68. data/lib/sequel/plugins/modification_detection.rb +90 -0
  69. data/lib/sequel/plugins/serialization.rb +13 -15
  70. data/lib/sequel/plugins/serialization_modification_detection.rb +9 -9
  71. data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
  72. data/lib/sequel/plugins/timestamps.rb +6 -6
  73. data/lib/sequel/version.rb +1 -1
  74. data/spec/adapters/mysql_spec.rb +7 -0
  75. data/spec/adapters/postgres_spec.rb +41 -0
  76. data/spec/bin_spec.rb +4 -1
  77. data/spec/core/database_spec.rb +6 -0
  78. data/spec/core/dataset_spec.rb +100 -90
  79. data/spec/core/object_graph_spec.rb +5 -0
  80. data/spec/extensions/class_table_inheritance_spec.rb +18 -13
  81. data/spec/extensions/column_select_spec.rb +108 -0
  82. data/spec/extensions/composition_spec.rb +20 -0
  83. data/spec/extensions/dataset_source_alias_spec.rb +51 -0
  84. data/spec/extensions/insert_returning_select_spec.rb +46 -0
  85. data/spec/extensions/lazy_attributes_spec.rb +24 -20
  86. data/spec/extensions/list_spec.rb +5 -0
  87. data/spec/extensions/modification_detection_spec.rb +80 -0
  88. data/spec/extensions/pg_enum_spec.rb +64 -0
  89. data/spec/extensions/pg_json_spec.rb +7 -13
  90. data/spec/extensions/prepared_statements_spec.rb +6 -4
  91. data/spec/extensions/round_timestamps_spec.rb +43 -0
  92. data/spec/extensions/serialization_modification_detection_spec.rb +10 -1
  93. data/spec/extensions/serialization_spec.rb +18 -0
  94. data/spec/extensions/single_table_inheritance_spec.rb +5 -0
  95. data/spec/extensions/timestamps_spec.rb +6 -0
  96. data/spec/integration/plugin_test.rb +14 -8
  97. data/spec/integration/prepared_statement_test.rb +12 -0
  98. data/spec/model/associations_spec.rb +24 -0
  99. data/spec/model/model_spec.rb +13 -3
  100. data/spec/model/record_spec.rb +24 -1
  101. metadata +22 -6
@@ -106,6 +106,11 @@ describe "List plugin" do
106
106
  "SELECT * FROM items WHERE (id = 3) ORDER BY scope_id, position LIMIT 1"]
107
107
  end
108
108
 
109
+ it "should update positions automatically on deletion" do
110
+ @o.destroy
111
+ @db.sqls.should == ["DELETE FROM items WHERE (id = 7)", "UPDATE items SET position = (position - 1) WHERE (position > 3)"]
112
+ end
113
+
109
114
  it "should have last_position return the last position in the list" do
110
115
  @c.dataset._fetch = {:max=>10}
111
116
  @o.last_position.should == 10
@@ -0,0 +1,80 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+ require 'yaml'
3
+
4
+ describe "serialization_modification_detection plugin" do
5
+ before do
6
+ @ds = Sequel.mock(:fetch=>{:id=>1, :a=>'a', :b=>1, :c=>['a'], :d=>{'b'=>'c'}}, :numrows=>1, :autoid=>1)[:items]
7
+ @c = Class.new(Sequel::Model(@ds))
8
+ @c.plugin :modification_detection
9
+ @c.columns :a, :b, :c, :d
10
+ @o = @c.first
11
+ @ds.db.sqls
12
+ end
13
+
14
+ it "should only detect columns that have been changed" do
15
+ @o.changed_columns.should == []
16
+ @o.a << 'b'
17
+ @o.changed_columns.should == [:a]
18
+ @o.a.replace('a')
19
+ @o.changed_columns.should == []
20
+
21
+ @o.values[:b] = 2
22
+ @o.changed_columns.should == [:b]
23
+ @o.values[:b] = 1
24
+ @o.changed_columns.should == []
25
+
26
+ @o.c[0] << 'b'
27
+ @o.d['b'] << 'b'
28
+ @o.changed_columns.sort_by{|c| c.to_s}.should == [:c, :d]
29
+ @o.c[0] = 'a'
30
+ @o.changed_columns.should == [:d]
31
+ @o.d['b'] = 'c'
32
+ @o.changed_columns.should == []
33
+ end
34
+
35
+ it "should not list a column twice" do
36
+ @o.a = 'b'
37
+ @o.a << 'a'
38
+ @o.changed_columns.should == [:a]
39
+ end
40
+
41
+ it "should report correct changed_columns after updating" do
42
+ @o.a << 'a'
43
+ @o.save_changes
44
+ @o.changed_columns.should == []
45
+
46
+ @o.values[:b] = 2
47
+ @o.save_changes
48
+ @o.changed_columns.should == []
49
+
50
+ @o.c[0] << 'b'
51
+ @o.save_changes
52
+ @o.changed_columns.should == []
53
+
54
+ @o.d['b'] << 'a'
55
+ @o.save_changes
56
+ @o.changed_columns.should == []
57
+
58
+ @ds.db.sqls.should == ["UPDATE items SET a = 'aa' WHERE (id = 1)",
59
+ "UPDATE items SET b = 2 WHERE (id = 1)",
60
+ "UPDATE items SET c = ('ab') WHERE (id = 1)",
61
+ "UPDATE items SET d = ('b' = 'ca') WHERE (id = 1)"]
62
+ end
63
+
64
+ it "should report correct changed_columns after creating new object" do
65
+ o = @c.create
66
+ o.changed_columns.should == []
67
+ o.a << 'a'
68
+ o.changed_columns.should == [:a]
69
+ @ds.db.sqls.should == ["INSERT INTO items DEFAULT VALUES", "SELECT * FROM items WHERE (id = 1) LIMIT 1"]
70
+ end
71
+
72
+ it "should report correct changed_columns after refreshing existing object" do
73
+ @o.a << 'a'
74
+ @o.changed_columns.should == [:a]
75
+ @o.refresh
76
+ @o.changed_columns.should == []
77
+ @o.a << 'a'
78
+ @o.changed_columns.should == [:a]
79
+ end
80
+ end
@@ -0,0 +1,64 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "pg_inet extension" do
4
+ before do
5
+ @db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
6
+ @db.extend(Module.new do
7
+ def schema_parse_table(*)
8
+ [[:a, {:oid=>1}]]
9
+ end
10
+ end)
11
+ @db.send(:metadata_dataset)._fetch = [[{:v=>1, :enumlabel=>'a'}, {:v=>1, :enumlabel=>'b'}, {:v=>1, :enumlabel=>'c'}],
12
+ [{:typname=>'enum1', :v=>212389}]]
13
+ @db.extension(:pg_array, :pg_enum)
14
+ @db.sqls
15
+ end
16
+
17
+ it "should include enum information in the schema entry" do
18
+ @db.schema(:a).should == [[:a, {:oid=>1, :ruby_default=>nil, :type=>:enum, :enum_values=>%w'a b c'}]]
19
+ end
20
+
21
+ it "should typecast objects to string" do
22
+ @db.typecast_value(:enum, :a).should == 'a'
23
+ end
24
+
25
+ it "should add array parsers for enum values" do
26
+ @db.conversion_procs[212389].call('{a,b,c}').should == %w'a b c'
27
+ end
28
+
29
+ it "should support #create_enum method for adding a new enum" do
30
+ @db.create_enum(:foo, [:a, :b, :c])
31
+ @db.sqls.first.should == "CREATE TYPE foo AS ENUM ('a', 'b', 'c')"
32
+ @db.create_enum(:sch__foo, %w'a b c')
33
+ @db.sqls.first.should == "CREATE TYPE sch.foo AS ENUM ('a', 'b', 'c')"
34
+ end
35
+
36
+ it "should support #drop_enum method for dropping an enum" do
37
+ @db.drop_enum(:foo)
38
+ @db.sqls.first.should == "DROP TYPE foo"
39
+ @db.drop_enum(:sch__foo, :if_exists=>true)
40
+ @db.sqls.first.should == "DROP TYPE IF EXISTS sch.foo"
41
+ @db.drop_enum('foo', :cascade=>true)
42
+ @db.sqls.first.should == "DROP TYPE foo CASCADE"
43
+ end
44
+
45
+ it "should support #add_enum_value method for adding value to an existing enum" do
46
+ @db.add_enum_value(:foo, :a)
47
+ @db.sqls.first.should == "ALTER TYPE foo ADD VALUE 'a'"
48
+ end
49
+
50
+ it "should support :before option for #add_enum_value method for adding value before an existing enum value" do
51
+ @db.add_enum_value('foo', :a, :before=>:b)
52
+ @db.sqls.first.should == "ALTER TYPE foo ADD VALUE 'a' BEFORE 'b'"
53
+ end
54
+
55
+ it "should support :after option for #add_enum_value method for adding value after an existing enum value" do
56
+ @db.add_enum_value(:sch__foo, :a, :after=>:b)
57
+ @db.sqls.first.should == "ALTER TYPE sch.foo ADD VALUE 'a' AFTER 'b'"
58
+ end
59
+
60
+ it "should support :if_not_exists option for #add_enum_value method for not adding the value if it exists" do
61
+ @db.add_enum_value(:foo, :a, :if_not_exists=>true)
62
+ @db.sqls.first.should == "ALTER TYPE foo ADD VALUE IF NOT EXISTS 'a'"
63
+ end
64
+ end
@@ -10,17 +10,6 @@ describe "pg_json extension" do
10
10
  @ac = m::JSONArray
11
11
  @bhc = m::JSONBHash
12
12
  @bac = m::JSONBArray
13
-
14
- # Create subclass in correct namespace for easily overriding methods
15
- j = m::JSON = JSON.dup
16
- j.instance_eval do
17
- Parser = JSON::Parser
18
- alias old_parse parse
19
- def parse(s)
20
- return 1 if s == '1'
21
- old_parse(s)
22
- end
23
- end
24
13
  end
25
14
  before do
26
15
  @db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
@@ -64,10 +53,15 @@ describe "pg_json extension" do
64
53
  Sequel.instance_eval do
65
54
  alias pj parse_json
66
55
  def parse_json(v)
67
- v
56
+ {'1'=>1, "'a'"=>'a', 'true'=>true, 'false'=>false, 'null'=>nil, 'o'=>Object.new}.fetch(v){pj(v)}
68
57
  end
69
58
  end
70
- proc{@m.parse_json('1')}.should raise_error(Sequel::InvalidValue)
59
+ @m.parse_json('1').should == 1
60
+ @m.parse_json("'a'").should == 'a'
61
+ @m.parse_json('true').should == true
62
+ @m.parse_json('false').should == false
63
+ @m.parse_json('null').should == nil
64
+ proc{@m.parse_json('o')}.should raise_error(Sequel::InvalidValue)
71
65
  ensure
72
66
  Sequel.instance_eval do
73
67
  alias parse_json pj
@@ -38,13 +38,15 @@ describe "prepared_statements plugin" do
38
38
  def supports_insert_select?
39
39
  true
40
40
  end
41
+ def supports_returning?(type)
42
+ true
43
+ end
41
44
  def insert_select(h)
42
45
  self._fetch = {:id=>1, :name=>'foo', :i => 2}
43
- ds = opts[:returning] ? self : returning
44
- ds.server(:default).with_sql(:insert_sql, h).first
46
+ server(:default).with_sql_first(insert_select_sql(h))
45
47
  end
46
- def insert_sql(*)
47
- "#{super}#{" RETURNING #{opts[:returning] && !opts[:returning].empty? ? opts[:returning].map{|c| literal(c)}.join(', ') : '*'}" if opts.has_key?(:returning)}"
48
+ def insert_select_sql(*v)
49
+ "#{insert_sql(*v)} RETURNING #{(opts[:returning] && !opts[:returning].empty?) ? opts[:returning].map{|c| literal(c)}.join(', ') : '*'}"
48
50
  end
49
51
  end
50
52
  @c.create(:name=>'foo').should == @c.load(:id=>1, :name=>'foo', :i => 2)
@@ -0,0 +1,43 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ if RUBY_VERSION >= '1.9.0'
4
+ describe "Sequel::Dataset::RoundTimestamps" do
5
+ before do
6
+ @dataset = Sequel.mock.dataset.extension(:round_timestamps)
7
+ end
8
+
9
+ specify "should round times properly for databases supporting microsecond precision" do
10
+ @dataset.literal(Sequel::SQLTime.create(1, 2, 3, 499999.5)).should == "'01:02:03.500000'"
11
+ @dataset.literal(Time.local(2010, 1, 2, 3, 4, 5.4999995)).should == "'2010-01-02 03:04:05.500000'"
12
+ @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, Rational(54999995, 10000000))).should == "'2010-01-02 03:04:05.500000'"
13
+
14
+ @dataset.literal(Sequel::SQLTime.create(1, 2, 3, 499999.4)).should == "'01:02:03.499999'"
15
+ @dataset.literal(Time.local(2010, 1, 2, 3, 4, 5.4999994)).should == "'2010-01-02 03:04:05.499999'"
16
+ @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, Rational(54999994, 10000000))).should == "'2010-01-02 03:04:05.499999'"
17
+ end
18
+
19
+ specify "should round times properly for databases supporting millisecond precision" do
20
+ def @dataset.timestamp_precision() 3 end
21
+ @dataset.literal(Sequel::SQLTime.create(1, 2, 3, 499500)).should == "'01:02:03.500'"
22
+ @dataset.literal(Time.local(2010, 1, 2, 3, 4, 5.4995)).should == "'2010-01-02 03:04:05.500'"
23
+ @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, Rational(54995, 10000))).should == "'2010-01-02 03:04:05.500'"
24
+
25
+ @dataset.literal(Sequel::SQLTime.create(1, 2, 3, 499499)).should == "'01:02:03.499'"
26
+ @dataset.literal(Time.local(2010, 1, 2, 3, 4, 5.4994)).should == "'2010-01-02 03:04:05.499'"
27
+ @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, Rational(54994, 10000))).should == "'2010-01-02 03:04:05.499'"
28
+ end
29
+
30
+ specify "should round times properly for databases supporting second precision" do
31
+ def @dataset.supports_timestamp_usecs?() false end
32
+ @dataset.literal(Sequel::SQLTime.create(1, 2, 3, 500000)).should == "'01:02:04'"
33
+ @dataset.literal(Time.local(2010, 1, 2, 3, 4, 5.5)).should == "'2010-01-02 03:04:06'"
34
+ @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, Rational(55, 10))).should == "'2010-01-02 03:04:06'"
35
+
36
+ @dataset.literal(Sequel::SQLTime.create(1, 2, 3, 499999)).should == "'01:02:03'"
37
+ @dataset.literal(Time.local(2010, 1, 2, 3, 4, 5.4999999)).should == "'2010-01-02 03:04:05'"
38
+ @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, Rational(54999999, 10000000))).should == "'2010-01-02 03:04:05'"
39
+ end
40
+ end
41
+ else
42
+ skip_warn "round_timestamps extension: only works on ruby 1.9+"
43
+ end
@@ -78,7 +78,7 @@ describe "serialization_modification_detection plugin" do
78
78
  @o1.changed_columns.should == [:h]
79
79
  end
80
80
 
81
- it "should work with frozen objects" do
81
+ it "should work with duplicating objects" do
82
82
  @o2.changed_columns.should == []
83
83
  o = @o2.dup
84
84
  @o2.h.should == {}
@@ -86,4 +86,13 @@ describe "serialization_modification_detection plugin" do
86
86
  @o2.changed_columns.should == [:h]
87
87
  o.changed_columns.should == []
88
88
  end
89
+
90
+ it "should work with duplicating objects after modifying them" do
91
+ @o2.changed_columns.should == []
92
+ @o2.h.should == {}
93
+ @o2.h[1] = 2
94
+ @o2.changed_columns.should == [:h]
95
+ o = @o2.dup
96
+ o.changed_columns.should == [:h]
97
+ end
89
98
  end
@@ -26,6 +26,24 @@ describe "Serialization plugin" do
26
26
  DB.sqls.last.should =~ /INSERT INTO items \((ghi)\) VALUES \('\[123\]'\)/
27
27
  end
28
28
 
29
+ it "should handle validations of underlying column" do
30
+ @c.plugin :serialization, :yaml, :abc
31
+ o = @c.new
32
+ def o.validate
33
+ errors.add(:abc, "not present") unless self[:abc]
34
+ end
35
+ o.valid?.should == false
36
+ o.abc = {}
37
+ o.valid?.should == true
38
+ end
39
+
40
+ it "should set column values even when not validating" do
41
+ @c.set_primary_key :id
42
+ @c.plugin :serialization, :yaml, :abc
43
+ @c.load({:id=>1}).set(:abc=>{}).save(:validate=>false)
44
+ DB.sqls.last.gsub("\n", '').should == "UPDATE items SET abc = '--- {}' WHERE (id = 1)"
45
+ end
46
+
29
47
  it "should allow serializing attributes to yaml" do
30
48
  @c.plugin :serialization, :yaml, :abc
31
49
  @c.create(:abc => 1)
@@ -85,6 +85,11 @@ describe Sequel::Model, "single table inheritance plugin" do
85
85
  o.valid?.should == true
86
86
  end
87
87
 
88
+ it "should set type column field even if validations are skipped" do
89
+ StiTestSub1.new.save(:validate=>false)
90
+ DB.sqls.should == ["INSERT INTO sti_tests (kind) VALUES ('StiTestSub1')", "SELECT * FROM sti_tests WHERE ((sti_tests.kind IN ('StiTestSub1')) AND (id = 10)) LIMIT 1"]
91
+ end
92
+
88
93
  it "should override an existing value in the class name field" do
89
94
  StiTest.create(:kind=>'StiTestSub1')
90
95
  DB.sqls.should == ["INSERT INTO sti_tests (kind) VALUES ('StiTestSub1')", "SELECT * FROM sti_tests WHERE (id = 10) LIMIT 1"]
@@ -32,6 +32,12 @@ describe "Sequel::Plugins::Timestamps" do
32
32
  o.valid?.should == true
33
33
  end
34
34
 
35
+ it "should set timestamp fields when skipping validations" do
36
+ @c.plugin :timestamps
37
+ @c.new.save(:validate=>false)
38
+ @c.db.sqls.should == ["INSERT INTO t (created_at) VALUES ('2009-08-01')"]
39
+ end
40
+
35
41
  it "should set the create timestamp field on creation" do
36
42
  o = @c.create
37
43
  @c.db.sqls.should == ["INSERT INTO t (created_at) VALUES ('2009-08-01')"]
@@ -1,8 +1,5 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
2
2
 
3
- # DB2 does not seem to support USING joins in every version; it seems to be
4
- # valid expression in DB2 iSeries UDB though.
5
- unless !DB.dataset.supports_join_using? || Sequel.guarded?(:db2)
6
3
  describe "Class Table Inheritance Plugin" do
7
4
  before(:all) do
8
5
  @db = DB
@@ -37,7 +34,7 @@ describe "Class Table Inheritance Plugin" do
37
34
  class ::Executive < Manager
38
35
  end
39
36
  class ::Staff < Employee
40
- many_to_one :manager, :qualify=>false
37
+ many_to_one :manager
41
38
  end
42
39
 
43
40
  @i1 =@db[:employees].insert(:name=>'E', :kind=>'Employee')
@@ -96,10 +93,10 @@ describe "Class Table Inheritance Plugin" do
96
93
  end
97
94
 
98
95
  specify "should handle associations only defined in subclasses" do
99
- Employee.filter(:id=>@i2).all.first.manager.id.should == @i4
96
+ Employee.filter(:employees__id=>@i2).all.first.manager.id.should == @i4
100
97
  end
101
98
 
102
- cspecify "should insert rows into all tables", [proc{|db| db.sqlite_version < 30709}, :sqlite] do
99
+ specify "should insert rows into all tables" do
103
100
  e = Executive.create(:name=>'Ex2', :num_managers=>8, :num_staff=>9)
104
101
  i = e.id
105
102
  @db[:employees][:id=>i].should == {:id=>i, :name=>'Ex2', :kind=>'Executive'}
@@ -138,13 +135,12 @@ describe "Class Table Inheritance Plugin" do
138
135
  Executive.limit(1).eager(:staff_members).first.staff_members.should == [Staff[@i2]]
139
136
  end
140
137
 
141
- cspecify "should handle eagerly graphing one_to_many relationships", [proc{|db| db.sqlite_version < 30709}, :sqlite] do
138
+ specify "should handle eagerly graphing one_to_many relationships" do
142
139
  es = Executive.limit(1).eager_graph(:staff_members).all
143
140
  es.should == [Executive[@i4]]
144
141
  es.map{|x| x.staff_members}.should == [[Staff[@i2]]]
145
142
  end
146
143
  end
147
- end
148
144
 
149
145
  describe "Many Through Many Plugin" do
150
146
  before(:all) do
@@ -1494,6 +1490,11 @@ describe "List plugin without a scope" do
1494
1490
  proc { @c[:name => "def"].move_up(10) }.should raise_error(Sequel::Error)
1495
1491
  proc { @c[:name => "def"].move_down(10) }.should raise_error(Sequel::Error)
1496
1492
  end
1493
+
1494
+ it "should update positions on destroy" do
1495
+ @c[:name => "def"].destroy
1496
+ @c.select_map([:position, :name]).should == [[1, 'abc'], [2, 'hig']]
1497
+ end
1497
1498
  end
1498
1499
 
1499
1500
  describe "List plugin with a scope" do
@@ -1572,6 +1573,11 @@ describe "List plugin with a scope" do
1572
1573
  proc { @c[:name => "P1"].move_up(10) }.should raise_error(Sequel::Error)
1573
1574
  proc { @c[:name => "P1"].move_down(10) }.should raise_error(Sequel::Error)
1574
1575
  end
1576
+
1577
+ it "should update positions on destroy" do
1578
+ @c[:name => "P2"].destroy
1579
+ @c.select_order_map([:pos, :name]).should == [[1, "Hm"], [1, "P1"], [1, "Ps"], [2, "Au"], [2, "P3"]]
1580
+ end
1575
1581
  end
1576
1582
 
1577
1583
  describe "Sequel::Plugins::Tree" do
@@ -117,6 +117,12 @@ describe "Prepared Statements and Bound Arguments" do
117
117
  @ds.filter(:id=>2).first[:numb].should == 20
118
118
  end
119
119
 
120
+ specify "should support bound variables with insert_select" do
121
+ @ds.call(:insert_select, {:n=>20}, :numb=>:$n).should == {:id=>2, :numb=>20}
122
+ @ds.count.should == 2
123
+ @ds.order(:id).map(:numb).should == [10, 20]
124
+ end if DB.dataset.supports_insert_select?
125
+
120
126
  specify "should support bound variables with delete" do
121
127
  @ds.filter(:numb=>:$n).call(:delete, :n=>10).should == 1
122
128
  @ds.count.should == 0
@@ -228,6 +234,12 @@ describe "Prepared Statements and Bound Arguments" do
228
234
  @ds.filter(:id=>2).first[:numb].should == 20
229
235
  end
230
236
 
237
+ specify "should support prepared_statements with insert_select" do
238
+ @ds.prepare(:insert_select, :insert_select_n, :numb=>:$n).call(:n=>20).should == {:id=>2, :numb=>20}
239
+ @ds.count.should == 2
240
+ @ds.order(:id).map(:numb).should == [10, 20]
241
+ end if DB.dataset.supports_insert_select?
242
+
231
243
  specify "should support prepared statements with delete" do
232
244
  @ds.filter(:numb=>:$n).prepare(:delete, :delete_n)
233
245
  @db.call(:delete_n, :n=>10).should == 1
@@ -1890,6 +1890,30 @@ describe Sequel::Model, "many_to_many" do
1890
1890
  end
1891
1891
  end
1892
1892
 
1893
+ it "should not override a selection consisting completely of qualified columns using Sequel::SQL::QualifiedIdentifier" do
1894
+ @c1.dataset = @c1.dataset.select(Sequel.qualify(:attributes, :id), Sequel.qualify(:attributes, :b))
1895
+ @c2.many_to_many :attributes, :class => @c1
1896
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT attributes.id, attributes.b FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234)'
1897
+ end
1898
+
1899
+ it "should not override a selection consisting completely of qualified columns using symbols" do
1900
+ @c1.dataset = @c1.dataset.select(:attributes__id, :attributes__b)
1901
+ @c2.many_to_many :attributes, :class => @c1
1902
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT attributes.id, attributes.b FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234)'
1903
+ end
1904
+
1905
+ it "should not override a selection consisting completely of qualified columns using Sequel::SQL::AliasedExpression" do
1906
+ @c1.dataset = @c1.dataset.select(Sequel.qualify(:attributes, :id).as(:a), Sequel.as(:attributes__b, :c))
1907
+ @c2.many_to_many :attributes, :class => @c1
1908
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT attributes.id AS a, attributes.b AS c FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234)'
1909
+ end
1910
+
1911
+ it "should override a selection consisting of non qualified columns" do
1912
+ @c1.dataset = @c1.dataset.select{foo(:bar)}
1913
+ @c2.many_to_many :attributes, :class => @c1
1914
+ @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id = 1234)'
1915
+ end
1916
+
1893
1917
  it "should respect :eager_loader_predicate_key when lazily loading" do
1894
1918
  @c2.many_to_many :attributes, :class => @c1, :eager_loading_predicate_key=>Sequel.subscript(:attributes_nodes__node_id, 0)
1895
1919
  @c2.new(:id => 1234).attributes_dataset.sql.should == 'SELECT attributes.* FROM attributes INNER JOIN attributes_nodes ON (attributes_nodes.attribute_id = attributes.id) WHERE (attributes_nodes.node_id[0] = 1234)'