sequel 4.49.0 → 5.3.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 (484) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +130 -0
  3. data/README.rdoc +195 -136
  4. data/Rakefile +26 -42
  5. data/bin/sequel +6 -9
  6. data/doc/advanced_associations.rdoc +91 -168
  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/release_notes/5.1.0.txt +31 -0
  29. data/doc/release_notes/5.2.0.txt +33 -0
  30. data/doc/release_notes/5.3.0.txt +121 -0
  31. data/doc/schema_modification.rdoc +78 -64
  32. data/doc/security.rdoc +97 -88
  33. data/doc/sharding.rdoc +43 -30
  34. data/doc/sql.rdoc +53 -65
  35. data/doc/testing.rdoc +4 -5
  36. data/doc/thread_safety.rdoc +2 -4
  37. data/doc/transactions.rdoc +18 -17
  38. data/doc/validations.rdoc +48 -45
  39. data/doc/virtual_rows.rdoc +87 -115
  40. data/lib/sequel/adapters/ado/access.rb +7 -13
  41. data/lib/sequel/adapters/ado/mssql.rb +2 -9
  42. data/lib/sequel/adapters/ado.rb +9 -25
  43. data/lib/sequel/adapters/amalgalite.rb +3 -18
  44. data/lib/sequel/adapters/ibmdb.rb +9 -45
  45. data/lib/sequel/adapters/jdbc/db2.rb +8 -37
  46. data/lib/sequel/adapters/jdbc/derby.rb +4 -50
  47. data/lib/sequel/adapters/jdbc/h2.rb +6 -26
  48. data/lib/sequel/adapters/jdbc/hsqldb.rb +2 -27
  49. data/lib/sequel/adapters/jdbc/jtds.rb +2 -9
  50. data/lib/sequel/adapters/jdbc/mssql.rb +1 -11
  51. data/lib/sequel/adapters/jdbc/mysql.rb +11 -15
  52. data/lib/sequel/adapters/jdbc/oracle.rb +4 -26
  53. data/lib/sequel/adapters/jdbc/postgresql.rb +23 -33
  54. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +4 -17
  55. data/lib/sequel/adapters/jdbc/sqlite.rb +1 -7
  56. data/lib/sequel/adapters/jdbc/sqlserver.rb +1 -13
  57. data/lib/sequel/adapters/jdbc/transactions.rb +1 -14
  58. data/lib/sequel/adapters/jdbc.rb +18 -74
  59. data/lib/sequel/adapters/mock.rb +4 -30
  60. data/lib/sequel/adapters/mysql.rb +7 -44
  61. data/lib/sequel/adapters/mysql2.rb +5 -23
  62. data/lib/sequel/adapters/odbc/db2.rb +1 -1
  63. data/lib/sequel/adapters/odbc/mssql.rb +4 -12
  64. data/lib/sequel/adapters/odbc/oracle.rb +1 -1
  65. data/lib/sequel/adapters/odbc.rb +0 -19
  66. data/lib/sequel/adapters/oracle.rb +8 -13
  67. data/lib/sequel/adapters/postgres.rb +28 -150
  68. data/lib/sequel/adapters/postgresql.rb +1 -1
  69. data/lib/sequel/adapters/shared/access.rb +11 -51
  70. data/lib/sequel/adapters/shared/db2.rb +3 -61
  71. data/lib/sequel/adapters/shared/mssql.rb +21 -157
  72. data/lib/sequel/adapters/shared/mysql.rb +61 -227
  73. data/lib/sequel/adapters/shared/oracle.rb +13 -41
  74. data/lib/sequel/adapters/shared/postgres.rb +58 -264
  75. data/lib/sequel/adapters/shared/sqlanywhere.rb +4 -96
  76. data/lib/sequel/adapters/shared/sqlite.rb +22 -101
  77. data/lib/sequel/adapters/sqlanywhere.rb +4 -23
  78. data/lib/sequel/adapters/sqlite.rb +2 -19
  79. data/lib/sequel/adapters/tinytds.rb +5 -15
  80. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +1 -1
  81. data/lib/sequel/adapters/utils/mysql_mysql2.rb +4 -4
  82. data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +3 -6
  83. data/lib/sequel/adapters/utils/replace.rb +0 -5
  84. data/lib/sequel/adapters/utils/stored_procedures.rb +0 -2
  85. data/lib/sequel/adapters/utils/unmodified_identifiers.rb +2 -0
  86. data/lib/sequel/ast_transformer.rb +3 -94
  87. data/lib/sequel/connection_pool/sharded_single.rb +1 -4
  88. data/lib/sequel/connection_pool/sharded_threaded.rb +97 -95
  89. data/lib/sequel/connection_pool/single.rb +0 -2
  90. data/lib/sequel/connection_pool/threaded.rb +94 -110
  91. data/lib/sequel/connection_pool.rb +38 -28
  92. data/lib/sequel/core.rb +42 -101
  93. data/lib/sequel/database/connecting.rb +23 -60
  94. data/lib/sequel/database/dataset.rb +6 -9
  95. data/lib/sequel/database/dataset_defaults.rb +4 -48
  96. data/lib/sequel/database/features.rb +5 -4
  97. data/lib/sequel/database/logging.rb +2 -9
  98. data/lib/sequel/database/misc.rb +36 -55
  99. data/lib/sequel/database/query.rb +8 -13
  100. data/lib/sequel/database/schema_generator.rb +93 -64
  101. data/lib/sequel/database/schema_methods.rb +61 -79
  102. data/lib/sequel/database/transactions.rb +4 -24
  103. data/lib/sequel/database.rb +12 -2
  104. data/lib/sequel/dataset/actions.rb +57 -107
  105. data/lib/sequel/dataset/dataset_module.rb +4 -16
  106. data/lib/sequel/dataset/features.rb +35 -30
  107. data/lib/sequel/dataset/graph.rb +40 -49
  108. data/lib/sequel/dataset/misc.rb +12 -37
  109. data/lib/sequel/dataset/placeholder_literalizer.rb +4 -4
  110. data/lib/sequel/dataset/prepared_statements.rb +23 -51
  111. data/lib/sequel/dataset/query.rb +91 -161
  112. data/lib/sequel/dataset/sql.rb +33 -225
  113. data/lib/sequel/dataset.rb +18 -10
  114. data/lib/sequel/deprecated.rb +18 -27
  115. data/lib/sequel/exceptions.rb +1 -17
  116. data/lib/sequel/extensions/_model_pg_row.rb +0 -7
  117. data/lib/sequel/extensions/_pretty_table.rb +1 -3
  118. data/lib/sequel/extensions/arbitrary_servers.rb +10 -10
  119. data/lib/sequel/extensions/connection_expiration.rb +1 -1
  120. data/lib/sequel/extensions/connection_validator.rb +1 -1
  121. data/lib/sequel/extensions/constraint_validations.rb +11 -11
  122. data/lib/sequel/extensions/core_extensions.rb +39 -49
  123. data/lib/sequel/extensions/core_refinements.rb +39 -45
  124. data/lib/sequel/extensions/current_datetime_timestamp.rb +0 -4
  125. data/lib/sequel/extensions/date_arithmetic.rb +7 -7
  126. data/lib/sequel/extensions/duplicate_columns_handler.rb +12 -9
  127. data/lib/sequel/extensions/empty_array_consider_nulls.rb +2 -2
  128. data/lib/sequel/extensions/eval_inspect.rb +4 -11
  129. data/lib/sequel/extensions/freeze_datasets.rb +1 -69
  130. data/lib/sequel/extensions/from_block.rb +1 -35
  131. data/lib/sequel/extensions/graph_each.rb +2 -2
  132. data/lib/sequel/extensions/identifier_mangling.rb +9 -19
  133. data/lib/sequel/extensions/implicit_subquery.rb +2 -2
  134. data/lib/sequel/extensions/inflector.rb +4 -4
  135. data/lib/sequel/extensions/migration.rb +27 -43
  136. data/lib/sequel/extensions/no_auto_literal_strings.rb +2 -84
  137. data/lib/sequel/extensions/null_dataset.rb +2 -8
  138. data/lib/sequel/extensions/pagination.rb +1 -17
  139. data/lib/sequel/extensions/pg_array.rb +20 -189
  140. data/lib/sequel/extensions/pg_extended_date_support.rb +230 -0
  141. data/lib/sequel/extensions/pg_hstore.rb +11 -50
  142. data/lib/sequel/extensions/pg_hstore_ops.rb +2 -2
  143. data/lib/sequel/extensions/pg_inet.rb +3 -16
  144. data/lib/sequel/extensions/pg_interval.rb +1 -20
  145. data/lib/sequel/extensions/pg_json.rb +7 -27
  146. data/lib/sequel/extensions/pg_loose_count.rb +1 -1
  147. data/lib/sequel/extensions/pg_range.rb +6 -121
  148. data/lib/sequel/extensions/pg_range_ops.rb +1 -3
  149. data/lib/sequel/extensions/pg_row.rb +5 -77
  150. data/lib/sequel/extensions/pg_row_ops.rb +2 -13
  151. data/lib/sequel/extensions/query.rb +3 -4
  152. data/lib/sequel/extensions/round_timestamps.rb +0 -6
  153. data/lib/sequel/extensions/schema_dumper.rb +13 -13
  154. data/lib/sequel/extensions/select_remove.rb +3 -3
  155. data/lib/sequel/extensions/split_array_nil.rb +2 -2
  156. data/lib/sequel/extensions/sql_comments.rb +2 -2
  157. data/lib/sequel/extensions/string_agg.rb +11 -8
  158. data/lib/sequel/extensions/symbol_aref.rb +6 -20
  159. data/lib/sequel/extensions/synchronize_sql.rb +45 -0
  160. data/lib/sequel/model/associations.rb +129 -131
  161. data/lib/sequel/model/base.rb +133 -731
  162. data/lib/sequel/model/default_inflections.rb +1 -1
  163. data/lib/sequel/model/errors.rb +0 -3
  164. data/lib/sequel/model/exceptions.rb +2 -6
  165. data/lib/sequel/model/inflections.rb +1 -26
  166. data/lib/sequel/model/plugins.rb +1 -0
  167. data/lib/sequel/model.rb +27 -62
  168. data/lib/sequel/plugins/active_model.rb +2 -5
  169. data/lib/sequel/plugins/association_dependencies.rb +15 -15
  170. data/lib/sequel/plugins/association_pks.rb +14 -28
  171. data/lib/sequel/plugins/association_proxies.rb +6 -7
  172. data/lib/sequel/plugins/auto_validations.rb +4 -4
  173. data/lib/sequel/plugins/before_after_save.rb +0 -43
  174. data/lib/sequel/plugins/blacklist_security.rb +9 -8
  175. data/lib/sequel/plugins/boolean_readers.rb +3 -3
  176. data/lib/sequel/plugins/boolean_subsets.rb +2 -2
  177. data/lib/sequel/plugins/caching.rb +5 -5
  178. data/lib/sequel/plugins/class_table_inheritance.rb +71 -102
  179. data/lib/sequel/plugins/column_conflicts.rb +2 -2
  180. data/lib/sequel/plugins/column_select.rb +2 -2
  181. data/lib/sequel/plugins/composition.rb +15 -24
  182. data/lib/sequel/plugins/constraint_validations.rb +4 -3
  183. data/lib/sequel/plugins/csv_serializer.rb +13 -20
  184. data/lib/sequel/plugins/dataset_associations.rb +2 -2
  185. data/lib/sequel/plugins/def_dataset_method.rb +5 -5
  186. data/lib/sequel/plugins/defaults_setter.rb +1 -1
  187. data/lib/sequel/plugins/delay_add_association.rb +1 -1
  188. data/lib/sequel/plugins/finder.rb +16 -10
  189. data/lib/sequel/plugins/force_encoding.rb +1 -7
  190. data/lib/sequel/plugins/hook_class_methods.rb +4 -106
  191. data/lib/sequel/plugins/input_transformer.rb +10 -11
  192. data/lib/sequel/plugins/insert_returning_select.rb +1 -9
  193. data/lib/sequel/plugins/instance_filters.rb +5 -5
  194. data/lib/sequel/plugins/instance_hooks.rb +7 -52
  195. data/lib/sequel/plugins/inverted_subsets.rb +3 -1
  196. data/lib/sequel/plugins/json_serializer.rb +19 -19
  197. data/lib/sequel/plugins/lazy_attributes.rb +1 -10
  198. data/lib/sequel/plugins/list.rb +6 -6
  199. data/lib/sequel/plugins/many_through_many.rb +11 -8
  200. data/lib/sequel/plugins/mssql_optimistic_locking.rb +3 -3
  201. data/lib/sequel/plugins/nested_attributes.rb +18 -31
  202. data/lib/sequel/plugins/optimistic_locking.rb +3 -3
  203. data/lib/sequel/plugins/pg_array_associations.rb +8 -2
  204. data/lib/sequel/plugins/pg_row.rb +2 -11
  205. data/lib/sequel/plugins/prepared_statements.rb +13 -66
  206. data/lib/sequel/plugins/prepared_statements_safe.rb +1 -1
  207. data/lib/sequel/plugins/rcte_tree.rb +7 -7
  208. data/lib/sequel/plugins/serialization.rb +15 -33
  209. data/lib/sequel/plugins/serialization_modification_detection.rb +1 -1
  210. data/lib/sequel/plugins/sharding.rb +2 -8
  211. data/lib/sequel/plugins/single_table_inheritance.rb +10 -13
  212. data/lib/sequel/plugins/skip_create_refresh.rb +3 -3
  213. data/lib/sequel/plugins/static_cache.rb +8 -9
  214. data/lib/sequel/plugins/string_stripper.rb +3 -3
  215. data/lib/sequel/plugins/subclasses.rb +1 -1
  216. data/lib/sequel/plugins/subset_conditions.rb +2 -2
  217. data/lib/sequel/plugins/table_select.rb +2 -2
  218. data/lib/sequel/plugins/tactical_eager_loading.rb +4 -4
  219. data/lib/sequel/plugins/timestamps.rb +6 -7
  220. data/lib/sequel/plugins/touch.rb +4 -8
  221. data/lib/sequel/plugins/tree.rb +3 -3
  222. data/lib/sequel/plugins/typecast_on_load.rb +2 -2
  223. data/lib/sequel/plugins/unlimited_update.rb +1 -7
  224. data/lib/sequel/plugins/update_or_create.rb +3 -3
  225. data/lib/sequel/plugins/update_refresh.rb +3 -3
  226. data/lib/sequel/plugins/uuid.rb +7 -11
  227. data/lib/sequel/plugins/validation_class_methods.rb +10 -9
  228. data/lib/sequel/plugins/validation_contexts.rb +4 -4
  229. data/lib/sequel/plugins/validation_helpers.rb +26 -25
  230. data/lib/sequel/plugins/whitelist_security.rb +13 -9
  231. data/lib/sequel/plugins/xml_serializer.rb +24 -25
  232. data/lib/sequel/sql.rb +145 -276
  233. data/lib/sequel/timezones.rb +8 -23
  234. data/lib/sequel/version.rb +2 -2
  235. data/lib/sequel.rb +1 -1
  236. data/spec/adapter_spec.rb +1 -1
  237. data/spec/adapters/db2_spec.rb +2 -103
  238. data/spec/adapters/mssql_spec.rb +89 -68
  239. data/spec/adapters/mysql_spec.rb +111 -478
  240. data/spec/adapters/oracle_spec.rb +1 -9
  241. data/spec/adapters/postgres_spec.rb +459 -664
  242. data/spec/adapters/spec_helper.rb +12 -31
  243. data/spec/adapters/sqlanywhere_spec.rb +2 -77
  244. data/spec/adapters/sqlite_spec.rb +8 -146
  245. data/spec/bin_spec.rb +11 -16
  246. data/spec/core/connection_pool_spec.rb +173 -74
  247. data/spec/core/database_spec.rb +96 -244
  248. data/spec/core/dataset_spec.rb +99 -414
  249. data/spec/core/deprecated_spec.rb +3 -3
  250. data/spec/core/expression_filters_spec.rb +37 -144
  251. data/spec/core/mock_adapter_spec.rb +241 -4
  252. data/spec/core/object_graph_spec.rb +11 -60
  253. data/spec/core/placeholder_literalizer_spec.rb +1 -14
  254. data/spec/core/schema_generator_spec.rb +51 -40
  255. data/spec/core/schema_spec.rb +88 -77
  256. data/spec/core/spec_helper.rb +6 -24
  257. data/spec/core/version_spec.rb +1 -1
  258. data/spec/core_extensions_spec.rb +7 -83
  259. data/spec/core_model_spec.rb +2 -2
  260. data/spec/deprecation_helper.rb +2 -14
  261. data/spec/extensions/accessed_columns_spec.rb +1 -1
  262. data/spec/extensions/active_model_spec.rb +3 -3
  263. data/spec/extensions/after_initialize_spec.rb +1 -1
  264. data/spec/extensions/arbitrary_servers_spec.rb +2 -2
  265. data/spec/extensions/association_dependencies_spec.rb +1 -1
  266. data/spec/extensions/association_pks_spec.rb +30 -92
  267. data/spec/extensions/association_proxies_spec.rb +1 -1
  268. data/spec/extensions/auto_literal_strings_spec.rb +1 -12
  269. data/spec/extensions/auto_validations_spec.rb +1 -1
  270. data/spec/extensions/blacklist_security_spec.rb +1 -1
  271. data/spec/extensions/blank_spec.rb +1 -1
  272. data/spec/extensions/boolean_readers_spec.rb +1 -1
  273. data/spec/extensions/boolean_subsets_spec.rb +1 -1
  274. data/spec/extensions/caching_spec.rb +1 -1
  275. data/spec/extensions/class_table_inheritance_spec.rb +53 -1118
  276. data/spec/extensions/column_conflicts_spec.rb +1 -1
  277. data/spec/extensions/column_select_spec.rb +4 -4
  278. data/spec/extensions/columns_introspection_spec.rb +1 -1
  279. data/spec/extensions/columns_updated_spec.rb +1 -1
  280. data/spec/extensions/composition_spec.rb +8 -30
  281. data/spec/extensions/connection_expiration_spec.rb +3 -3
  282. data/spec/extensions/connection_validator_spec.rb +3 -3
  283. data/spec/extensions/constraint_validations_plugin_spec.rb +1 -1
  284. data/spec/extensions/constraint_validations_spec.rb +1 -1
  285. data/spec/extensions/core_refinements_spec.rb +1 -3
  286. data/spec/extensions/csv_serializer_spec.rb +4 -9
  287. data/spec/extensions/current_datetime_timestamp_spec.rb +1 -1
  288. data/spec/extensions/dataset_associations_spec.rb +2 -1
  289. data/spec/extensions/dataset_source_alias_spec.rb +1 -1
  290. data/spec/extensions/date_arithmetic_spec.rb +3 -3
  291. data/spec/extensions/def_dataset_method_spec.rb +1 -1
  292. data/spec/extensions/defaults_setter_spec.rb +2 -2
  293. data/spec/extensions/delay_add_association_spec.rb +8 -9
  294. data/spec/extensions/dirty_spec.rb +1 -1
  295. data/spec/extensions/duplicate_columns_handler_spec.rb +1 -1
  296. data/spec/extensions/eager_each_spec.rb +2 -2
  297. data/spec/extensions/empty_array_consider_nulls_spec.rb +1 -1
  298. data/spec/extensions/error_splitter_spec.rb +1 -1
  299. data/spec/extensions/error_sql_spec.rb +1 -1
  300. data/spec/extensions/eval_inspect_spec.rb +1 -1
  301. data/spec/extensions/finder_spec.rb +1 -1
  302. data/spec/extensions/force_encoding_spec.rb +2 -5
  303. data/spec/extensions/freeze_datasets_spec.rb +1 -1
  304. data/spec/extensions/graph_each_spec.rb +5 -5
  305. data/spec/extensions/hook_class_methods_spec.rb +1 -194
  306. data/spec/extensions/identifier_mangling_spec.rb +17 -170
  307. data/spec/extensions/implicit_subquery_spec.rb +1 -5
  308. data/spec/extensions/inflector_spec.rb +1 -1
  309. data/spec/extensions/input_transformer_spec.rb +7 -2
  310. data/spec/extensions/insert_returning_select_spec.rb +1 -1
  311. data/spec/extensions/instance_filters_spec.rb +1 -1
  312. data/spec/extensions/instance_hooks_spec.rb +1 -95
  313. data/spec/extensions/inverted_subsets_spec.rb +1 -1
  314. data/spec/extensions/json_serializer_spec.rb +1 -1
  315. data/spec/extensions/lazy_attributes_spec.rb +1 -7
  316. data/spec/extensions/list_spec.rb +5 -6
  317. data/spec/extensions/looser_typecasting_spec.rb +1 -1
  318. data/spec/extensions/many_through_many_spec.rb +25 -33
  319. data/spec/extensions/migration_spec.rb +12 -2
  320. data/spec/extensions/modification_detection_spec.rb +1 -1
  321. data/spec/extensions/mssql_optimistic_locking_spec.rb +1 -1
  322. data/spec/extensions/named_timezones_spec.rb +3 -3
  323. data/spec/extensions/nested_attributes_spec.rb +1 -29
  324. data/spec/extensions/null_dataset_spec.rb +1 -11
  325. data/spec/extensions/optimistic_locking_spec.rb +2 -2
  326. data/spec/extensions/pagination_spec.rb +1 -1
  327. data/spec/extensions/pg_array_associations_spec.rb +22 -26
  328. data/spec/extensions/pg_array_ops_spec.rb +1 -1
  329. data/spec/extensions/pg_array_spec.rb +3 -48
  330. data/spec/extensions/pg_enum_spec.rb +1 -1
  331. data/spec/extensions/pg_extended_date_support_spec.rb +122 -0
  332. data/spec/extensions/pg_hstore_ops_spec.rb +1 -1
  333. data/spec/extensions/pg_hstore_spec.rb +22 -31
  334. data/spec/extensions/pg_inet_ops_spec.rb +1 -1
  335. data/spec/extensions/pg_inet_spec.rb +1 -14
  336. data/spec/extensions/pg_interval_spec.rb +3 -13
  337. data/spec/extensions/pg_json_ops_spec.rb +1 -1
  338. data/spec/extensions/pg_json_spec.rb +1 -13
  339. data/spec/extensions/pg_loose_count_spec.rb +1 -1
  340. data/spec/extensions/pg_range_ops_spec.rb +1 -1
  341. data/spec/extensions/pg_range_spec.rb +3 -88
  342. data/spec/extensions/pg_row_ops_spec.rb +1 -1
  343. data/spec/extensions/pg_row_plugin_spec.rb +1 -1
  344. data/spec/extensions/pg_row_spec.rb +1 -44
  345. data/spec/extensions/pg_static_cache_updater_spec.rb +1 -1
  346. data/spec/extensions/prepared_statements_safe_spec.rb +7 -7
  347. data/spec/extensions/prepared_statements_spec.rb +13 -48
  348. data/spec/extensions/pretty_table_spec.rb +40 -9
  349. data/spec/extensions/query_spec.rb +1 -12
  350. data/spec/extensions/rcte_tree_spec.rb +23 -34
  351. data/spec/extensions/round_timestamps_spec.rb +1 -5
  352. data/spec/extensions/s_spec.rb +1 -1
  353. data/spec/extensions/schema_caching_spec.rb +1 -1
  354. data/spec/extensions/schema_dumper_spec.rb +43 -32
  355. data/spec/extensions/select_remove_spec.rb +1 -1
  356. data/spec/extensions/sequel_4_dataset_methods_spec.rb +1 -1
  357. data/spec/extensions/serialization_modification_detection_spec.rb +1 -1
  358. data/spec/extensions/serialization_spec.rb +5 -17
  359. data/spec/extensions/server_block_spec.rb +1 -1
  360. data/spec/extensions/server_logging_spec.rb +2 -2
  361. data/spec/extensions/sharding_spec.rb +1 -1
  362. data/spec/extensions/shared_caching_spec.rb +1 -28
  363. data/spec/extensions/single_table_inheritance_spec.rb +2 -5
  364. data/spec/extensions/singular_table_names_spec.rb +1 -1
  365. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  366. data/spec/extensions/spec_helper.rb +5 -27
  367. data/spec/extensions/split_array_nil_spec.rb +1 -1
  368. data/spec/extensions/split_values_spec.rb +1 -1
  369. data/spec/extensions/sql_comments_spec.rb +1 -1
  370. data/spec/extensions/sql_expr_spec.rb +1 -1
  371. data/spec/extensions/static_cache_spec.rb +1 -1
  372. data/spec/extensions/string_agg_spec.rb +2 -2
  373. data/spec/extensions/string_date_time_spec.rb +1 -1
  374. data/spec/extensions/string_stripper_spec.rb +1 -1
  375. data/spec/extensions/subclasses_spec.rb +1 -1
  376. data/spec/extensions/subset_conditions_spec.rb +1 -1
  377. data/spec/extensions/symbol_aref_refinement_spec.rb +1 -1
  378. data/spec/extensions/symbol_as_refinement_spec.rb +1 -1
  379. data/spec/extensions/synchronize_sql_spec.rb +124 -0
  380. data/spec/extensions/table_select_spec.rb +4 -4
  381. data/spec/extensions/tactical_eager_loading_spec.rb +1 -6
  382. data/spec/extensions/thread_local_timezones_spec.rb +1 -1
  383. data/spec/extensions/timestamps_spec.rb +5 -7
  384. data/spec/extensions/to_dot_spec.rb +1 -1
  385. data/spec/extensions/touch_spec.rb +1 -1
  386. data/spec/extensions/tree_spec.rb +1 -1
  387. data/spec/extensions/typecast_on_load_spec.rb +1 -1
  388. data/spec/extensions/unlimited_update_spec.rb +1 -1
  389. data/spec/extensions/update_or_create_spec.rb +12 -16
  390. data/spec/extensions/update_primary_key_spec.rb +4 -3
  391. data/spec/extensions/update_refresh_spec.rb +1 -1
  392. data/spec/extensions/uuid_spec.rb +10 -13
  393. data/spec/extensions/validate_associated_spec.rb +1 -1
  394. data/spec/extensions/validation_class_methods_spec.rb +3 -3
  395. data/spec/extensions/validation_contexts_spec.rb +1 -1
  396. data/spec/extensions/validation_helpers_spec.rb +10 -44
  397. data/spec/extensions/whitelist_security_spec.rb +5 -5
  398. data/spec/extensions/xml_serializer_spec.rb +8 -13
  399. data/spec/guards_helper.rb +2 -1
  400. data/spec/integration/associations_test.rb +1 -23
  401. data/spec/integration/database_test.rb +7 -7
  402. data/spec/integration/dataset_test.rb +12 -47
  403. data/spec/integration/eager_loader_test.rb +1 -1
  404. data/spec/integration/migrator_test.rb +1 -1
  405. data/spec/integration/model_test.rb +4 -82
  406. data/spec/integration/plugin_test.rb +7 -23
  407. data/spec/integration/prepared_statement_test.rb +8 -88
  408. data/spec/integration/schema_test.rb +10 -10
  409. data/spec/integration/spec_helper.rb +17 -21
  410. data/spec/integration/timezone_test.rb +5 -5
  411. data/spec/integration/transaction_test.rb +3 -55
  412. data/spec/integration/type_test.rb +9 -9
  413. data/spec/model/association_reflection_spec.rb +24 -9
  414. data/spec/model/associations_spec.rb +124 -303
  415. data/spec/model/base_spec.rb +43 -137
  416. data/spec/model/class_dataset_methods_spec.rb +2 -20
  417. data/spec/model/dataset_methods_spec.rb +1 -20
  418. data/spec/model/eager_loading_spec.rb +48 -17
  419. data/spec/model/hooks_spec.rb +5 -300
  420. data/spec/model/inflector_spec.rb +1 -1
  421. data/spec/model/model_spec.rb +29 -339
  422. data/spec/model/plugins_spec.rb +2 -16
  423. data/spec/model/record_spec.rb +33 -129
  424. data/spec/model/spec_helper.rb +5 -15
  425. data/spec/model/validations_spec.rb +1 -1
  426. data/spec/sequel_warning.rb +1 -12
  427. metadata +19 -65
  428. data/doc/active_record.rdoc +0 -927
  429. data/lib/sequel/adapters/cubrid.rb +0 -160
  430. data/lib/sequel/adapters/do/mysql.rb +0 -69
  431. data/lib/sequel/adapters/do/postgres.rb +0 -46
  432. data/lib/sequel/adapters/do/sqlite3.rb +0 -41
  433. data/lib/sequel/adapters/do.rb +0 -166
  434. data/lib/sequel/adapters/jdbc/as400.rb +0 -92
  435. data/lib/sequel/adapters/jdbc/cubrid.rb +0 -65
  436. data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -37
  437. data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -34
  438. data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -34
  439. data/lib/sequel/adapters/odbc/progress.rb +0 -12
  440. data/lib/sequel/adapters/shared/cubrid.rb +0 -245
  441. data/lib/sequel/adapters/shared/firebird.rb +0 -261
  442. data/lib/sequel/adapters/shared/informix.rb +0 -63
  443. data/lib/sequel/adapters/shared/progress.rb +0 -40
  444. data/lib/sequel/adapters/swift/mysql.rb +0 -50
  445. data/lib/sequel/adapters/swift/postgres.rb +0 -49
  446. data/lib/sequel/adapters/swift/sqlite.rb +0 -48
  447. data/lib/sequel/adapters/swift.rb +0 -169
  448. data/lib/sequel/adapters/utils/pg_types.rb +0 -4
  449. data/lib/sequel/dataset/mutation.rb +0 -98
  450. data/lib/sequel/extensions/_deprecated_identifier_mangling.rb +0 -117
  451. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -8
  452. data/lib/sequel/extensions/filter_having.rb +0 -65
  453. data/lib/sequel/extensions/hash_aliases.rb +0 -51
  454. data/lib/sequel/extensions/meta_def.rb +0 -37
  455. data/lib/sequel/extensions/query_literals.rb +0 -86
  456. data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -26
  457. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -133
  458. data/lib/sequel/extensions/set_overrides.rb +0 -82
  459. data/lib/sequel/no_core_ext.rb +0 -4
  460. data/lib/sequel/plugins/association_autoreloading.rb +0 -11
  461. data/lib/sequel/plugins/identifier_columns.rb +0 -49
  462. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -11
  463. data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -90
  464. data/lib/sequel/plugins/prepared_statements_associations.rb +0 -137
  465. data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -71
  466. data/lib/sequel/plugins/schema.rb +0 -84
  467. data/lib/sequel/plugins/scissors.rb +0 -37
  468. data/spec/core/dataset_mutation_spec.rb +0 -253
  469. data/spec/extensions/_deprecated_identifier_mangling_spec.rb +0 -314
  470. data/spec/extensions/before_after_save_spec.rb +0 -40
  471. data/spec/extensions/filter_having_spec.rb +0 -42
  472. data/spec/extensions/from_block_spec.rb +0 -21
  473. data/spec/extensions/hash_aliases_spec.rb +0 -26
  474. data/spec/extensions/identifier_columns_spec.rb +0 -19
  475. data/spec/extensions/meta_def_spec.rb +0 -35
  476. data/spec/extensions/no_auto_literal_strings_spec.rb +0 -69
  477. data/spec/extensions/pg_typecast_on_load_spec.rb +0 -70
  478. data/spec/extensions/prepared_statements_associations_spec.rb +0 -212
  479. data/spec/extensions/prepared_statements_with_pk_spec.rb +0 -40
  480. data/spec/extensions/query_literals_spec.rb +0 -185
  481. data/spec/extensions/schema_spec.rb +0 -123
  482. data/spec/extensions/scissors_spec.rb +0 -27
  483. data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -118
  484. data/spec/extensions/set_overrides_spec.rb +0 -75
@@ -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)"]
@@ -1323,25 +274,19 @@ describe "class_table_inheritance plugin with :alias option" do
1323
274
 
1324
275
  it "should insert the correct rows into all tables when inserting into parent class" do
1325
276
  Employee.create(:name=>'E')
1326
- sqls = @db.sqls
1327
- sqls.length.must_equal 1
1328
- sqls[0].must_match(/INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Employee)', '(E|Employee)'\)/)
277
+ @db.sqls.must_equal ["INSERT INTO employees (name, kind) VALUES ('E', 'Employee')"]
1329
278
  end
1330
279
 
1331
280
  it "should insert the correct rows into all tables when inserting into subclass without separate table" do
1332
281
  Intern.create(:name=>'E')
1333
- sqls = @db.sqls
1334
- sqls.length.must_equal 1
1335
- sqls[0].must_match(/INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Intern)', '(E|Intern)'\)/)
282
+ @db.sqls.must_equal ["INSERT INTO employees (name, kind) VALUES ('E', 'Intern')"]
1336
283
  end
1337
284
 
1338
285
  it "should insert the correct rows into all tables when inserting" do
1339
286
  Ceo.create(:num_managers=>3, :num_staff=>2, :name=>'E')
1340
- sqls = @db.sqls
1341
- sqls.length.must_equal 3
1342
- sqls[0].must_match(/INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Ceo)', '(E|Ceo)'\)/)
1343
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \([12], [12]\)/)
1344
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([13], [13]\)/)
287
+ @db.sqls.must_equal ["INSERT INTO employees (name, kind) VALUES ('E', 'Ceo')",
288
+ "INSERT INTO managers (id, num_staff) VALUES (1, 2)",
289
+ "INSERT INTO executives (id, num_managers) VALUES (1, 3)"]
1345
290
  end
1346
291
 
1347
292
  it "should insert the correct rows into all tables when inserting when insert_select is supported" do
@@ -1355,22 +300,18 @@ describe "class_table_inheritance plugin with :alias option" do
1355
300
  end)
1356
301
  end
1357
302
  Ceo.create(:num_managers=>3, :num_staff=>2, :name=>'E')
1358
- sqls = @db.sqls
1359
- sqls.length.must_equal 3
1360
- sqls[0].must_match(/INSERT INTO employees \((name|kind), (name|kind)\) VALUES \('(E|Ceo)', '(E|Ceo)'\) RETURNING \*/)
1361
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \([12], [12]\) RETURNING \*/)
1362
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([13], [13]\) RETURNING \*/)
303
+ @db.sqls.must_equal ["INSERT INTO employees (name, kind) VALUES ('E', 'Ceo') RETURNING *",
304
+ "INSERT INTO managers (id, num_staff) VALUES (1, 2) RETURNING *",
305
+ "INSERT INTO executives (id, num_managers) VALUES (1, 3) RETURNING *"]
1363
306
  end
1364
307
 
1365
308
  it "should insert the correct rows into all tables with a given primary key" do
1366
309
  e = Ceo.new(:num_managers=>3, :num_staff=>2, :name=>'E')
1367
310
  e.id = 2
1368
311
  e.save
1369
- sqls = @db.sqls
1370
- sqls.length.must_equal 3
1371
- 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)\)/)
1372
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \(2, 2\)/)
1373
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([23], [23]\)/)
312
+ @db.sqls.must_equal ["INSERT INTO employees (id, name, kind) VALUES (2, 'E', 'Ceo')",
313
+ "INSERT INTO managers (id, num_staff) VALUES (2, 2)",
314
+ "INSERT INTO executives (id, num_managers) VALUES (2, 3)"]
1374
315
  end
1375
316
 
1376
317
  it "should update the correct rows in all tables when updating parent class" do
@@ -1388,6 +329,12 @@ describe "class_table_inheritance plugin with :alias option" do
1388
329
  @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
330
  end
1390
331
 
332
+ it "should raise error if one of the updates does not update a single row" do
333
+ @db.numrows = [1, 0]
334
+ proc{Ceo.load(:id=>2).update(:num_managers=>3, :num_staff=>2, :name=>'E')}.must_raise Sequel::NoExistingObject
335
+ @db.sqls.must_equal ["UPDATE employees SET name = 'E' WHERE (id = 2)", "UPDATE managers SET num_staff = 2 WHERE (id = 2)"]
336
+ end
337
+
1391
338
  it "should handle many_to_one relationships correctly" do
1392
339
  Manager.dataset = Manager.dataset.with_fetch(:id=>3, :name=>'E', :kind=>'Ceo', :num_managers=>3)
1393
340
  Staff.load(:manager_id=>3).manager.must_equal Ceo.load(:id=>3, :name=>'E', :kind=>'Ceo', :num_managers=>3)
@@ -1403,7 +350,7 @@ end
1403
350
 
1404
351
  describe "class_table_inheritance plugin without sti_key with :alias option" do
1405
352
  before do
1406
- @db = Sequel.mock(:autoid=>proc{|sql| 1})
353
+ @db = Sequel.mock(:numrows=>1, :autoid=>proc{|sql| 1})
1407
354
  def @db.supports_schema_parsing?() true end
1408
355
  def @db.schema(table, opts={})
1409
356
  {:employees=>[[:id, {:primary_key=>true, :type=>:integer}], [:name, {:type=>:string}]],
@@ -1429,7 +376,7 @@ describe "class_table_inheritance plugin without sti_key with :alias option" do
1429
376
  def self.columns
1430
377
  dataset.columns || dataset.opts[:from].first.expression.columns
1431
378
  end
1432
- plugin :class_table_inheritance, :table_map=>{:Staff=>:staff}, :alias=>:employees
379
+ plugin :class_table_inheritance, :table_map=>{:Staff=>:staff}, :alias=>:emps
1433
380
  end
1434
381
  class ::Manager < Employee
1435
382
  one_to_many :staff_members, :class=>:Staff
@@ -1463,18 +410,17 @@ describe "class_table_inheritance plugin without sti_key with :alias option" do
1463
410
 
1464
411
  it "should use a joined dataset in subclasses" do
1465
412
  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'
413
+ 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'
414
+ 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'
415
+ 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
416
  end
1470
417
 
1471
- it "should return rows with the current class if cti_key is nil" do
418
+ it "should return rows with the current class if sti_key is nil" do
1472
419
  Employee.plugin(:class_table_inheritance)
1473
420
  Employee.dataset = Employee.dataset.with_fetch([{}])
1474
421
  Employee.first.class.must_equal Employee
1475
422
  end
1476
423
 
1477
-
1478
424
  it "should include schema for columns for tables for ancestor classes" do
1479
425
  Employee.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string})
1480
426
  Manager.db_schema.must_equal(:id=>{:primary_key=>true, :type=>:integer}, :name=>{:type=>:string}, :num_staff=>{:type=>:integer})
@@ -1488,9 +434,9 @@ describe "class_table_inheritance plugin without sti_key with :alias option" do
1488
434
 
1489
435
  it "should have table_name return the table name of the most specific table" do
1490
436
  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
437
+ Manager.table_name.must_equal :emps
438
+ Executive.table_name.must_equal :emps
439
+ Staff.table_name.must_equal :emps
1494
440
  end
1495
441
 
1496
442
  it "should delete the correct rows from all tables when deleting" do
@@ -1507,22 +453,18 @@ describe "class_table_inheritance plugin without sti_key with :alias option" do
1507
453
 
1508
454
  it "should insert the correct rows into all tables when inserting" do
1509
455
  Executive.create(:num_managers=>3, :num_staff=>2, :name=>'E')
1510
- sqls = @db.sqls
1511
- sqls.length.must_equal 3
1512
- sqls[0].must_match(/INSERT INTO employees \(name\) VALUES \('E'\)/)
1513
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \([12], [12]\)/)
1514
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([13], [13]\)/)
1515
- end
456
+ @db.sqls.must_equal ["INSERT INTO employees (name) VALUES ('E')",
457
+ "INSERT INTO managers (id, num_staff) VALUES (1, 2)",
458
+ "INSERT INTO executives (id, num_managers) VALUES (1, 3)"]
459
+ end
1516
460
 
1517
461
  it "should insert the correct rows into all tables with a given primary key" do
1518
462
  e = Executive.new(:num_managers=>3, :num_staff=>2, :name=>'E')
1519
463
  e.id = 2
1520
464
  e.save
1521
- sqls = @db.sqls
1522
- sqls.length.must_equal 3
1523
- sqls[0].must_match(/INSERT INTO employees \((name|id), (name|id)\) VALUES \(('E'|2), ('E'|2)\)/)
1524
- sqls[1].must_match(/INSERT INTO managers \((num_staff|id), (num_staff|id)\) VALUES \(2, 2\)/)
1525
- sqls[2].must_match(/INSERT INTO executives \((num_managers|id), (num_managers|id)\) VALUES \([23], [23]\)/)
465
+ @db.sqls.must_equal ["INSERT INTO employees (id, name) VALUES (2, 'E')",
466
+ "INSERT INTO managers (id, num_staff) VALUES (2, 2)",
467
+ "INSERT INTO executives (id, num_managers) VALUES (2, 3)"]
1526
468
  end
1527
469
 
1528
470
  it "should update the correct rows in all tables when updating" do
@@ -1533,18 +475,18 @@ describe "class_table_inheritance plugin without sti_key with :alias option" do
1533
475
  it "should handle many_to_one relationships correctly" do
1534
476
  Manager.dataset = Manager.dataset.with_fetch(:id=>3, :name=>'E', :num_staff=>3)
1535
477
  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']
478
+ @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
479
  end
1538
480
 
1539
481
  it "should handle one_to_many relationships correctly" do
1540
482
  Staff.dataset = Staff.dataset.with_fetch(:id=>1, :name=>'S', :manager_id=>3)
1541
483
  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)']
484
+ @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
485
  end
1544
486
  end
1545
487
 
1546
- describe "class_table_inheritance plugin with duplicate columns with :alias option" do
1547
- before do
488
+ describe "class_table_inheritance plugin with duplicate columns" do
489
+ it "should raise error" do
1548
490
  @db = Sequel.mock(:autoid=>proc{|sql| 1})
1549
491
  def @db.supports_schema_parsing?() true end
1550
492
  def @db.schema(table, opts={})
@@ -1564,20 +506,13 @@ describe "class_table_inheritance plugin with duplicate columns with :alias opti
1564
506
  def self.columns
1565
507
  dataset.columns || dataset.opts[:from].first.expression.columns
1566
508
  end
1567
- plugin :class_table_inheritance, :key=>:kind, :table_map=>{:Staff=>:staff}, :alias=>:employees
509
+ plugin :class_table_inheritance
1568
510
  end
1569
- deprecated do
1570
- class ::Manager < Employee; end
1571
- end
1572
- @ds = Employee.dataset
1573
- @db.sqls
511
+ proc{class ::Manager < Employee; end}.must_raise Sequel::Error
1574
512
  end
1575
513
  after do
1576
514
  Object.send(:remove_const, :Manager)
1577
515
  Object.send(:remove_const, :Employee)
1578
516
  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
517
  end
518
+