sequel 3.21.0 → 3.31.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 (225) hide show
  1. data/CHANGELOG +485 -3
  2. data/README.rdoc +20 -6
  3. data/Rakefile +37 -19
  4. data/bin/sequel +1 -5
  5. data/doc/association_basics.rdoc +249 -43
  6. data/doc/dataset_basics.rdoc +4 -4
  7. data/doc/dataset_filtering.rdoc +8 -0
  8. data/doc/mass_assignment.rdoc +54 -0
  9. data/doc/migration.rdoc +15 -538
  10. data/doc/model_hooks.rdoc +72 -27
  11. data/doc/opening_databases.rdoc +89 -50
  12. data/doc/prepared_statements.rdoc +40 -13
  13. data/doc/reflection.rdoc +8 -2
  14. data/doc/release_notes/3.22.0.txt +39 -0
  15. data/doc/release_notes/3.23.0.txt +172 -0
  16. data/doc/release_notes/3.24.0.txt +420 -0
  17. data/doc/release_notes/3.25.0.txt +88 -0
  18. data/doc/release_notes/3.26.0.txt +88 -0
  19. data/doc/release_notes/3.27.0.txt +82 -0
  20. data/doc/release_notes/3.28.0.txt +304 -0
  21. data/doc/release_notes/3.29.0.txt +459 -0
  22. data/doc/release_notes/3.30.0.txt +135 -0
  23. data/doc/release_notes/3.31.0.txt +146 -0
  24. data/doc/schema_modification.rdoc +547 -0
  25. data/doc/sharding.rdoc +7 -1
  26. data/doc/testing.rdoc +129 -0
  27. data/doc/transactions.rdoc +137 -0
  28. data/doc/virtual_rows.rdoc +2 -2
  29. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  30. data/lib/sequel/adapters/ado.rb +40 -18
  31. data/lib/sequel/adapters/amalgalite.rb +17 -9
  32. data/lib/sequel/adapters/db2.rb +175 -86
  33. data/lib/sequel/adapters/dbi.rb +15 -15
  34. data/lib/sequel/adapters/do/mysql.rb +5 -7
  35. data/lib/sequel/adapters/do/postgres.rb +0 -5
  36. data/lib/sequel/adapters/do/sqlite.rb +0 -5
  37. data/lib/sequel/adapters/do.rb +17 -36
  38. data/lib/sequel/adapters/firebird.rb +27 -208
  39. data/lib/sequel/adapters/ibmdb.rb +448 -0
  40. data/lib/sequel/adapters/informix.rb +6 -23
  41. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  42. data/lib/sequel/adapters/jdbc/db2.rb +45 -0
  43. data/lib/sequel/adapters/jdbc/derby.rb +247 -0
  44. data/lib/sequel/adapters/jdbc/firebird.rb +29 -0
  45. data/lib/sequel/adapters/jdbc/h2.rb +56 -29
  46. data/lib/sequel/adapters/jdbc/hsqldb.rb +170 -0
  47. data/lib/sequel/adapters/jdbc/informix.rb +26 -0
  48. data/lib/sequel/adapters/jdbc/jtds.rb +34 -0
  49. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  50. data/lib/sequel/adapters/jdbc/mysql.rb +11 -11
  51. data/lib/sequel/adapters/jdbc/oracle.rb +81 -25
  52. data/lib/sequel/adapters/jdbc/postgresql.rb +9 -13
  53. data/lib/sequel/adapters/jdbc/sqlite.rb +2 -6
  54. data/lib/sequel/adapters/jdbc/sqlserver.rb +71 -0
  55. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  56. data/lib/sequel/adapters/jdbc.rb +231 -78
  57. data/lib/sequel/adapters/mock.rb +335 -0
  58. data/lib/sequel/adapters/mysql.rb +82 -184
  59. data/lib/sequel/adapters/mysql2.rb +26 -25
  60. data/lib/sequel/adapters/odbc/db2.rb +17 -0
  61. data/lib/sequel/adapters/odbc/mssql.rb +1 -6
  62. data/lib/sequel/adapters/odbc.rb +28 -9
  63. data/lib/sequel/adapters/openbase.rb +3 -5
  64. data/lib/sequel/adapters/oracle.rb +351 -53
  65. data/lib/sequel/adapters/postgres.rb +194 -33
  66. data/lib/sequel/adapters/shared/access.rb +32 -9
  67. data/lib/sequel/adapters/shared/db2.rb +321 -0
  68. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  69. data/lib/sequel/adapters/shared/informix.rb +53 -0
  70. data/lib/sequel/adapters/shared/mssql.rb +231 -106
  71. data/lib/sequel/adapters/shared/mysql.rb +181 -63
  72. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +149 -0
  73. data/lib/sequel/adapters/shared/oracle.rb +231 -41
  74. data/lib/sequel/adapters/shared/postgres.rb +214 -82
  75. data/lib/sequel/adapters/shared/progress.rb +4 -7
  76. data/lib/sequel/adapters/shared/sqlite.rb +201 -57
  77. data/lib/sequel/adapters/sqlite.rb +29 -21
  78. data/lib/sequel/adapters/swift/mysql.rb +12 -7
  79. data/lib/sequel/adapters/swift/postgres.rb +0 -5
  80. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  81. data/lib/sequel/adapters/swift.rb +5 -5
  82. data/lib/sequel/adapters/tinytds.rb +160 -19
  83. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  84. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  85. data/lib/sequel/ast_transformer.rb +190 -0
  86. data/lib/sequel/connection_pool/threaded.rb +3 -2
  87. data/lib/sequel/connection_pool.rb +1 -1
  88. data/lib/sequel/core.rb +46 -5
  89. data/lib/sequel/database/connecting.rb +5 -6
  90. data/lib/sequel/database/dataset.rb +4 -4
  91. data/lib/sequel/database/dataset_defaults.rb +59 -1
  92. data/lib/sequel/database/logging.rb +1 -1
  93. data/lib/sequel/database/misc.rb +104 -19
  94. data/lib/sequel/database/query.rb +153 -58
  95. data/lib/sequel/database/schema_generator.rb +17 -7
  96. data/lib/sequel/database/schema_methods.rb +59 -29
  97. data/lib/sequel/dataset/actions.rb +231 -76
  98. data/lib/sequel/dataset/features.rb +91 -8
  99. data/lib/sequel/dataset/graph.rb +38 -11
  100. data/lib/sequel/dataset/misc.rb +50 -23
  101. data/lib/sequel/dataset/mutation.rb +5 -6
  102. data/lib/sequel/dataset/prepared_statements.rb +48 -27
  103. data/lib/sequel/dataset/query.rb +236 -43
  104. data/lib/sequel/dataset/sql.rb +665 -253
  105. data/lib/sequel/dataset.rb +8 -0
  106. data/lib/sequel/exceptions.rb +4 -0
  107. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  108. data/lib/sequel/extensions/migration.rb +6 -4
  109. data/lib/sequel/extensions/named_timezones.rb +5 -0
  110. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  111. data/lib/sequel/extensions/to_dot.rb +95 -83
  112. data/lib/sequel/model/associations.rb +1020 -337
  113. data/lib/sequel/model/base.rb +414 -132
  114. data/lib/sequel/model/errors.rb +1 -1
  115. data/lib/sequel/model/exceptions.rb +5 -1
  116. data/lib/sequel/model.rb +15 -8
  117. data/lib/sequel/plugins/association_pks.rb +22 -4
  118. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  119. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  120. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  121. data/lib/sequel/plugins/force_encoding.rb +6 -6
  122. data/lib/sequel/plugins/identity_map.rb +114 -7
  123. data/lib/sequel/plugins/many_through_many.rb +65 -7
  124. data/lib/sequel/plugins/prepared_statements.rb +151 -0
  125. data/lib/sequel/plugins/prepared_statements_associations.rb +84 -0
  126. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  127. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  128. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  129. data/lib/sequel/plugins/serialization.rb +88 -44
  130. data/lib/sequel/plugins/serialization_modification_detection.rb +51 -0
  131. data/lib/sequel/plugins/sharding.rb +21 -54
  132. data/lib/sequel/plugins/single_table_inheritance.rb +3 -1
  133. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  134. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  135. data/lib/sequel/plugins/xml_serializer.rb +3 -3
  136. data/lib/sequel/sql.rb +109 -52
  137. data/lib/sequel/timezones.rb +57 -38
  138. data/lib/sequel/version.rb +1 -1
  139. data/spec/adapters/db2_spec.rb +146 -0
  140. data/spec/adapters/mssql_spec.rb +111 -29
  141. data/spec/adapters/mysql_spec.rb +135 -123
  142. data/spec/adapters/oracle_spec.rb +49 -77
  143. data/spec/adapters/postgres_spec.rb +267 -78
  144. data/spec/adapters/spec_helper.rb +6 -5
  145. data/spec/adapters/sqlite_spec.rb +35 -21
  146. data/spec/core/connection_pool_spec.rb +71 -92
  147. data/spec/core/core_sql_spec.rb +21 -30
  148. data/spec/core/database_spec.rb +788 -512
  149. data/spec/core/dataset_spec.rb +1073 -1053
  150. data/spec/core/expression_filters_spec.rb +159 -42
  151. data/spec/core/mock_adapter_spec.rb +419 -0
  152. data/spec/core/object_graph_spec.rb +86 -114
  153. data/spec/core/schema_generator_spec.rb +3 -3
  154. data/spec/core/schema_spec.rb +298 -38
  155. data/spec/core/spec_helper.rb +6 -48
  156. data/spec/extensions/association_autoreloading_spec.rb +1 -10
  157. data/spec/extensions/association_dependencies_spec.rb +2 -12
  158. data/spec/extensions/association_pks_spec.rb +66 -32
  159. data/spec/extensions/caching_spec.rb +23 -50
  160. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  161. data/spec/extensions/columns_introspection_spec.rb +91 -0
  162. data/spec/extensions/composition_spec.rb +18 -13
  163. data/spec/extensions/dataset_associations_spec.rb +199 -0
  164. data/spec/extensions/defaults_setter_spec.rb +64 -0
  165. data/spec/extensions/hook_class_methods_spec.rb +65 -91
  166. data/spec/extensions/identity_map_spec.rb +114 -22
  167. data/spec/extensions/instance_filters_spec.rb +11 -21
  168. data/spec/extensions/instance_hooks_spec.rb +53 -0
  169. data/spec/extensions/json_serializer_spec.rb +4 -5
  170. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  171. data/spec/extensions/list_spec.rb +17 -39
  172. data/spec/extensions/many_through_many_spec.rb +283 -250
  173. data/spec/extensions/migration_spec.rb +35 -32
  174. data/spec/extensions/named_timezones_spec.rb +23 -3
  175. data/spec/extensions/nested_attributes_spec.rb +97 -88
  176. data/spec/extensions/optimistic_locking_spec.rb +9 -20
  177. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  178. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  179. data/spec/extensions/prepared_statements_spec.rb +53 -0
  180. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  181. data/spec/extensions/pretty_table_spec.rb +1 -6
  182. data/spec/extensions/rcte_tree_spec.rb +41 -43
  183. data/spec/extensions/schema_dumper_spec.rb +5 -8
  184. data/spec/extensions/schema_spec.rb +13 -21
  185. data/spec/extensions/serialization_modification_detection_spec.rb +37 -0
  186. data/spec/extensions/serialization_spec.rb +72 -43
  187. data/spec/extensions/sharding_spec.rb +66 -140
  188. data/spec/extensions/single_table_inheritance_spec.rb +18 -29
  189. data/spec/extensions/spec_helper.rb +13 -61
  190. data/spec/extensions/sql_expr_spec.rb +20 -60
  191. data/spec/extensions/tactical_eager_loading_spec.rb +9 -19
  192. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  193. data/spec/extensions/timestamps_spec.rb +6 -6
  194. data/spec/extensions/to_dot_spec.rb +4 -7
  195. data/spec/extensions/touch_spec.rb +13 -14
  196. data/spec/extensions/tree_spec.rb +11 -26
  197. data/spec/extensions/typecast_on_load_spec.rb +1 -6
  198. data/spec/extensions/update_primary_key_spec.rb +30 -24
  199. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  200. data/spec/extensions/validation_helpers_spec.rb +16 -35
  201. data/spec/extensions/xml_serializer_spec.rb +16 -4
  202. data/spec/integration/associations_test.rb +537 -21
  203. data/spec/integration/database_test.rb +4 -2
  204. data/spec/integration/dataset_test.rb +461 -65
  205. data/spec/integration/eager_loader_test.rb +19 -21
  206. data/spec/integration/model_test.rb +80 -1
  207. data/spec/integration/plugin_test.rb +304 -116
  208. data/spec/integration/prepared_statement_test.rb +212 -122
  209. data/spec/integration/schema_test.rb +161 -30
  210. data/spec/integration/spec_helper.rb +39 -30
  211. data/spec/integration/timezone_test.rb +38 -12
  212. data/spec/integration/transaction_test.rb +172 -5
  213. data/spec/integration/type_test.rb +17 -3
  214. data/spec/model/association_reflection_spec.rb +201 -7
  215. data/spec/model/associations_spec.rb +865 -662
  216. data/spec/model/base_spec.rb +275 -95
  217. data/spec/model/dataset_methods_spec.rb +7 -27
  218. data/spec/model/eager_loading_spec.rb +677 -676
  219. data/spec/model/hooks_spec.rb +309 -67
  220. data/spec/model/model_spec.rb +222 -168
  221. data/spec/model/plugins_spec.rb +24 -13
  222. data/spec/model/record_spec.rb +381 -218
  223. data/spec/model/spec_helper.rb +13 -71
  224. data/spec/model/validations_spec.rb +11 -0
  225. metadata +115 -73
@@ -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
@@ -39,7 +39,27 @@ describe "Sequel thread_local_timezones extension" do
39
39
  end
40
40
 
41
41
  it "should be thread safe" do
42
- [Thread.new{Sequel.thread_application_timezone = :utc; sleep 0.03; Sequel.application_timezone.should == :utc},
43
- Thread.new{sleep 0.01; Sequel.thread_application_timezone = :local; sleep 0.01; Sequel.application_timezone.should == :local}].each{|x| x.join}
42
+ q, q1, q2 = Queue.new, Queue.new, Queue.new
43
+ tz1, tz2 = nil, nil
44
+ t1 = Thread.new do
45
+ Sequel.thread_application_timezone = :utc
46
+ q2.push nil
47
+ q.pop
48
+ tz1 = Sequel.application_timezone
49
+ end
50
+ t2 = Thread.new do
51
+ Sequel.thread_application_timezone = :local
52
+ q2.push nil
53
+ q1.pop
54
+ tz2 = Sequel.application_timezone
55
+ end
56
+ q2.pop
57
+ q2.pop
58
+ q.push nil
59
+ q1.push nil
60
+ t1.join
61
+ t2.join
62
+ tz1.should == :utc
63
+ tz2.should == :local
44
64
  end
45
65
  end
@@ -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)"]
@@ -2,9 +2,7 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe Sequel::Model, "to_dot extension" do
4
4
  def dot(ds)
5
- a = []
6
- ds.send(:_to_dot, a, "", 0, ds, 0)
7
- a[2..-1]
5
+ Sequel::ToDot.new(ds).instance_variable_get(:@dot)[4...-1]
8
6
  end
9
7
 
10
8
  before do
@@ -13,14 +11,13 @@ describe Sequel::Model, "to_dot extension" do
13
11
  end
14
12
 
15
13
  it "should output a string suitable for input to the graphviz dot program" do
16
- @ds.to_dot.should == (<<END
14
+ @ds.to_dot.should == (<<END).strip
17
15
  digraph G {
18
16
  0 [label="self"];
19
17
  0 -> 1 [label=""];
20
18
  1 [label="Dataset"];
21
19
  }
22
20
  END
23
- ).strip
24
21
  end
25
22
 
26
23
  it "should handle an empty dataset" do
@@ -123,7 +120,7 @@ END
123
120
  end
124
121
 
125
122
  it "should handle SQL::Subscript" do
126
- dot(@ds.select(:a.sql_subscript(1))).should == ["1 -> 2 [label=\"select\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\"Subscript: a\"];", "3 -> 4 [label=\"f\"];", "4 [label=\":a\"];", "3 -> 5 [label=\"sub\"];", "5 [label=\"Array\"];", "5 -> 6 [label=\"0\"];", "6 [label=\"1\"];"]
123
+ dot(@ds.select(:a.sql_subscript(1))).should == ["1 -> 2 [label=\"select\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\"Subscript\"];", "3 -> 4 [label=\"f\"];", "4 [label=\":a\"];", "3 -> 5 [label=\"sub\"];", "5 [label=\"Array\"];", "5 -> 6 [label=\"0\"];", "6 [label=\"1\"];"]
127
124
  end
128
125
 
129
126
  it "should handle SQL::WindowFunction" do
@@ -135,7 +132,7 @@ END
135
132
  end
136
133
 
137
134
  it "should handle JOIN ON" do
138
- dot(@ds.from(:a).join(:d, :b=>:c)).should == ["1 -> 2 [label=\"from\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\":a\"];", "1 -> 4 [label=\"join\"];", "4 [label=\"Array\"];", "4 -> 5 [label=\"0\"];", "5 [label=\"INNER JOIN ON\"];", "5 -> 6 [label=\"table\"];", "6 [label=\":d\"];", "5 -> 7 [label=\"on\"];", "7 [label=\"Array\"];", "7 -> 8 [label=\"0\"];", "8 [label=\"Array\"];", "8 -> 9 [label=\"0\"];", "9 [label=\"QualifiedIdentifier\"];", "9 -> 10 [label=\"table\"];", "10 [label=\"\\\"d\\\"\"];", "9 -> 11 [label=\"column\"];", "11 [label=\"\\\"b\\\"\"];", "8 -> 12 [label=\"1\"];", "12 [label=\"QualifiedIdentifier\"];", "12 -> 13 [label=\"table\"];", "13 [label=\"\\\"a\\\"\"];", "12 -> 14 [label=\"column\"];", "14 [label=\"\\\"c\\\"\"];"]
135
+ dot(@ds.from(:a).join(:d, :b=>:c)).should == ["1 -> 2 [label=\"from\"];", "2 [label=\"Array\"];", "2 -> 3 [label=\"0\"];", "3 [label=\":a\"];", "1 -> 4 [label=\"join\"];", "4 [label=\"Array\"];", "4 -> 5 [label=\"0\"];", "5 [label=\"INNER JOIN ON\"];", "5 -> 6 [label=\"table\"];", "6 [label=\":d\"];", "5 -> 7 [label=\"on\"];", "7 [label=\"ComplexExpression: =\"];", "7 -> 8 [label=\"0\"];", "8 [label=\"QualifiedIdentifier\"];", "8 -> 9 [label=\"table\"];", "9 [label=\"\\\"d\\\"\"];", "8 -> 10 [label=\"column\"];", "10 [label=\"\\\"b\\\"\"];", "7 -> 11 [label=\"1\"];", "11 [label=\"QualifiedIdentifier\"];", "11 -> 12 [label=\"table\"];", "12 [label=\"\\\"a\\\"\"];", "11 -> 13 [label=\"column\"];", "13 [label=\"\\\"c\\\"\"];"]
139
136
  end
140
137
 
141
138
  it "should handle JOIN USING" 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)
@@ -7,26 +7,11 @@ describe Sequel::Model, "tree plugin" do
7
7
  c.class_eval do
8
8
  def self.name; 'Node'; end
9
9
  columns :id, :name, :parent_id, :i, :pi
10
+ plugin :tree, opts
10
11
  end
11
- ds = c.dataset
12
- class << ds
13
- attr_accessor :row_sets
14
- def fetch_rows(sql)
15
- @db << sql
16
- if rs = row_sets.shift
17
- rs.each{|row| yield row}
18
- end
19
- end
20
- end
21
- c.plugin :tree, opts
22
12
  c
23
13
  end
24
14
 
25
- def y(c, *hs)
26
- ds = c.dataset
27
- ds.row_sets = hs
28
- end
29
-
30
15
  before do
31
16
  @c = klass
32
17
  @ds = @c.dataset
@@ -71,7 +56,7 @@ describe Sequel::Model, "tree plugin" do
71
56
  end
72
57
 
73
58
  it "should have roots return an array of the tree's roots" do
74
- y(@c, [{:id=>1, :parent_id=>nil, :name=>'r'}])
59
+ @ds._fetch = [{:id=>1, :parent_id=>nil, :name=>'r'}]
75
60
  @c.roots.should == [@c.load(:id=>1, :parent_id=>nil, :name=>'r')]
76
61
  @db.sqls.should == ["SELECT * FROM nodes WHERE (parent_id IS NULL)"]
77
62
  end
@@ -81,14 +66,14 @@ describe Sequel::Model, "tree plugin" do
81
66
  end
82
67
 
83
68
  it "should have ancestors return the ancestors of the current node" do
84
- y(@c, [{:id=>1, :parent_id=>5, :name=>'r'}], [{:id=>5, :parent_id=>nil, :name=>'r2'}])
69
+ @ds._fetch = [[{:id=>1, :parent_id=>5, :name=>'r'}], [{:id=>5, :parent_id=>nil, :name=>'r2'}]]
85
70
  @o.ancestors.should == [@c.load(:id=>1, :parent_id=>5, :name=>'r'), @c.load(:id=>5, :parent_id=>nil, :name=>'r2')]
86
71
  @db.sqls.should == ["SELECT * FROM nodes WHERE (nodes.id = 1) LIMIT 1",
87
72
  "SELECT * FROM nodes WHERE (nodes.id = 5) LIMIT 1"]
88
73
  end
89
74
 
90
75
  it "should have descendants return the descendants of the current node" do
91
- y(@c, [{:id=>3, :parent_id=>2, :name=>'r'}, {:id=>4, :parent_id=>2, :name=>'r2'}], [{:id=>5, :parent_id=>4, :name=>'r3'}], [])
76
+ @ds._fetch = [[{:id=>3, :parent_id=>2, :name=>'r'}, {:id=>4, :parent_id=>2, :name=>'r2'}], [{:id=>5, :parent_id=>4, :name=>'r3'}], []]
92
77
  @o.descendants.should == [@c.load(:id=>3, :parent_id=>2, :name=>'r'), @c.load(:id=>4, :parent_id=>2, :name=>'r2'), @c.load(:id=>5, :parent_id=>4, :name=>'r3')]
93
78
  @db.sqls.should == ["SELECT * FROM nodes WHERE (nodes.parent_id = 2)",
94
79
  "SELECT * FROM nodes WHERE (nodes.parent_id = 3)",
@@ -97,7 +82,7 @@ describe Sequel::Model, "tree plugin" do
97
82
  end
98
83
 
99
84
  it "should have root return the root of the current node" do
100
- y(@c, [{:id=>1, :parent_id=>5, :name=>'r'}], [{:id=>5, :parent_id=>nil, :name=>'r2'}])
85
+ @ds._fetch = [[{:id=>1, :parent_id=>5, :name=>'r'}], [{:id=>5, :parent_id=>nil, :name=>'r2'}]]
101
86
  @o.root.should == @c.load(:id=>5, :parent_id=>nil, :name=>'r2')
102
87
  @db.sqls.should == ["SELECT * FROM nodes WHERE (nodes.id = 1) LIMIT 1",
103
88
  "SELECT * FROM nodes WHERE (nodes.id = 5) LIMIT 1"]
@@ -113,14 +98,14 @@ describe Sequel::Model, "tree plugin" do
113
98
  end
114
99
 
115
100
  it "should have self_and_siblings return the children of the current node's parent" do
116
- y(@c, [{:id=>1, :parent_id=>3, :name=>'r'}], [{:id=>7, :parent_id=>1, :name=>'r2'}, @o.values.dup])
101
+ @ds._fetch = [[{:id=>1, :parent_id=>3, :name=>'r'}], [{:id=>7, :parent_id=>1, :name=>'r2'}, @o.values.dup]]
117
102
  @o.self_and_siblings.should == [@c.load(:id=>7, :parent_id=>1, :name=>'r2'), @o]
118
103
  @db.sqls.should == ["SELECT * FROM nodes WHERE (nodes.id = 1) LIMIT 1",
119
104
  "SELECT * FROM nodes WHERE (nodes.parent_id = 1)"]
120
105
  end
121
106
 
122
107
  it "should have siblings return the children of the current node's parent, except for the current node" do
123
- y(@c, [{:id=>1, :parent_id=>3, :name=>'r'}], [{:id=>7, :parent_id=>1, :name=>'r2'}, @o.values.dup])
108
+ @ds._fetch = [[{:id=>1, :parent_id=>3, :name=>'r'}], [{:id=>7, :parent_id=>1, :name=>'r2'}, @o.values.dup]]
124
109
  @o.siblings.should == [@c.load(:id=>7, :parent_id=>1, :name=>'r2')]
125
110
  @db.sqls.should == ["SELECT * FROM nodes WHERE (nodes.id = 1) LIMIT 1",
126
111
  "SELECT * FROM nodes WHERE (nodes.parent_id = 1)"]
@@ -132,23 +117,23 @@ describe Sequel::Model, "tree plugin" do
132
117
  end
133
118
 
134
119
  it "should have root class method return the root" do
135
- y(@c, [{:id=>1, :parent_id=>nil, :name=>'r'}])
120
+ @c.dataset._fetch = [{:id=>1, :parent_id=>nil, :name=>'r'}]
136
121
  @c.root.should == @c.load(:id=>1, :parent_id=>nil, :name=>'r')
137
122
  end
138
123
 
139
124
  it "prevents creating a second root" do
140
- y(@c, [{:id=>1, :parent_id=>nil, :name=>'r'}])
125
+ @c.dataset._fetch = [{:id=>1, :parent_id=>nil, :name=>'r'}]
141
126
  lambda { @c.create }.should raise_error(Sequel::Plugins::Tree::TreeMultipleRootError)
142
127
  end
143
128
 
144
129
  it "errors when promoting an existing record to a second root" do
145
- y(@c, [{:id=>1, :parent_id=>nil, :name=>'r'}])
130
+ @c.dataset._fetch = [{:id=>1, :parent_id=>nil, :name=>'r'}]
146
131
  n = @c.load(:id => 2, :parent_id => 1)
147
132
  lambda { n.update(:parent_id => nil) }.should raise_error(Sequel::Plugins::Tree::TreeMultipleRootError)
148
133
  end
149
134
 
150
135
  it "allows updating existing root" do
151
- y(@c, [{:id=>1, :parent_id=>nil, :name=>'r'}])
136
+ @c.dataset._fetch = [{:id=>1, :parent_id=>nil, :name=>'r'}]
152
137
  lambda { @c.root.update(:name => 'fdsa') }.should_not raise_error
153
138
  end
154
139
  end
@@ -2,22 +2,17 @@ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
2
 
3
3
  describe Sequel::Model, "TypecastOnLoad plugin" do
4
4
  before do
5
- @db = Sequel::Database.new({})
5
+ @db = Sequel.mock(:fetch=>{:id=>1, :b=>"1", :y=>"0"}, :columns=>[:id, :b, :y])
6
6
  def @db.schema(*args)
7
7
  [[:id, {}], [:y, {:type=>:boolean, :db_type=>'tinyint(1)'}], [:b, {:type=>:integer, :db_type=>'integer'}]]
8
8
  end
9
9
  @c = Class.new(Sequel::Model(@db[:items])) do
10
- include(Module.new{def _refresh(ds); values[:b] = b.to_s; self; end})
11
10
  attr_accessor :bset
12
11
  def b=(x)
13
12
  self.bset = true
14
13
  super
15
14
  end
16
15
  end
17
- @c.instance_eval do
18
- @columns = [:id, :b, :y]
19
- def columns; @columns; end
20
- end
21
16
  end
22
17
 
23
18
  specify "should call setter method with value when loading the object, for all given columns" do
@@ -9,57 +9,63 @@ describe "Sequel::Plugins::UpdatePrimaryKey" do
9
9
  @c.unrestrict_primary_key
10
10
  @o = @c.new
11
11
  @ds = @c.dataset
12
- @ds.extend(Module.new do
13
- attr_accessor :a
14
- def fetch_rows(sql)
15
- yield(a.dup)
16
- end
17
-
18
- def update(h)
19
- if literal(opts[:where]) =~ /a = (\d)/ and $1.to_i == a[:a]
20
- a.update(h)
21
- end
22
- super
23
- end
24
- end)
25
- @ds.a = {:a=>1, :b=>3}
26
- @ds2 = @ds.naked
27
12
  MODEL_DB.reset
28
13
  end
29
14
 
30
15
  specify "should handle regular updates" do
16
+ @ds._fetch = [[{:a=>1, :b=>3}], [{:a=>1, :b=>4}], [{:a=>1, :b=>4}], [{:a=>1, :b=>5}], [{:a=>1, :b=>5}], [{:a=>1, :b=>6}], [{:a=>1, :b=>6}]]
31
17
  @c.first.update(:b=>4)
32
- @ds2.all.should == [{:a=>1, :b=>4}]
18
+ @c.all.should == [@c.load(:a=>1, :b=>4)]
19
+ MODEL_DB.sqls.should == ["SELECT * FROM a LIMIT 1", "UPDATE a SET b = 4 WHERE (a = 1)", "SELECT * FROM a"]
33
20
  @c.first.set(:b=>5).save
34
- @ds2.all.should == [{:a=>1, :b=>5}]
21
+ @c.all.should == [@c.load(:a=>1, :b=>5)]
22
+ MODEL_DB.sqls.should == ["SELECT * FROM a LIMIT 1", "UPDATE a SET b = 5 WHERE (a = 1)", "SELECT * FROM a"]
35
23
  @c.first.set(:b=>6).save(:b)
36
- @ds2.all.should == [{:a=>1, :b=>6}]
24
+ @c.all.should == [@c.load(:a=>1, :b=>6)]
25
+ MODEL_DB.sqls.should == ["SELECT * FROM a LIMIT 1", "UPDATE a SET b = 6 WHERE (a = 1)", "SELECT * FROM a"]
37
26
  end
38
27
 
39
28
  specify "should handle updating the primary key field with another field" do
29
+ @ds._fetch = [[{:a=>1, :b=>3}], [{:a=>2, :b=>4}]]
40
30
  @c.first.update(:a=>2, :b=>4)
41
- @ds2.all.should == [{:a=>2, :b=>4}]
31
+ @c.all.should == [@c.load(:a=>2, :b=>4)]
32
+ sqls = MODEL_DB.sqls
33
+ ["UPDATE a SET a = 2, b = 4 WHERE (a = 1)", "UPDATE a SET b = 4, a = 2 WHERE (a = 1)"].should include(sqls.slice!(1))
34
+ sqls.should == ["SELECT * FROM a LIMIT 1", "SELECT * FROM a"]
42
35
  end
43
36
 
44
37
  specify "should handle updating just the primary key field when saving changes" do
38
+ @ds._fetch = [[{:a=>1, :b=>3}], [{:a=>2, :b=>3}], [{:a=>2, :b=>3}], [{:a=>3, :b=>3}]]
45
39
  @c.first.update(:a=>2)
46
- @ds2.all.should == [{:a=>2, :b=>3}]
40
+ @c.all.should == [@c.load(:a=>2, :b=>3)]
41
+ MODEL_DB.sqls.should == ["SELECT * FROM a LIMIT 1", "UPDATE a SET a = 2 WHERE (a = 1)", "SELECT * FROM a"]
47
42
  @c.first.set(:a=>3).save(:a)
48
- @ds2.all.should == [{:a=>3, :b=>3}]
43
+ @c.all.should == [@c.load(:a=>3, :b=>3)]
44
+ MODEL_DB.sqls.should == ["SELECT * FROM a LIMIT 1", "UPDATE a SET a = 3 WHERE (a = 2)", "SELECT * FROM a"]
49
45
  end
50
46
 
51
47
  specify "should handle saving after modifying the primary key field with another field" do
48
+ @ds._fetch = [[{:a=>1, :b=>3}], [{:a=>2, :b=>4}]]
52
49
  @c.first.set(:a=>2, :b=>4).save
53
- @ds2.all.should == [{:a=>2, :b=>4}]
50
+ @c.all.should == [@c.load(:a=>2, :b=>4)]
51
+ sqls = MODEL_DB.sqls
52
+ ["UPDATE a SET a = 2, b = 4 WHERE (a = 1)", "UPDATE a SET b = 4, a = 2 WHERE (a = 1)"].should include(sqls.slice!(1))
53
+ sqls.should == ["SELECT * FROM a LIMIT 1", "SELECT * FROM a"]
54
54
  end
55
55
 
56
56
  specify "should handle saving after modifying just the primary key field" do
57
+ @ds._fetch = [[{:a=>1, :b=>3}], [{:a=>2, :b=>3}]]
57
58
  @c.first.set(:a=>2).save
58
- @ds2.all.should == [{:a=>2, :b=>3}]
59
+ @c.all.should == [@c.load(:a=>2, :b=>3)]
60
+ sqls = MODEL_DB.sqls
61
+ ["UPDATE a SET a = 2, b = 3 WHERE (a = 1)", "UPDATE a SET b = 3, a = 2 WHERE (a = 1)"].should include(sqls.slice!(1))
62
+ sqls.should == ["SELECT * FROM a LIMIT 1", "SELECT * FROM a"]
59
63
  end
60
64
 
61
65
  specify "should handle saving after updating the primary key" do
66
+ @ds._fetch = [[{:a=>1, :b=>3}], [{:a=>2, :b=>5}]]
62
67
  @c.first.update(:a=>2).update(:b=>4).set(:b=>5).save
63
- @ds2.all.should == [{:a=>2, :b=>5}]
68
+ @c.all.should == [@c.load(:a=>2, :b=>5)]
69
+ MODEL_DB.sqls.should == ["SELECT * FROM a LIMIT 1", "UPDATE a SET a = 2 WHERE (a = 1)", "UPDATE a SET b = 4 WHERE (a = 2)", "UPDATE a SET b = 5 WHERE (a = 2)", "SELECT * FROM a"]
64
70
  end
65
71
  end