sequel 3.12.1 → 3.13.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (150) hide show
  1. data/CHANGELOG +42 -0
  2. data/README.rdoc +137 -118
  3. data/Rakefile +21 -66
  4. data/doc/active_record.rdoc +9 -9
  5. data/doc/advanced_associations.rdoc +59 -188
  6. data/doc/association_basics.rdoc +15 -2
  7. data/doc/cheat_sheet.rdoc +38 -33
  8. data/doc/dataset_filtering.rdoc +16 -7
  9. data/doc/prepared_statements.rdoc +7 -7
  10. data/doc/querying.rdoc +5 -4
  11. data/doc/release_notes/3.13.0.txt +210 -0
  12. data/doc/sharding.rdoc +1 -1
  13. data/doc/sql.rdoc +5 -5
  14. data/doc/validations.rdoc +11 -11
  15. data/lib/sequel/adapters/ado.rb +1 -1
  16. data/lib/sequel/adapters/do.rb +3 -3
  17. data/lib/sequel/adapters/firebird.rb +3 -3
  18. data/lib/sequel/adapters/jdbc/h2.rb +39 -0
  19. data/lib/sequel/adapters/jdbc/mysql.rb +5 -0
  20. data/lib/sequel/adapters/jdbc/oracle.rb +3 -3
  21. data/lib/sequel/adapters/mysql.rb +7 -4
  22. data/lib/sequel/adapters/oracle.rb +3 -3
  23. data/lib/sequel/adapters/shared/mssql.rb +10 -1
  24. data/lib/sequel/adapters/shared/mysql.rb +63 -0
  25. data/lib/sequel/adapters/shared/postgres.rb +61 -3
  26. data/lib/sequel/adapters/sqlite.rb +105 -18
  27. data/lib/sequel/connection_pool.rb +31 -30
  28. data/lib/sequel/core.rb +58 -58
  29. data/lib/sequel/core_sql.rb +52 -43
  30. data/lib/sequel/database/misc.rb +11 -0
  31. data/lib/sequel/database/query.rb +55 -17
  32. data/lib/sequel/dataset/actions.rb +2 -1
  33. data/lib/sequel/dataset/query.rb +2 -3
  34. data/lib/sequel/dataset/sql.rb +24 -11
  35. data/lib/sequel/extensions/schema_dumper.rb +1 -1
  36. data/lib/sequel/metaprogramming.rb +4 -0
  37. data/lib/sequel/model.rb +37 -19
  38. data/lib/sequel/model/associations.rb +33 -25
  39. data/lib/sequel/model/base.rb +2 -2
  40. data/lib/sequel/model/plugins.rb +7 -2
  41. data/lib/sequel/plugins/active_model.rb +1 -1
  42. data/lib/sequel/plugins/association_pks.rb +2 -2
  43. data/lib/sequel/plugins/association_proxies.rb +1 -1
  44. data/lib/sequel/plugins/boolean_readers.rb +2 -2
  45. data/lib/sequel/plugins/class_table_inheritance.rb +10 -2
  46. data/lib/sequel/plugins/identity_map.rb +3 -3
  47. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  48. data/lib/sequel/plugins/json_serializer.rb +212 -0
  49. data/lib/sequel/plugins/lazy_attributes.rb +1 -1
  50. data/lib/sequel/plugins/list.rb +174 -0
  51. data/lib/sequel/plugins/many_through_many.rb +2 -2
  52. data/lib/sequel/plugins/rcte_tree.rb +6 -7
  53. data/lib/sequel/plugins/tree.rb +118 -0
  54. data/lib/sequel/plugins/xml_serializer.rb +321 -0
  55. data/lib/sequel/sql.rb +315 -206
  56. data/lib/sequel/timezones.rb +40 -17
  57. data/lib/sequel/version.rb +8 -2
  58. data/spec/adapters/firebird_spec.rb +2 -2
  59. data/spec/adapters/informix_spec.rb +1 -1
  60. data/spec/adapters/mssql_spec.rb +2 -2
  61. data/spec/adapters/mysql_spec.rb +2 -2
  62. data/spec/adapters/oracle_spec.rb +1 -1
  63. data/spec/adapters/postgres_spec.rb +36 -6
  64. data/spec/adapters/spec_helper.rb +2 -2
  65. data/spec/adapters/sqlite_spec.rb +1 -1
  66. data/spec/core/connection_pool_spec.rb +3 -3
  67. data/spec/core/core_sql_spec.rb +31 -13
  68. data/spec/core/database_spec.rb +39 -2
  69. data/spec/core/dataset_spec.rb +24 -12
  70. data/spec/core/expression_filters_spec.rb +5 -1
  71. data/spec/core/object_graph_spec.rb +1 -1
  72. data/spec/core/schema_generator_spec.rb +1 -1
  73. data/spec/core/schema_spec.rb +1 -1
  74. data/spec/core/spec_helper.rb +1 -1
  75. data/spec/core/version_spec.rb +1 -1
  76. data/spec/extensions/active_model_spec.rb +82 -67
  77. data/spec/extensions/association_dependencies_spec.rb +1 -1
  78. data/spec/extensions/association_pks_spec.rb +1 -1
  79. data/spec/extensions/association_proxies_spec.rb +1 -1
  80. data/spec/extensions/blank_spec.rb +1 -1
  81. data/spec/extensions/boolean_readers_spec.rb +1 -1
  82. data/spec/extensions/caching_spec.rb +1 -1
  83. data/spec/extensions/class_table_inheritance_spec.rb +3 -2
  84. data/spec/extensions/composition_spec.rb +2 -5
  85. data/spec/extensions/force_encoding_spec.rb +3 -1
  86. data/spec/extensions/hook_class_methods_spec.rb +1 -1
  87. data/spec/extensions/identity_map_spec.rb +1 -1
  88. data/spec/extensions/inflector_spec.rb +1 -1
  89. data/spec/extensions/instance_filters_spec.rb +1 -1
  90. data/spec/extensions/instance_hooks_spec.rb +1 -1
  91. data/spec/extensions/json_serializer_spec.rb +154 -0
  92. data/spec/extensions/lazy_attributes_spec.rb +1 -2
  93. data/spec/extensions/list_spec.rb +251 -0
  94. data/spec/extensions/looser_typecasting_spec.rb +1 -1
  95. data/spec/extensions/many_through_many_spec.rb +3 -3
  96. data/spec/extensions/migration_spec.rb +1 -1
  97. data/spec/extensions/named_timezones_spec.rb +5 -6
  98. data/spec/extensions/nested_attributes_spec.rb +1 -1
  99. data/spec/extensions/optimistic_locking_spec.rb +1 -1
  100. data/spec/extensions/pagination_spec.rb +1 -1
  101. data/spec/extensions/pretty_table_spec.rb +1 -1
  102. data/spec/extensions/query_spec.rb +1 -1
  103. data/spec/extensions/rcte_tree_spec.rb +1 -1
  104. data/spec/extensions/schema_dumper_spec.rb +3 -2
  105. data/spec/extensions/schema_spec.rb +1 -1
  106. data/spec/extensions/serialization_spec.rb +6 -2
  107. data/spec/extensions/sharding_spec.rb +1 -1
  108. data/spec/extensions/single_table_inheritance_spec.rb +1 -1
  109. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  110. data/spec/extensions/spec_helper.rb +7 -3
  111. data/spec/extensions/sql_expr_spec.rb +1 -1
  112. data/spec/extensions/string_date_time_spec.rb +1 -1
  113. data/spec/extensions/string_stripper_spec.rb +1 -1
  114. data/spec/extensions/subclasses_spec.rb +1 -1
  115. data/spec/extensions/tactical_eager_loading_spec.rb +1 -1
  116. data/spec/extensions/thread_local_timezones_spec.rb +1 -1
  117. data/spec/extensions/timestamps_spec.rb +1 -1
  118. data/spec/extensions/touch_spec.rb +1 -1
  119. data/spec/extensions/tree_spec.rb +119 -0
  120. data/spec/extensions/typecast_on_load_spec.rb +1 -1
  121. data/spec/extensions/update_primary_key_spec.rb +1 -1
  122. data/spec/extensions/validation_class_methods_spec.rb +1 -1
  123. data/spec/extensions/validation_helpers_spec.rb +1 -1
  124. data/spec/extensions/xml_serializer_spec.rb +142 -0
  125. data/spec/integration/associations_test.rb +1 -1
  126. data/spec/integration/database_test.rb +1 -1
  127. data/spec/integration/dataset_test.rb +29 -14
  128. data/spec/integration/eager_loader_test.rb +1 -1
  129. data/spec/integration/migrator_test.rb +1 -1
  130. data/spec/integration/model_test.rb +1 -1
  131. data/spec/integration/plugin_test.rb +316 -1
  132. data/spec/integration/prepared_statement_test.rb +1 -1
  133. data/spec/integration/schema_test.rb +8 -8
  134. data/spec/integration/spec_helper.rb +1 -1
  135. data/spec/integration/timezone_test.rb +1 -1
  136. data/spec/integration/transaction_test.rb +35 -20
  137. data/spec/integration/type_test.rb +1 -1
  138. data/spec/model/association_reflection_spec.rb +1 -1
  139. data/spec/model/associations_spec.rb +49 -34
  140. data/spec/model/base_spec.rb +1 -1
  141. data/spec/model/dataset_methods_spec.rb +4 -4
  142. data/spec/model/eager_loading_spec.rb +1 -1
  143. data/spec/model/hooks_spec.rb +1 -1
  144. data/spec/model/inflector_spec.rb +1 -1
  145. data/spec/model/model_spec.rb +7 -1
  146. data/spec/model/plugins_spec.rb +1 -1
  147. data/spec/model/record_spec.rb +1 -3
  148. data/spec/model/spec_helper.rb +2 -2
  149. data/spec/model/validations_spec.rb +1 -1
  150. metadata +29 -5
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  context "Dataset" do
4
4
  before do
@@ -465,6 +465,7 @@ context "Dataset#where" do
465
465
  @dataset.filter([:id1, :id2] => @d1.select(:id1, :id2)).sql.should == "SELECT * FROM test WHERE ((id1, id2) IN (SELECT id1, id2 FROM test WHERE (region = 'Asia')))"
466
466
  @dataset.filter([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE ((id1 != id1) AND (id2 != id2))"
467
467
  @dataset.filter([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE ((id1, id2) IN ((1, 2), (3, 4)))"
468
+ @dataset.filter([:id1, :id2] => [[1, 2], [3,4]]).sql.should == "SELECT * FROM test WHERE ((id1, id2) IN ((1, 2), (3, 4)))"
468
469
 
469
470
  @dataset.exclude(:id => @d1.select(:id)).sql.should == "SELECT * FROM test WHERE (id NOT IN (SELECT id FROM test WHERE (region = 'Asia')))"
470
471
  @dataset.exclude(:id => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
@@ -472,6 +473,7 @@ context "Dataset#where" do
472
473
  @dataset.exclude([:id1, :id2] => @d1.select(:id1, :id2)).sql.should == "SELECT * FROM test WHERE ((id1, id2) NOT IN (SELECT id1, id2 FROM test WHERE (region = 'Asia')))"
473
474
  @dataset.exclude([:id1, :id2] => []).sql.should == "SELECT * FROM test WHERE (1 = 1)"
474
475
  @dataset.exclude([:id1, :id2] => [[1, 2], [3,4]].sql_array).sql.should == "SELECT * FROM test WHERE ((id1, id2) NOT IN ((1, 2), (3, 4)))"
476
+ @dataset.exclude([:id1, :id2] => [[1, 2], [3,4]]).sql.should == "SELECT * FROM test WHERE ((id1, id2) NOT IN ((1, 2), (3, 4)))"
475
477
  end
476
478
 
477
479
  specify "should handle IN/NOT IN queries with multiple columns and an array where the database doesn't support it" do
@@ -1204,6 +1206,11 @@ context "Dataset#order" do
1204
1206
  'SELECT * FROM test ORDER BY name, price DESC'
1205
1207
  end
1206
1208
 
1209
+ specify "should accept :nulls options for asc and desc" do
1210
+ @dataset.order(:name.asc(:nulls=>:last), :price.desc(:nulls=>:first)).sql.should ==
1211
+ 'SELECT * FROM test ORDER BY name ASC NULLS LAST, price DESC NULLS FIRST'
1212
+ end
1213
+
1207
1214
  specify "should overrun a previous ordering" do
1208
1215
  @dataset.order(:name).order(:stamp).sql.should ==
1209
1216
  'SELECT * FROM test ORDER BY stamp'
@@ -1385,6 +1392,11 @@ context "Dataset#reverse_order" do
1385
1392
  'SELECT * FROM test ORDER BY name DESC, price ASC'
1386
1393
  end
1387
1394
 
1395
+ specify "should handles NULLS ordering correctly when reversing" do
1396
+ @dataset.reverse_order(:name.asc(:nulls=>:first), :price.desc(:nulls=>:last)).sql.should ==
1397
+ 'SELECT * FROM test ORDER BY name DESC NULLS LAST, price ASC NULLS FIRST'
1398
+ end
1399
+
1388
1400
  specify "should reverse a previous ordering if no arguments are given" do
1389
1401
  @dataset.order(:name).reverse_order.sql.should ==
1390
1402
  'SELECT * FROM test ORDER BY name DESC'
@@ -2185,12 +2197,12 @@ end
2185
2197
  context "Dataset#range" do
2186
2198
  before do
2187
2199
  c = Class.new(Sequel::Dataset) do
2188
- @@sql = nil
2200
+ class_variable_set(:@@sql, nil)
2189
2201
 
2190
- def last_sql; @@sql; end
2202
+ def last_sql; self.class.send(:class_variable_get, :@@sql); end
2191
2203
 
2192
2204
  def fetch_rows(sql)
2193
- @@sql = sql
2205
+ self.class.send(:class_variable_set, :@@sql, sql)
2194
2206
  yield(:v1 => 1, :v2 => 10)
2195
2207
  end
2196
2208
  end
@@ -2218,12 +2230,12 @@ end
2218
2230
  context "Dataset#interval" do
2219
2231
  before do
2220
2232
  c = Class.new(Sequel::Dataset) do
2221
- @@sql = nil
2233
+ class_variable_set(:@@sql, nil)
2222
2234
 
2223
- def last_sql; @@sql; end
2235
+ def last_sql; self.class.send(:class_variable_get, :@@sql); end
2224
2236
 
2225
2237
  def fetch_rows(sql)
2226
- @@sql = sql
2238
+ self.class.send(:class_variable_set, :@@sql, sql)
2227
2239
  yield(:v => 1234)
2228
2240
  end
2229
2241
  end
@@ -2428,14 +2440,14 @@ end
2428
2440
  context "Dataset#[]" do
2429
2441
  before do
2430
2442
  @c = Class.new(Sequel::Dataset) do
2431
- @@last_dataset = nil
2443
+ class_variable_set(:@@last_dataset, nil)
2432
2444
 
2433
2445
  def self.last_dataset
2434
- @@last_dataset
2446
+ class_variable_get(:@@last_dataset)
2435
2447
  end
2436
2448
 
2437
2449
  def single_record
2438
- @@last_dataset = opts ? clone(opts) : self
2450
+ self.class.send(:class_variable_set, :@@last_dataset, opts ? clone(opts) : self)
2439
2451
  {1 => 2, 3 => 4}
2440
2452
  end
2441
2453
  end
@@ -3443,8 +3455,8 @@ context "Sequel::Dataset#qualify_to_first_source" do
3443
3455
  @ds.filter{(a+b)<(c-3)}.qualify_to_first_source.sql.should == 'SELECT t.* FROM t WHERE ((t.a + t.b) < (t.c - 3))'
3444
3456
  end
3445
3457
 
3446
- specify "should handle SQL::SQLArrays" do
3447
- @ds.filter(:a=>[:b, :c].sql_array).qualify_to_first_source.sql.should == 'SELECT t.* FROM t WHERE (t.a IN (t.b, t.c))'
3458
+ specify "should handle SQL::ValueLists" do
3459
+ @ds.filter(:a=>[:b, :c].sql_value_list).qualify_to_first_source.sql.should == 'SELECT t.* FROM t WHERE (t.a IN (t.b, t.c))'
3448
3460
  end
3449
3461
 
3450
3462
  specify "should handle SQL::Subscripts" do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), 'spec_helper')
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
3
  Regexp.send(:include, Sequel::SQL::StringMethods)
4
4
  String.send(:include, Sequel::SQL::StringMethods)
@@ -556,6 +556,10 @@ context Sequel::SQL::VirtualRow do
556
556
  @d.l{rank(:over, :frame=>:rows){}}.should == 'rank() OVER (ROWS UNBOUNDED PRECEDING)'
557
557
  end
558
558
 
559
+ it "should support :frame=>'some string' option for window function calls" do
560
+ @d.l{rank(:over, :frame=>'RANGE BETWEEN 3 PRECEDING AND CURRENT ROW'){}}.should == 'rank() OVER (RANGE BETWEEN 3 PRECEDING AND CURRENT ROW)'
561
+ end
562
+
559
563
  it "should raise an error if an invalid :frame option is used" do
560
564
  proc{@d.l{rank(:over, :frame=>:blah){}}}.should raise_error(Sequel::Error)
561
565
  end
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), 'spec_helper')
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
3
  describe Sequel::Dataset, " graphing" do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), 'spec_helper')
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
3
  describe Sequel::Schema::Generator do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), 'spec_helper')
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
3
  context "DB#create_table" do
4
4
  before do
@@ -1,6 +1,6 @@
1
1
  require 'rubygems'
2
2
  unless Object.const_defined?('Sequel')
3
- $:.unshift(File.join(File.dirname(__FILE__), "../../lib/"))
3
+ $:.unshift(File.join(File.dirname(File.expand_path(__FILE__)), "../../lib/"))
4
4
  require 'sequel/core'
5
5
  end
6
6
 
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), 'spec_helper')
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
3
  context "Sequel.version" do
4
4
  specify "should be in the form X.Y.Z with all being numbers" do
@@ -1,76 +1,91 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
2
- if RUBY_PLATFORM !~ /(win|w)32|java$/
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ begin
4
+ require 'active_model'
5
+ require 'test/unit'
6
+ if Test::Unit.respond_to?(:run=)
7
+ Test::Unit.run = false
8
+ require 'test/unit/testresult'
9
+ elsif defined?(MiniTest::Unit)
10
+ class << MiniTest::Unit
11
+ def autorun; end
12
+ end
13
+ end
14
+ rescue LoadError => e
15
+ skip_warn "active_model plugin: can't load active_model (#{e.class}: #{e})"
16
+ else
3
17
  describe "ActiveModel plugin" do
4
18
  specify "should be compliant to the ActiveModel spec" do
5
- s = ''
6
- IO.popen('-') do |f|
7
- if f
8
- s = f.read
9
- else
10
- begin
11
- require 'rubygems'
12
- require 'active_model'
13
- rescue LoadError
14
- puts "0 failures, 0 errors, skipping tests"
15
- else
16
- require 'test/unit'
17
- require "test/unit/ui/console/testrunner"
18
- class AMLintTest < Test::Unit::TestCase
19
- def setup
20
- @c = Class.new(Sequel::Model) do
21
- set_primary_key :id
22
- columns :id, :id2
23
- def delete; end
24
- end
25
- @c.plugin :active_model
26
- @m = @model = @c.new
27
- @o = @c.load({})
28
- end
29
- include ActiveModel::Lint::Tests
19
+ tc = Class.new(Test::Unit::TestCase)
20
+ tc.class_eval do
21
+ define_method(:setup) do
22
+ class ::AMLintTest < Sequel::Model
23
+ set_primary_key :id
24
+ columns :id, :id2
25
+ def delete; end
26
+ end
27
+ @c = AMLintTest
28
+ @c.plugin :active_model
29
+ @m = @model = @c.new
30
+ @o = @c.load({})
31
+ super()
32
+ end
33
+ def teardown
34
+ super
35
+ Object.send(:remove_const, :AMLintTest)
36
+ end
37
+ include ActiveModel::Lint::Tests
30
38
 
31
- # Should return self, not a proxy object
32
- def test__to_model
33
- assert_equal @m.to_model.object_id.should, @m.object_id
34
- end
35
-
36
- def test__to_key
37
- assert_equal nil, @m.to_key
38
- @o.id = 1
39
- assert_equal [1], @o.to_key
40
- @c.set_primary_key [:id2, :id]
41
- @o.id2 = 2
42
- assert_equal [2, 1], @o.to_key
43
- @o.destroy
44
- assert_equal nil, @o.to_key
45
- end
46
-
47
- def test__to_param
48
- assert_equal nil, @m.to_param
49
- @o.id = 1
50
- assert_equal '1', @o.to_param
51
- @c.set_primary_key [:id2, :id]
52
- @o.id2 = 2
53
- assert_equal '2-1', @o.to_param
54
- @o.meta_def(:to_param_joiner){'|'}
55
- assert_equal '2|1', @o.to_param
56
- @o.destroy
57
- assert_equal nil, @o.to_param
58
- end
39
+ # Should return self, not a proxy object
40
+ def test__to_model
41
+ assert_equal @m.to_model.object_id.should, @m.object_id
42
+ end
43
+
44
+ def test__to_key
45
+ assert_equal nil, @m.to_key
46
+ @o.id = 1
47
+ assert_equal [1], @o.to_key
48
+ @c.set_primary_key [:id2, :id]
49
+ @o.id2 = 2
50
+ assert_equal [2, 1], @o.to_key
51
+ @o.destroy
52
+ assert_equal nil, @o.to_key
53
+ end
54
+
55
+ def test__to_param
56
+ assert_equal nil, @m.to_param
57
+ @o.id = 1
58
+ assert_equal '1', @o.to_param
59
+ @c.set_primary_key [:id2, :id]
60
+ @o.id2 = 2
61
+ assert_equal '2-1', @o.to_param
62
+ @o.meta_def(:to_param_joiner){'|'}
63
+ assert_equal '2|1', @o.to_param
64
+ @o.destroy
65
+ assert_equal nil, @o.to_param
66
+ end
59
67
 
60
- def test__persisted?
61
- assert_equal false, @m.persisted?
62
- assert_equal true, @o.persisted?
63
- @m.destroy
64
- @o.destroy
65
- assert_equal false, @m.persisted?
66
- assert_equal false, @o.persisted?
67
- end
68
- end
69
- Test::Unit::UI::Console::TestRunner.run(AMLintTest)
70
- end
68
+ def test__persisted?
69
+ assert_equal false, @m.persisted?
70
+ assert_equal true, @o.persisted?
71
+ @m.destroy
72
+ @o.destroy
73
+ assert_equal false, @m.persisted?
74
+ assert_equal false, @o.persisted?
75
+ end
76
+ end
77
+ if defined?(MiniTest::Unit)
78
+ tc.instance_methods.map{|x| x.to_s}.reject{|n| n !~ /\Atest_/}.each do |m|
79
+ i = tc.new(m)
80
+ i.setup
81
+ i.send(m)
82
+ i.teardown
71
83
  end
84
+ else
85
+ res = ::Test::Unit::TestResult.new
86
+ tc.suite.run(res){}
87
+ res.failure_count.should == 0
72
88
  end
73
- s.should =~ /0 failures, 0 errors/
74
89
  end
75
90
  end
76
91
  end
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe "AssociationDependencies plugin" do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe "Sequel::Plugins::AssociationPks" do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe "Sequel::Plugins::AssociationProxies" do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), 'spec_helper')
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
3
  context "Object#blank?" do
4
4
  specify "it should be true if the object responds true to empty?" do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe Sequel::Model, "BooleanReaders plugin" do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe Sequel::Model, "caching" do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe "class_table_inheritance plugin" do
4
4
  before do
@@ -88,7 +88,8 @@ describe "class_table_inheritance plugin" do
88
88
 
89
89
  it "should return rows with the current class if cti_key is nil" do
90
90
  Employee.plugin(:class_table_inheritance)
91
- def @ds.fetch_rows(sql)
91
+ ds = Employee.dataset
92
+ def ds.fetch_rows(sql)
92
93
  yield({:kind=>'Employee'})
93
94
  yield({:kind=>'Manager'})
94
95
  yield({:kind=>'Executive'})
@@ -1,9 +1,6 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
- require 'yaml'
4
- require 'json'
5
-
6
- describe "Serialization plugin" do
3
+ describe "Composition plugin" do
7
4
  before do
8
5
  @c = Class.new(Sequel::Model(:items))
9
6
  @c.plugin :composition
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
  if RUBY_VERSION >= '1.9.0'
3
3
  describe "force_encoding plugin" do
4
4
  before do
@@ -114,4 +114,6 @@ describe "force_encoding plugin" do
114
114
  end
115
115
  end
116
116
  end
117
+ else
118
+ skip_warn "force_encoding plugin: only works on ruby 1.9"
117
119
  end
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe "Model hooks" do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe "Sequel::Plugins::IdentityMap" do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), 'spec_helper')
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
3
  describe String do
4
4
  it "#camelize and #camelcase should transform the word to CamelCase" do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe "instance_filters plugin" do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(__FILE__), "spec_helper")
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe "InstanceHooks plugin" do
4
4
  def r(x)
@@ -0,0 +1,154 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ begin
4
+ require 'json'
5
+ rescue LoadError => e
6
+ skip_warn "json_serializer plugin: can't load json (#{e.class}: #{e})"
7
+ else
8
+ describe "Sequel::Plugins::JsonSerializer" do
9
+ before do
10
+ class ::Artist < Sequel::Model
11
+ plugin :json_serializer
12
+ columns :id, :name
13
+ one_to_many :albums
14
+ end
15
+ class ::Album < Sequel::Model
16
+ attr_accessor :blah
17
+ plugin :json_serializer
18
+ columns :id, :name, :artist_id
19
+ many_to_one :artist
20
+ end
21
+ @artist = Artist.load(:id=>2, :name=>'YJM')
22
+ @artist.associations[:albums] = []
23
+ @album = Album.load(:id=>1, :name=>'RF')
24
+ @album.artist = @artist
25
+ @album.blah = 'Blah'
26
+ end
27
+ after do
28
+ Object.send(:remove_const, :Artist)
29
+ Object.send(:remove_const, :Album)
30
+ end
31
+
32
+ it "should round trip successfully" do
33
+ JSON.parse(@artist.to_json).should == @artist
34
+ JSON.parse(@album.to_json).should == @album
35
+ end
36
+
37
+ it "should handle the :only option" do
38
+ JSON.parse(@artist.to_json(:only=>:name)).should == Artist.load(:name=>@artist.name)
39
+ JSON.parse(@album.to_json(:only=>[:id, :name])).should == Album.load(:id=>@album.id, :name=>@album.name)
40
+ end
41
+
42
+ it "should handle the :except option" do
43
+ JSON.parse(@artist.to_json(:except=>:id)).should == Artist.load(:name=>@artist.name)
44
+ JSON.parse(@album.to_json(:except=>[:id, :artist_id])).should == Album.load(:name=>@album.name)
45
+ end
46
+
47
+ it "should handle the :include option for associations" do
48
+ JSON.parse(@artist.to_json(:include=>:albums)).albums.should == [@album]
49
+ JSON.parse(@album.to_json(:include=>:artist)).artist.should == @artist
50
+ end
51
+
52
+ it "should handle the :include option for arbitrary attributes" do
53
+ JSON.parse(@album.to_json(:include=>:blah)).blah.should == @album.blah
54
+ end
55
+
56
+ it "should handle multiple inclusions using an array for the :include option" do
57
+ a = JSON.parse(@album.to_json(:include=>[:blah, :artist]))
58
+ a.blah.should == @album.blah
59
+ a.artist.should == @artist
60
+ end
61
+
62
+ it "should handle cascading using a hash for the :include option" do
63
+ JSON.parse(@artist.to_json(:include=>{:albums=>{:include=>:artist}})).albums.map{|a| a.artist}.should == [@artist]
64
+ JSON.parse(@album.to_json(:include=>{:artist=>{:include=>:albums}})).artist.albums.should == [@album]
65
+
66
+ JSON.parse(@artist.to_json(:include=>{:albums=>{:only=>:name}})).albums.should == [Album.load(:name=>@album.name)]
67
+ JSON.parse(@album.to_json(:include=>{:artist=>{:except=>:name}})).artist.should == Artist.load(:id=>@artist.id)
68
+
69
+ JSON.parse(@artist.to_json(:include=>{:albums=>{:include=>{:artist=>{:include=>:albums}}}})).albums.map{|a| a.artist.albums}.should == [[@album]]
70
+ JSON.parse(@album.to_json(:include=>{:artist=>{:include=>{:albums=>{:only=>:name}}}})).artist.albums.should == [Album.load(:name=>@album.name)]
71
+ end
72
+
73
+ it "should handle the :include option cascading with an empty hash" do
74
+ JSON.parse(@album.to_json(:include=>{:artist=>{}})).artist.should == @artist
75
+ JSON.parse(@album.to_json(:include=>{:blah=>{}})).blah.should == @album.blah
76
+ end
77
+
78
+ it "should accept a :naked option to not include the JSON.create_id, so parsing yields a plain hash" do
79
+ JSON.parse(@album.to_json(:naked=>true)).should == @album.values.inject({}){|h, (k, v)| h[k.to_s] = v; h}
80
+ end
81
+
82
+ it "should support #from_json to set column values" do
83
+ @artist.from_json('{"name": "AS"}')
84
+ @artist.name.should == 'AS'
85
+ @artist.id.should == 2
86
+ end
87
+
88
+ it "should raise an exception for json keys that aren't associations, columns, or setter methods" do
89
+ Album.send(:undef_method, :blah=)
90
+ proc{JSON.parse(@album.to_json(:include=>:blah))}.should raise_error(Sequel::Error)
91
+ end
92
+
93
+ it "should support a to_json class and dataset method" do
94
+ album = @album
95
+ Album.dataset.meta_def(:all){[album]}
96
+ JSON.parse(Album.to_json).should == [@album]
97
+ JSON.parse(Album.to_json(:include=>:artist)).map{|x| x.artist}.should == [@artist]
98
+ JSON.parse(Album.dataset.to_json(:only=>:name)).should == [Album.load(:name=>@album.name)]
99
+ end
100
+
101
+ it "should have dataset to_json method work with naked datasets" do
102
+ album = @album
103
+ ds = Album.dataset.naked
104
+ ds.meta_def(:all){[album.values]}
105
+ JSON.parse(ds.to_json).should == [@album.values.inject({}){|h, (k, v)| h[k.to_s] = v; h}]
106
+ end
107
+
108
+ it "should propagate class default options to instance to_json output" do
109
+ class ::Album2 < Sequel::Model
110
+ attr_accessor :blah
111
+ plugin :json_serializer, :naked => true, :except => :id
112
+ columns :id, :name, :artist_id
113
+ many_to_one :artist
114
+ end
115
+ @album2 = Album2.load(:id=>2, :name=>'JK')
116
+ @album2.artist = @artist
117
+ @album2.blah = 'Gak'
118
+ JSON.parse(@album2.to_json).should == @album2.values.reject{|k,v| k.to_s == 'id'}.inject({}){|h, (k, v)| h[k.to_s] = v; h}
119
+ JSON.parse(@album2.to_json(:only => :name)).should == @album2.values.reject{|k,v| k.to_s != 'name'}.inject({}){|h, (k, v)| h[k.to_s] = v; h}
120
+ JSON.parse(@album2.to_json(:except => :artist_id)).should == @album2.values.reject{|k,v| k.to_s == 'artist_id'}.inject({}){|h, (k, v)| h[k.to_s] = v; h}
121
+ end
122
+
123
+ it "should handle the :root option to qualify single records" do
124
+ @album.to_json(:root=>true, :except => [:name, :artist_id]).to_s.should == '{"album":{"id":1}}'
125
+ @album.to_json(:root=>true, :only => :name).to_s.should == '{"album":{"name":"RF"}}'
126
+ end
127
+
128
+ it "should handle the :root option to qualify a dataset of records" do
129
+ album = @album
130
+ Album.dataset.meta_def(:all){[album, album]}
131
+ Album.dataset.to_json(:root=>true, :only => :id).to_s.should == '{"albums":[{"album":{"id":1}},{"album":{"id":1}}]}'
132
+ end
133
+
134
+ it "should store the default options in json_serializer_opts" do
135
+ Album.json_serializer_opts.should == {}
136
+ c = Class.new(Album)
137
+ c.plugin :json_serializer, :naked=>true
138
+ c.json_serializer_opts.should == {:naked=>true}
139
+ end
140
+
141
+ it "should work correctly when subclassing" do
142
+ class ::Artist2 < Artist
143
+ plugin :json_serializer, :only=>:name
144
+ end
145
+ JSON.parse(Artist2.load(:id=>2, :name=>'YYY').to_json).should == Artist2.load(:name=>'YYY')
146
+ class ::Artist3 < Artist2
147
+ plugin :json_serializer, :naked=>:true
148
+ end
149
+ JSON.parse(Artist3.load(:id=>2, :name=>'YYY').to_json).should == {"name"=>'YYY'}
150
+ Object.send(:remove_const, :Artist2)
151
+ Object.send(:remove_const, :Artist3)
152
+ end
153
+ end
154
+ end