sequel 3.21.0 → 3.36.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 (311) hide show
  1. data/CHANGELOG +855 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +23 -7
  4. data/Rakefile +42 -24
  5. data/bin/sequel +26 -8
  6. data/doc/active_record.rdoc +1 -0
  7. data/doc/advanced_associations.rdoc +171 -11
  8. data/doc/association_basics.rdoc +293 -43
  9. data/doc/dataset_basics.rdoc +5 -5
  10. data/doc/dataset_filtering.rdoc +8 -0
  11. data/doc/mass_assignment.rdoc +56 -0
  12. data/doc/migration.rdoc +85 -552
  13. data/doc/model_hooks.rdoc +78 -27
  14. data/doc/object_model.rdoc +541 -0
  15. data/doc/opening_databases.rdoc +97 -50
  16. data/doc/prepared_statements.rdoc +40 -14
  17. data/doc/querying.rdoc +28 -4
  18. data/doc/reflection.rdoc +30 -4
  19. data/doc/release_notes/3.22.0.txt +39 -0
  20. data/doc/release_notes/3.23.0.txt +172 -0
  21. data/doc/release_notes/3.24.0.txt +420 -0
  22. data/doc/release_notes/3.25.0.txt +88 -0
  23. data/doc/release_notes/3.26.0.txt +88 -0
  24. data/doc/release_notes/3.27.0.txt +82 -0
  25. data/doc/release_notes/3.28.0.txt +304 -0
  26. data/doc/release_notes/3.29.0.txt +459 -0
  27. data/doc/release_notes/3.30.0.txt +135 -0
  28. data/doc/release_notes/3.31.0.txt +146 -0
  29. data/doc/release_notes/3.32.0.txt +202 -0
  30. data/doc/release_notes/3.33.0.txt +157 -0
  31. data/doc/release_notes/3.34.0.txt +671 -0
  32. data/doc/release_notes/3.35.0.txt +144 -0
  33. data/doc/release_notes/3.36.0.txt +245 -0
  34. data/doc/schema_modification.rdoc +572 -0
  35. data/doc/sharding.rdoc +95 -3
  36. data/doc/testing.rdoc +129 -0
  37. data/doc/thread_safety.rdoc +17 -0
  38. data/doc/transactions.rdoc +137 -0
  39. data/doc/virtual_rows.rdoc +51 -2
  40. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  41. data/lib/sequel/adapters/ado.rb +40 -18
  42. data/lib/sequel/adapters/amalgalite.rb +17 -9
  43. data/lib/sequel/adapters/db2.rb +175 -86
  44. data/lib/sequel/adapters/dbi.rb +15 -15
  45. data/lib/sequel/adapters/do/mysql.rb +17 -11
  46. data/lib/sequel/adapters/do/postgres.rb +1 -57
  47. data/lib/sequel/adapters/do/sqlite.rb +0 -10
  48. data/lib/sequel/adapters/do.rb +18 -36
  49. data/lib/sequel/adapters/firebird.rb +27 -208
  50. data/lib/sequel/adapters/ibmdb.rb +453 -0
  51. data/lib/sequel/adapters/informix.rb +6 -23
  52. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  53. data/lib/sequel/adapters/jdbc/db2.rb +47 -0
  54. data/lib/sequel/adapters/jdbc/derby.rb +287 -0
  55. data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
  56. data/lib/sequel/adapters/jdbc/h2.rb +73 -31
  57. data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
  58. data/lib/sequel/adapters/jdbc/informix.rb +21 -0
  59. data/lib/sequel/adapters/jdbc/jtds.rb +29 -0
  60. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  61. data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
  62. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  63. data/lib/sequel/adapters/jdbc/postgresql.rb +58 -48
  64. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  65. data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
  66. data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
  67. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  68. data/lib/sequel/adapters/jdbc.rb +265 -94
  69. data/lib/sequel/adapters/mock.rb +361 -0
  70. data/lib/sequel/adapters/mysql.rb +118 -222
  71. data/lib/sequel/adapters/mysql2.rb +58 -57
  72. data/lib/sequel/adapters/odbc/mssql.rb +15 -7
  73. data/lib/sequel/adapters/odbc.rb +28 -9
  74. data/lib/sequel/adapters/openbase.rb +3 -5
  75. data/lib/sequel/adapters/oracle.rb +349 -53
  76. data/lib/sequel/adapters/postgres.rb +356 -107
  77. data/lib/sequel/adapters/shared/access.rb +32 -9
  78. data/lib/sequel/adapters/shared/db2.rb +342 -0
  79. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  80. data/lib/sequel/adapters/shared/informix.rb +53 -0
  81. data/lib/sequel/adapters/shared/mssql.rb +335 -118
  82. data/lib/sequel/adapters/shared/mysql.rb +340 -76
  83. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
  84. data/lib/sequel/adapters/shared/oracle.rb +243 -45
  85. data/lib/sequel/adapters/shared/postgres.rb +524 -279
  86. data/lib/sequel/adapters/shared/progress.rb +5 -8
  87. data/lib/sequel/adapters/shared/sqlite.rb +265 -89
  88. data/lib/sequel/adapters/sqlite.rb +101 -39
  89. data/lib/sequel/adapters/swift/mysql.rb +9 -12
  90. data/lib/sequel/adapters/swift/postgres.rb +9 -74
  91. data/lib/sequel/adapters/swift/sqlite.rb +8 -6
  92. data/lib/sequel/adapters/swift.rb +8 -7
  93. data/lib/sequel/adapters/tinytds.rb +161 -21
  94. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +66 -0
  95. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  96. data/lib/sequel/ast_transformer.rb +194 -0
  97. data/lib/sequel/connection_pool/sharded_single.rb +11 -1
  98. data/lib/sequel/connection_pool/sharded_threaded.rb +28 -2
  99. data/lib/sequel/connection_pool/single.rb +5 -0
  100. data/lib/sequel/connection_pool/threaded.rb +38 -14
  101. data/lib/sequel/connection_pool.rb +10 -2
  102. data/lib/sequel/core.rb +118 -11
  103. data/lib/sequel/database/connecting.rb +38 -28
  104. data/lib/sequel/database/dataset.rb +4 -4
  105. data/lib/sequel/database/dataset_defaults.rb +63 -2
  106. data/lib/sequel/database/logging.rb +7 -2
  107. data/lib/sequel/database/misc.rb +150 -46
  108. data/lib/sequel/database/query.rb +215 -65
  109. data/lib/sequel/database/schema_generator.rb +64 -20
  110. data/lib/sequel/database/schema_methods.rb +212 -54
  111. data/lib/sequel/dataset/actions.rb +322 -85
  112. data/lib/sequel/dataset/features.rb +96 -8
  113. data/lib/sequel/dataset/graph.rb +38 -11
  114. data/lib/sequel/dataset/misc.rb +50 -23
  115. data/lib/sequel/dataset/mutation.rb +12 -7
  116. data/lib/sequel/dataset/prepared_statements.rb +68 -30
  117. data/lib/sequel/dataset/query.rb +237 -44
  118. data/lib/sequel/dataset/sql.rb +698 -278
  119. data/lib/sequel/dataset.rb +8 -0
  120. data/lib/sequel/exceptions.rb +4 -0
  121. data/lib/sequel/extensions/_pretty_table.rb +79 -0
  122. data/lib/sequel/extensions/arbitrary_servers.rb +108 -0
  123. data/lib/sequel/extensions/columns_introspection.rb +61 -0
  124. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +16 -34
  125. data/lib/sequel/extensions/migration.rb +97 -11
  126. data/lib/sequel/extensions/named_timezones.rb +5 -0
  127. data/lib/sequel/extensions/null_dataset.rb +90 -0
  128. data/lib/sequel/extensions/pg_array.rb +460 -0
  129. data/lib/sequel/extensions/pg_array_ops.rb +220 -0
  130. data/lib/sequel/extensions/pg_auto_parameterize.rb +169 -0
  131. data/lib/sequel/extensions/pg_hstore.rb +296 -0
  132. data/lib/sequel/extensions/pg_hstore_ops.rb +259 -0
  133. data/lib/sequel/extensions/pg_inet.rb +89 -0
  134. data/lib/sequel/extensions/pg_json.rb +178 -0
  135. data/lib/sequel/extensions/pg_statement_cache.rb +316 -0
  136. data/lib/sequel/extensions/pretty_table.rb +5 -71
  137. data/lib/sequel/extensions/query.rb +1 -1
  138. data/lib/sequel/extensions/query_literals.rb +79 -0
  139. data/lib/sequel/extensions/schema_caching.rb +76 -0
  140. data/lib/sequel/extensions/schema_dumper.rb +251 -37
  141. data/lib/sequel/extensions/select_remove.rb +35 -0
  142. data/lib/sequel/extensions/server_block.rb +139 -0
  143. data/lib/sequel/extensions/sql_expr.rb +4 -110
  144. data/lib/sequel/extensions/thread_local_timezones.rb +1 -1
  145. data/lib/sequel/extensions/to_dot.rb +95 -83
  146. data/lib/sequel/model/associations.rb +1187 -393
  147. data/lib/sequel/model/base.rb +578 -170
  148. data/lib/sequel/model/errors.rb +1 -1
  149. data/lib/sequel/model/exceptions.rb +5 -1
  150. data/lib/sequel/model/inflections.rb +1 -1
  151. data/lib/sequel/model.rb +30 -11
  152. data/lib/sequel/no_core_ext.rb +2 -0
  153. data/lib/sequel/plugins/active_model.rb +13 -1
  154. data/lib/sequel/plugins/association_pks.rb +22 -4
  155. data/lib/sequel/plugins/caching.rb +25 -18
  156. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  157. data/lib/sequel/plugins/composition.rb +44 -12
  158. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  159. data/lib/sequel/plugins/defaults_setter.rb +58 -0
  160. data/lib/sequel/plugins/dirty.rb +214 -0
  161. data/lib/sequel/plugins/eager_each.rb +59 -0
  162. data/lib/sequel/plugins/force_encoding.rb +6 -6
  163. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  164. data/lib/sequel/plugins/identity_map.rb +123 -8
  165. data/lib/sequel/plugins/instance_filters.rb +10 -0
  166. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  167. data/lib/sequel/plugins/json_serializer.rb +58 -6
  168. data/lib/sequel/plugins/list.rb +12 -2
  169. data/lib/sequel/plugins/many_through_many.rb +79 -28
  170. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  171. data/lib/sequel/plugins/nested_attributes.rb +139 -63
  172. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  173. data/lib/sequel/plugins/prepared_statements.rb +167 -0
  174. data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
  175. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  176. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  177. data/lib/sequel/plugins/rcte_tree.rb +29 -15
  178. data/lib/sequel/plugins/schema.rb +7 -2
  179. data/lib/sequel/plugins/serialization.rb +98 -49
  180. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  181. data/lib/sequel/plugins/sharding.rb +21 -54
  182. data/lib/sequel/plugins/single_table_inheritance.rb +5 -3
  183. data/lib/sequel/plugins/static_cache.rb +99 -0
  184. data/lib/sequel/plugins/subclasses.rb +10 -2
  185. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  186. data/lib/sequel/plugins/timestamps.rb +1 -1
  187. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  188. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  189. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  190. data/lib/sequel/plugins/xml_serializer.rb +15 -4
  191. data/lib/sequel/sql.rb +526 -59
  192. data/lib/sequel/timezones.rb +57 -38
  193. data/lib/sequel/version.rb +1 -1
  194. data/spec/adapters/db2_spec.rb +146 -0
  195. data/spec/adapters/firebird_spec.rb +1 -1
  196. data/spec/adapters/mssql_spec.rb +142 -40
  197. data/spec/adapters/mysql_spec.rb +380 -234
  198. data/spec/adapters/oracle_spec.rb +67 -77
  199. data/spec/adapters/postgres_spec.rb +1050 -212
  200. data/spec/adapters/spec_helper.rb +8 -5
  201. data/spec/adapters/sqlite_spec.rb +139 -27
  202. data/spec/core/connection_pool_spec.rb +196 -93
  203. data/spec/core/database_spec.rb +879 -510
  204. data/spec/core/dataset_spec.rb +1415 -1086
  205. data/spec/core/expression_filters_spec.rb +554 -109
  206. data/spec/core/mock_adapter_spec.rb +449 -0
  207. data/spec/core/object_graph_spec.rb +86 -114
  208. data/spec/core/schema_generator_spec.rb +4 -4
  209. data/spec/core/schema_spec.rb +482 -38
  210. data/spec/core/spec_helper.rb +6 -48
  211. data/spec/extensions/active_model_spec.rb +13 -0
  212. data/spec/extensions/arbitrary_servers_spec.rb +110 -0
  213. data/spec/extensions/association_autoreloading_spec.rb +18 -10
  214. data/spec/extensions/association_dependencies_spec.rb +15 -25
  215. data/spec/extensions/association_pks_spec.rb +66 -32
  216. data/spec/extensions/association_proxies_spec.rb +4 -4
  217. data/spec/extensions/caching_spec.rb +47 -51
  218. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  219. data/spec/extensions/columns_introspection_spec.rb +91 -0
  220. data/spec/extensions/composition_spec.rb +18 -13
  221. data/spec/{core/core_sql_spec.rb → extensions/core_extensions_spec.rb} +119 -139
  222. data/spec/extensions/dataset_associations_spec.rb +199 -0
  223. data/spec/extensions/defaults_setter_spec.rb +64 -0
  224. data/spec/extensions/dirty_spec.rb +155 -0
  225. data/spec/extensions/eager_each_spec.rb +34 -0
  226. data/spec/extensions/force_encoding_spec.rb +4 -2
  227. data/spec/extensions/hook_class_methods_spec.rb +69 -92
  228. data/spec/extensions/identity_map_spec.rb +131 -22
  229. data/spec/extensions/inflector_spec.rb +0 -4
  230. data/spec/extensions/instance_filters_spec.rb +11 -21
  231. data/spec/extensions/instance_hooks_spec.rb +72 -0
  232. data/spec/extensions/json_serializer_spec.rb +49 -6
  233. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  234. data/spec/extensions/list_spec.rb +48 -39
  235. data/spec/extensions/many_through_many_spec.rb +283 -250
  236. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  237. data/spec/extensions/migration_spec.rb +140 -35
  238. data/spec/extensions/named_timezones_spec.rb +29 -11
  239. data/spec/extensions/nested_attributes_spec.rb +251 -89
  240. data/spec/extensions/null_dataset_spec.rb +85 -0
  241. data/spec/extensions/optimistic_locking_spec.rb +24 -21
  242. data/spec/extensions/pg_array_ops_spec.rb +105 -0
  243. data/spec/extensions/pg_array_spec.rb +196 -0
  244. data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
  245. data/spec/extensions/pg_hstore_ops_spec.rb +136 -0
  246. data/spec/extensions/pg_hstore_spec.rb +195 -0
  247. data/spec/extensions/pg_inet_spec.rb +44 -0
  248. data/spec/extensions/pg_json_spec.rb +101 -0
  249. data/spec/extensions/pg_statement_cache_spec.rb +209 -0
  250. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  251. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  252. data/spec/extensions/prepared_statements_spec.rb +87 -0
  253. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  254. data/spec/extensions/pretty_table_spec.rb +7 -6
  255. data/spec/extensions/query_literals_spec.rb +168 -0
  256. data/spec/extensions/query_spec.rb +6 -0
  257. data/spec/extensions/rcte_tree_spec.rb +50 -43
  258. data/spec/extensions/schema_caching_spec.rb +41 -0
  259. data/spec/extensions/schema_dumper_spec.rb +429 -22
  260. data/spec/extensions/schema_spec.rb +25 -21
  261. data/spec/extensions/select_remove_spec.rb +38 -0
  262. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  263. data/spec/extensions/serialization_spec.rb +85 -43
  264. data/spec/extensions/server_block_spec.rb +90 -0
  265. data/spec/extensions/sharding_spec.rb +69 -143
  266. data/spec/extensions/single_table_inheritance_spec.rb +23 -29
  267. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  268. data/spec/extensions/spec_helper.rb +22 -61
  269. data/spec/extensions/sql_expr_spec.rb +29 -60
  270. data/spec/extensions/static_cache_spec.rb +145 -0
  271. data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
  272. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  273. data/spec/extensions/timestamps_spec.rb +6 -6
  274. data/spec/extensions/to_dot_spec.rb +4 -7
  275. data/spec/extensions/touch_spec.rb +13 -14
  276. data/spec/extensions/tree_spec.rb +11 -26
  277. data/spec/extensions/typecast_on_load_spec.rb +9 -6
  278. data/spec/extensions/update_primary_key_spec.rb +30 -24
  279. data/spec/extensions/validation_class_methods_spec.rb +30 -51
  280. data/spec/extensions/validation_helpers_spec.rb +16 -35
  281. data/spec/extensions/xml_serializer_spec.rb +29 -4
  282. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
  283. data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
  284. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
  285. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
  286. data/spec/integration/associations_test.rb +659 -21
  287. data/spec/integration/database_test.rb +9 -3
  288. data/spec/integration/dataset_test.rb +605 -91
  289. data/spec/integration/eager_loader_test.rb +19 -21
  290. data/spec/integration/migrator_test.rb +2 -3
  291. data/spec/integration/model_test.rb +81 -2
  292. data/spec/integration/plugin_test.rb +454 -143
  293. data/spec/integration/prepared_statement_test.rb +263 -128
  294. data/spec/integration/schema_test.rb +309 -43
  295. data/spec/integration/spec_helper.rb +40 -30
  296. data/spec/integration/timezone_test.rb +38 -12
  297. data/spec/integration/transaction_test.rb +183 -8
  298. data/spec/integration/type_test.rb +18 -4
  299. data/spec/model/association_reflection_spec.rb +201 -7
  300. data/spec/model/associations_spec.rb +1067 -661
  301. data/spec/model/base_spec.rb +329 -95
  302. data/spec/model/dataset_methods_spec.rb +7 -27
  303. data/spec/model/eager_loading_spec.rb +677 -676
  304. data/spec/model/hooks_spec.rb +349 -67
  305. data/spec/model/model_spec.rb +240 -168
  306. data/spec/model/plugins_spec.rb +24 -13
  307. data/spec/model/record_spec.rb +490 -232
  308. data/spec/model/spec_helper.rb +14 -71
  309. data/spec/model/validations_spec.rb +11 -0
  310. data/spec/rcov.opts +2 -0
  311. metadata +178 -80
@@ -1,89 +1,58 @@
1
1
  require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper')
2
2
 
3
3
  describe "Sequel sql_expr extension" do
4
+ before do
5
+ @ds = Sequel.mock.dataset
6
+ end
7
+
4
8
  specify "Object#sql_expr should wrap the object in a GenericComplexExpression" do
5
9
  o = Object.new
10
+ def o.sql_literal(ds) 'foo' end
6
11
  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)
12
+ @ds.literal(s).should == "foo"
13
+ @ds.literal(s+1).should == "(foo + 1)"
14
+ @ds.literal(s & true).should == "(foo AND 't')"
15
+ @ds.literal(s < 1).should == "(foo < 1)"
16
+ @ds.literal(s.sql_subscript(1)).should == "foo[1]"
17
+ @ds.literal(s.like('a')).should == "(foo LIKE 'a')"
18
+ @ds.literal(s.as(:a)).should == "foo AS a"
19
+ @ds.literal(s.cast(Integer)).should == "CAST(foo AS integer)"
20
+ @ds.literal(s.desc).should == "foo DESC"
21
+ @ds.literal(s.sql_string + '1').should == "(foo || '1')"
19
22
  end
20
23
 
21
24
  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]
25
+ [1, 2.0, 2^70, BigDecimal.new('1.0')].each do |o|
26
+ @ds.literal(o.sql_expr).should == @ds.literal(o)
27
+ @ds.literal(o.sql_expr + 1).should == "(#{@ds.literal(o)} + 1)"
27
28
  end
28
29
  end
29
30
 
30
31
  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]
32
+ @ds.literal("".sql_expr).should == "''"
33
+ @ds.literal("".sql_expr + :a).should == "('' || a)"
36
34
  end
37
35
 
38
36
  specify "NilClass, TrueClass, and FalseClass#sql_expr should wrap the object in a BooleanExpression" do
39
37
  [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]
38
+ @ds.literal(o.sql_expr).should == @ds.literal(o)
39
+ @ds.literal(o.sql_expr & :a).should == "(#{@ds.literal(o)} AND a)"
44
40
  end
45
41
  end
46
42
 
47
43
  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
44
+ @ds.literal(proc{a}.sql_expr).should == "a"
45
+ @ds.literal(proc{a__b}.sql_expr).should == "a.b"
46
+ @ds.literal(proc{a(b)}.sql_expr).should == "a(b)"
63
47
  end
64
48
 
65
49
  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]
50
+ @ds.literal(proc{1}.sql_expr).should == "1"
51
+ @ds.literal(proc{1}.sql_expr + 2).should == "(1 + 2)"
70
52
  end
71
53
 
72
54
  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
55
+ @ds.literal(proc{{a=>b}}.sql_expr).should == "(a = b)"
56
+ @ds.literal(proc{[[a, b]]}.sql_expr & :a).should == "((a = b) AND a)"
88
57
  end
89
58
  end
@@ -0,0 +1,145 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "Sequel::Plugins::StaticCache" do
4
+ before do
5
+ @db = Sequel.mock
6
+ @db.fetch = [{:id=>1}, {:id=>2}]
7
+ @c = Class.new(Sequel::Model(@db[:t]))
8
+ @c.columns :id
9
+ @c.plugin :static_cache
10
+ @c1 = @c.cache[1]
11
+ @c2 = @c.cache[2]
12
+ @db.sqls
13
+ end
14
+
15
+ it "should use a ruby hash as a cache of all model instances" do
16
+ @c.cache.should == {1=>@c.load(:id=>1), 2=>@c.load(:id=>2)}
17
+ end
18
+
19
+ it "should work correctly with composite keys" do
20
+ @db.fetch = [{:id=>1, :id2=>1}, {:id=>2, :id2=>1}]
21
+ @c = Class.new(Sequel::Model(@db[:t]))
22
+ @c.columns :id, :id2
23
+ @c.set_primary_key([:id, :id2])
24
+ @c.plugin :static_cache
25
+ @db.sqls
26
+ @c1 = @c.cache[[1, 2]]
27
+ @c2 = @c.cache[[2, 1]]
28
+ @c[[1, 2]].should equal(@c1)
29
+ @c[[2, 1]].should equal(@c2)
30
+ @db.sqls.should == []
31
+ end
32
+
33
+ it "should make .[] method with primary key use the cache" do
34
+ @c[1].should equal(@c1)
35
+ @c[2].should equal(@c2)
36
+ @c[3].should be_nil
37
+ @c[[1, 2]].should be_nil
38
+ @c[nil].should be_nil
39
+ @c[].should be_nil
40
+ @db.sqls.should == []
41
+ end
42
+
43
+ it "should have .[] with a hash not use the cache" do
44
+ @db.fetch = {:id=>2}
45
+ @c[:id=>2].should == @c2
46
+ @db.sqls.should == ['SELECT * FROM t WHERE (id = 2) LIMIT 1']
47
+ end
48
+
49
+ it "should support cache_get_pk" do
50
+ @c.cache_get_pk(1).should equal(@c1)
51
+ @c.cache_get_pk(2).should equal(@c2)
52
+ @c.cache_get_pk(3).should be_nil
53
+ @db.sqls.should == []
54
+ end
55
+
56
+ it "should have each just iterate over the hash's values without sending a query" do
57
+ a = []
58
+ @c.each{|o| a << o}
59
+ a = a.sort_by{|o| o.id}
60
+ a.first.should equal(@c1)
61
+ a.last.should equal(@c2)
62
+ @db.sqls.should == []
63
+ end
64
+
65
+ it "should have map just iterate over the hash's values without sending a query if no argument is given" do
66
+ @c.map{|v| v.id}.sort.should == [1, 2]
67
+ @db.sqls.should == []
68
+ end
69
+
70
+ it "should have map send a query if given an argument" do
71
+ @c.map(:id).sort.should == [1, 2]
72
+ @db.sqls.should == ["SELECT * FROM t"]
73
+ end
74
+
75
+ it "should have map without a block or argument not raise an exception or issue a query" do
76
+ @c.map
77
+ @db.sqls.should == []
78
+ end
79
+
80
+ it "should have map without a block not return a frozen object" do
81
+ @c.map.frozen?.should be_false
82
+ end
83
+
84
+ it "should have other enumerable methods work without sending a query" do
85
+ a = @c.sort_by{|o| o.id}
86
+ a.first.should equal(@c1)
87
+ a.last.should equal(@c2)
88
+ @db.sqls.should == []
89
+ end
90
+
91
+ it "should have all just return the hashes' values" do
92
+ a = @c.all.sort_by{|o| o.id}
93
+ a.first.should equal(@c1)
94
+ a.last.should equal(@c2)
95
+ @db.sqls.should == []
96
+ end
97
+
98
+ it "should have all not return a frozen object" do
99
+ @c.all.frozen?.should be_false
100
+ end
101
+
102
+ it "should have all return things in dataset order" do
103
+ @c.all.should == [@c1, @c2]
104
+ end
105
+
106
+ it "should have to_hash without arguments return the cached objects without a query" do
107
+ a = @c.to_hash
108
+ a[1].should equal(@c1)
109
+ a[2].should equal(@c2)
110
+ @db.sqls.should == []
111
+ end
112
+
113
+ it "should have to_hash with any arguments use a query" do
114
+ @c.to_hash(:id).should == {1=>@c1, 2=>@c2}
115
+ @db.sqls.should == ['SELECT * FROM t']
116
+ @c.to_hash(:id, :id).should == {1=>1, 2=>2}
117
+ @db.sqls.should == ['SELECT * FROM t']
118
+ end
119
+
120
+ it "should have all not return a frozen object" do
121
+ @c.to_hash.frozen?.should be_false
122
+ end
123
+
124
+ it "all of the static cache values (model instances) should be frozen" do
125
+ @c.all.all?{|o| o.frozen?}.should be_true
126
+ end
127
+
128
+ it "subclasses should work correctly" do
129
+ c = Class.new(@c)
130
+ c.all.should == [c.load(:id=>1), c.load(:id=>2)]
131
+ c.to_hash.should == {1=>c.load(:id=>1), 2=>c.load(:id=>2)}
132
+ @db.sqls.should == ['SELECT * FROM t']
133
+ end
134
+
135
+ it "set_dataset should work correctly" do
136
+ ds = @c.dataset.from(:t2)
137
+ ds.instance_variable_set(:@columns, [:id])
138
+ ds._fetch = {:id=>3}
139
+ @c.dataset = ds
140
+ @c.all.should == [@c.load(:id=>3)]
141
+ @c.to_hash.should == {3=>@c.load(:id=>3)}
142
+ @c.to_hash[3].should equal(@c.all.first)
143
+ @db.sqls.should == ['SELECT * FROM t2']
144
+ end
145
+ 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
@@ -62,4 +52,12 @@ describe "Sequel::Plugins::TacticalEagerLoading" do
62
52
  @ds.should_not_receive(:eager_load)
63
53
  ts.map{|x| x.parent}.should == [ts[2], ts[3], nil, nil]
64
54
  end
55
+
56
+ it "should handle case where an association is valid on an instance, but not on all instances" do
57
+ c = Class.new(@c)
58
+ c.many_to_one :parent2, :class=>@c, :key=>:parent_id
59
+ @c.dataset.row_proc = proc{|r| (r[:parent_id] == 101 ? c : @c).call(r)}
60
+ @c.all{|x| x.parent2 if x.is_a?(c)}
61
+ end
62
+
65
63
  end
@@ -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], :numrows=>1)
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
@@ -35,6 +30,14 @@ describe Sequel::Model, "TypecastOnLoad plugin" do
35
30
  o.bset.should == true
36
31
  end
37
32
 
33
+ specify "should call setter method with value when automatically reloading the object on creation via insert_select" do
34
+ @c.plugin :typecast_on_load, :b
35
+ @c.dataset.meta_def(:insert_select){|h| insert(h); first}
36
+ o = @c.new({:id=>1, :b=>"1", :y=>"0"}, true)
37
+ o.save.values.should == {:id=>1, :b=>1, :y=>"0"}
38
+ o.bset.should == true
39
+ end
40
+
38
41
  specify "should allowing setting columns separately via add_typecast_on_load_columns" do
39
42
  @c.plugin :typecast_on_load
40
43
  @c.load(:id=>1, :b=>"1", :y=>"0").values.should == {:id=>1, :b=>"1", :y=>"0"}