sequel 4.49.0 → 5.0.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 (477) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +70 -0
  3. data/README.rdoc +195 -136
  4. data/Rakefile +26 -42
  5. data/bin/sequel +3 -5
  6. data/doc/advanced_associations.rdoc +86 -163
  7. data/doc/association_basics.rdoc +197 -274
  8. data/doc/bin_sequel.rdoc +5 -3
  9. data/doc/cheat_sheet.rdoc +66 -43
  10. data/doc/code_order.rdoc +1 -8
  11. data/doc/core_extensions.rdoc +81 -56
  12. data/doc/dataset_basics.rdoc +8 -17
  13. data/doc/dataset_filtering.rdoc +81 -86
  14. data/doc/extensions.rdoc +3 -10
  15. data/doc/mass_assignment.rdoc +73 -30
  16. data/doc/migration.rdoc +19 -36
  17. data/doc/model_dataset_method_design.rdoc +14 -17
  18. data/doc/model_hooks.rdoc +15 -25
  19. data/doc/model_plugins.rdoc +10 -10
  20. data/doc/mssql_stored_procedures.rdoc +3 -3
  21. data/doc/object_model.rdoc +52 -70
  22. data/doc/opening_databases.rdoc +39 -32
  23. data/doc/postgresql.rdoc +48 -38
  24. data/doc/prepared_statements.rdoc +27 -22
  25. data/doc/querying.rdoc +173 -150
  26. data/doc/reflection.rdoc +5 -6
  27. data/doc/release_notes/5.0.0.txt +159 -0
  28. data/doc/schema_modification.rdoc +63 -60
  29. data/doc/security.rdoc +97 -88
  30. data/doc/sharding.rdoc +43 -30
  31. data/doc/sql.rdoc +53 -65
  32. data/doc/testing.rdoc +3 -5
  33. data/doc/thread_safety.rdoc +2 -4
  34. data/doc/transactions.rdoc +18 -17
  35. data/doc/validations.rdoc +48 -45
  36. data/doc/virtual_rows.rdoc +87 -115
  37. data/lib/sequel.rb +1 -1
  38. data/lib/sequel/adapters/ado.rb +9 -25
  39. data/lib/sequel/adapters/ado/access.rb +7 -13
  40. data/lib/sequel/adapters/ado/mssql.rb +2 -9
  41. data/lib/sequel/adapters/amalgalite.rb +3 -18
  42. data/lib/sequel/adapters/ibmdb.rb +9 -45
  43. data/lib/sequel/adapters/jdbc.rb +13 -73
  44. data/lib/sequel/adapters/jdbc/db2.rb +8 -37
  45. data/lib/sequel/adapters/jdbc/derby.rb +4 -50
  46. data/lib/sequel/adapters/jdbc/h2.rb +4 -25
  47. data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -26
  48. data/lib/sequel/adapters/jdbc/jtds.rb +2 -9
  49. data/lib/sequel/adapters/jdbc/mssql.rb +1 -11
  50. data/lib/sequel/adapters/jdbc/mysql.rb +1 -15
  51. data/lib/sequel/adapters/jdbc/oracle.rb +4 -26
  52. data/lib/sequel/adapters/jdbc/postgresql.rb +2 -31
  53. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +4 -17
  54. data/lib/sequel/adapters/jdbc/sqlite.rb +1 -7
  55. data/lib/sequel/adapters/jdbc/sqlserver.rb +1 -13
  56. data/lib/sequel/adapters/jdbc/transactions.rb +1 -14
  57. data/lib/sequel/adapters/mock.rb +4 -30
  58. data/lib/sequel/adapters/mysql.rb +7 -44
  59. data/lib/sequel/adapters/mysql2.rb +5 -23
  60. data/lib/sequel/adapters/odbc.rb +0 -19
  61. data/lib/sequel/adapters/odbc/db2.rb +1 -1
  62. data/lib/sequel/adapters/odbc/mssql.rb +4 -12
  63. data/lib/sequel/adapters/odbc/oracle.rb +1 -1
  64. data/lib/sequel/adapters/oracle.rb +7 -13
  65. data/lib/sequel/adapters/postgres.rb +13 -57
  66. data/lib/sequel/adapters/postgresql.rb +1 -1
  67. data/lib/sequel/adapters/shared/access.rb +11 -51
  68. data/lib/sequel/adapters/shared/db2.rb +3 -61
  69. data/lib/sequel/adapters/shared/mssql.rb +21 -157
  70. data/lib/sequel/adapters/shared/mysql.rb +23 -224
  71. data/lib/sequel/adapters/shared/oracle.rb +13 -41
  72. data/lib/sequel/adapters/shared/postgres.rb +44 -259
  73. data/lib/sequel/adapters/shared/sqlanywhere.rb +4 -96
  74. data/lib/sequel/adapters/shared/sqlite.rb +12 -101
  75. data/lib/sequel/adapters/sqlanywhere.rb +4 -23
  76. data/lib/sequel/adapters/sqlite.rb +2 -19
  77. data/lib/sequel/adapters/tinytds.rb +5 -15
  78. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +1 -1
  79. data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -4
  80. data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +3 -6
  81. data/lib/sequel/adapters/utils/replace.rb +0 -5
  82. data/lib/sequel/adapters/utils/stored_procedures.rb +0 -2
  83. data/lib/sequel/adapters/utils/unmodified_identifiers.rb +2 -0
  84. data/lib/sequel/ast_transformer.rb +3 -94
  85. data/lib/sequel/connection_pool.rb +26 -28
  86. data/lib/sequel/connection_pool/sharded_single.rb +1 -4
  87. data/lib/sequel/connection_pool/sharded_threaded.rb +97 -95
  88. data/lib/sequel/connection_pool/single.rb +0 -2
  89. data/lib/sequel/connection_pool/threaded.rb +94 -110
  90. data/lib/sequel/core.rb +42 -101
  91. data/lib/sequel/database.rb +12 -2
  92. data/lib/sequel/database/connecting.rb +23 -60
  93. data/lib/sequel/database/dataset.rb +6 -9
  94. data/lib/sequel/database/dataset_defaults.rb +4 -48
  95. data/lib/sequel/database/features.rb +5 -4
  96. data/lib/sequel/database/logging.rb +2 -9
  97. data/lib/sequel/database/misc.rb +23 -55
  98. data/lib/sequel/database/query.rb +8 -13
  99. data/lib/sequel/database/schema_generator.rb +89 -64
  100. data/lib/sequel/database/schema_methods.rb +61 -79
  101. data/lib/sequel/database/transactions.rb +4 -24
  102. data/lib/sequel/dataset.rb +18 -10
  103. data/lib/sequel/dataset/actions.rb +53 -107
  104. data/lib/sequel/dataset/dataset_module.rb +3 -15
  105. data/lib/sequel/dataset/features.rb +30 -30
  106. data/lib/sequel/dataset/graph.rb +40 -49
  107. data/lib/sequel/dataset/misc.rb +12 -37
  108. data/lib/sequel/dataset/placeholder_literalizer.rb +4 -4
  109. data/lib/sequel/dataset/prepared_statements.rb +23 -51
  110. data/lib/sequel/dataset/query.rb +71 -155
  111. data/lib/sequel/dataset/sql.rb +30 -225
  112. data/lib/sequel/deprecated.rb +18 -27
  113. data/lib/sequel/exceptions.rb +1 -17
  114. data/lib/sequel/extensions/_model_pg_row.rb +0 -7
  115. data/lib/sequel/extensions/_pretty_table.rb +1 -3
  116. data/lib/sequel/extensions/arbitrary_servers.rb +10 -10
  117. data/lib/sequel/extensions/connection_expiration.rb +1 -1
  118. data/lib/sequel/extensions/connection_validator.rb +1 -1
  119. data/lib/sequel/extensions/constraint_validations.rb +11 -11
  120. data/lib/sequel/extensions/core_extensions.rb +39 -49
  121. data/lib/sequel/extensions/core_refinements.rb +39 -45
  122. data/lib/sequel/extensions/current_datetime_timestamp.rb +0 -4
  123. data/lib/sequel/extensions/date_arithmetic.rb +7 -7
  124. data/lib/sequel/extensions/duplicate_columns_handler.rb +12 -9
  125. data/lib/sequel/extensions/empty_array_consider_nulls.rb +2 -2
  126. data/lib/sequel/extensions/eval_inspect.rb +4 -11
  127. data/lib/sequel/extensions/freeze_datasets.rb +1 -69
  128. data/lib/sequel/extensions/from_block.rb +1 -35
  129. data/lib/sequel/extensions/graph_each.rb +2 -2
  130. data/lib/sequel/extensions/identifier_mangling.rb +9 -19
  131. data/lib/sequel/extensions/implicit_subquery.rb +2 -2
  132. data/lib/sequel/extensions/inflector.rb +4 -4
  133. data/lib/sequel/extensions/migration.rb +23 -40
  134. data/lib/sequel/extensions/no_auto_literal_strings.rb +2 -84
  135. data/lib/sequel/extensions/null_dataset.rb +2 -8
  136. data/lib/sequel/extensions/pagination.rb +1 -17
  137. data/lib/sequel/extensions/pg_array.rb +20 -189
  138. data/lib/sequel/extensions/pg_hstore.rb +11 -50
  139. data/lib/sequel/extensions/pg_hstore_ops.rb +2 -2
  140. data/lib/sequel/extensions/pg_inet.rb +2 -15
  141. data/lib/sequel/extensions/pg_interval.rb +1 -20
  142. data/lib/sequel/extensions/pg_json.rb +7 -27
  143. data/lib/sequel/extensions/pg_loose_count.rb +1 -1
  144. data/lib/sequel/extensions/pg_range.rb +6 -121
  145. data/lib/sequel/extensions/pg_range_ops.rb +1 -3
  146. data/lib/sequel/extensions/pg_row.rb +5 -77
  147. data/lib/sequel/extensions/pg_row_ops.rb +2 -13
  148. data/lib/sequel/extensions/query.rb +3 -4
  149. data/lib/sequel/extensions/round_timestamps.rb +0 -6
  150. data/lib/sequel/extensions/schema_dumper.rb +13 -13
  151. data/lib/sequel/extensions/select_remove.rb +3 -3
  152. data/lib/sequel/extensions/split_array_nil.rb +2 -2
  153. data/lib/sequel/extensions/sql_comments.rb +2 -2
  154. data/lib/sequel/extensions/string_agg.rb +11 -8
  155. data/lib/sequel/extensions/symbol_aref.rb +6 -20
  156. data/lib/sequel/model.rb +27 -62
  157. data/lib/sequel/model/associations.rb +128 -131
  158. data/lib/sequel/model/base.rb +171 -711
  159. data/lib/sequel/model/default_inflections.rb +1 -1
  160. data/lib/sequel/model/errors.rb +0 -3
  161. data/lib/sequel/model/exceptions.rb +2 -6
  162. data/lib/sequel/model/inflections.rb +1 -26
  163. data/lib/sequel/model/plugins.rb +1 -0
  164. data/lib/sequel/plugins/active_model.rb +2 -5
  165. data/lib/sequel/plugins/association_dependencies.rb +15 -15
  166. data/lib/sequel/plugins/association_pks.rb +14 -28
  167. data/lib/sequel/plugins/association_proxies.rb +6 -7
  168. data/lib/sequel/plugins/auto_validations.rb +4 -4
  169. data/lib/sequel/plugins/before_after_save.rb +0 -43
  170. data/lib/sequel/plugins/blacklist_security.rb +9 -8
  171. data/lib/sequel/plugins/boolean_readers.rb +3 -3
  172. data/lib/sequel/plugins/boolean_subsets.rb +2 -2
  173. data/lib/sequel/plugins/caching.rb +5 -5
  174. data/lib/sequel/plugins/class_table_inheritance.rb +71 -102
  175. data/lib/sequel/plugins/column_conflicts.rb +2 -2
  176. data/lib/sequel/plugins/column_select.rb +2 -2
  177. data/lib/sequel/plugins/composition.rb +15 -24
  178. data/lib/sequel/plugins/constraint_validations.rb +4 -3
  179. data/lib/sequel/plugins/csv_serializer.rb +13 -20
  180. data/lib/sequel/plugins/dataset_associations.rb +2 -2
  181. data/lib/sequel/plugins/def_dataset_method.rb +5 -5
  182. data/lib/sequel/plugins/defaults_setter.rb +1 -1
  183. data/lib/sequel/plugins/delay_add_association.rb +1 -1
  184. data/lib/sequel/plugins/finder.rb +16 -10
  185. data/lib/sequel/plugins/force_encoding.rb +1 -7
  186. data/lib/sequel/plugins/hook_class_methods.rb +4 -106
  187. data/lib/sequel/plugins/input_transformer.rb +10 -11
  188. data/lib/sequel/plugins/insert_returning_select.rb +1 -9
  189. data/lib/sequel/plugins/instance_filters.rb +5 -5
  190. data/lib/sequel/plugins/instance_hooks.rb +7 -52
  191. data/lib/sequel/plugins/inverted_subsets.rb +3 -1
  192. data/lib/sequel/plugins/json_serializer.rb +19 -19
  193. data/lib/sequel/plugins/lazy_attributes.rb +1 -10
  194. data/lib/sequel/plugins/list.rb +6 -6
  195. data/lib/sequel/plugins/many_through_many.rb +11 -8
  196. data/lib/sequel/plugins/mssql_optimistic_locking.rb +3 -3
  197. data/lib/sequel/plugins/nested_attributes.rb +18 -31
  198. data/lib/sequel/plugins/optimistic_locking.rb +3 -3
  199. data/lib/sequel/plugins/pg_array_associations.rb +8 -2
  200. data/lib/sequel/plugins/pg_row.rb +2 -11
  201. data/lib/sequel/plugins/prepared_statements.rb +13 -66
  202. data/lib/sequel/plugins/prepared_statements_safe.rb +1 -1
  203. data/lib/sequel/plugins/rcte_tree.rb +7 -7
  204. data/lib/sequel/plugins/serialization.rb +15 -33
  205. data/lib/sequel/plugins/serialization_modification_detection.rb +1 -1
  206. data/lib/sequel/plugins/sharding.rb +2 -8
  207. data/lib/sequel/plugins/single_table_inheritance.rb +10 -13
  208. data/lib/sequel/plugins/skip_create_refresh.rb +3 -3
  209. data/lib/sequel/plugins/static_cache.rb +8 -9
  210. data/lib/sequel/plugins/string_stripper.rb +3 -3
  211. data/lib/sequel/plugins/subclasses.rb +1 -1
  212. data/lib/sequel/plugins/subset_conditions.rb +2 -2
  213. data/lib/sequel/plugins/table_select.rb +2 -2
  214. data/lib/sequel/plugins/tactical_eager_loading.rb +4 -4
  215. data/lib/sequel/plugins/timestamps.rb +6 -7
  216. data/lib/sequel/plugins/touch.rb +4 -8
  217. data/lib/sequel/plugins/tree.rb +3 -3
  218. data/lib/sequel/plugins/typecast_on_load.rb +2 -2
  219. data/lib/sequel/plugins/unlimited_update.rb +1 -7
  220. data/lib/sequel/plugins/update_or_create.rb +3 -3
  221. data/lib/sequel/plugins/update_refresh.rb +3 -3
  222. data/lib/sequel/plugins/uuid.rb +7 -11
  223. data/lib/sequel/plugins/validation_class_methods.rb +10 -9
  224. data/lib/sequel/plugins/validation_contexts.rb +4 -4
  225. data/lib/sequel/plugins/validation_helpers.rb +26 -25
  226. data/lib/sequel/plugins/whitelist_security.rb +13 -9
  227. data/lib/sequel/plugins/xml_serializer.rb +24 -25
  228. data/lib/sequel/sql.rb +145 -276
  229. data/lib/sequel/timezones.rb +8 -22
  230. data/lib/sequel/version.rb +2 -2
  231. data/spec/adapter_spec.rb +1 -1
  232. data/spec/adapters/db2_spec.rb +2 -103
  233. data/spec/adapters/mssql_spec.rb +89 -68
  234. data/spec/adapters/mysql_spec.rb +101 -480
  235. data/spec/adapters/oracle_spec.rb +1 -9
  236. data/spec/adapters/postgres_spec.rb +312 -565
  237. data/spec/adapters/spec_helper.rb +12 -31
  238. data/spec/adapters/sqlanywhere_spec.rb +2 -77
  239. data/spec/adapters/sqlite_spec.rb +8 -146
  240. data/spec/bin_spec.rb +11 -16
  241. data/spec/core/connection_pool_spec.rb +173 -74
  242. data/spec/core/database_spec.rb +64 -244
  243. data/spec/core/dataset_spec.rb +81 -415
  244. data/spec/core/deprecated_spec.rb +3 -3
  245. data/spec/core/expression_filters_spec.rb +37 -144
  246. data/spec/core/mock_adapter_spec.rb +176 -4
  247. data/spec/core/object_graph_spec.rb +11 -60
  248. data/spec/core/placeholder_literalizer_spec.rb +1 -14
  249. data/spec/core/schema_generator_spec.rb +51 -40
  250. data/spec/core/schema_spec.rb +74 -77
  251. data/spec/core/spec_helper.rb +6 -24
  252. data/spec/core/version_spec.rb +1 -1
  253. data/spec/core_extensions_spec.rb +7 -83
  254. data/spec/core_model_spec.rb +2 -2
  255. data/spec/deprecation_helper.rb +2 -14
  256. data/spec/extensions/accessed_columns_spec.rb +1 -1
  257. data/spec/extensions/active_model_spec.rb +3 -3
  258. data/spec/extensions/after_initialize_spec.rb +1 -1
  259. data/spec/extensions/arbitrary_servers_spec.rb +2 -2
  260. data/spec/extensions/association_dependencies_spec.rb +1 -1
  261. data/spec/extensions/association_pks_spec.rb +4 -59
  262. data/spec/extensions/association_proxies_spec.rb +1 -1
  263. data/spec/extensions/auto_literal_strings_spec.rb +1 -12
  264. data/spec/extensions/auto_validations_spec.rb +1 -1
  265. data/spec/extensions/blacklist_security_spec.rb +1 -1
  266. data/spec/extensions/blank_spec.rb +1 -1
  267. data/spec/extensions/boolean_readers_spec.rb +1 -1
  268. data/spec/extensions/boolean_subsets_spec.rb +1 -1
  269. data/spec/extensions/caching_spec.rb +1 -1
  270. data/spec/extensions/class_table_inheritance_spec.rb +35 -1086
  271. data/spec/extensions/column_conflicts_spec.rb +1 -1
  272. data/spec/extensions/column_select_spec.rb +4 -4
  273. data/spec/extensions/columns_introspection_spec.rb +1 -1
  274. data/spec/extensions/columns_updated_spec.rb +1 -1
  275. data/spec/extensions/composition_spec.rb +1 -7
  276. data/spec/extensions/connection_expiration_spec.rb +3 -3
  277. data/spec/extensions/connection_validator_spec.rb +3 -3
  278. data/spec/extensions/constraint_validations_plugin_spec.rb +1 -1
  279. data/spec/extensions/constraint_validations_spec.rb +1 -1
  280. data/spec/extensions/core_refinements_spec.rb +1 -3
  281. data/spec/extensions/csv_serializer_spec.rb +4 -9
  282. data/spec/extensions/current_datetime_timestamp_spec.rb +1 -1
  283. data/spec/extensions/dataset_associations_spec.rb +2 -1
  284. data/spec/extensions/dataset_source_alias_spec.rb +1 -1
  285. data/spec/extensions/date_arithmetic_spec.rb +3 -3
  286. data/spec/extensions/def_dataset_method_spec.rb +1 -1
  287. data/spec/extensions/defaults_setter_spec.rb +2 -2
  288. data/spec/extensions/delay_add_association_spec.rb +8 -9
  289. data/spec/extensions/dirty_spec.rb +1 -1
  290. data/spec/extensions/duplicate_columns_handler_spec.rb +1 -1
  291. data/spec/extensions/eager_each_spec.rb +2 -2
  292. data/spec/extensions/empty_array_consider_nulls_spec.rb +1 -1
  293. data/spec/extensions/error_splitter_spec.rb +1 -1
  294. data/spec/extensions/error_sql_spec.rb +1 -1
  295. data/spec/extensions/eval_inspect_spec.rb +1 -1
  296. data/spec/extensions/finder_spec.rb +1 -1
  297. data/spec/extensions/force_encoding_spec.rb +2 -5
  298. data/spec/extensions/freeze_datasets_spec.rb +1 -1
  299. data/spec/extensions/graph_each_spec.rb +5 -5
  300. data/spec/extensions/hook_class_methods_spec.rb +1 -194
  301. data/spec/extensions/identifier_mangling_spec.rb +17 -170
  302. data/spec/extensions/implicit_subquery_spec.rb +1 -5
  303. data/spec/extensions/inflector_spec.rb +1 -1
  304. data/spec/extensions/input_transformer_spec.rb +7 -2
  305. data/spec/extensions/insert_returning_select_spec.rb +1 -1
  306. data/spec/extensions/instance_filters_spec.rb +1 -1
  307. data/spec/extensions/instance_hooks_spec.rb +1 -95
  308. data/spec/extensions/inverted_subsets_spec.rb +1 -1
  309. data/spec/extensions/json_serializer_spec.rb +1 -1
  310. data/spec/extensions/lazy_attributes_spec.rb +1 -7
  311. data/spec/extensions/list_spec.rb +1 -1
  312. data/spec/extensions/looser_typecasting_spec.rb +1 -1
  313. data/spec/extensions/many_through_many_spec.rb +1 -1
  314. data/spec/extensions/migration_spec.rb +2 -2
  315. data/spec/extensions/modification_detection_spec.rb +1 -1
  316. data/spec/extensions/mssql_optimistic_locking_spec.rb +1 -1
  317. data/spec/extensions/named_timezones_spec.rb +3 -3
  318. data/spec/extensions/nested_attributes_spec.rb +1 -29
  319. data/spec/extensions/null_dataset_spec.rb +1 -11
  320. data/spec/extensions/optimistic_locking_spec.rb +1 -1
  321. data/spec/extensions/pagination_spec.rb +1 -1
  322. data/spec/extensions/pg_array_associations_spec.rb +4 -1
  323. data/spec/extensions/pg_array_ops_spec.rb +1 -1
  324. data/spec/extensions/pg_array_spec.rb +3 -48
  325. data/spec/extensions/pg_enum_spec.rb +1 -1
  326. data/spec/extensions/pg_hstore_ops_spec.rb +1 -1
  327. data/spec/extensions/pg_hstore_spec.rb +23 -32
  328. data/spec/extensions/pg_inet_ops_spec.rb +1 -1
  329. data/spec/extensions/pg_inet_spec.rb +1 -14
  330. data/spec/extensions/pg_interval_spec.rb +3 -13
  331. data/spec/extensions/pg_json_ops_spec.rb +1 -1
  332. data/spec/extensions/pg_json_spec.rb +1 -13
  333. data/spec/extensions/pg_loose_count_spec.rb +1 -1
  334. data/spec/extensions/pg_range_ops_spec.rb +1 -1
  335. data/spec/extensions/pg_range_spec.rb +3 -88
  336. data/spec/extensions/pg_row_ops_spec.rb +1 -1
  337. data/spec/extensions/pg_row_plugin_spec.rb +1 -1
  338. data/spec/extensions/pg_row_spec.rb +1 -44
  339. data/spec/extensions/pg_static_cache_updater_spec.rb +1 -1
  340. data/spec/extensions/prepared_statements_safe_spec.rb +1 -1
  341. data/spec/extensions/prepared_statements_spec.rb +13 -48
  342. data/spec/extensions/pretty_table_spec.rb +1 -1
  343. data/spec/extensions/query_spec.rb +1 -12
  344. data/spec/extensions/rcte_tree_spec.rb +1 -1
  345. data/spec/extensions/round_timestamps_spec.rb +1 -5
  346. data/spec/extensions/s_spec.rb +1 -1
  347. data/spec/extensions/schema_caching_spec.rb +1 -1
  348. data/spec/extensions/schema_dumper_spec.rb +1 -1
  349. data/spec/extensions/select_remove_spec.rb +1 -1
  350. data/spec/extensions/sequel_4_dataset_methods_spec.rb +1 -1
  351. data/spec/extensions/serialization_modification_detection_spec.rb +1 -1
  352. data/spec/extensions/serialization_spec.rb +2 -14
  353. data/spec/extensions/server_block_spec.rb +1 -1
  354. data/spec/extensions/server_logging_spec.rb +2 -2
  355. data/spec/extensions/sharding_spec.rb +1 -1
  356. data/spec/extensions/shared_caching_spec.rb +1 -28
  357. data/spec/extensions/single_table_inheritance_spec.rb +2 -5
  358. data/spec/extensions/singular_table_names_spec.rb +1 -1
  359. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  360. data/spec/extensions/spec_helper.rb +5 -27
  361. data/spec/extensions/split_array_nil_spec.rb +1 -1
  362. data/spec/extensions/split_values_spec.rb +1 -1
  363. data/spec/extensions/sql_comments_spec.rb +1 -1
  364. data/spec/extensions/sql_expr_spec.rb +1 -1
  365. data/spec/extensions/static_cache_spec.rb +1 -1
  366. data/spec/extensions/string_agg_spec.rb +2 -2
  367. data/spec/extensions/string_date_time_spec.rb +1 -1
  368. data/spec/extensions/string_stripper_spec.rb +1 -1
  369. data/spec/extensions/subclasses_spec.rb +1 -1
  370. data/spec/extensions/subset_conditions_spec.rb +1 -1
  371. data/spec/extensions/symbol_aref_refinement_spec.rb +1 -1
  372. data/spec/extensions/symbol_as_refinement_spec.rb +1 -1
  373. data/spec/extensions/table_select_spec.rb +4 -4
  374. data/spec/extensions/tactical_eager_loading_spec.rb +1 -6
  375. data/spec/extensions/thread_local_timezones_spec.rb +1 -1
  376. data/spec/extensions/timestamps_spec.rb +3 -3
  377. data/spec/extensions/to_dot_spec.rb +1 -1
  378. data/spec/extensions/touch_spec.rb +1 -1
  379. data/spec/extensions/tree_spec.rb +1 -1
  380. data/spec/extensions/typecast_on_load_spec.rb +1 -1
  381. data/spec/extensions/unlimited_update_spec.rb +1 -1
  382. data/spec/extensions/update_or_create_spec.rb +1 -1
  383. data/spec/extensions/update_primary_key_spec.rb +4 -3
  384. data/spec/extensions/update_refresh_spec.rb +1 -1
  385. data/spec/extensions/uuid_spec.rb +10 -12
  386. data/spec/extensions/validate_associated_spec.rb +1 -1
  387. data/spec/extensions/validation_class_methods_spec.rb +3 -3
  388. data/spec/extensions/validation_contexts_spec.rb +1 -1
  389. data/spec/extensions/validation_helpers_spec.rb +10 -44
  390. data/spec/extensions/whitelist_security_spec.rb +5 -5
  391. data/spec/extensions/xml_serializer_spec.rb +3 -3
  392. data/spec/guards_helper.rb +2 -1
  393. data/spec/integration/associations_test.rb +1 -23
  394. data/spec/integration/database_test.rb +7 -7
  395. data/spec/integration/dataset_test.rb +5 -47
  396. data/spec/integration/eager_loader_test.rb +1 -1
  397. data/spec/integration/migrator_test.rb +1 -1
  398. data/spec/integration/model_test.rb +4 -82
  399. data/spec/integration/plugin_test.rb +6 -22
  400. data/spec/integration/prepared_statement_test.rb +8 -88
  401. data/spec/integration/schema_test.rb +6 -6
  402. data/spec/integration/spec_helper.rb +13 -21
  403. data/spec/integration/timezone_test.rb +5 -5
  404. data/spec/integration/transaction_test.rb +3 -55
  405. data/spec/integration/type_test.rb +9 -9
  406. data/spec/model/association_reflection_spec.rb +24 -9
  407. data/spec/model/associations_spec.rb +124 -303
  408. data/spec/model/base_spec.rb +18 -137
  409. data/spec/model/class_dataset_methods_spec.rb +2 -20
  410. data/spec/model/dataset_methods_spec.rb +1 -20
  411. data/spec/model/eager_loading_spec.rb +17 -11
  412. data/spec/model/hooks_spec.rb +5 -300
  413. data/spec/model/inflector_spec.rb +1 -1
  414. data/spec/model/model_spec.rb +15 -320
  415. data/spec/model/plugins_spec.rb +2 -16
  416. data/spec/model/record_spec.rb +29 -121
  417. data/spec/model/spec_helper.rb +5 -15
  418. data/spec/model/validations_spec.rb +1 -1
  419. data/spec/sequel_warning.rb +1 -12
  420. metadata +8 -64
  421. data/doc/active_record.rdoc +0 -927
  422. data/lib/sequel/adapters/cubrid.rb +0 -160
  423. data/lib/sequel/adapters/do.rb +0 -166
  424. data/lib/sequel/adapters/do/mysql.rb +0 -69
  425. data/lib/sequel/adapters/do/postgres.rb +0 -46
  426. data/lib/sequel/adapters/do/sqlite3.rb +0 -41
  427. data/lib/sequel/adapters/jdbc/as400.rb +0 -92
  428. data/lib/sequel/adapters/jdbc/cubrid.rb +0 -65
  429. data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -37
  430. data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -34
  431. data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -34
  432. data/lib/sequel/adapters/odbc/progress.rb +0 -12
  433. data/lib/sequel/adapters/shared/cubrid.rb +0 -245
  434. data/lib/sequel/adapters/shared/firebird.rb +0 -261
  435. data/lib/sequel/adapters/shared/informix.rb +0 -63
  436. data/lib/sequel/adapters/shared/progress.rb +0 -40
  437. data/lib/sequel/adapters/swift.rb +0 -169
  438. data/lib/sequel/adapters/swift/mysql.rb +0 -50
  439. data/lib/sequel/adapters/swift/postgres.rb +0 -49
  440. data/lib/sequel/adapters/swift/sqlite.rb +0 -48
  441. data/lib/sequel/adapters/utils/pg_types.rb +0 -4
  442. data/lib/sequel/dataset/mutation.rb +0 -98
  443. data/lib/sequel/extensions/_deprecated_identifier_mangling.rb +0 -117
  444. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -8
  445. data/lib/sequel/extensions/filter_having.rb +0 -65
  446. data/lib/sequel/extensions/hash_aliases.rb +0 -51
  447. data/lib/sequel/extensions/meta_def.rb +0 -37
  448. data/lib/sequel/extensions/query_literals.rb +0 -86
  449. data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -26
  450. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -133
  451. data/lib/sequel/extensions/set_overrides.rb +0 -82
  452. data/lib/sequel/no_core_ext.rb +0 -4
  453. data/lib/sequel/plugins/association_autoreloading.rb +0 -11
  454. data/lib/sequel/plugins/identifier_columns.rb +0 -49
  455. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -11
  456. data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -90
  457. data/lib/sequel/plugins/prepared_statements_associations.rb +0 -137
  458. data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -71
  459. data/lib/sequel/plugins/schema.rb +0 -84
  460. data/lib/sequel/plugins/scissors.rb +0 -37
  461. data/spec/core/dataset_mutation_spec.rb +0 -253
  462. data/spec/extensions/_deprecated_identifier_mangling_spec.rb +0 -314
  463. data/spec/extensions/before_after_save_spec.rb +0 -40
  464. data/spec/extensions/filter_having_spec.rb +0 -42
  465. data/spec/extensions/from_block_spec.rb +0 -21
  466. data/spec/extensions/hash_aliases_spec.rb +0 -26
  467. data/spec/extensions/identifier_columns_spec.rb +0 -19
  468. data/spec/extensions/meta_def_spec.rb +0 -35
  469. data/spec/extensions/no_auto_literal_strings_spec.rb +0 -69
  470. data/spec/extensions/pg_typecast_on_load_spec.rb +0 -70
  471. data/spec/extensions/prepared_statements_associations_spec.rb +0 -212
  472. data/spec/extensions/prepared_statements_with_pk_spec.rb +0 -40
  473. data/spec/extensions/query_literals_spec.rb +0 -185
  474. data/spec/extensions/schema_spec.rb +0 -123
  475. data/spec/extensions/scissors_spec.rb +0 -27
  476. data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -118
  477. data/spec/extensions/set_overrides_spec.rb +0 -75
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
1
+ require_relative "spec_helper"
2
2
 
3
3
  describe "boolean_subsets plugin" do
4
4
  before do
@@ -1,4 +1,4 @@
1
- require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
1
+ require_relative "spec_helper"
2
2
 
3
3
  describe Sequel::Model, "caching" do
4
4
  before do
@@ -1,1048 +1,8 @@
1
- require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
1
+ require_relative "spec_helper"
2
2
 
3
3
  describe "class_table_inheritance plugin" do
4
4
  before do
5
- @db = Sequel.mock(: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}], [:kind, {:type=>:string}]],
9
- :managers=>[[:id, {:type=>:integer}], [:num_staff, {:type=>:integer}]],
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
- class ::Employee < Sequel::Model(@db)
27
- def _save_refresh; @values[:id] = 1 end
28
- def self.columns
29
- dataset.columns
30
- end
31
- plugin :class_table_inheritance, :key=>:kind, :table_map=>{:Staff=>:staff}
32
- end
33
- deprecated do
34
- class ::Manager < Employee
35
- one_to_many :staff_members, :class=>:Staff
36
- end
37
- class ::Executive < Manager
38
- end
39
- class ::Ceo < Executive
40
- end
41
- class ::Staff < Employee
42
- many_to_one :manager
43
- end
44
- end
45
- @ds = Employee.dataset
46
- @db.sqls
47
- end
48
- after do
49
- Object.send(:remove_const, :Ceo)
50
- Object.send(:remove_const, :Executive)
51
- Object.send(:remove_const, :Manager)
52
- Object.send(:remove_const, :Staff)
53
- Object.send(:remove_const, :Employee)
54
- end
55
-
56
- deprecated "should freeze CTI information when freezing model class" do
57
- Employee.freeze
58
- Employee.cti_models.frozen?.must_equal true
59
- Employee.cti_tables.frozen?.must_equal true
60
- Employee.cti_instance_dataset.frozen?.must_equal true
61
- Employee.cti_table_columns.frozen?.must_equal true
62
- Employee.cti_table_map.frozen?.must_equal true
63
- end
64
-
65
- deprecated "should support cti_key and cti_model_map" do
66
- Employee.cti_key.must_equal Employee.sti_key
67
- Employee.cti_model_map.must_equal Employee.sti_model_map
68
- end
69
-
70
- deprecated "should not attempt to use prepared statements" do
71
- Manager.plugin :prepared_statements
72
- Manager[1]
73
- @db.sqls.must_equal ["SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id) WHERE (managers.id = 1) LIMIT 1"]
74
- Manager.load(:id=>1, :kind=>'Manager', :num_staff=>2).save
75
- @db.sqls.must_equal ["UPDATE employees SET kind = 'Manager' WHERE (id = 1)", "UPDATE managers SET num_staff = 2 WHERE (id = 1)"]
76
- @db.fetch = {:id=>1, :kind=>'Manager', :num_staff=>2}
77
- Manager.load(:id=>1, :kind=>'Manager', :num_staff=>2).refresh
78
- @db.sqls.must_equal ["SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id) WHERE (managers.id = 1) LIMIT 1"]
79
- end
80
-
81
- deprecated "#cti_base_model should be the model that loaded the plugin" do
82
- Executive.cti_base_model.must_equal Employee
83
- end
84
-
85
- deprecated "#cti_columns should be a mapping of table names to columns" do
86
- Executive.cti_columns.must_equal(:employees=>[:id, :name, :kind], :managers=>[:id, :num_staff], :executives=>[:id, :num_managers])
87
- end
88
-
89
- deprecated "should have simple_table = nil for all subclasses" do
90
- Manager.simple_table.must_be_nil
91
- Executive.simple_table.must_be_nil
92
- Ceo.simple_table.must_be_nil
93
- Staff.simple_table.must_be_nil
94
- end
95
-
96
- deprecated "should have working row_proc if using set_dataset in subclass to remove columns" do
97
- Manager.set_dataset(Manager.dataset.select(*(Manager.columns - [:blah])))
98
- Manager.dataset = Manager.dataset.with_fetch(:id=>1, :kind=>'Ceo')
99
- Manager[1].must_equal Ceo.load(:id=>1, :kind=>'Ceo')
100
- end
101
-
102
- deprecated "should use a joined dataset in subclasses" do
103
- Employee.dataset.sql.must_equal 'SELECT * FROM employees'
104
- Manager.dataset.sql.must_equal 'SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id)'
105
- Executive.dataset.sql.must_equal '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)'
106
- Ceo.dataset.sql.must_equal '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\'))'
107
- Staff.dataset.sql.must_equal 'SELECT employees.id, employees.name, employees.kind, staff.manager_id FROM employees INNER JOIN staff ON (staff.id = employees.id)'
108
- end
109
-
110
- deprecated "should return rows with the correct class based on the polymorphic_key value" do
111
- @ds.with_fetch([{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}, {:kind=>'Staff'}]).all.collect{|x| x.class}.must_equal [Employee, Manager, Executive, Ceo, Staff]
112
- end
113
-
114
- deprecated "should return rows with the correct class based on the polymorphic_key value for subclasses" do
115
- Manager.dataset.with_fetch([{:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}]).all.collect{|x| x.class}.must_equal [Manager, Executive, Ceo]
116
- end
117
-
118
- deprecated "should have refresh return all columns in subclass after loading from superclass" do
119
- Employee.dataset = Employee.dataset.with_fetch([{:id=>1, :name=>'A', :kind=>'Ceo'}])
120
- Ceo.dataset = Ceo.dataset.with_fetch([{:id=>1, :name=>'A', :kind=>'Ceo', :num_staff=>3, :num_managers=>2}])
121
- a = Employee.first
122
- a.class.must_equal Ceo
123
- a.values.must_equal(:id=>1, :name=>'A', :kind=>'Ceo')
124
- a.refresh.values.must_equal(:id=>1, :name=>'A', :kind=>'Ceo', :num_staff=>3, :num_managers=>2)
125
- @db.sqls.must_equal ["SELECT * FROM employees LIMIT 1",
126
- "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')) AND (executives.id = 1)) LIMIT 1"]
127
- end
128
-
129
- deprecated "should return rows with the current class if cti_key is nil" do
130
- Employee.plugin(:class_table_inheritance)
131
- Employee.dataset.with_fetch([{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}, {:kind=>'Staff'}]).all.map{|x| x.class}.must_equal [Employee, Employee, Employee, Employee, Employee]
132
- end
133
-
134
- deprecated "should return rows with the current class if cti_key is nil in subclasses" do
135
- Employee.plugin(:class_table_inheritance)
136
- Object.send(:remove_const, :Executive)
137
- Object.send(:remove_const, :Manager)
138
- class ::Manager < Employee; end
139
- class ::Executive < Manager; end
140
- Manager.dataset.with_fetch([{:kind=>'Manager'}, {:kind=>'Executive'}]).all.map{|x| x.class}.must_equal [Manager, Manager]
141
- end
142
-
143
- deprecated "should handle a model map with integer values" do
144
- Employee.plugin(:class_table_inheritance, :key=>:kind, :model_map=>{0=>:Employee, 1=>:Manager, 2=>:Executive, 3=>:Ceo})
145
- Object.send(:remove_const, :Ceo)
146
- Object.send(:remove_const, :Executive)
147
- Object.send(:remove_const, :Manager)
148
- class ::Manager < Employee; end
149
- class ::Executive < Manager; end
150
- class ::Ceo < Executive; end
151
- Employee.dataset = Employee.dataset.with_fetch([{:kind=>nil},{:kind=>0},{:kind=>1}, {:kind=>2}, {:kind=>3}])
152
- Employee.all.collect{|x| x.class}.must_equal [Employee, Employee, Manager, Executive, Ceo]
153
- Manager.dataset = Manager.dataset.with_fetch([{:kind=>nil},{:kind=>0},{:kind=>1}, {:kind=>2}, {:kind=>3}])
154
- Manager.all.collect{|x| x.class}.must_equal [Manager, Employee, Manager, Executive, Ceo]
155
- end
156
-
157
- deprecated "should fallback to the main class if the given class does not exist" do
158
- @ds.with_fetch([{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Blah'}, {:kind=>'Staff'}]).all.map{|x| x.class}.must_equal [Employee, Manager, Employee, Staff]
159
- end
160
-
161
- deprecated "should fallback to the main class if the given class does not exist in subclasses" do
162
- Manager.dataset.with_fetch([{:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}, {:kind=>'Blah'}]).all.map{|x| x.class}.must_equal [Manager, Executive, Ceo, Manager]
163
- end
164
-
165
- deprecated "should sets the model class name for the key when creating new parent class records" do
166
- Employee.create
167
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Employee')"]
168
- end
169
-
170
- deprecated "should sets the model class name for the key when creating new subclass records" do
171
- Ceo.create
172
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Ceo')",
173
- "INSERT INTO managers (id) VALUES (1)",
174
- "INSERT INTO executives (id) VALUES (1)"]
175
- end
176
-
177
- deprecated "should ignore existing cti_key value when creating new records" do
178
- Employee.create(:kind=>'Manager')
179
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Employee')"]
180
- end
181
-
182
- deprecated "should ignore existing cti_key value in subclasses" do
183
- Manager.create(:kind=>'Executive')
184
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Manager')",
185
- "INSERT INTO managers (id) VALUES (1)"]
186
- end
187
-
188
- deprecated "should handle validations on the type column field" do
189
- o = Employee.new
190
- def o.validate
191
- errors.add(:kind, 'not present') unless kind
192
- end
193
- o.valid?.must_equal true
194
- end
195
-
196
- deprecated "should set the type column field even when not validating" do
197
- Employee.new.save(:validate=>false)
198
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Employee')"]
199
- end
200
-
201
- deprecated "should allow specifying a map of names to tables to override implicit mapping" do
202
- Manager.dataset.sql.must_equal 'SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id)'
203
- Staff.dataset.sql.must_equal 'SELECT employees.id, employees.name, employees.kind, staff.manager_id FROM employees INNER JOIN staff ON (staff.id = employees.id)'
204
- end
205
-
206
- deprecated "should lazily load attributes for columns in subclass tables" do
207
- Manager.dataset = Manager.dataset.with_fetch(:id=>1, :name=>'J', :kind=>'Ceo', :num_staff=>2)
208
- m = Manager[1]
209
- @db.sqls.must_equal ['SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id) WHERE (managers.id = 1) LIMIT 1']
210
- @db.fetch = {:num_managers=>3}
211
- m.must_be_kind_of Ceo
212
- m.num_managers.must_equal 3
213
- @db.sqls.must_equal ['SELECT executives.num_managers FROM employees INNER JOIN managers ON (managers.id = employees.id) INNER JOIN executives ON (executives.id = managers.id) WHERE (executives.id = 1) LIMIT 1']
214
- m.values.must_equal(:id=>1, :name=>'J', :kind=>'Ceo', :num_staff=>2, :num_managers=>3)
215
- end
216
-
217
- deprecated "should lazily load columns in middle classes correctly when loaded from parent class" do
218
- Employee.dataset = Employee.dataset.with_fetch(:id=>1, :kind=>'Ceo')
219
- @db.fetch = [[:num_staff=>2]]
220
- e = Employee[1]
221
- e.must_be_kind_of(Ceo)
222
- @db.sqls.must_equal ["SELECT * FROM employees WHERE (id = 1) LIMIT 1"]
223
- e.num_staff.must_equal 2
224
- @db.sqls.must_equal ["SELECT managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id) WHERE (managers.id = 1) LIMIT 1"]
225
- end
226
-
227
- deprecated "should eagerly load lazily columns in subclasses when loaded from parent class" do
228
- Employee.dataset = Employee.dataset.with_fetch(:id=>1, :kind=>'Ceo')
229
- @db.fetch = [[{:id=>1, :num_staff=>2}], [{:id=>1, :num_managers=>3}]]
230
- e = Employee.all.first
231
- e.must_be_kind_of(Ceo)
232
- @db.sqls.must_equal ["SELECT * FROM employees"]
233
- e.num_staff.must_equal 2
234
- @db.sqls.must_equal ["SELECT managers.id, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id) WHERE (managers.id IN (1))"]
235
- e.num_managers.must_equal 3
236
- @db.sqls.must_equal ['SELECT executives.id, executives.num_managers FROM employees INNER JOIN managers ON (managers.id = employees.id) INNER JOIN executives ON (executives.id = managers.id) WHERE (executives.id IN (1))']
237
- end
238
-
239
- deprecated "should include schema for columns for tables for ancestor classes" do
240
- Employee.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string})
241
- Manager.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :num_staff=>{:type=>:integer})
242
- Executive.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :num_staff=>{:type=>:integer}, :num_managers=>{:type=>:integer})
243
- Staff.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :manager_id=>{:type=>:integer})
244
- end
245
-
246
- deprecated "should use the correct primary key (which should have the same name in all subclasses)" do
247
- [Employee, Manager, Executive, Ceo, Staff].each{|c| c.primary_key.must_equal :id}
248
- end
249
-
250
- deprecated "should have table_name return the table name of the most specific table" do
251
- Employee.table_name.must_equal :employees
252
- Manager.table_name.must_equal :managers
253
- Executive.table_name.must_equal :executives
254
- Ceo.table_name.must_equal :executives
255
- Staff.table_name.must_equal :staff
256
- end
257
-
258
- deprecated "should delete the correct rows from all tables when deleting" do
259
- Ceo.load(:id=>1).delete
260
- @db.sqls.must_equal ["DELETE FROM executives WHERE (id = 1)", "DELETE FROM managers WHERE (id = 1)", "DELETE FROM employees WHERE (id = 1)"]
261
- end
262
-
263
- deprecated "should not allow deletion of frozen object" do
264
- o = Ceo.load(:id=>1)
265
- o.freeze
266
- proc{o.delete}.must_raise(Sequel::Error)
267
- @db.sqls.must_equal []
268
- end
269
-
270
- deprecated "should insert the correct rows into all tables when inserting" do
271
- Ceo.create(:num_managers=>3, :num_staff=>2, :name=>'E')
272
- sqls = @db.sqls
273
- sqls.length.must_equal 3
274
- sqls[0].must_match(/INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Ceo)', '(E|Ceo)'\)/)
275
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \([12], [12]\)/)
276
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([13], [13]\)/)
277
- end
278
-
279
- deprecated "should insert the correct rows into all tables when inserting when insert_select is supported" do
280
- [Executive, Manager, Employee].each do |klass|
281
- klass.instance_variable_set(:@cti_instance_dataset, klass.cti_instance_dataset.with_extend do
282
- def supports_insert_select?; true; end
283
- def insert_select(v)
284
- db.run(insert_sql(v) + " RETURNING *")
285
- v.merge(:id=>1)
286
- end
287
- end)
288
- end
289
- Ceo.create(:num_managers=>3, :num_staff=>2, :name=>'E')
290
- sqls = @db.sqls
291
- sqls.length.must_equal 3
292
- sqls[0].must_match(/INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Ceo)', '(E|Ceo)'\) RETURNING \*/)
293
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \([12], [12]\) RETURNING \*/)
294
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([13], [13]\) RETURNING \*/)
295
- end
296
-
297
- deprecated "should insert the correct rows into all tables with a given primary key" do
298
- e = Ceo.new(:num_managers=>3, :num_staff=>2, :name=>'E')
299
- e.id = 2
300
- e.save
301
- sqls = @db.sqls
302
- sqls.length.must_equal 3
303
- sqls[0].must_match(/INSERT INTO employees \((name|kind|id), (name|kind|id), (name|kind|id)\) VALUES \(('E'|'Ceo'|2), ('E'|'Ceo'|2), ('E'|'Ceo'|2)\)/)
304
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \(2, 2\)/)
305
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([23], [23]\)/)
306
- end
307
-
308
- deprecated "should update the correct rows in all tables when updating" do
309
- Ceo.load(:id=>2).update(:num_managers=>3, :num_staff=>2, :name=>'E')
310
- @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)"]
311
- end
312
-
313
- deprecated "should handle many_to_one relationships correctly" do
314
- Manager.dataset = Manager.dataset.with_fetch(:id=>3, :name=>'E', :kind=>'Ceo', :num_managers=>3)
315
- Staff.load(:manager_id=>3).manager.must_equal Ceo.load(:id=>3, :name=>'E', :kind=>'Ceo', :num_managers=>3)
316
- @db.sqls.must_equal ['SELECT employees.id, employees.name, employees.kind, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id) WHERE (managers.id = 3) LIMIT 1']
317
- end
318
-
319
- deprecated "should handle one_to_many relationships correctly" do
320
- Staff.dataset = Staff.dataset.with_fetch(:id=>1, :name=>'S', :kind=>'Staff', :manager_id=>3)
321
- Ceo.load(:id=>3).staff_members.must_equal [Staff.load(:id=>1, :name=>'S', :kind=>'Staff', :manager_id=>3)]
322
- @db.sqls.must_equal ['SELECT employees.id, employees.name, employees.kind, staff.manager_id FROM employees INNER JOIN staff ON (staff.id = employees.id) WHERE (staff.manager_id = 3)']
323
- end
324
- end
325
-
326
- describe "class_table_inheritance plugin without sti_key" do
327
- before do
328
- @db = Sequel.mock(:autoid=>proc{|sql| 1})
329
- def @db.supports_schema_parsing?() true end
330
- def @db.schema(table, opts={})
331
- {:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}]],
332
- :managers=>[[:id, {:type=>:integer}], [:num_staff, {:type=>:integer}]],
333
- :executives=>[[:id, {:type=>:integer}], [:num_managers, {:type=>:integer}]],
334
- :staff=>[[:id, {:type=>:integer}], [:manager_id, {:type=>:integer}]],
335
- }[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
336
- end
337
- @db.extend_datasets do
338
- def columns
339
- {[:employees]=>[:id, :name],
340
- [:managers]=>[:id, :num_staff],
341
- [:executives]=>[:id, :num_managers],
342
- [:staff]=>[:id, :manager_id],
343
- [:employees, :managers]=>[:id, :name, :num_staff],
344
- [:employees, :managers, :executives]=>[:id, :name, :num_staff, :num_managers],
345
- [:employees, :staff]=>[:id, :name, :manager_id],
346
- }[opts[:from] + (opts[:join] || []).map{|x| x.table}]
347
- end
348
- end
349
- class ::Employee < Sequel::Model(@db)
350
- def _save_refresh; @values[:id] = 1 end
351
- def self.columns
352
- dataset.columns
353
- end
354
- plugin :class_table_inheritance, :table_map=>{:Staff=>:staff}
355
- end
356
- deprecated do
357
- class ::Manager < Employee
358
- one_to_many :staff_members, :class=>:Staff
359
- end
360
- class ::Executive < Manager
361
- end
362
- class ::Staff < Employee
363
- many_to_one :manager
364
- end
365
- end
366
- @ds = Employee.dataset
367
- @db.sqls
368
- end
369
- after do
370
- Object.send(:remove_const, :Executive)
371
- Object.send(:remove_const, :Manager)
372
- Object.send(:remove_const, :Staff)
373
- Object.send(:remove_const, :Employee)
374
- end
375
-
376
- deprecated "should have simple_table = nil for all subclasses" do
377
- Manager.simple_table.must_be_nil
378
- Executive.simple_table.must_be_nil
379
- Staff.simple_table.must_be_nil
380
- end
381
-
382
- deprecated "should have working row_proc if using set_dataset in subclass to remove columns" do
383
- Manager.set_dataset(Manager.dataset.select(*(Manager.columns - [:blah])))
384
- Manager.dataset = Manager.dataset.with_fetch(:id=>1)
385
- Manager[1].must_equal Manager.load(:id=>1)
386
- end
387
-
388
- deprecated "should use a dataset in subclasses" do
389
- Employee.dataset.sql.must_equal 'SELECT * FROM employees'
390
- Manager.dataset.sql.must_equal 'SELECT employees.id, employees.name, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id)'
391
- Executive.dataset.sql.must_equal '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)'
392
- Staff.dataset.sql.must_equal 'SELECT employees.id, employees.name, staff.manager_id FROM employees INNER JOIN staff ON (staff.id = employees.id)'
393
- end
394
-
395
- deprecated "should return rows with the current class if cti_key is nil" do
396
- Employee.plugin(:class_table_inheritance)
397
- Employee.dataset = Employee.dataset.with_fetch([{}])
398
- Employee.first.class.must_equal Employee
399
- end
400
-
401
-
402
- deprecated "should include schema for columns for tables for ancestor classes" do
403
- Employee.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string})
404
- Manager.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :num_staff=>{:type=>:integer})
405
- Executive.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :num_staff=>{:type=>:integer}, :num_managers=>{:type=>:integer})
406
- Staff.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :manager_id=>{:type=>:integer})
407
- end
408
-
409
- deprecated "should use the correct primary key (which should have the same name in all subclasses)" do
410
- [Employee, Manager, Executive, Staff].each{|c| c.primary_key.must_equal :id}
411
- end
412
-
413
- deprecated "should have table_name return the table name of the most specific table" do
414
- Employee.table_name.must_equal :employees
415
- Manager.table_name.must_equal :managers
416
- Executive.table_name.must_equal :executives
417
- Staff.table_name.must_equal :staff
418
- end
419
-
420
- deprecated "should delete the correct rows from all tables when deleting" do
421
- Executive.load(:id=>1).delete
422
- @db.sqls.must_equal ["DELETE FROM executives WHERE (id = 1)", "DELETE FROM managers WHERE (id = 1)", "DELETE FROM employees WHERE (id = 1)"]
423
- end
424
-
425
- deprecated "should not allow deletion of frozen object" do
426
- o = Executive.load(:id=>1)
427
- o.freeze
428
- proc{o.delete}.must_raise(Sequel::Error)
429
- @db.sqls.must_equal []
430
- end
431
-
432
- deprecated "should insert the correct rows into all tables when inserting" do
433
- Executive.create(:num_managers=>3, :num_staff=>2, :name=>'E')
434
- sqls = @db.sqls
435
- sqls.length.must_equal 3
436
- sqls[0].must_match(/INSERT INTO employees \(name\) VALUES \('E'\)/)
437
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \([12], [12]\)/)
438
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([13], [13]\)/)
439
- end
440
-
441
- deprecated "should insert the correct rows into all tables with a given primary key" do
442
- e = Executive.new(:num_managers=>3, :num_staff=>2, :name=>'E')
443
- e.id = 2
444
- e.save
445
- sqls = @db.sqls
446
- sqls.length.must_equal 3
447
- sqls[0].must_match(/INSERT INTO employees \((name|id), (name|id)\) VALUES \(('E'|2), ('E'|2)\)/)
448
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \(2, 2\)/)
449
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([23], [23]\)/)
450
- end
451
-
452
- deprecated "should update the correct rows in all tables when updating" do
453
- Executive.load(:id=>2).update(:num_managers=>3, :num_staff=>2, :name=>'E')
454
- @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)"]
455
- end
456
-
457
- deprecated "should handle many_to_one relationships correctly" do
458
- Manager.dataset = Manager.dataset.with_fetch(:id=>3, :name=>'E', :num_staff=>3)
459
- Staff.load(:manager_id=>3).manager.must_equal Manager.load(:id=>3, :name=>'E', :num_staff=>3)
460
- @db.sqls.must_equal ['SELECT employees.id, employees.name, managers.num_staff FROM employees INNER JOIN managers ON (managers.id = employees.id) WHERE (managers.id = 3) LIMIT 1']
461
- end
462
-
463
- deprecated "should handle one_to_many relationships correctly" do
464
- Staff.dataset = Staff.dataset.with_fetch(:id=>1, :name=>'S', :manager_id=>3)
465
- Executive.load(:id=>3).staff_members.must_equal [Staff.load(:id=>1, :name=>'S', :manager_id=>3)]
466
- @db.sqls.must_equal ['SELECT employees.id, employees.name, staff.manager_id FROM employees INNER JOIN staff ON (staff.id = employees.id) WHERE (staff.manager_id = 3)']
467
- end
468
- end
469
-
470
- describe "class_table_inheritance plugin with duplicate columns" do
471
- before do
472
- @db = Sequel.mock(:autoid=>proc{|sql| 1})
473
- def @db.supports_schema_parsing?() true end
474
- def @db.schema(table, opts={})
475
- {:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}], [:kind, {:type=>:string}]],
476
- :managers=>[[:id, {:type=>:integer}], [:name, {:type=>:string}]],
477
- }[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
478
- end
479
- @db.extend_datasets do
480
- def columns
481
- {[:employees]=>[:id, :name, :kind],
482
- [:managers]=>[:id, :name],
483
- }[opts[:from] + (opts[:join] || []).map{|x| x.table}]
484
- end
485
- end
486
- class ::Employee < Sequel::Model(@db)
487
- def _save_refresh; @values[:id] = 1 end
488
- def self.columns
489
- dataset.columns
490
- end
491
- plugin :class_table_inheritance, :key=>:kind, :table_map=>{:Staff=>:staff}
492
- end
493
- deprecated do
494
- class ::Manager < Employee; end
495
- end
496
- @ds = Employee.dataset
497
- @db.sqls
498
- end
499
- after do
500
- Object.send(:remove_const, :Manager)
501
- Object.send(:remove_const, :Employee)
502
- end
503
-
504
- deprecated "should select names from both tables" do
505
- Manager.dataset.sql.must_equal 'SELECT employees.id, employees.name, employees.kind, managers.name FROM employees INNER JOIN managers ON (managers.id = employees.id)'
506
- end
507
- end
508
-
509
- describe "class_table_inheritance plugin with :alias option" do
510
- before do
511
- @db = Sequel.mock(:autoid=>proc{|sql| 1})
512
- def @db.supports_schema_parsing?() true end
513
- def @db.schema(table, opts={})
514
- {:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}], [:kind, {:type=>:string}]],
515
- :managers=>[[:id, {:type=>:integer}], [:num_staff, {:type=>:integer}]],
516
- :executives=>[[:id, {:type=>:integer}], [:num_managers, {:type=>:integer}]],
517
- :staff=>[[:id, {:type=>:integer}], [:manager_id, {:type=>:integer}]],
518
- }[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
519
- end
520
- @db.extend_datasets do
521
- def columns
522
- {[:employees]=>[:id, :name, :kind],
523
- [:managers]=>[:id, :num_staff],
524
- [:executives]=>[:id, :num_managers],
525
- [:staff]=>[:id, :manager_id],
526
- [:employees, :managers]=>[:id, :name, :kind, :num_staff],
527
- [:employees, :managers, :executives]=>[:id, :name, :kind, :num_staff, :num_managers],
528
- [:employees, :staff]=>[:id, :name, :kind, :manager_id],
529
- }[opts[:from] + (opts[:join] || []).map{|x| x.table}]
530
- end
531
- end
532
- class ::Employee < Sequel::Model(@db)
533
- def _save_refresh; @values[:id] = 1 end
534
- def self.columns
535
- dataset.columns || dataset.opts[:from].first.expression.columns
536
- end
537
- plugin :class_table_inheritance, :key=>:kind, :table_map=>{:Staff=>:staff}, :alias=>:employees
538
- end
539
- class ::Manager < Employee
540
- one_to_many :staff_members, :class=>:Staff
541
- end
542
- class ::Executive < Manager
543
- end
544
- class ::Ceo < Executive
545
- end
546
- class ::Staff < Employee
547
- many_to_one :manager
548
- end
549
- @ds = Employee.dataset
550
- @db.sqls
551
- end
552
- after do
553
- Object.send(:remove_const, :Ceo)
554
- Object.send(:remove_const, :Executive)
555
- Object.send(:remove_const, :Manager)
556
- Object.send(:remove_const, :Staff)
557
- Object.send(:remove_const, :Employee)
558
- end
559
-
560
- it "should freeze CTI information when freezing model class" do
561
- Employee.freeze
562
- Employee.cti_models.frozen?.must_equal true
563
- Employee.cti_tables.frozen?.must_equal true
564
- Employee.cti_instance_dataset.frozen?.must_equal true
565
- Employee.cti_table_columns.frozen?.must_equal true
566
- Employee.cti_table_map.frozen?.must_equal true
567
- end
568
-
569
- it "should not attempt to use prepared statements" do
570
- Manager.plugin :prepared_statements
571
- Manager[1]
572
- @db.sqls.must_equal ["SELECT id, name, kind, 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 (id = 1) LIMIT 1"]
573
- Manager.load(:id=>1, :kind=>'Manager', :num_staff=>2).save
574
- @db.sqls.must_equal ["UPDATE employees SET kind = 'Manager' WHERE (id = 1)", "UPDATE managers SET num_staff = 2 WHERE (id = 1)"]
575
- @db.fetch = {:id=>1, :kind=>'Manager', :num_staff=>2}
576
- Manager.load(:id=>1, :kind=>'Manager', :num_staff=>2).refresh
577
- @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"]
578
- end
579
-
580
- deprecated "#cti_base_model should be the model that loaded the plugin" do
581
- Executive.cti_base_model.must_equal Employee
582
- end
583
-
584
- it "#cti_models.first should be the model that loaded the plugin" do
585
- Executive.cti_models.first.must_equal Employee
586
- end
587
-
588
- deprecated "#cti_columns should be a mapping of table names to columns" do
589
- Executive.cti_columns.must_equal(:employees=>[:id, :name, :kind], :managers=>[:id, :num_staff], :executives=>[:id, :num_managers])
590
- end
591
-
592
- it "should have simple_table = nil for all subclasses" do
593
- Manager.simple_table.must_be_nil
594
- Executive.simple_table.must_be_nil
595
- Ceo.simple_table.must_be_nil
596
- Staff.simple_table.must_be_nil
597
- end
598
-
599
- it "should have working row_proc if using set_dataset in subclass to remove columns" do
600
- Manager.set_dataset(Manager.dataset.select(*(Manager.columns - [:blah])))
601
- Manager.dataset = Manager.dataset.with_fetch(:id=>1, :kind=>'Ceo')
602
- Manager[1].must_equal Ceo.load(:id=>1, :kind=>'Ceo')
603
- end
604
-
605
- it "should use a subquery in subclasses" do
606
- Employee.dataset.sql.must_equal 'SELECT * FROM employees'
607
- 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'
608
- 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'
609
- 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'
610
- 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'
611
- end
612
-
613
- it "should return rows with the correct class based on the polymorphic_key value" do
614
- @ds.with_fetch([{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}, {:kind=>'Staff'}]).all.collect{|x| x.class}.must_equal [Employee, Manager, Executive, Ceo, Staff]
615
- end
616
-
617
- it "should return rows with the correct class based on the polymorphic_key value for subclasses" do
618
- Manager.dataset.with_fetch([{:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}]).all.collect{|x| x.class}.must_equal [Manager, Executive, Ceo]
619
- end
620
-
621
- it "should have refresh return all columns in subclass after loading from superclass" do
622
- Employee.dataset = Employee.dataset.with_fetch([{:id=>1, :name=>'A', :kind=>'Ceo'}])
623
- Ceo.dataset = Ceo.dataset.with_fetch([{:id=>1, :name=>'A', :kind=>'Ceo', :num_staff=>3, :num_managers=>2}])
624
- a = Employee.first
625
- a.class.must_equal Ceo
626
- a.values.must_equal(:id=>1, :name=>'A', :kind=>'Ceo')
627
- a.refresh.values.must_equal(:id=>1, :name=>'A', :kind=>'Ceo', :num_staff=>3, :num_managers=>2)
628
- @db.sqls.must_equal ["SELECT * FROM employees LIMIT 1",
629
- "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"]
630
- end
631
-
632
- it "should return rows with the current class if cti_key is nil" do
633
- Employee.plugin(:class_table_inheritance, :alias=>:employees)
634
- Employee.dataset.with_fetch([{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}, {:kind=>'Staff'}]).all.map{|x| x.class}.must_equal [Employee, Employee, Employee, Employee, Employee]
635
- end
636
-
637
- it "should return rows with the current class if cti_key is nil in subclasses" do
638
- Employee.plugin(:class_table_inheritance, :alias=>:employees)
639
- Object.send(:remove_const, :Executive)
640
- Object.send(:remove_const, :Manager)
641
- class ::Manager < Employee; end
642
- class ::Executive < Manager; end
643
- Manager.dataset.with_fetch([{:kind=>'Manager'}, {:kind=>'Executive'}]).all.map{|x| x.class}.must_equal [Manager, Manager]
644
- end
645
-
646
- it "should handle a model map with integer values" do
647
- Employee.plugin(:class_table_inheritance, :key=>:kind, :model_map=>{0=>:Employee, 1=>:Manager, 2=>:Executive, 3=>:Ceo}, :alias=>:employees)
648
- Object.send(:remove_const, :Ceo)
649
- Object.send(:remove_const, :Executive)
650
- Object.send(:remove_const, :Manager)
651
- class ::Manager < Employee; end
652
- class ::Executive < Manager; end
653
- class ::Ceo < Executive; end
654
- Employee.dataset = Employee.dataset.with_fetch([{:kind=>nil},{:kind=>0},{:kind=>1}, {:kind=>2}, {:kind=>3}])
655
- Employee.all.collect{|x| x.class}.must_equal [Employee, Employee, Manager, Executive, Ceo]
656
- Manager.dataset = Manager.dataset.with_fetch([{:kind=>nil},{:kind=>0},{:kind=>1}, {:kind=>2}, {:kind=>3}])
657
- Manager.all.collect{|x| x.class}.must_equal [Manager, Employee, Manager, Executive, Ceo]
658
- end
659
-
660
- it "should fallback to the main class if the given class does not exist" do
661
- @ds.with_fetch([{:kind=>'Employee'}, {:kind=>'Manager'}, {:kind=>'Blah'}, {:kind=>'Staff'}]).all.map{|x| x.class}.must_equal [Employee, Manager, Employee, Staff]
662
- end
663
-
664
- it "should fallback to the main class if the given class does not exist in subclasses" do
665
- Manager.dataset.with_fetch([{:kind=>'Manager'}, {:kind=>'Executive'}, {:kind=>'Ceo'}, {:kind=>'Blah'}]).all.map{|x| x.class}.must_equal [Manager, Executive, Ceo, Manager]
666
- end
667
-
668
- it "should sets the model class name for the key when creating new parent class records" do
669
- Employee.create
670
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Employee')"]
671
- end
672
-
673
- it "should sets the model class name for the key when creating new subclass records" do
674
- Ceo.create
675
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Ceo')",
676
- "INSERT INTO managers (id) VALUES (1)",
677
- "INSERT INTO executives (id) VALUES (1)"]
678
- end
679
-
680
- it "should sets the model class name for the key when creating new subclass records" do
681
- Employee.plugin(:class_table_inheritance, :key=>:kind, :model_map=>{0=>:Employee, 1=>:Manager, 2=>:Executive, 3=>:Ceo}, :alias=>:employees)
682
- Object.send(:remove_const, :Ceo)
683
- Object.send(:remove_const, :Executive)
684
- Object.send(:remove_const, :Manager)
685
- class ::Manager < Employee; end
686
- class ::Executive < Manager; end
687
- class ::Ceo < Executive; end
688
- Ceo.create
689
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('3')",
690
- "INSERT INTO managers (id) VALUES (1)",
691
- "INSERT INTO executives (id) VALUES (1)"]
692
- end
693
-
694
- it "should sets the model class name for the key when creating new subclass records" do
695
- Employee.plugin(:class_table_inheritance, :key=>:kind, :model_map=>{0=>:Employee, 1=>:Manager, 2=>:Executive, 3=>:Ceo}, :alias=>:employees)
696
- Object.send(:remove_const, :Ceo)
697
- Object.send(:remove_const, :Executive)
698
- Object.send(:remove_const, :Manager)
699
- class ::Manager < Employee; end
700
- class ::Executive < Employee; end
701
- class ::Ceo < Employee; end
702
- Ceo.create
703
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('3')"]
704
- end
705
-
706
- it "should not use a subquery for a class that doesn't join to a separate table" do
707
- Employee.plugin(:class_table_inheritance, :key=>:kind, :model_map=>{0=>:Employee, 1=>:Manager, 2=>:Executive, 3=>:Ceo}, :alias=>:employees)
708
- Object.send(:remove_const, :Ceo)
709
- class ::Ceo < Employee; end
710
- Ceo.dataset.sql.must_equal 'SELECT * FROM employees WHERE (employees.kind IN (3))'
711
- end
712
-
713
- it "should ignore existing cti_key value when creating new records" do
714
- Employee.create(:kind=>'Manager')
715
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Employee')"]
716
- end
717
-
718
- it "should ignore existing cti_key value in subclasses" do
719
- Manager.create(:kind=>'Executive')
720
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Manager')",
721
- "INSERT INTO managers (id) VALUES (1)"]
722
- end
723
-
724
- it "should handle validations on the type column field" do
725
- o = Employee.new
726
- def o.validate
727
- errors.add(:kind, 'not present') unless kind
728
- end
729
- o.valid?.must_equal true
730
- end
731
-
732
- it "should set the type column field even when not validating" do
733
- Employee.new.save(:validate=>false)
734
- @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Employee')"]
735
- end
736
-
737
- it "should allow specifying a map of names to tables to override implicit mapping" do
738
- 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'
739
- 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'
740
- end
741
-
742
- it "should lazily load attributes for columns in subclass tables" do
743
- Manager.dataset = Manager.dataset.with_fetch(:id=>1, :name=>'J', :kind=>'Ceo', :num_staff=>2)
744
- m = Manager[1]
745
- @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']
746
- @db.fetch = {:num_managers=>3}
747
- m.must_be_kind_of Ceo
748
- m.num_managers.must_equal 3
749
- @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']
750
- m.values.must_equal(:id=>1, :name=>'J', :kind=>'Ceo', :num_staff=>2, :num_managers=>3)
751
- end
752
-
753
- it "should lazily load columns in middle classes correctly when loaded from parent class" do
754
- Employee.dataset = Employee.dataset.with_fetch(:id=>1, :kind=>'Ceo')
755
- @db.fetch = [[:num_staff=>2]]
756
- e = Employee[1]
757
- e.must_be_kind_of(Ceo)
758
- @db.sqls.must_equal ["SELECT * FROM employees WHERE (id = 1) LIMIT 1"]
759
- e.num_staff.must_equal 2
760
- @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"]
761
- end
762
-
763
- it "should eagerly load lazily columns in subclasses when loaded from parent class" do
764
- Employee.dataset = Employee.dataset.with_fetch(:id=>1, :kind=>'Ceo')
765
- @db.fetch = [[{:id=>1, :num_staff=>2}], [{:id=>1, :num_managers=>3}]]
766
- e = Employee.all.first
767
- e.must_be_kind_of(Ceo)
768
- @db.sqls.must_equal ["SELECT * FROM employees"]
769
- e.num_staff.must_equal 2
770
- @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))"]
771
- e.num_managers.must_equal 3
772
- @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))']
773
- end
774
-
775
- it "should include schema for columns for tables for ancestor classes" do
776
- Employee.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string})
777
- Manager.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :num_staff=>{:type=>:integer})
778
- Executive.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :num_staff=>{:type=>:integer}, :num_managers=>{:type=>:integer})
779
- Staff.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :kind=>{:type=>:string}, :manager_id=>{:type=>:integer})
780
- end
781
-
782
- it "should use the correct primary key (which should have the same name in all subclasses)" do
783
- [Employee, Manager, Executive, Ceo, Staff].each{|c| c.primary_key.must_equal :id}
784
- end
785
-
786
- it "should have table_name return the table name of the most specific table" do
787
- Employee.table_name.must_equal :employees
788
- Manager.table_name.must_equal :employees
789
- Executive.table_name.must_equal :employees
790
- Ceo.table_name.must_equal :employees
791
- Staff.table_name.must_equal :employees
792
- end
793
-
794
- it "should delete the correct rows from all tables when deleting" do
795
- Ceo.load(:id=>1).delete
796
- @db.sqls.must_equal ["DELETE FROM executives WHERE (id = 1)", "DELETE FROM managers WHERE (id = 1)", "DELETE FROM employees WHERE (id = 1)"]
797
- end
798
-
799
- it "should not allow deletion of frozen object" do
800
- o = Ceo.load(:id=>1)
801
- o.freeze
802
- proc{o.delete}.must_raise(Sequel::Error)
803
- @db.sqls.must_equal []
804
- end
805
-
806
- it "should insert the correct rows into all tables when inserting" do
807
- Ceo.create(:num_managers=>3, :num_staff=>2, :name=>'E')
808
- sqls = @db.sqls
809
- sqls.length.must_equal 3
810
- sqls[0].must_match(/INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Ceo)', '(E|Ceo)'\)/)
811
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \([12], [12]\)/)
812
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([13], [13]\)/)
813
- end
814
-
815
- it "should insert the correct rows into all tables when inserting when insert_select is supported" do
816
- [Executive, Manager, Employee].each do |klass|
817
- klass.instance_variable_set(:@cti_instance_dataset, klass.cti_instance_dataset.with_extend do
818
- def supports_insert_select?; true; end
819
- def insert_select(v)
820
- db.run(insert_sql(v) + " RETURNING *")
821
- v.merge(:id=>1)
822
- end
823
- end)
824
- end
825
- Ceo.create(:num_managers=>3, :num_staff=>2, :name=>'E')
826
- sqls = @db.sqls
827
- sqls.length.must_equal 3
828
- sqls[0].must_match(/INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Ceo)', '(E|Ceo)'\) RETURNING \*/)
829
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \([12], [12]\) RETURNING \*/)
830
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([13], [13]\) RETURNING \*/)
831
- end
832
-
833
- it "should insert the correct rows into all tables with a given primary key" do
834
- e = Ceo.new(:num_managers=>3, :num_staff=>2, :name=>'E')
835
- e.id = 2
836
- e.save
837
- sqls = @db.sqls
838
- sqls.length.must_equal 3
839
- sqls[0].must_match(/INSERT INTO employees \((name|kind|id), (name|kind|id), (name|kind|id)\) VALUES \(('E'|'Ceo'|2), ('E'|'Ceo'|2), ('E'|'Ceo'|2)\)/)
840
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \(2, 2\)/)
841
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([23], [23]\)/)
842
- end
843
-
844
- it "should update the correct rows in all tables when updating" do
845
- Ceo.load(:id=>2).update(:num_managers=>3, :num_staff=>2, :name=>'E')
846
- @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)"]
847
- end
848
-
849
- it "should handle many_to_one relationships correctly" do
850
- Manager.dataset = Manager.dataset.with_fetch(:id=>3, :name=>'E', :kind=>'Ceo', :num_managers=>3)
851
- Staff.load(:manager_id=>3).manager.must_equal Ceo.load(:id=>3, :name=>'E', :kind=>'Ceo', :num_managers=>3)
852
- @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']
853
- end
854
-
855
- it "should handle one_to_many relationships correctly" do
856
- Staff.dataset = Staff.dataset.with_fetch(:id=>1, :name=>'S', :kind=>'Staff', :manager_id=>3)
857
- Ceo.load(:id=>3).staff_members.must_equal [Staff.load(:id=>1, :name=>'S', :kind=>'Staff', :manager_id=>3)]
858
- @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)']
859
- end
860
- end
861
-
862
- describe "class_table_inheritance plugin without sti_key with :alias option" do
863
- before do
864
- @db = Sequel.mock(:autoid=>proc{|sql| 1})
865
- def @db.supports_schema_parsing?() true end
866
- def @db.schema(table, opts={})
867
- {:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}]],
868
- :managers=>[[:id, {:type=>:integer}], [:num_staff, {:type=>:integer}]],
869
- :executives=>[[:id, {:type=>:integer}], [:num_managers, {:type=>:integer}]],
870
- :staff=>[[:id, {:type=>:integer}], [:manager_id, {:type=>:integer}]],
871
- }[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
872
- end
873
- @db.extend_datasets do
874
- def columns
875
- {[:employees]=>[:id, :name],
876
- [:managers]=>[:id, :num_staff],
877
- [:executives]=>[:id, :num_managers],
878
- [:staff]=>[:id, :manager_id],
879
- [:employees, :managers]=>[:id, :name, :num_staff],
880
- [:employees, :managers, :executives]=>[:id, :name, :num_staff, :num_managers],
881
- [:employees, :staff]=>[:id, :name, :manager_id],
882
- }[opts[:from] + (opts[:join] || []).map{|x| x.table}]
883
- end
884
- end
885
- class ::Employee < Sequel::Model(@db)
886
- def _save_refresh; @values[:id] = 1 end
887
- def self.columns
888
- dataset.columns || dataset.opts[:from].first.expression.columns
889
- end
890
- plugin :class_table_inheritance, :table_map=>{:Staff=>:staff}, :alias=>:employees
891
- end
892
- class ::Manager < Employee
893
- one_to_many :staff_members, :class=>:Staff
894
- end
895
- class ::Executive < Manager
896
- end
897
- class ::Staff < Employee
898
- many_to_one :manager
899
- end
900
- @ds = Employee.dataset
901
- @db.sqls
902
- end
903
- after do
904
- Object.send(:remove_const, :Executive)
905
- Object.send(:remove_const, :Manager)
906
- Object.send(:remove_const, :Staff)
907
- Object.send(:remove_const, :Employee)
908
- end
909
-
910
- it "should have simple_table = nil for all subclasses" do
911
- Manager.simple_table.must_be_nil
912
- Executive.simple_table.must_be_nil
913
- Staff.simple_table.must_be_nil
914
- end
915
-
916
- it "should have working row_proc if using set_dataset in subclass to remove columns" do
917
- Manager.set_dataset(Manager.dataset.select(*(Manager.columns - [:blah])))
918
- Manager.dataset = Manager.dataset.with_fetch(:id=>1)
919
- Manager[1].must_equal Manager.load(:id=>1)
920
- end
921
-
922
- it "should use a joined dataset in subclasses" do
923
- Employee.dataset.sql.must_equal 'SELECT * FROM employees'
924
- 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 employees'
925
- 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 employees'
926
- 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 employees'
927
- end
928
-
929
- it "should return rows with the current class if cti_key is nil" do
930
- Employee.plugin(:class_table_inheritance)
931
- Employee.dataset = Employee.dataset.with_fetch([{}])
932
- Employee.first.class.must_equal Employee
933
- end
934
-
935
-
936
- it "should include schema for columns for tables for ancestor classes" do
937
- Employee.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string})
938
- Manager.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :num_staff=>{:type=>:integer})
939
- Executive.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :num_staff=>{:type=>:integer}, :num_managers=>{:type=>:integer})
940
- Staff.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :manager_id=>{:type=>:integer})
941
- end
942
-
943
- it "should use the correct primary key (which should have the same name in all subclasses)" do
944
- [Employee, Manager, Executive, Staff].each{|c| c.primary_key.must_equal :id}
945
- end
946
-
947
- it "should have table_name return the table name of the most specific table" do
948
- Employee.table_name.must_equal :employees
949
- Manager.table_name.must_equal :employees
950
- Executive.table_name.must_equal :employees
951
- Staff.table_name.must_equal :employees
952
- end
953
-
954
- it "should delete the correct rows from all tables when deleting" do
955
- Executive.load(:id=>1).delete
956
- @db.sqls.must_equal ["DELETE FROM executives WHERE (id = 1)", "DELETE FROM managers WHERE (id = 1)", "DELETE FROM employees WHERE (id = 1)"]
957
- end
958
-
959
- it "should not allow deletion of frozen object" do
960
- o = Executive.load(:id=>1)
961
- o.freeze
962
- proc{o.delete}.must_raise(Sequel::Error)
963
- @db.sqls.must_equal []
964
- end
965
-
966
- it "should insert the correct rows into all tables when inserting" do
967
- Executive.create(:num_managers=>3, :num_staff=>2, :name=>'E')
968
- sqls = @db.sqls
969
- sqls.length.must_equal 3
970
- sqls[0].must_match(/INSERT INTO employees \(name\) VALUES \('E'\)/)
971
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \([12], [12]\)/)
972
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([13], [13]\)/)
973
- end
974
-
975
- it "should insert the correct rows into all tables with a given primary key" do
976
- e = Executive.new(:num_managers=>3, :num_staff=>2, :name=>'E')
977
- e.id = 2
978
- e.save
979
- sqls = @db.sqls
980
- sqls.length.must_equal 3
981
- sqls[0].must_match(/INSERT INTO employees \((name|id), (name|id)\) VALUES \(('E'|2), ('E'|2)\)/)
982
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \(2, 2\)/)
983
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([23], [23]\)/)
984
- end
985
-
986
- it "should update the correct rows in all tables when updating" do
987
- Executive.load(:id=>2).update(:num_managers=>3, :num_staff=>2, :name=>'E')
988
- @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)"]
989
- end
990
-
991
- it "should handle many_to_one relationships correctly" do
992
- Manager.dataset = Manager.dataset.with_fetch(:id=>3, :name=>'E', :num_staff=>3)
993
- Staff.load(:manager_id=>3).manager.must_equal Manager.load(:id=>3, :name=>'E', :num_staff=>3)
994
- @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 employees WHERE (id = 3) LIMIT 1']
995
- end
996
-
997
- it "should handle one_to_many relationships correctly" do
998
- Staff.dataset = Staff.dataset.with_fetch(:id=>1, :name=>'S', :manager_id=>3)
999
- Executive.load(:id=>3).staff_members.must_equal [Staff.load(:id=>1, :name=>'S', :manager_id=>3)]
1000
- @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 employees WHERE (employees.manager_id = 3)']
1001
- end
1002
- end
1003
-
1004
- describe "class_table_inheritance plugin with duplicate columns with :alias option" do
1005
- before do
1006
- @db = Sequel.mock(:autoid=>proc{|sql| 1})
1007
- def @db.supports_schema_parsing?() true end
1008
- def @db.schema(table, opts={})
1009
- {:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}], [:kind, {:type=>:string}]],
1010
- :managers=>[[:id, {:type=>:integer}], [:name, {:type=>:string}]],
1011
- }[table.is_a?(Sequel::Dataset) ? table.first_source_table : table]
1012
- end
1013
- @db.extend_datasets do
1014
- def columns
1015
- {[:employees]=>[:id, :name, :kind],
1016
- [:managers]=>[:id, :name],
1017
- }[opts[:from] + (opts[:join] || []).map{|x| x.table}]
1018
- end
1019
- end
1020
- class ::Employee < Sequel::Model(@db)
1021
- def _save_refresh; @values[:id] = 1 end
1022
- def self.columns
1023
- dataset.columns || dataset.opts[:from].first.expression.columns
1024
- end
1025
- plugin :class_table_inheritance, :key=>:kind, :table_map=>{:Staff=>:staff}, :alias=>:employees
1026
- end
1027
- deprecated do
1028
- class ::Manager < Employee; end
1029
- end
1030
- @ds = Employee.dataset
1031
- @db.sqls
1032
- end
1033
- after do
1034
- Object.send(:remove_const, :Manager)
1035
- Object.send(:remove_const, :Employee)
1036
- end
1037
-
1038
- it "should select names from both tables" do
1039
- Manager.dataset.sql.must_equal 'SELECT * FROM (SELECT employees.id, employees.name, employees.kind, managers.name FROM employees INNER JOIN managers ON (managers.id = employees.id)) AS employees'
1040
- end
1041
- end
1042
-
1043
- describe "class_table_inheritance plugin with :alias option" do
1044
- before do
1045
- @db = Sequel.mock(:autoid=>proc{|sql| 1})
5
+ @db = Sequel.mock(:numrows=>1, :autoid=>proc{|sql| 1})
1046
6
  def @db.supports_schema_parsing?() true end
1047
7
  def @db.schema(table, opts={})
1048
8
  {:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}], [:kind, {:type=>:string}]],
@@ -1068,7 +28,7 @@ describe "class_table_inheritance plugin with :alias option" do
1068
28
  def self.columns
1069
29
  dataset.columns || dataset.opts[:from].first.expression.columns
1070
30
  end
1071
- plugin :class_table_inheritance, :key=>:kind, :table_map=>{:Staff=>:staff}, :alias=>:employees
31
+ plugin :class_table_inheritance, :key=>:kind, :table_map=>{:Staff=>:staff}
1072
32
  end
1073
33
  class ::Manager < Employee
1074
34
  one_to_many :staff_members, :class=>:Staff
@@ -1100,27 +60,18 @@ describe "class_table_inheritance plugin with :alias option" do
1100
60
 
1101
61
  it "should not attempt to use prepared statements" do
1102
62
  Manager.plugin :prepared_statements
1103
- Manager[1]
1104
- @db.sqls.must_equal ["SELECT id, name, kind, 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 (id = 1) LIMIT 1"]
1105
63
  Manager.load(:id=>1, :kind=>'Manager', :num_staff=>2).save
1106
64
  @db.sqls.must_equal ["UPDATE employees SET kind = 'Manager' WHERE (id = 1)", "UPDATE managers SET num_staff = 2 WHERE (id = 1)"]
1107
- @db.fetch = {:id=>1, :kind=>'Manager', :num_staff=>2}
1108
- Manager.load(:id=>1, :kind=>'Manager', :num_staff=>2).refresh
1109
- @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"]
1110
- end
1111
65
 
1112
- deprecated "#cti_base_model should be the model that loaded the plugin" do
1113
- Executive.cti_base_model.must_equal Employee
66
+ Employee.plugin :prepared_statements
67
+ Employee.load(:id=>2, :kind=>'Employee').save
68
+ @db.sqls.must_equal ["UPDATE employees SET kind = 'Employee' WHERE (id = 2)"]
1114
69
  end
1115
70
 
1116
71
  it "#cti_models.first should be the model that loaded the plugin" do
1117
72
  Executive.cti_models.first.must_equal Employee
1118
73
  end
1119
74
 
1120
- deprecated "#cti_columns should be a mapping of table names to columns" do
1121
- Executive.cti_columns.must_equal(:employees=>[:id, :name, :kind], :managers=>[:id, :num_staff], :executives=>[:id, :num_managers])
1122
- end
1123
-
1124
75
  it "should have simple_table = nil for all subclasses" do
1125
76
  Manager.simple_table.must_be_nil
1126
77
  Executive.simple_table.must_be_nil
@@ -1163,13 +114,13 @@ describe "class_table_inheritance plugin with :alias option" do
1163
114
  "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"]
1164
115
  end
1165
116
 
1166
- it "should return rows with the current class if cti_key is nil" do
1167
- Employee.plugin(:class_table_inheritance, :alias=>:employees)
117
+ it "should return rows with the current class if sti_key is nil" do
118
+ Employee.plugin :class_table_inheritance
1168
119
  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]
1169
120
  end
1170
121
 
1171
- it "should return rows with the current class if cti_key is nil in subclasses" do
1172
- Employee.plugin(:class_table_inheritance, :alias=>:employees)
122
+ it "should return rows with the current class if sti_key is nil in subclasses" do
123
+ Employee.plugin :class_table_inheritance
1173
124
  Object.send(:remove_const, :Executive)
1174
125
  Object.send(:remove_const, :Manager)
1175
126
  class ::Manager < Employee; end
@@ -1178,7 +129,7 @@ describe "class_table_inheritance plugin with :alias option" do
1178
129
  end
1179
130
 
1180
131
  it "should handle a model map with integer values" do
1181
- Employee.plugin(:class_table_inheritance, :key=>:kind, :model_map=>{0=>:Employee, 1=>:Manager, 2=>:Executive, 3=>:Ceo, 4=>:Intern}, :alias=>:employees)
132
+ Employee.plugin :class_table_inheritance, :key=>:kind, :model_map=>{0=>:Employee, 1=>:Manager, 2=>:Executive, 3=>:Ceo, 4=>:Intern}
1182
133
  Object.send(:remove_const, :Intern)
1183
134
  Object.send(:remove_const, :Ceo)
1184
135
  Object.send(:remove_const, :Executive)
@@ -1218,12 +169,12 @@ describe "class_table_inheritance plugin with :alias option" do
1218
169
  "INSERT INTO executives (id) VALUES (1)"]
1219
170
  end
1220
171
 
1221
- it "should ignore existing cti_key value when creating new records" do
172
+ it "should ignore existing sti_key value when creating new records" do
1222
173
  Employee.create(:kind=>'Manager')
1223
174
  @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Employee')"]
1224
175
  end
1225
176
 
1226
- it "should ignore existing cti_key value in subclasses" do
177
+ it "should ignore existing sti_key value in subclasses" do
1227
178
  Manager.create(:kind=>'Executive')
1228
179
  @db.sqls.must_equal ["INSERT INTO employees (kind) VALUES ('Manager')",
1229
180
  "INSERT INTO managers (id) VALUES (1)"]
@@ -1388,6 +339,12 @@ describe "class_table_inheritance plugin with :alias option" do
1388
339
  @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)"]
1389
340
  end
1390
341
 
342
+ it "should raise error if one of the updates does not update a single row" do
343
+ @db.numrows = [1, 0]
344
+ proc{Ceo.load(:id=>2).update(:num_managers=>3, :num_staff=>2, :name=>'E')}.must_raise Sequel::NoExistingObject
345
+ @db.sqls.must_equal ["UPDATE employees SET name = 'E' WHERE (id = 2)", "UPDATE managers SET num_staff = 2 WHERE (id = 2)"]
346
+ end
347
+
1391
348
  it "should handle many_to_one relationships correctly" do
1392
349
  Manager.dataset = Manager.dataset.with_fetch(:id=>3, :name=>'E', :kind=>'Ceo', :num_managers=>3)
1393
350
  Staff.load(:manager_id=>3).manager.must_equal Ceo.load(:id=>3, :name=>'E', :kind=>'Ceo', :num_managers=>3)
@@ -1403,7 +360,7 @@ end
1403
360
 
1404
361
  describe "class_table_inheritance plugin without sti_key with :alias option" do
1405
362
  before do
1406
- @db = Sequel.mock(:autoid=>proc{|sql| 1})
363
+ @db = Sequel.mock(:numrows=>1, :autoid=>proc{|sql| 1})
1407
364
  def @db.supports_schema_parsing?() true end
1408
365
  def @db.schema(table, opts={})
1409
366
  {:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}]],
@@ -1429,7 +386,7 @@ describe "class_table_inheritance plugin without sti_key with :alias option" do
1429
386
  def self.columns
1430
387
  dataset.columns || dataset.opts[:from].first.expression.columns
1431
388
  end
1432
- plugin :class_table_inheritance, :table_map=>{:Staff=>:staff}, :alias=>:employees
389
+ plugin :class_table_inheritance, :table_map=>{:Staff=>:staff}, :alias=>:emps
1433
390
  end
1434
391
  class ::Manager < Employee
1435
392
  one_to_many :staff_members, :class=>:Staff
@@ -1463,18 +420,17 @@ describe "class_table_inheritance plugin without sti_key with :alias option" do
1463
420
 
1464
421
  it "should use a joined dataset in subclasses" do
1465
422
  Employee.dataset.sql.must_equal 'SELECT * FROM employees'
1466
- 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 employees'
1467
- 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 employees'
1468
- 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 employees'
423
+ 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'
424
+ 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'
425
+ 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'
1469
426
  end
1470
427
 
1471
- it "should return rows with the current class if cti_key is nil" do
428
+ it "should return rows with the current class if sti_key is nil" do
1472
429
  Employee.plugin(:class_table_inheritance)
1473
430
  Employee.dataset = Employee.dataset.with_fetch([{}])
1474
431
  Employee.first.class.must_equal Employee
1475
432
  end
1476
433
 
1477
-
1478
434
  it "should include schema for columns for tables for ancestor classes" do
1479
435
  Employee.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string})
1480
436
  Manager.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :num_staff=>{:type=>:integer})
@@ -1488,9 +444,9 @@ describe "class_table_inheritance plugin without sti_key with :alias option" do
1488
444
 
1489
445
  it "should have table_name return the table name of the most specific table" do
1490
446
  Employee.table_name.must_equal :employees
1491
- Manager.table_name.must_equal :employees
1492
- Executive.table_name.must_equal :employees
1493
- Staff.table_name.must_equal :employees
447
+ Manager.table_name.must_equal :emps
448
+ Executive.table_name.must_equal :emps
449
+ Staff.table_name.must_equal :emps
1494
450
  end
1495
451
 
1496
452
  it "should delete the correct rows from all tables when deleting" do
@@ -1533,18 +489,18 @@ describe "class_table_inheritance plugin without sti_key with :alias option" do
1533
489
  it "should handle many_to_one relationships correctly" do
1534
490
  Manager.dataset = Manager.dataset.with_fetch(:id=>3, :name=>'E', :num_staff=>3)
1535
491
  Staff.load(:manager_id=>3).manager.must_equal Manager.load(:id=>3, :name=>'E', :num_staff=>3)
1536
- @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 employees WHERE (id = 3) LIMIT 1']
492
+ @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']
1537
493
  end
1538
494
 
1539
495
  it "should handle one_to_many relationships correctly" do
1540
496
  Staff.dataset = Staff.dataset.with_fetch(:id=>1, :name=>'S', :manager_id=>3)
1541
497
  Executive.load(:id=>3).staff_members.must_equal [Staff.load(:id=>1, :name=>'S', :manager_id=>3)]
1542
- @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 employees WHERE (employees.manager_id = 3)']
498
+ @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)']
1543
499
  end
1544
500
  end
1545
501
 
1546
- describe "class_table_inheritance plugin with duplicate columns with :alias option" do
1547
- before do
502
+ describe "class_table_inheritance plugin with duplicate columns" do
503
+ it "should raise error" do
1548
504
  @db = Sequel.mock(:autoid=>proc{|sql| 1})
1549
505
  def @db.supports_schema_parsing?() true end
1550
506
  def @db.schema(table, opts={})
@@ -1564,20 +520,13 @@ describe "class_table_inheritance plugin with duplicate columns with :alias opti
1564
520
  def self.columns
1565
521
  dataset.columns || dataset.opts[:from].first.expression.columns
1566
522
  end
1567
- plugin :class_table_inheritance, :key=>:kind, :table_map=>{:Staff=>:staff}, :alias=>:employees
523
+ plugin :class_table_inheritance
1568
524
  end
1569
- deprecated do
1570
- class ::Manager < Employee; end
1571
- end
1572
- @ds = Employee.dataset
1573
- @db.sqls
525
+ proc{class ::Manager < Employee; end}.must_raise Sequel::Error
1574
526
  end
1575
527
  after do
1576
528
  Object.send(:remove_const, :Manager)
1577
529
  Object.send(:remove_const, :Employee)
1578
530
  end
1579
-
1580
- it "should select names from both tables" do
1581
- Manager.dataset.sql.must_equal 'SELECT * FROM (SELECT employees.id, employees.name, employees.kind, managers.name FROM employees INNER JOIN managers ON (managers.id = employees.id)) AS employees'
1582
- end
1583
531
  end
532
+