sequel 5.29.0 → 5.30.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (323) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +8 -1922
  3. data/doc/release_notes/5.30.0.txt +20 -0
  4. data/lib/sequel/adapters/shared/sqlite.rb +7 -1
  5. data/lib/sequel/database/transactions.rb +5 -9
  6. data/lib/sequel/version.rb +1 -1
  7. metadata +4 -368
  8. data/Rakefile +0 -151
  9. data/doc/release_notes/4.0.0.txt +0 -262
  10. data/doc/release_notes/4.1.0.txt +0 -85
  11. data/doc/release_notes/4.10.0.txt +0 -226
  12. data/doc/release_notes/4.11.0.txt +0 -147
  13. data/doc/release_notes/4.12.0.txt +0 -105
  14. data/doc/release_notes/4.13.0.txt +0 -169
  15. data/doc/release_notes/4.14.0.txt +0 -68
  16. data/doc/release_notes/4.15.0.txt +0 -56
  17. data/doc/release_notes/4.16.0.txt +0 -36
  18. data/doc/release_notes/4.17.0.txt +0 -38
  19. data/doc/release_notes/4.18.0.txt +0 -36
  20. data/doc/release_notes/4.19.0.txt +0 -45
  21. data/doc/release_notes/4.2.0.txt +0 -129
  22. data/doc/release_notes/4.20.0.txt +0 -79
  23. data/doc/release_notes/4.21.0.txt +0 -94
  24. data/doc/release_notes/4.22.0.txt +0 -72
  25. data/doc/release_notes/4.23.0.txt +0 -65
  26. data/doc/release_notes/4.24.0.txt +0 -99
  27. data/doc/release_notes/4.25.0.txt +0 -181
  28. data/doc/release_notes/4.26.0.txt +0 -44
  29. data/doc/release_notes/4.27.0.txt +0 -78
  30. data/doc/release_notes/4.28.0.txt +0 -57
  31. data/doc/release_notes/4.29.0.txt +0 -41
  32. data/doc/release_notes/4.3.0.txt +0 -40
  33. data/doc/release_notes/4.30.0.txt +0 -37
  34. data/doc/release_notes/4.31.0.txt +0 -57
  35. data/doc/release_notes/4.32.0.txt +0 -132
  36. data/doc/release_notes/4.33.0.txt +0 -88
  37. data/doc/release_notes/4.34.0.txt +0 -86
  38. data/doc/release_notes/4.35.0.txt +0 -130
  39. data/doc/release_notes/4.36.0.txt +0 -116
  40. data/doc/release_notes/4.37.0.txt +0 -50
  41. data/doc/release_notes/4.38.0.txt +0 -67
  42. data/doc/release_notes/4.39.0.txt +0 -127
  43. data/doc/release_notes/4.4.0.txt +0 -92
  44. data/doc/release_notes/4.40.0.txt +0 -179
  45. data/doc/release_notes/4.41.0.txt +0 -77
  46. data/doc/release_notes/4.42.0.txt +0 -221
  47. data/doc/release_notes/4.43.0.txt +0 -87
  48. data/doc/release_notes/4.44.0.txt +0 -125
  49. data/doc/release_notes/4.45.0.txt +0 -370
  50. data/doc/release_notes/4.46.0.txt +0 -404
  51. data/doc/release_notes/4.47.0.txt +0 -56
  52. data/doc/release_notes/4.48.0.txt +0 -293
  53. data/doc/release_notes/4.49.0.txt +0 -222
  54. data/doc/release_notes/4.5.0.txt +0 -34
  55. data/doc/release_notes/4.6.0.txt +0 -30
  56. data/doc/release_notes/4.7.0.txt +0 -103
  57. data/doc/release_notes/4.8.0.txt +0 -175
  58. data/doc/release_notes/4.9.0.txt +0 -190
  59. data/spec/adapter_spec.rb +0 -4
  60. data/spec/adapters/db2_spec.rb +0 -170
  61. data/spec/adapters/mssql_spec.rb +0 -828
  62. data/spec/adapters/mysql_spec.rb +0 -1060
  63. data/spec/adapters/oracle_spec.rb +0 -371
  64. data/spec/adapters/postgres_spec.rb +0 -4476
  65. data/spec/adapters/spec_helper.rb +0 -44
  66. data/spec/adapters/sqlanywhere_spec.rb +0 -97
  67. data/spec/adapters/sqlite_spec.rb +0 -652
  68. data/spec/bin_spec.rb +0 -278
  69. data/spec/core/connection_pool_spec.rb +0 -1250
  70. data/spec/core/database_spec.rb +0 -2915
  71. data/spec/core/dataset_spec.rb +0 -5544
  72. data/spec/core/deprecated_spec.rb +0 -70
  73. data/spec/core/expression_filters_spec.rb +0 -1498
  74. data/spec/core/mock_adapter_spec.rb +0 -722
  75. data/spec/core/object_graph_spec.rb +0 -336
  76. data/spec/core/placeholder_literalizer_spec.rb +0 -166
  77. data/spec/core/schema_generator_spec.rb +0 -214
  78. data/spec/core/schema_spec.rb +0 -1844
  79. data/spec/core/spec_helper.rb +0 -24
  80. data/spec/core/version_spec.rb +0 -14
  81. data/spec/core_extensions_spec.rb +0 -763
  82. data/spec/core_model_spec.rb +0 -2
  83. data/spec/core_spec.rb +0 -1
  84. data/spec/deprecation_helper.rb +0 -30
  85. data/spec/extensions/accessed_columns_spec.rb +0 -51
  86. data/spec/extensions/active_model_spec.rb +0 -99
  87. data/spec/extensions/after_initialize_spec.rb +0 -28
  88. data/spec/extensions/any_not_empty_spec.rb +0 -23
  89. data/spec/extensions/arbitrary_servers_spec.rb +0 -109
  90. data/spec/extensions/association_dependencies_spec.rb +0 -125
  91. data/spec/extensions/association_multi_add_remove_spec.rb +0 -1041
  92. data/spec/extensions/association_pks_spec.rb +0 -423
  93. data/spec/extensions/association_proxies_spec.rb +0 -100
  94. data/spec/extensions/auto_literal_strings_spec.rb +0 -205
  95. data/spec/extensions/auto_validations_spec.rb +0 -229
  96. data/spec/extensions/blacklist_security_spec.rb +0 -95
  97. data/spec/extensions/blank_spec.rb +0 -69
  98. data/spec/extensions/boolean_readers_spec.rb +0 -93
  99. data/spec/extensions/boolean_subsets_spec.rb +0 -47
  100. data/spec/extensions/caching_spec.rb +0 -273
  101. data/spec/extensions/caller_logging_spec.rb +0 -52
  102. data/spec/extensions/class_table_inheritance_spec.rb +0 -750
  103. data/spec/extensions/column_conflicts_spec.rb +0 -75
  104. data/spec/extensions/column_select_spec.rb +0 -129
  105. data/spec/extensions/columns_introspection_spec.rb +0 -90
  106. data/spec/extensions/columns_updated_spec.rb +0 -35
  107. data/spec/extensions/composition_spec.rb +0 -248
  108. data/spec/extensions/connection_expiration_spec.rb +0 -151
  109. data/spec/extensions/connection_validator_spec.rb +0 -144
  110. data/spec/extensions/constant_sql_override_spec.rb +0 -24
  111. data/spec/extensions/constraint_validations_plugin_spec.rb +0 -300
  112. data/spec/extensions/constraint_validations_spec.rb +0 -439
  113. data/spec/extensions/core_refinements_spec.rb +0 -528
  114. data/spec/extensions/csv_serializer_spec.rb +0 -183
  115. data/spec/extensions/current_datetime_timestamp_spec.rb +0 -27
  116. data/spec/extensions/dataset_associations_spec.rb +0 -365
  117. data/spec/extensions/dataset_source_alias_spec.rb +0 -51
  118. data/spec/extensions/date_arithmetic_spec.rb +0 -181
  119. data/spec/extensions/datetime_parse_to_time_spec.rb +0 -169
  120. data/spec/extensions/def_dataset_method_spec.rb +0 -100
  121. data/spec/extensions/defaults_setter_spec.rb +0 -150
  122. data/spec/extensions/delay_add_association_spec.rb +0 -73
  123. data/spec/extensions/dirty_spec.rb +0 -222
  124. data/spec/extensions/duplicate_columns_handler_spec.rb +0 -104
  125. data/spec/extensions/eager_each_spec.rb +0 -62
  126. data/spec/extensions/eager_graph_eager_spec.rb +0 -100
  127. data/spec/extensions/empty_array_consider_nulls_spec.rb +0 -24
  128. data/spec/extensions/empty_failure_backtraces_spec.rb +0 -60
  129. data/spec/extensions/error_splitter_spec.rb +0 -18
  130. data/spec/extensions/error_sql_spec.rb +0 -20
  131. data/spec/extensions/escaped_like_spec.rb +0 -40
  132. data/spec/extensions/eval_inspect_spec.rb +0 -81
  133. data/spec/extensions/exclude_or_null_spec.rb +0 -15
  134. data/spec/extensions/finder_spec.rb +0 -260
  135. data/spec/extensions/force_encoding_spec.rb +0 -126
  136. data/spec/extensions/freeze_datasets_spec.rb +0 -31
  137. data/spec/extensions/graph_each_spec.rb +0 -113
  138. data/spec/extensions/hook_class_methods_spec.rb +0 -402
  139. data/spec/extensions/identifier_mangling_spec.rb +0 -201
  140. data/spec/extensions/implicit_subquery_spec.rb +0 -58
  141. data/spec/extensions/index_caching_spec.rb +0 -66
  142. data/spec/extensions/inflector_spec.rb +0 -183
  143. data/spec/extensions/input_transformer_spec.rb +0 -69
  144. data/spec/extensions/insert_conflict_spec.rb +0 -103
  145. data/spec/extensions/insert_returning_select_spec.rb +0 -72
  146. data/spec/extensions/instance_filters_spec.rb +0 -79
  147. data/spec/extensions/instance_hooks_spec.rb +0 -246
  148. data/spec/extensions/integer64_spec.rb +0 -22
  149. data/spec/extensions/inverted_subsets_spec.rb +0 -33
  150. data/spec/extensions/json_serializer_spec.rb +0 -346
  151. data/spec/extensions/lazy_attributes_spec.rb +0 -183
  152. data/spec/extensions/list_spec.rb +0 -291
  153. data/spec/extensions/looser_typecasting_spec.rb +0 -43
  154. data/spec/extensions/many_through_many_spec.rb +0 -2177
  155. data/spec/extensions/migration_spec.rb +0 -864
  156. data/spec/extensions/modification_detection_spec.rb +0 -93
  157. data/spec/extensions/mssql_optimistic_locking_spec.rb +0 -92
  158. data/spec/extensions/named_timezones_spec.rb +0 -218
  159. data/spec/extensions/nested_attributes_spec.rb +0 -815
  160. data/spec/extensions/null_dataset_spec.rb +0 -85
  161. data/spec/extensions/optimistic_locking_spec.rb +0 -127
  162. data/spec/extensions/pagination_spec.rb +0 -116
  163. data/spec/extensions/pg_array_associations_spec.rb +0 -802
  164. data/spec/extensions/pg_array_ops_spec.rb +0 -144
  165. data/spec/extensions/pg_array_spec.rb +0 -398
  166. data/spec/extensions/pg_auto_constraint_validations_spec.rb +0 -209
  167. data/spec/extensions/pg_enum_spec.rb +0 -118
  168. data/spec/extensions/pg_extended_date_support_spec.rb +0 -126
  169. data/spec/extensions/pg_hstore_ops_spec.rb +0 -238
  170. data/spec/extensions/pg_hstore_spec.rb +0 -219
  171. data/spec/extensions/pg_inet_ops_spec.rb +0 -102
  172. data/spec/extensions/pg_inet_spec.rb +0 -72
  173. data/spec/extensions/pg_interval_spec.rb +0 -103
  174. data/spec/extensions/pg_json_ops_spec.rb +0 -356
  175. data/spec/extensions/pg_json_spec.rb +0 -451
  176. data/spec/extensions/pg_loose_count_spec.rb +0 -23
  177. data/spec/extensions/pg_range_ops_spec.rb +0 -60
  178. data/spec/extensions/pg_range_spec.rb +0 -600
  179. data/spec/extensions/pg_row_ops_spec.rb +0 -61
  180. data/spec/extensions/pg_row_plugin_spec.rb +0 -60
  181. data/spec/extensions/pg_row_spec.rb +0 -363
  182. data/spec/extensions/pg_static_cache_updater_spec.rb +0 -93
  183. data/spec/extensions/pg_timestamptz_spec.rb +0 -17
  184. data/spec/extensions/prepared_statements_safe_spec.rb +0 -66
  185. data/spec/extensions/prepared_statements_spec.rb +0 -177
  186. data/spec/extensions/pretty_table_spec.rb +0 -123
  187. data/spec/extensions/query_spec.rb +0 -94
  188. data/spec/extensions/rcte_tree_spec.rb +0 -387
  189. data/spec/extensions/round_timestamps_spec.rb +0 -39
  190. data/spec/extensions/s_spec.rb +0 -60
  191. data/spec/extensions/schema_caching_spec.rb +0 -64
  192. data/spec/extensions/schema_dumper_spec.rb +0 -870
  193. data/spec/extensions/select_remove_spec.rb +0 -38
  194. data/spec/extensions/sequel_4_dataset_methods_spec.rb +0 -121
  195. data/spec/extensions/serialization_modification_detection_spec.rb +0 -98
  196. data/spec/extensions/serialization_spec.rb +0 -365
  197. data/spec/extensions/server_block_spec.rb +0 -135
  198. data/spec/extensions/server_logging_spec.rb +0 -45
  199. data/spec/extensions/sharding_spec.rb +0 -197
  200. data/spec/extensions/shared_caching_spec.rb +0 -151
  201. data/spec/extensions/single_table_inheritance_spec.rb +0 -347
  202. data/spec/extensions/singular_table_names_spec.rb +0 -22
  203. data/spec/extensions/skip_create_refresh_spec.rb +0 -18
  204. data/spec/extensions/spec_helper.rb +0 -70
  205. data/spec/extensions/split_array_nil_spec.rb +0 -24
  206. data/spec/extensions/split_values_spec.rb +0 -57
  207. data/spec/extensions/sql_comments_spec.rb +0 -33
  208. data/spec/extensions/sql_expr_spec.rb +0 -59
  209. data/spec/extensions/static_cache_cache_spec.rb +0 -35
  210. data/spec/extensions/static_cache_spec.rb +0 -471
  211. data/spec/extensions/string_agg_spec.rb +0 -90
  212. data/spec/extensions/string_date_time_spec.rb +0 -95
  213. data/spec/extensions/string_stripper_spec.rb +0 -68
  214. data/spec/extensions/subclasses_spec.rb +0 -79
  215. data/spec/extensions/subset_conditions_spec.rb +0 -38
  216. data/spec/extensions/symbol_aref_refinement_spec.rb +0 -28
  217. data/spec/extensions/symbol_as_refinement_spec.rb +0 -21
  218. data/spec/extensions/synchronize_sql_spec.rb +0 -124
  219. data/spec/extensions/table_select_spec.rb +0 -83
  220. data/spec/extensions/tactical_eager_loading_spec.rb +0 -402
  221. data/spec/extensions/thread_local_timezones_spec.rb +0 -67
  222. data/spec/extensions/throw_failures_spec.rb +0 -74
  223. data/spec/extensions/timestamps_spec.rb +0 -209
  224. data/spec/extensions/to_dot_spec.rb +0 -153
  225. data/spec/extensions/touch_spec.rb +0 -226
  226. data/spec/extensions/tree_spec.rb +0 -334
  227. data/spec/extensions/typecast_on_load_spec.rb +0 -86
  228. data/spec/extensions/unlimited_update_spec.rb +0 -21
  229. data/spec/extensions/update_or_create_spec.rb +0 -83
  230. data/spec/extensions/update_primary_key_spec.rb +0 -105
  231. data/spec/extensions/update_refresh_spec.rb +0 -59
  232. data/spec/extensions/uuid_spec.rb +0 -101
  233. data/spec/extensions/validate_associated_spec.rb +0 -52
  234. data/spec/extensions/validation_class_methods_spec.rb +0 -1040
  235. data/spec/extensions/validation_contexts_spec.rb +0 -31
  236. data/spec/extensions/validation_helpers_spec.rb +0 -525
  237. data/spec/extensions/whitelist_security_spec.rb +0 -157
  238. data/spec/extensions/xml_serializer_spec.rb +0 -213
  239. data/spec/files/bad_down_migration/001_create_alt_basic.rb +0 -4
  240. data/spec/files/bad_down_migration/002_create_alt_advanced.rb +0 -4
  241. data/spec/files/bad_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  242. data/spec/files/bad_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  243. data/spec/files/bad_timestamped_migrations/1273253853_3_create_users.rb +0 -3
  244. data/spec/files/bad_up_migration/001_create_alt_basic.rb +0 -4
  245. data/spec/files/bad_up_migration/002_create_alt_advanced.rb +0 -3
  246. data/spec/files/convert_to_timestamp_migrations/001_create_sessions.rb +0 -9
  247. data/spec/files/convert_to_timestamp_migrations/002_create_nodes.rb +0 -9
  248. data/spec/files/convert_to_timestamp_migrations/003_3_create_users.rb +0 -4
  249. data/spec/files/convert_to_timestamp_migrations/1273253850_create_artists.rb +0 -9
  250. data/spec/files/convert_to_timestamp_migrations/1273253852_create_albums.rb +0 -9
  251. data/spec/files/double_migration/001_create_sessions.rb +0 -9
  252. data/spec/files/double_migration/002_create_nodes.rb +0 -19
  253. data/spec/files/double_migration/003_3_create_users.rb +0 -4
  254. data/spec/files/duplicate_integer_migrations/001_create_alt_advanced.rb +0 -4
  255. data/spec/files/duplicate_integer_migrations/001_create_alt_basic.rb +0 -4
  256. data/spec/files/duplicate_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  257. data/spec/files/duplicate_timestamped_migrations/1273253853_create_nodes.rb +0 -9
  258. data/spec/files/duplicate_timestamped_migrations/1273253853_create_users.rb +0 -4
  259. data/spec/files/empty_migration/001_create_sessions.rb +0 -9
  260. data/spec/files/empty_migration/002_create_nodes.rb +0 -0
  261. data/spec/files/empty_migration/003_3_create_users.rb +0 -4
  262. data/spec/files/integer_migrations/001_create_sessions.rb +0 -9
  263. data/spec/files/integer_migrations/002_create_nodes.rb +0 -9
  264. data/spec/files/integer_migrations/003_3_create_users.rb +0 -4
  265. data/spec/files/interleaved_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  266. data/spec/files/interleaved_timestamped_migrations/1273253850_create_artists.rb +0 -9
  267. data/spec/files/interleaved_timestamped_migrations/1273253851_create_nodes.rb +0 -9
  268. data/spec/files/interleaved_timestamped_migrations/1273253852_create_albums.rb +0 -9
  269. data/spec/files/interleaved_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  270. data/spec/files/missing_integer_migrations/001_create_alt_basic.rb +0 -4
  271. data/spec/files/missing_integer_migrations/003_create_alt_advanced.rb +0 -4
  272. data/spec/files/missing_timestamped_migrations/1273253849_create_sessions.rb +0 -9
  273. data/spec/files/missing_timestamped_migrations/1273253853_3_create_users.rb +0 -4
  274. data/spec/files/reversible_migrations/001_reversible.rb +0 -5
  275. data/spec/files/reversible_migrations/002_reversible.rb +0 -5
  276. data/spec/files/reversible_migrations/003_reversible.rb +0 -5
  277. data/spec/files/reversible_migrations/004_reversible.rb +0 -5
  278. data/spec/files/reversible_migrations/005_reversible.rb +0 -10
  279. data/spec/files/reversible_migrations/006_reversible.rb +0 -10
  280. data/spec/files/reversible_migrations/007_reversible.rb +0 -10
  281. data/spec/files/timestamped_migrations/1273253849_create_sessions.rb +0 -9
  282. data/spec/files/timestamped_migrations/1273253851_create_nodes.rb +0 -9
  283. data/spec/files/timestamped_migrations/1273253853_3_create_users.rb +0 -4
  284. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +0 -4
  285. data/spec/files/transaction_specified_migrations/002_create_basic.rb +0 -4
  286. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +0 -3
  287. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +0 -3
  288. data/spec/files/uppercase_timestamped_migrations/1273253849_CREATE_SESSIONS.RB +0 -9
  289. data/spec/files/uppercase_timestamped_migrations/1273253851_CREATE_NODES.RB +0 -9
  290. data/spec/files/uppercase_timestamped_migrations/1273253853_3_CREATE_USERS.RB +0 -4
  291. data/spec/guards_helper.rb +0 -59
  292. data/spec/integration/associations_test.rb +0 -2597
  293. data/spec/integration/database_test.rb +0 -113
  294. data/spec/integration/dataset_test.rb +0 -2037
  295. data/spec/integration/eager_loader_test.rb +0 -687
  296. data/spec/integration/migrator_test.rb +0 -262
  297. data/spec/integration/model_test.rb +0 -203
  298. data/spec/integration/plugin_test.rb +0 -2423
  299. data/spec/integration/prepared_statement_test.rb +0 -405
  300. data/spec/integration/schema_test.rb +0 -903
  301. data/spec/integration/spec_helper.rb +0 -71
  302. data/spec/integration/timezone_test.rb +0 -86
  303. data/spec/integration/transaction_test.rb +0 -603
  304. data/spec/integration/type_test.rb +0 -127
  305. data/spec/model/association_reflection_spec.rb +0 -803
  306. data/spec/model/associations_spec.rb +0 -4738
  307. data/spec/model/base_spec.rb +0 -875
  308. data/spec/model/class_dataset_methods_spec.rb +0 -146
  309. data/spec/model/dataset_methods_spec.rb +0 -198
  310. data/spec/model/eager_loading_spec.rb +0 -2377
  311. data/spec/model/hooks_spec.rb +0 -370
  312. data/spec/model/inflector_spec.rb +0 -26
  313. data/spec/model/model_spec.rb +0 -956
  314. data/spec/model/plugins_spec.rb +0 -429
  315. data/spec/model/record_spec.rb +0 -2118
  316. data/spec/model/spec_helper.rb +0 -46
  317. data/spec/model/validations_spec.rb +0 -220
  318. data/spec/model_no_assoc_spec.rb +0 -1
  319. data/spec/model_spec.rb +0 -1
  320. data/spec/plugin_spec.rb +0 -1
  321. data/spec/sequel_coverage.rb +0 -15
  322. data/spec/sequel_warning.rb +0 -5
  323. data/spec/spec_config.rb +0 -12
@@ -1,52 +0,0 @@
1
- require_relative "spec_helper"
2
- require 'logger'
3
-
4
- describe "caller_logging extension" do
5
- before do
6
- @db = Sequel.mock(:extensions=>[:caller_logging])
7
- @log_stream = StringIO.new
8
- @db.loggers << Logger.new(@log_stream)
9
- @ds = @db[:items]
10
- end
11
-
12
- exec_sql_line = __LINE__ + 2
13
- def exec_sql(sql)
14
- @db[sql].all
15
- end
16
-
17
- it "should log caller information, skipping internal Sequel code" do
18
- exec_sql("SELECT * FROM items")
19
- @log_stream.rewind
20
- lines = @log_stream.read.split("\n")
21
- lines.length.must_equal 1
22
- lines[0].must_match(/ \(source: #{__FILE__}:#{exec_sql_line}:in `exec_sql'\) SELECT \* FROM items\z/)
23
- end
24
-
25
- it "should allow formatting of caller information" do
26
- @db.caller_logging_formatter = lambda{|line| line.sub(/\A.+(caller_logging_spec\.rb:\d+).+\z/, '\1:')}
27
- exec_sql("SELECT * FROM items")
28
- @log_stream.rewind
29
- lines = @log_stream.read.split("\n")
30
- lines.length.must_equal 1
31
- lines[0].must_match(/ caller_logging_spec\.rb:#{exec_sql_line}: SELECT \* FROM items\z/)
32
- end
33
-
34
- it "should allow ignoring additional caller lines in application" do
35
- @db.caller_logging_ignore = /exec_sql/
36
- exec_sql("SELECT * FROM items"); line = __LINE__
37
- @log_stream.rewind
38
- lines = @log_stream.read.split("\n")
39
- lines.length.must_equal 1
40
- lines[0].must_match(/ \(source: #{__FILE__}:#{line}:in `block.+\) SELECT \* FROM items\z/)
41
- end
42
-
43
- it "should not log caller information if all callers lines are filtered" do
44
- @db.caller_logging_ignore = /./
45
- exec_sql("SELECT * FROM items")
46
- @log_stream.rewind
47
- lines = @log_stream.read.split("\n")
48
- lines.length.must_equal 1
49
- lines[0].must_match(/ SELECT \* FROM items\z/)
50
- lines[0].wont_match(/ source: #{__FILE__}/)
51
- end
52
- end
@@ -1,750 +0,0 @@
1
- require_relative "spec_helper"
2
-
3
- describe "class_table_inheritance plugin" do
4
- before do
5
- @db = Sequel.mock(:numrows=>1, :autoid=>proc{|sql| 1})
6
- def @db.supports_schema_parsing?() true end
7
- def @db.schema(table, opts={})
8
- {:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string, :allow_null=>false}], [:kind, {:type=>:string}]],
9
- :managers=>[[:id, {:type=>:integer}], [:num_staff, {:type=>:integer, :allow_null=>false}] ],
10
- :executives=>[[:id, {:type=>:integer}], [:num_managers, {:type=>:integer}]],
11
- :staff=>[[:id, {:type=>:integer}], [:manager_id, {:type=>:integer}]],
12
- }[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
13
- end
14
- @db.extend_datasets do
15
- def columns
16
- {[:employees]=>[:id, :name, :kind],
17
- [:managers]=>[:id, :num_staff],
18
- [:executives]=>[:id, :num_managers],
19
- [:staff]=>[:id, :manager_id],
20
- [:employees, :managers]=>[:id, :name, :kind, :num_staff],
21
- [:employees, :managers, :executives]=>[:id, :name, :kind, :num_staff, :num_managers],
22
- [:employees, :staff]=>[:id, :name, :kind, :manager_id],
23
- }[opts[:from] + (opts[:join] || []).map{|x| x.table}]
24
- end
25
- end
26
- base = Sequel::Model(@db)
27
- base.plugin :auto_validations if @use_auto_validations
28
- class ::Employee < base
29
- def _save_refresh; @values[:id] = 1 end
30
- def self.columns
31
- dataset.columns || dataset.opts[:from].first.expression.columns
32
- end
33
- plugin :class_table_inheritance, :key=>:kind, :table_map=>{:Staff=>:staff}
34
- end
35
- class ::Manager < Employee
36
- one_to_many :staff_members, :class=>:Staff
37
- end
38
- class ::Executive < Manager
39
- end
40
- class ::Ceo < Executive
41
- end
42
- class ::Staff < Employee
43
- many_to_one :manager
44
- end
45
- class ::Intern < Employee
46
- end
47
- @ds = Employee.dataset
48
- @db.sqls
49
- end
50
- after do
51
- [:Intern, :Ceo, :Executive, :Manager, :Staff, :Employee].each{|s| Object.send(:remove_const, s)}
52
- end
53
-
54
- it "should freeze CTI information when freezing model class" do
55
- Employee.freeze
56
- Employee.cti_models.frozen?.must_equal true
57
- Employee.cti_tables.frozen?.must_equal true
58
- Employee.cti_instance_dataset.frozen?.must_equal true
59
- Employee.cti_table_columns.frozen?.must_equal true
60
- Employee.cti_table_map.frozen?.must_equal true
61
- end
62
-
63
- it "should not attempt to use prepared statements" do
64
- Manager.plugin :prepared_statements
65
- Manager.load(:id=>1, :kind=>'Manager', :num_staff=>2).save
66
- @db.sqls.must_equal ["UPDATE employees SET kind = 'Manager' WHERE (id = 1)", "UPDATE managers SET num_staff = 2 WHERE (id = 1)"]
67
-
68
- Employee.plugin :prepared_statements
69
- Employee.load(:id=>2, :kind=>'Employee').save
70
- @db.sqls.must_equal ["UPDATE employees SET kind = 'Employee' WHERE (id = 2)"]
71
- end
72
-
73
- it "#cti_models.first should be the model that loaded the plugin" do
74
- Executive.cti_models.first.must_equal Employee
75
- end
76
-
77
- it "should have simple_table = nil for all subclasses" do
78
- Manager.simple_table.must_be_nil
79
- Executive.simple_table.must_be_nil
80
- Ceo.simple_table.must_be_nil
81
- Staff.simple_table.must_be_nil
82
- Intern.simple_table.must_be_nil
83
- end
84
-
85
- it "should have working row_proc if using set_dataset in subclass to remove columns" do
86
- Manager.set_dataset(Manager.dataset.select(*(Manager.columns - [:blah])))
87
- Manager.dataset = Manager.dataset.with_fetch(:id=>1, :kind=>'Ceo')
88
- Manager[1].must_equal Ceo.load(:id=>1, :kind=>'Ceo')
89
- end
90
-
91
- it "should use a subquery in subclasses" do
92
- Employee.dataset.sql.must_equal 'SELECT * FROM employees'
93
- Manager.dataset.sql.must_equal 'SELECT * FROM (SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id)) AS employees'
94
- Executive.dataset.sql.must_equal 'SELECT * FROM (SELECT employees.id, employees.name, employees.kind, managers.num_staff, executives.num_managers FROM employees INNER JOIN managers ON (managers.id = employees.id) INNER JOIN executives ON (executives.id = managers.id)) AS employees'
95
- Ceo.dataset.sql.must_equal 'SELECT * FROM (SELECT employees.id, employees.name, employees.kind, managers.num_staff, executives.num_managers FROM employees INNER JOIN managers ON (managers.id = employees.id) INNER JOIN executives ON (executives.id = managers.id) WHERE (employees.kind IN (\'Ceo\'))) AS employees'
96
- Staff.dataset.sql.must_equal 'SELECT * FROM (SELECT employees.id, employees.name, employees.kind, staff.manager_id FROM employees INNER JOIN staff ON (staff.id = employees.id)) AS employees'
97
- Intern.dataset.sql.must_equal 'SELECT * FROM employees WHERE (employees.kind IN (\'Intern\'))'
98
- end
99
-
100
- it "should return rows with the correct class based on the polymorphic_key value" do
101
- @ds.with_fetch([{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}, {:kind=>'Staff'}, {:kind=>'Intern'}]).all.collect{|x| x.class}.must_equal [Employee, Manager, Executive, Ceo, Staff, Intern]
102
- end
103
-
104
- it "should return rows with the correct class based on the polymorphic_key value for subclasses" do
105
- Manager.dataset.with_fetch([{:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}]).all.collect{|x| x.class}.must_equal [Manager, Executive, Ceo]
106
- end
107
-
108
- it "should have refresh return all columns in subclass after loading from superclass" do
109
- Employee.dataset = Employee.dataset.with_fetch([{:id=>1, :name=>'A', :kind=>'Ceo'}])
110
- Ceo.dataset = Ceo.dataset.with_fetch([{:id=>1, :name=>'A', :kind=>'Ceo', :num_staff=>3, :num_managers=>2}])
111
- a = Employee.first
112
- a.class.must_equal Ceo
113
- a.values.must_equal(:id=>1, :name=>'A', :kind=>'Ceo')
114
- a.refresh.values.must_equal(:id=>1, :name=>'A', :kind=>'Ceo', :num_staff=>3, :num_managers=>2)
115
- @db.sqls.must_equal ["SELECT * FROM employees LIMIT 1",
116
- "SELECT * FROM (SELECT employees.id, employees.name, employees.kind, managers.num_staff, executives.num_managers FROM employees INNER JOIN managers ON (managers.id = employees.id) INNER JOIN executives ON (executives.id = managers.id) WHERE (employees.kind IN ('Ceo'))) AS employees WHERE (id = 1) LIMIT 1"]
117
- end
118
-
119
- describe "with auto_validations plugin" do
120
- before(:all) do
121
- @use_auto_validations = true
122
- end
123
-
124
- it "should work" do
125
- e = Employee.new
126
- e.valid?.must_equal false
127
- e.errors.must_equal(:name=>["is not present"])
128
-
129
- e = Manager.new
130
- e.valid?.must_equal false
131
- e.errors.must_equal(:name=>["is not present"], :num_staff=>["is not present"])
132
-
133
- e = Executive.new
134
- e.valid?.must_equal false
135
- e.errors.must_equal(:name=>["is not present"], :num_staff=>["is not present"])
136
- end
137
- end
138
-
139
- it "should return rows with the current class if sti_key is nil" do
140
- Employee.plugin :class_table_inheritance
141
- Employee.dataset.with_fetch([{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}, {:kind=>'Staff'}, {:kind=>'Intern'}]).all.map{|x| x.class}.must_equal [Employee, Employee, Employee, Employee, Employee, Employee]
142
- end
143
-
144
- it "should return rows with the current class if sti_key is nil in subclasses" do
145
- Employee.plugin :class_table_inheritance
146
- Object.send(:remove_const, :Executive)
147
- Object.send(:remove_const, :Manager)
148
- class ::Manager < Employee; end
149
- class ::Executive < Manager; end
150
- Manager.dataset.with_fetch([{:kind=>'Manager'}, {:kind=>'Executive'}]).all.map{|x| x.class}.must_equal [Manager, Manager]
151
- end
152
-
153
- it "should handle a model map with integer values" do
154
- Employee.plugin :class_table_inheritance, :key=>:kind, :model_map=>{0=>:Employee, 1=>:Manager, 2=>:Executive, 3=>:Ceo, 4=>:Intern}
155
- Object.send(:remove_const, :Intern)
156
- Object.send(:remove_const, :Ceo)
157
- Object.send(:remove_const, :Executive)
158
- Object.send(:remove_const, :Manager)
159
- class ::Intern < Employee; end
160
- class ::Manager < Employee; end
161
- class ::Executive < Manager; end
162
- class ::Ceo < Executive; end
163
- Employee.dataset = Employee.dataset.with_fetch([{:kind=>nil},{:kind=>0},{:kind=>1}, {:kind=>2}, {:kind=>3}, {:kind=>4}])
164
- Employee.all.collect{|x| x.class}.must_equal [Employee, Employee, Manager, Executive, Ceo, Intern]
165
- Manager.dataset = Manager.dataset.with_fetch([{:kind=>nil},{:kind=>0},{:kind=>1}, {:kind=>2}, {:kind=>3}])
166
- Manager.all.collect{|x| x.class}.must_equal [Manager, Employee, Manager, Executive, Ceo]
167
- end
168
-
169
- it "should fallback to the main class if the given class does not exist" do
170
- @ds.with_fetch([{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Blah'}, {:kind=>'Staff'}]).all.map{|x| x.class}.must_equal [Employee, Manager, Employee, Staff]
171
- end
172
-
173
- it "should fallback to the main class if the given class does not exist in subclasses" do
174
- Manager.dataset.with_fetch([{:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}, {:kind=>'Blah'}]).all.map{|x| x.class}.must_equal [Manager, Executive, Ceo, Manager]
175
- end
176
-
177
- it "should sets the model class name for the key when creating new parent class records" do
178
- Employee.create
179
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Employee')"]
180
- end
181
-
182
- it "should sets the model class name for the key when creating new class records for subclass without separate table" do
183
- Intern.create
184
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Intern')"]
185
- end
186
-
187
- it "should sets the model class name for the key when creating new subclass records" do
188
- Ceo.create
189
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Ceo')",
190
- "INSERT INTO managers (id) VALUES (1)",
191
- "INSERT INTO executives (id) VALUES (1)"]
192
- end
193
-
194
- it "should ignore existing sti_key value when creating new records" do
195
- Employee.create(:kind=>'Manager')
196
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Employee')"]
197
- end
198
-
199
- it "should ignore existing sti_key value in subclasses" do
200
- Manager.create(:kind=>'Executive')
201
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Manager')",
202
- "INSERT INTO managers (id) VALUES (1)"]
203
- end
204
-
205
- it "should handle validations on the type column field" do
206
- o = Employee.new
207
- def o.validate
208
- errors.add(:kind, 'not present') unless kind
209
- end
210
- o.valid?.must_equal true
211
- end
212
-
213
- it "should set the type column field even when not validating" do
214
- Employee.new.save(:validate=>false)
215
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Employee')"]
216
- end
217
-
218
- it "should allow specifying a map of names to tables to override implicit mapping" do
219
- Manager.dataset.sql.must_equal 'SELECT * FROM (SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id)) AS employees'
220
- Staff.dataset.sql.must_equal 'SELECT * FROM (SELECT employees.id, employees.name, employees.kind, staff.manager_id FROM employees INNER JOIN staff ON (staff.id = employees.id)) AS employees'
221
- end
222
-
223
- it "should lazily load attributes for columns in subclass tables" do
224
- Manager.dataset = Manager.dataset.with_fetch(:id=>1, :name=>'J', :kind=>'Ceo', :num_staff=>2)
225
- m = Manager[1]
226
- @db.sqls.must_equal ['SELECT * FROM (SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id)) AS employees WHERE (id = 1) LIMIT 1']
227
- @db.fetch = {:num_managers=>3}
228
- m.must_be_kind_of Ceo
229
- m.num_managers.must_equal 3
230
- @db.sqls.must_equal ['SELECT employees.num_managers FROM (SELECT employees.id, employees.name, employees.kind, managers.num_staff, executives.num_managers FROM employees INNER JOIN managers ON (managers.id = employees.id) INNER JOIN executives ON (executives.id = managers.id)) AS employees WHERE (employees.id = 1) LIMIT 1']
231
- m.values.must_equal(:id=>1, :name=>'J', :kind=>'Ceo', :num_staff=>2, :num_managers=>3)
232
- end
233
-
234
- it "should lazily load columns in middle classes correctly when loaded from parent class" do
235
- Employee.dataset = Employee.dataset.with_fetch(:id=>1, :kind=>'Ceo')
236
- @db.fetch = [[:num_staff=>2]]
237
- e = Employee[1]
238
- e.must_be_kind_of(Ceo)
239
- @db.sqls.must_equal ["SELECT * FROM employees WHERE (id = 1) LIMIT 1"]
240
- e.num_staff.must_equal 2
241
- @db.sqls.must_equal ["SELECT employees.num_staff FROM (SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id)) AS employees WHERE (employees.id = 1) LIMIT 1"]
242
- end
243
-
244
- it "should eagerly load lazily columns in subclasses when loaded from parent class" do
245
- Employee.dataset = Employee.dataset.with_fetch(:id=>1, :kind=>'Ceo')
246
- @db.fetch = [[{:id=>1, :num_staff=>2}], [{:id=>1, :num_managers=>3}]]
247
- e = Employee.all.first
248
- e.must_be_kind_of(Ceo)
249
- @db.sqls.must_equal ["SELECT * FROM employees"]
250
- e.num_staff.must_equal 2
251
- @db.sqls.must_equal ["SELECT employees.id, employees.num_staff FROM (SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id)) AS employees WHERE (employees.id IN (1))"]
252
- e.num_managers.must_equal 3
253
- @db.sqls.must_equal ['SELECT employees.id, employees.num_managers FROM (SELECT employees.id, employees.name, employees.kind, managers.num_staff, executives.num_managers FROM employees INNER JOIN managers ON (managers.id = employees.id) INNER JOIN executives ON (executives.id = managers.id)) AS employees WHERE (employees.id IN (1))']
254
- end
255
-
256
- it "should include schema for columns for tables for ancestor classes" do
257
- Employee.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string, :allow_null=>false}, :kind=>{:type=>:string})
258
- Manager.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string, :allow_null=>false}, :kind=>{:type=>:string}, :num_staff=>{:type=>:integer, :allow_null=>false})
259
- Executive.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string, :allow_null=>false}, :kind=>{:type=>:string}, :num_staff=>{:type=>:integer, :allow_null=>false}, :num_managers=>{:type=>:integer})
260
- Staff.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string, :allow_null=>false}, :kind=>{:type=>:string}, :manager_id=>{:type=>:integer})
261
- Intern.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string, :allow_null=>false}, :kind=>{:type=>:string})
262
- end
263
-
264
- it "should use the correct primary key (which should have the same name in all subclasses)" do
265
- [Employee, Manager, Executive, Ceo, Staff, Intern].each{|c| c.primary_key.must_equal :id}
266
- end
267
-
268
- it "should have table_name return the table name of the most specific table" do
269
- Employee.table_name.must_equal :employees
270
- Manager.table_name.must_equal :employees
271
- Executive.table_name.must_equal :employees
272
- Ceo.table_name.must_equal :employees
273
- Staff.table_name.must_equal :employees
274
- Intern.table_name.must_equal :employees
275
- end
276
-
277
- it "should delete the correct rows from all tables when deleting" do
278
- Employee.load(:id=>1).delete
279
- @db.sqls.must_equal ["DELETE FROM employees WHERE (id = 1)"]
280
-
281
- Intern.load(:id=>1).delete
282
- @db.sqls.must_equal ["DELETE FROM employees WHERE (id = 1)"]
283
-
284
- Ceo.load(:id=>1).delete
285
- @db.sqls.must_equal ["DELETE FROM executives WHERE (id = 1)", "DELETE FROM managers WHERE (id = 1)", "DELETE FROM employees WHERE (id = 1)"]
286
- end
287
-
288
- it "should not allow deletion of frozen object" do
289
- [Ceo, Executive, Employee, Manager, Intern].each do |c|
290
- o = c.load(:id=>1)
291
- o.freeze
292
- proc{o.delete}.must_raise(Sequel::Error)
293
- @db.sqls.must_equal []
294
- end
295
- end
296
-
297
- it "should insert the correct rows into all tables when inserting into parent class" do
298
- Employee.create(:name=>'E')
299
- @db.sqls.must_equal ["INSERT INTO employees (name, kind) VALUES ('E', 'Employee')"]
300
- end
301
-
302
- it "should insert the correct rows into all tables when inserting into subclass without separate table" do
303
- Intern.create(:name=>'E')
304
- @db.sqls.must_equal ["INSERT INTO employees (name, kind) VALUES ('E', 'Intern')"]
305
- end
306
-
307
- it "should insert the correct rows into all tables when inserting" do
308
- Ceo.create(:num_managers=>3, :num_staff=>2, :name=>'E')
309
- @db.sqls.must_equal ["INSERT INTO employees (name, kind) VALUES ('E', 'Ceo')",
310
- "INSERT INTO managers (id, num_staff) VALUES (1, 2)",
311
- "INSERT INTO executives (id, num_managers) VALUES (1, 3)"]
312
- end
313
-
314
- it "should insert the correct rows into all tables when inserting when insert_select is supported" do
315
- [Executive, Manager, Employee].each do |klass|
316
- klass.instance_variable_set(:@cti_instance_dataset, klass.cti_instance_dataset.with_extend do
317
- def supports_insert_select?; true; end
318
- def insert_select(v)
319
- db.run(insert_sql(v) + " RETURNING *")
320
- v.merge(:id=>1)
321
- end
322
- end)
323
- end
324
- Ceo.create(:num_managers=>3, :num_staff=>2, :name=>'E')
325
- @db.sqls.must_equal ["INSERT INTO employees (name, kind) VALUES ('E', 'Ceo') RETURNING *",
326
- "INSERT INTO managers (id, num_staff) VALUES (1, 2) RETURNING *",
327
- "INSERT INTO executives (id, num_managers) VALUES (1, 3) RETURNING *"]
328
- end
329
-
330
- it "should insert the correct rows into all tables with a given primary key" do
331
- e = Ceo.new(:num_managers=>3, :num_staff=>2, :name=>'E')
332
- e.id = 2
333
- e.save
334
- @db.sqls.must_equal ["INSERT INTO employees (id, name, kind) VALUES (2, 'E', 'Ceo')",
335
- "INSERT INTO managers (id, num_staff) VALUES (2, 2)",
336
- "INSERT INTO executives (id, num_managers) VALUES (2, 3)"]
337
- end
338
-
339
- it "should update the correct rows in all tables when updating parent class" do
340
- Employee.load(:id=>2).update(:name=>'E')
341
- @db.sqls.must_equal ["UPDATE employees SET name = 'E' WHERE (id = 2)"]
342
- end
343
-
344
- it "should update the correct rows in all tables when updating subclass without separate table" do
345
- Intern.load(:id=>2).update(:name=>'E')
346
- @db.sqls.must_equal ["UPDATE employees SET name = 'E' WHERE (id = 2)"]
347
- end
348
-
349
- it "should update the correct rows in all tables when updating" do
350
- Ceo.load(:id=>2).update(:num_managers=>3, :num_staff=>2, :name=>'E')
351
- @db.sqls.must_equal ["UPDATE employees SET name = 'E' WHERE (id = 2)", "UPDATE managers SET num_staff = 2 WHERE (id = 2)", "UPDATE executives SET num_managers = 3 WHERE (id = 2)"]
352
- end
353
-
354
- it "should raise error if one of the updates does not update a single row" do
355
- @db.numrows = [1, 0]
356
- proc{Ceo.load(:id=>2).update(:num_managers=>3, :num_staff=>2, :name=>'E')}.must_raise Sequel::NoExistingObject
357
- @db.sqls.must_equal ["UPDATE employees SET name = 'E' WHERE (id = 2)", "UPDATE managers SET num_staff = 2 WHERE (id = 2)"]
358
- end
359
-
360
- it "should handle many_to_one relationships correctly" do
361
- Manager.dataset = Manager.dataset.with_fetch(:id=>3, :name=>'E', :kind=>'Ceo', :num_managers=>3)
362
- Staff.load(:manager_id=>3).manager.must_equal Ceo.load(:id=>3, :name=>'E', :kind=>'Ceo', :num_managers=>3)
363
- @db.sqls.must_equal ['SELECT * FROM (SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id)) AS employees WHERE (id = 3) LIMIT 1']
364
- end
365
-
366
- it "should handle one_to_many relationships correctly" do
367
- Staff.dataset = Staff.dataset.with_fetch(:id=>1, :name=>'S', :kind=>'Staff', :manager_id=>3)
368
- Ceo.load(:id=>3).staff_members.must_equal [Staff.load(:id=>1, :name=>'S', :kind=>'Staff', :manager_id=>3)]
369
- @db.sqls.must_equal ['SELECT * FROM (SELECT employees.id, employees.name, employees.kind, staff.manager_id FROM employees INNER JOIN staff ON (staff.id = employees.id)) AS employees WHERE (employees.manager_id = 3)']
370
- end
371
- end
372
-
373
- describe "class_table_inheritance plugin without sti_key with :alias option" do
374
- before do
375
- @db = Sequel.mock(:numrows=>1, :autoid=>proc{|sql| 1})
376
- def @db.supports_schema_parsing?() true end
377
- def @db.schema(table, opts={})
378
- {:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}]],
379
- :managers=>[[:id, {:type=>:integer}], [:num_staff, {:type=>:integer}]],
380
- :executives=>[[:id, {:type=>:integer}], [:num_managers, {:type=>:integer}]],
381
- :staff=>[[:id, {:type=>:integer}], [:manager_id, {:type=>:integer}]],
382
- }[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
383
- end
384
- @db.extend_datasets do
385
- def columns
386
- {[:employees]=>[:id, :name],
387
- [:managers]=>[:id, :num_staff],
388
- [:executives]=>[:id, :num_managers],
389
- [:staff]=>[:id, :manager_id],
390
- [:employees, :managers]=>[:id, :name, :num_staff],
391
- [:employees, :managers, :executives]=>[:id, :name, :num_staff, :num_managers],
392
- [:employees, :staff]=>[:id, :name, :manager_id],
393
- }[opts[:from] + (opts[:join] || []).map{|x| x.table}]
394
- end
395
- end
396
- class ::Employee < Sequel::Model(@db)
397
- def _save_refresh; @values[:id] = 1 end
398
- def self.columns
399
- dataset.columns || dataset.opts[:from].first.expression.columns
400
- end
401
- plugin :class_table_inheritance, :table_map=>{:Staff=>:staff}, :alias=>:emps
402
- end
403
- class ::Manager < Employee
404
- one_to_many :staff_members, :class=>:Staff
405
- end
406
- class ::Executive < Manager
407
- end
408
- class ::Staff < Employee
409
- many_to_one :manager
410
- end
411
- @ds = Employee.dataset
412
- @db.sqls
413
- end
414
- after do
415
- Object.send(:remove_const, :Executive)
416
- Object.send(:remove_const, :Manager)
417
- Object.send(:remove_const, :Staff)
418
- Object.send(:remove_const, :Employee)
419
- end
420
-
421
- it "should have simple_table = nil for all subclasses" do
422
- Manager.simple_table.must_be_nil
423
- Executive.simple_table.must_be_nil
424
- Staff.simple_table.must_be_nil
425
- end
426
-
427
- it "should have working row_proc if using set_dataset in subclass to remove columns" do
428
- Manager.set_dataset(Manager.dataset.select(*(Manager.columns - [:blah])))
429
- Manager.dataset = Manager.dataset.with_fetch(:id=>1)
430
- Manager[1].must_equal Manager.load(:id=>1)
431
- end
432
-
433
- it "should use a joined dataset in subclasses" do
434
- Employee.dataset.sql.must_equal 'SELECT * FROM employees'
435
- Manager.dataset.sql.must_equal 'SELECT * FROM (SELECT employees.id, employees.name, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id)) AS emps'
436
- Executive.dataset.sql.must_equal 'SELECT * FROM (SELECT employees.id, employees.name, managers.num_staff, executives.num_managers FROM employees INNER JOIN managers ON (managers.id = employees.id) INNER JOIN executives ON (executives.id = managers.id)) AS emps'
437
- Staff.dataset.sql.must_equal 'SELECT * FROM (SELECT employees.id, employees.name, staff.manager_id FROM employees INNER JOIN staff ON (staff.id = employees.id)) AS emps'
438
- end
439
-
440
- it "should return rows with the current class if sti_key is nil" do
441
- Employee.plugin(:class_table_inheritance)
442
- Employee.dataset = Employee.dataset.with_fetch([{}])
443
- Employee.first.class.must_equal Employee
444
- end
445
-
446
- it "should include schema for columns for tables for ancestor classes" do
447
- Employee.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string})
448
- Manager.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :num_staff=>{:type=>:integer})
449
- Executive.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :num_staff=>{:type=>:integer}, :num_managers=>{:type=>:integer})
450
- Staff.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :manager_id=>{:type=>:integer})
451
- end
452
-
453
- it "should use the correct primary key (which should have the same name in all subclasses)" do
454
- [Employee, Manager, Executive, Staff].each{|c| c.primary_key.must_equal :id}
455
- end
456
-
457
- it "should have table_name return the table name of the most specific table" do
458
- Employee.table_name.must_equal :employees
459
- Manager.table_name.must_equal :emps
460
- Executive.table_name.must_equal :emps
461
- Staff.table_name.must_equal :emps
462
- end
463
-
464
- it "should delete the correct rows from all tables when deleting" do
465
- Executive.load(:id=>1).delete
466
- @db.sqls.must_equal ["DELETE FROM executives WHERE (id = 1)", "DELETE FROM managers WHERE (id = 1)", "DELETE FROM employees WHERE (id = 1)"]
467
- end
468
-
469
- it "should not allow deletion of frozen object" do
470
- o = Executive.load(:id=>1)
471
- o.freeze
472
- proc{o.delete}.must_raise(Sequel::Error)
473
- @db.sqls.must_equal []
474
- end
475
-
476
- it "should insert the correct rows into all tables when inserting" do
477
- Executive.create(:num_managers=>3, :num_staff=>2, :name=>'E')
478
- @db.sqls.must_equal ["INSERT INTO employees (name) VALUES ('E')",
479
- "INSERT INTO managers (id, num_staff) VALUES (1, 2)",
480
- "INSERT INTO executives (id, num_managers) VALUES (1, 3)"]
481
- end
482
-
483
- it "should insert the correct rows into all tables with a given primary key" do
484
- e = Executive.new(:num_managers=>3, :num_staff=>2, :name=>'E')
485
- e.id = 2
486
- e.save
487
- @db.sqls.must_equal ["INSERT INTO employees (id, name) VALUES (2, 'E')",
488
- "INSERT INTO managers (id, num_staff) VALUES (2, 2)",
489
- "INSERT INTO executives (id, num_managers) VALUES (2, 3)"]
490
- end
491
-
492
- it "should update the correct rows in all tables when updating" do
493
- Executive.load(:id=>2).update(:num_managers=>3, :num_staff=>2, :name=>'E')
494
- @db.sqls.must_equal ["UPDATE employees SET name = 'E' WHERE (id = 2)", "UPDATE managers SET num_staff = 2 WHERE (id = 2)", "UPDATE executives SET num_managers = 3 WHERE (id = 2)"]
495
- end
496
-
497
- it "should handle many_to_one relationships correctly" do
498
- Manager.dataset = Manager.dataset.with_fetch(:id=>3, :name=>'E', :num_staff=>3)
499
- Staff.load(:manager_id=>3).manager.must_equal Manager.load(:id=>3, :name=>'E', :num_staff=>3)
500
- @db.sqls.must_equal ['SELECT * FROM (SELECT employees.id, employees.name, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id)) AS emps WHERE (id = 3) LIMIT 1']
501
- end
502
-
503
- it "should handle one_to_many relationships correctly" do
504
- Staff.dataset = Staff.dataset.with_fetch(:id=>1, :name=>'S', :manager_id=>3)
505
- Executive.load(:id=>3).staff_members.must_equal [Staff.load(:id=>1, :name=>'S', :manager_id=>3)]
506
- @db.sqls.must_equal ['SELECT * FROM (SELECT employees.id, employees.name, staff.manager_id FROM employees INNER JOIN staff ON (staff.id = employees.id)) AS emps WHERE (emps.manager_id = 3)']
507
- end
508
- end
509
-
510
- describe "class_table_inheritance plugin with duplicate columns" do
511
- it "should raise error if no columns are explicitly ignored" do
512
- @db = Sequel.mock(:autoid=>proc{|sql| 1})
513
- def @db.supports_schema_parsing?() true end
514
- def @db.schema(table, opts={})
515
- {:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}], [:kind, {:type=>:string}]],
516
- :managers=>[[:id, {:type=>:integer}], [:name, {:type=>:string}]],
517
- }[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
518
- end
519
- @db.extend_datasets do
520
- def columns
521
- {[:employees]=>[:id, :name, :kind],
522
- [:managers]=>[:id, :name],
523
- }[opts[:from] + (opts[:join] || []).map{|x| x.table}]
524
- end
525
- end
526
- class ::Employee < Sequel::Model(@db)
527
- def _save_refresh; @values[:id] = 1 end
528
- def self.columns
529
- dataset.columns || dataset.opts[:from].first.expression.columns
530
- end
531
- plugin :class_table_inheritance
532
- end
533
- proc{class ::Manager < Employee; end}.must_raise Sequel::Error
534
- end
535
-
536
- describe "with certain sub-class columns ignored" do
537
- before do
538
- @db = Sequel.mock(:autoid=>proc{|sql| 1})
539
- def @db.supports_schema_parsing?() true end
540
- def @db.schema(table, opts={})
541
- {:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}], [:kind, {:type=>:string}], [:updated_at, {:type=>:datetime}]],
542
- :managers=>[[:id, {:type=>:integer}], [:num_staff, {:type=>:integer}], [:updated_at, {:type=>:datetime}], [:another_duplicate_column, {:type=>:integer}]],
543
- :executives=>[[:id, {:type=>:integer}], [:num_managers, {:type=>:integer}], [:updated_at, {:type=>:datetime}], [:another_duplicate_column, {:type=>:integer}]],
544
- }[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
545
- end
546
- @db.extend_datasets do
547
- def columns
548
- {[:employees]=>[:id, :name, :kind, :updated_at],
549
- [:managers]=>[:id, :num_staff, :updated_at, :another_duplicate_column],
550
- [:executives]=>[:id, :num_managers, :updated_at, :another_duplicate_column],
551
- [:employees, :managers]=>[:id, :name, :kind, :updated_at, :num_staff],
552
- }[opts[:from] + (opts[:join] || []).map{|x| x.table}]
553
- end
554
- end
555
- class ::Employee < Sequel::Model(@db)
556
- def _save_refresh; @values[:id] = 1 end
557
- def self.columns
558
- dataset.columns || dataset.opts[:from].first.expression.columns
559
- end
560
- plugin :class_table_inheritance, :ignore_subclass_columns=>[:updated_at]
561
- end
562
- class ::Manager < Employee
563
- Manager.cti_ignore_subclass_columns.push(:another_duplicate_column)
564
- end
565
- class ::Executive < Manager; end
566
- end
567
-
568
- it "should not use the ignored column in a sub-class subquery" do
569
- Employee.dataset.sql.must_equal 'SELECT * FROM employees'
570
- Manager.dataset.sql.must_equal 'SELECT * FROM (SELECT employees.id, employees.name, employees.kind, employees.updated_at, managers.num_staff, managers.another_duplicate_column FROM employees INNER JOIN managers ON (managers.id = employees.id)) AS employees'
571
- Executive.dataset.sql.must_equal 'SELECT * FROM (SELECT employees.id, employees.name, employees.kind, employees.updated_at, managers.num_staff, managers.another_duplicate_column, executives.num_managers FROM employees INNER JOIN managers ON (managers.id = employees.id) INNER JOIN executives ON (executives.id = managers.id)) AS employees'
572
- end
573
-
574
- it "should include schema for columns for tables for ancestor classes" do
575
- Employee.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :updated_at=>{:type=>:datetime})
576
- Manager.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :updated_at=>{:type=>:datetime}, :num_staff=>{:type=>:integer}, :another_duplicate_column=>{:type=>:integer})
577
- Executive.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :updated_at=>{:type=>:datetime}, :num_staff=>{:type=>:integer}, :another_duplicate_column=>{:type=>:integer}, :num_managers=>{:type=>:integer})
578
- end
579
-
580
- after do
581
- Object.send(:remove_const, :Executive)
582
- end
583
- end
584
-
585
- after do
586
- Object.send(:remove_const, :Manager)
587
- Object.send(:remove_const, :Employee)
588
- end
589
- end
590
-
591
- describe "class_table_inheritance plugin with dataset defined with QualifiedIdentifier" do
592
- before do
593
- @db = Sequel.mock(:numrows=>1, :autoid=>proc{|sql| 1})
594
- def @db.supports_schema_parsing?() true end
595
- def @db.schema(table, opts={})
596
- {Sequel[:hr][:employees]=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}], [:kind, {:type=>:string}]],
597
- Sequel[:hr][:managers]=>[[:id, {:type=>:integer}]],
598
- Sequel[:hr][:staff]=>[[:id, {:type=>:integer}], [:manager_id, {:type=>:integer}]],
599
- Sequel[:hr][:executives]=>[[:id, {:type=>:integer}], [:num_managers, {:type=>:integer}]],
600
- }[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
601
- end
602
- @db.extend_datasets do
603
- def columns
604
- {[Sequel[:hr][:employees]]=>[:id, :name, :kind],
605
- [Sequel[:hr][:managers]]=>[:id],
606
- [Sequel[:hr][:staff]]=>[:id, :manager_id],
607
- [Sequel[:hr][:employees], Sequel[:hr][:managers]]=>[:id, :name, :kind],
608
- [Sequel[:hr][:employees], Sequel[:hr][:staff]]=>[:id, :name, :kind, :manager_id],
609
- [Sequel[:hr][:employees], Sequel[:hr][:managers], Sequel[:hr][:executives]]=>[:id, :name, :kind, :manager_id, :num_managers],
610
- }[opts[:from] + (opts[:join] || []).map{|x| x.table}]
611
- end
612
- end
613
- end
614
- after do
615
- [:Manager, :Staff, :Employee, :Executive].each{|s| Object.send(:remove_const, s) if Object.const_defined?(s)}
616
- end
617
-
618
- describe "with table_map used to qualify subclasses" do
619
- before do
620
- ::Employee = Class.new(Sequel::Model)
621
- ::Employee.db = @db
622
- ::Employee.set_dataset(Sequel[:hr][:employees])
623
- class ::Employee
624
- def _save_refresh; @values[:id] = 1 end
625
- def self.columns
626
- dataset.columns || dataset.opts[:from].first.expression.columns
627
- end
628
- plugin :class_table_inheritance, :table_map=>{:Manager=>Sequel[:hr][:managers],:Staff=>Sequel[:hr][:staff]}
629
- end
630
- class ::Manager < Employee
631
- one_to_many :staff_members, :class=>:Staff
632
- end
633
- class ::Staff < Employee
634
- many_to_one :manager
635
- end
636
- end
637
-
638
- it "should handle many_to_one relationships correctly" do
639
- Manager.dataset = Manager.dataset.with_fetch(:id=>3, :name=>'E')
640
- Staff.load(:manager_id=>3).manager.must_equal Manager.load(:id=>3, :name=>'E')
641
- @db.sqls.must_equal ['SELECT * FROM (SELECT hr.employees.id, hr.employees.name, hr.employees.kind FROM hr.employees INNER JOIN hr.managers ON (hr.managers.id = hr.employees.id)) AS employees WHERE (id = 3) LIMIT 1']
642
- end
643
-
644
- it "should handle one_to_many relationships correctly" do
645
- Staff.dataset = Staff.dataset.with_fetch(:id=>1, :name=>'S', :manager_id=>3)
646
- Manager.load(:id=>3).staff_members.must_equal [Staff.load(:id=>1, :name=>'S', :manager_id=>3)]
647
- @db.sqls.must_equal ['SELECT * FROM (SELECT hr.employees.id, hr.employees.name, hr.employees.kind, hr.staff.manager_id FROM hr.employees INNER JOIN hr.staff ON (hr.staff.id = hr.employees.id)) AS employees WHERE (employees.manager_id = 3)']
648
- end
649
- end
650
-
651
- describe "without table_map or qualify_tables set" do
652
- it "should use a non-qualified subquery in subclasses" do
653
- def @db.schema(table, opts={})
654
- {Sequel[:hr][:employees]=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}], [:kind, {:type=>:string}]],
655
- :managers=>[[:id, {:type=>:integer}]],
656
- }[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
657
- end
658
- @db.extend_datasets do
659
- def columns
660
- {[Sequel[:hr][:employees]]=>[:id, :name, :kind],
661
- [:managers]=>[:id],
662
- [Sequel[:hr][:employees], :managers]=>[:id, :name, :kind]
663
- }[opts[:from] + (opts[:join] || []).map{|x| x.table}]
664
- end
665
- end
666
- ::Employee = Class.new(Sequel::Model)
667
- ::Employee.db = @db
668
- ::Employee.set_dataset(Sequel[:hr][:employees])
669
- class ::Employee
670
- def _save_refresh; @values[:id] = 1 end
671
- def self.columns
672
- dataset.columns || dataset.opts[:from].first.expression.columns
673
- end
674
- plugin :class_table_inheritance
675
- end
676
- class ::Manager < ::Employee
677
- end
678
-
679
- Employee.dataset.sql.must_equal 'SELECT * FROM hr.employees'
680
- Manager.dataset.sql.must_equal 'SELECT * FROM (SELECT hr.employees.id, hr.employees.name, hr.employees.kind FROM hr.employees INNER JOIN managers ON (managers.id = hr.employees.id)) AS employees'
681
- end
682
- end
683
-
684
- describe "with qualify_tables option set" do
685
- it "should use a subquery with the same qualifier in subclasses" do
686
- ::Employee = Class.new(Sequel::Model)
687
- ::Employee.db = @db
688
- ::Employee.set_dataset(Sequel[:hr][:employees])
689
- class ::Employee
690
- def _save_refresh; @values[:id] = 1 end
691
- def self.columns
692
- dataset.columns || dataset.opts[:from].first.expression.columns
693
- end
694
- plugin :class_table_inheritance, :table_map=>{:Staff=>Sequel[:hr][:staff]}, qualify_tables: true
695
- end
696
- class ::Manager < ::Employee
697
- one_to_many :staff_members, :class=>:Staff
698
- end
699
- class ::Staff < ::Employee
700
- many_to_one :manager
701
- end
702
- class ::Executive < ::Manager
703
- end
704
-
705
- Employee.dataset.sql.must_equal 'SELECT * FROM hr.employees'
706
- Manager.dataset.sql.must_equal 'SELECT * FROM (SELECT hr.employees.id, hr.employees.name, hr.employees.kind FROM hr.employees INNER JOIN hr.managers ON (hr.managers.id = hr.employees.id)) AS employees'
707
- Staff.dataset.sql.must_equal 'SELECT * FROM (SELECT hr.employees.id, hr.employees.name, hr.employees.kind, hr.staff.manager_id FROM hr.employees INNER JOIN hr.staff ON (hr.staff.id = hr.employees.id)) AS employees'
708
- Executive.dataset.sql.must_equal 'SELECT * FROM (SELECT hr.employees.id, hr.employees.name, hr.employees.kind, hr.executives.num_managers FROM hr.employees INNER JOIN hr.managers ON (hr.managers.id = hr.employees.id) INNER JOIN hr.executives ON (hr.executives.id = hr.managers.id)) AS employees'
709
- end
710
- end
711
- end
712
-
713
- describe "class_table_inheritance plugin with schema_caching extension" do
714
- before do
715
- @db = Sequel.mock(:autoid=>proc{|sql| 1})
716
- def @db.supports_schema_parsing?() true end
717
- def @db.schema(table, opts={})
718
- {:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}], [:kind, {:type=>:string}]],
719
- :managers=>[[:id, {:type=>:integer}], [:num_staff, {:type=>:integer}] ],
720
- :executives=>[[:id, {:type=>:integer}], [:num_managers, {:type=>:integer}]],
721
- }[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
722
- end
723
- end
724
- after do
725
- [:Executive, :Manager, :Employee, :Staff].each{|s| Object.send(:remove_const, s) if Object.const_defined?(s)}
726
- end
727
-
728
- it "should not query for columns if the schema cache is present and a table_map is given" do
729
- class ::Employee < Sequel::Model(@db)
730
- plugin :class_table_inheritance, :table_map=>{:Staff=>:employees, :Manager=>:managers, :Executive=>:executives}
731
- end
732
- class ::Staff < Employee; end
733
- class ::Manager < Employee; end
734
- class ::Executive < Manager; end
735
- Employee.columns.must_equal [:id, :name, :kind]
736
- Staff.columns.must_equal [:id, :name, :kind]
737
- Manager.columns.must_equal [:id, :name, :kind, :num_staff]
738
- Executive.columns.must_equal [:id, :name, :kind, :num_staff, :num_managers]
739
- @db.sqls.must_equal []
740
- end
741
-
742
- it "should not query for columns if the schema cache is present and no table_map is given" do
743
- class ::Employee < Sequel::Model(@db)
744
- plugin :class_table_inheritance
745
- end
746
- class ::Manager < Employee; end
747
- class ::Executive < Manager; end
748
- @db.sqls.must_equal []
749
- end
750
- end