sequel 3.21.0 → 3.39.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 (352) hide show
  1. data/CHANGELOG +1061 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +103 -63
  4. data/Rakefile +59 -27
  5. data/bin/sequel +50 -26
  6. data/doc/active_record.rdoc +67 -51
  7. data/doc/advanced_associations.rdoc +189 -75
  8. data/doc/association_basics.rdoc +327 -79
  9. data/doc/cheat_sheet.rdoc +21 -21
  10. data/doc/core_extensions.rdoc +374 -0
  11. data/doc/dataset_basics.rdoc +10 -10
  12. data/doc/dataset_filtering.rdoc +54 -42
  13. data/doc/mass_assignment.rdoc +56 -0
  14. data/doc/migration.rdoc +89 -557
  15. data/doc/model_hooks.rdoc +80 -29
  16. data/doc/object_model.rdoc +547 -0
  17. data/doc/opening_databases.rdoc +114 -53
  18. data/doc/prepared_statements.rdoc +41 -15
  19. data/doc/querying.rdoc +137 -56
  20. data/doc/reflection.rdoc +36 -10
  21. data/doc/release_notes/3.22.0.txt +39 -0
  22. data/doc/release_notes/3.23.0.txt +172 -0
  23. data/doc/release_notes/3.24.0.txt +420 -0
  24. data/doc/release_notes/3.25.0.txt +88 -0
  25. data/doc/release_notes/3.26.0.txt +88 -0
  26. data/doc/release_notes/3.27.0.txt +82 -0
  27. data/doc/release_notes/3.28.0.txt +304 -0
  28. data/doc/release_notes/3.29.0.txt +459 -0
  29. data/doc/release_notes/3.30.0.txt +135 -0
  30. data/doc/release_notes/3.31.0.txt +146 -0
  31. data/doc/release_notes/3.32.0.txt +202 -0
  32. data/doc/release_notes/3.33.0.txt +157 -0
  33. data/doc/release_notes/3.34.0.txt +671 -0
  34. data/doc/release_notes/3.35.0.txt +144 -0
  35. data/doc/release_notes/3.36.0.txt +245 -0
  36. data/doc/release_notes/3.37.0.txt +338 -0
  37. data/doc/release_notes/3.38.0.txt +234 -0
  38. data/doc/release_notes/3.39.0.txt +237 -0
  39. data/doc/schema_modification.rdoc +585 -0
  40. data/doc/sharding.rdoc +99 -8
  41. data/doc/sql.rdoc +154 -112
  42. data/doc/testing.rdoc +169 -0
  43. data/doc/thread_safety.rdoc +17 -0
  44. data/doc/transactions.rdoc +137 -0
  45. data/doc/validations.rdoc +1 -1
  46. data/doc/virtual_rows.rdoc +78 -43
  47. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  48. data/lib/sequel/adapters/ado.rb +40 -18
  49. data/lib/sequel/adapters/amalgalite.rb +17 -9
  50. data/lib/sequel/adapters/db2.rb +175 -86
  51. data/lib/sequel/adapters/dbi.rb +15 -15
  52. data/lib/sequel/adapters/do/mysql.rb +17 -11
  53. data/lib/sequel/adapters/do/postgres.rb +2 -61
  54. data/lib/sequel/adapters/do/sqlite.rb +0 -10
  55. data/lib/sequel/adapters/do.rb +18 -36
  56. data/lib/sequel/adapters/firebird.rb +27 -208
  57. data/lib/sequel/adapters/ibmdb.rb +453 -0
  58. data/lib/sequel/adapters/informix.rb +6 -23
  59. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  60. data/lib/sequel/adapters/jdbc/db2.rb +56 -0
  61. data/lib/sequel/adapters/jdbc/derby.rb +325 -0
  62. data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
  63. data/lib/sequel/adapters/jdbc/h2.rb +73 -31
  64. data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
  65. data/lib/sequel/adapters/jdbc/informix.rb +21 -0
  66. data/lib/sequel/adapters/jdbc/jtds.rb +40 -0
  67. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  68. data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
  69. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  70. data/lib/sequel/adapters/jdbc/postgresql.rb +77 -52
  71. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  72. data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
  73. data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
  74. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  75. data/lib/sequel/adapters/jdbc.rb +279 -97
  76. data/lib/sequel/adapters/mock.rb +372 -0
  77. data/lib/sequel/adapters/mysql.rb +125 -222
  78. data/lib/sequel/adapters/mysql2.rb +65 -56
  79. data/lib/sequel/adapters/odbc/mssql.rb +17 -9
  80. data/lib/sequel/adapters/odbc.rb +28 -9
  81. data/lib/sequel/adapters/openbase.rb +3 -5
  82. data/lib/sequel/adapters/oracle.rb +349 -53
  83. data/lib/sequel/adapters/postgres.rb +368 -138
  84. data/lib/sequel/adapters/shared/access.rb +32 -9
  85. data/lib/sequel/adapters/shared/db2.rb +343 -0
  86. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  87. data/lib/sequel/adapters/shared/informix.rb +53 -0
  88. data/lib/sequel/adapters/shared/mssql.rb +401 -116
  89. data/lib/sequel/adapters/shared/mysql.rb +424 -89
  90. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
  91. data/lib/sequel/adapters/shared/oracle.rb +257 -45
  92. data/lib/sequel/adapters/shared/postgres.rb +675 -279
  93. data/lib/sequel/adapters/shared/progress.rb +5 -8
  94. data/lib/sequel/adapters/shared/sqlite.rb +285 -96
  95. data/lib/sequel/adapters/sqlite.rb +101 -39
  96. data/lib/sequel/adapters/swift/mysql.rb +10 -12
  97. data/lib/sequel/adapters/swift/postgres.rb +13 -79
  98. data/lib/sequel/adapters/swift/sqlite.rb +9 -6
  99. data/lib/sequel/adapters/swift.rb +28 -19
  100. data/lib/sequel/adapters/tinytds.rb +174 -22
  101. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +77 -0
  102. data/lib/sequel/adapters/utils/pg_types.rb +81 -0
  103. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  104. data/lib/sequel/ast_transformer.rb +194 -0
  105. data/lib/sequel/connection_pool/sharded_single.rb +11 -1
  106. data/lib/sequel/connection_pool/sharded_threaded.rb +33 -2
  107. data/lib/sequel/connection_pool/single.rb +5 -0
  108. data/lib/sequel/connection_pool/threaded.rb +43 -14
  109. data/lib/sequel/connection_pool.rb +10 -2
  110. data/lib/sequel/core.rb +143 -11
  111. data/lib/sequel/database/connecting.rb +38 -28
  112. data/lib/sequel/database/dataset.rb +4 -4
  113. data/lib/sequel/database/dataset_defaults.rb +63 -2
  114. data/lib/sequel/database/logging.rb +7 -2
  115. data/lib/sequel/database/misc.rb +190 -46
  116. data/lib/sequel/database/query.rb +272 -110
  117. data/lib/sequel/database/schema_generator.rb +103 -36
  118. data/lib/sequel/database/schema_methods.rb +300 -67
  119. data/lib/sequel/dataset/actions.rb +344 -90
  120. data/lib/sequel/dataset/features.rb +101 -8
  121. data/lib/sequel/dataset/graph.rb +42 -15
  122. data/lib/sequel/dataset/misc.rb +52 -25
  123. data/lib/sequel/dataset/mutation.rb +12 -7
  124. data/lib/sequel/dataset/prepared_statements.rb +68 -30
  125. data/lib/sequel/dataset/query.rb +305 -54
  126. data/lib/sequel/dataset/sql.rb +720 -292
  127. data/lib/sequel/dataset.rb +8 -0
  128. data/lib/sequel/exceptions.rb +4 -0
  129. data/lib/sequel/extensions/_pretty_table.rb +83 -0
  130. data/lib/sequel/extensions/arbitrary_servers.rb +109 -0
  131. data/lib/sequel/extensions/blank.rb +4 -0
  132. data/lib/sequel/extensions/columns_introspection.rb +72 -0
  133. data/lib/sequel/extensions/constraint_validations.rb +451 -0
  134. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +30 -46
  135. data/lib/sequel/extensions/eval_inspect.rb +173 -0
  136. data/lib/sequel/extensions/inflector.rb +4 -0
  137. data/lib/sequel/extensions/looser_typecasting.rb +5 -4
  138. data/lib/sequel/extensions/migration.rb +100 -11
  139. data/lib/sequel/extensions/named_timezones.rb +9 -0
  140. data/lib/sequel/extensions/null_dataset.rb +94 -0
  141. data/lib/sequel/extensions/pagination.rb +4 -0
  142. data/lib/sequel/extensions/pg_array.rb +537 -0
  143. data/lib/sequel/extensions/pg_array_ops.rb +263 -0
  144. data/lib/sequel/extensions/pg_auto_parameterize.rb +175 -0
  145. data/lib/sequel/extensions/pg_hstore.rb +313 -0
  146. data/lib/sequel/extensions/pg_hstore_ops.rb +293 -0
  147. data/lib/sequel/extensions/pg_inet.rb +113 -0
  148. data/lib/sequel/extensions/pg_interval.rb +191 -0
  149. data/lib/sequel/extensions/pg_json.rb +208 -0
  150. data/lib/sequel/extensions/pg_range.rb +512 -0
  151. data/lib/sequel/extensions/pg_range_ops.rb +150 -0
  152. data/lib/sequel/extensions/pg_row.rb +572 -0
  153. data/lib/sequel/extensions/pg_row_ops.rb +182 -0
  154. data/lib/sequel/extensions/pg_statement_cache.rb +317 -0
  155. data/lib/sequel/extensions/pretty_table.rb +17 -72
  156. data/lib/sequel/extensions/query.rb +8 -4
  157. data/lib/sequel/extensions/query_literals.rb +79 -0
  158. data/lib/sequel/extensions/schema_caching.rb +76 -0
  159. data/lib/sequel/extensions/schema_dumper.rb +282 -76
  160. data/lib/sequel/extensions/select_remove.rb +39 -0
  161. data/lib/sequel/extensions/server_block.rb +140 -0
  162. data/lib/sequel/extensions/split_array_nil.rb +65 -0
  163. data/lib/sequel/extensions/sql_expr.rb +8 -110
  164. data/lib/sequel/extensions/string_date_time.rb +4 -0
  165. data/lib/sequel/extensions/thread_local_timezones.rb +10 -4
  166. data/lib/sequel/extensions/to_dot.rb +99 -83
  167. data/lib/sequel/model/associations.rb +1263 -409
  168. data/lib/sequel/model/base.rb +624 -171
  169. data/lib/sequel/model/errors.rb +1 -1
  170. data/lib/sequel/model/exceptions.rb +24 -2
  171. data/lib/sequel/model/inflections.rb +1 -1
  172. data/lib/sequel/model.rb +30 -11
  173. data/lib/sequel/no_core_ext.rb +2 -0
  174. data/lib/sequel/plugins/active_model.rb +13 -1
  175. data/lib/sequel/plugins/association_pks.rb +22 -4
  176. data/lib/sequel/plugins/caching.rb +25 -18
  177. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  178. data/lib/sequel/plugins/composition.rb +44 -12
  179. data/lib/sequel/plugins/constraint_validations.rb +198 -0
  180. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  181. data/lib/sequel/plugins/defaults_setter.rb +72 -0
  182. data/lib/sequel/plugins/dirty.rb +214 -0
  183. data/lib/sequel/plugins/eager_each.rb +59 -0
  184. data/lib/sequel/plugins/force_encoding.rb +6 -6
  185. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  186. data/lib/sequel/plugins/identity_map.rb +134 -15
  187. data/lib/sequel/plugins/instance_filters.rb +10 -0
  188. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  189. data/lib/sequel/plugins/json_serializer.rb +58 -6
  190. data/lib/sequel/plugins/list.rb +13 -2
  191. data/lib/sequel/plugins/many_through_many.rb +103 -51
  192. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  193. data/lib/sequel/plugins/nested_attributes.rb +150 -66
  194. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  195. data/lib/sequel/plugins/pg_row.rb +121 -0
  196. data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
  197. data/lib/sequel/plugins/prepared_statements.rb +167 -0
  198. data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
  199. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  200. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  201. data/lib/sequel/plugins/rcte_tree.rb +31 -17
  202. data/lib/sequel/plugins/schema.rb +8 -3
  203. data/lib/sequel/plugins/serialization.rb +98 -49
  204. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  205. data/lib/sequel/plugins/sharding.rb +21 -54
  206. data/lib/sequel/plugins/single_table_inheritance.rb +5 -3
  207. data/lib/sequel/plugins/static_cache.rb +99 -0
  208. data/lib/sequel/plugins/subclasses.rb +29 -3
  209. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  210. data/lib/sequel/plugins/timestamps.rb +1 -1
  211. data/lib/sequel/plugins/tree.rb +3 -3
  212. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  213. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  214. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  215. data/lib/sequel/plugins/validation_helpers.rb +55 -4
  216. data/lib/sequel/plugins/xml_serializer.rb +15 -4
  217. data/lib/sequel/sql.rb +649 -122
  218. data/lib/sequel/timezones.rb +67 -40
  219. data/lib/sequel/version.rb +1 -1
  220. data/spec/adapters/db2_spec.rb +146 -0
  221. data/spec/adapters/firebird_spec.rb +1 -1
  222. data/spec/adapters/mssql_spec.rb +194 -66
  223. data/spec/adapters/mysql_spec.rb +475 -306
  224. data/spec/adapters/oracle_spec.rb +92 -117
  225. data/spec/adapters/postgres_spec.rb +1982 -325
  226. data/spec/adapters/spec_helper.rb +9 -6
  227. data/spec/adapters/sqlite_spec.rb +203 -75
  228. data/spec/core/connection_pool_spec.rb +218 -93
  229. data/spec/core/database_spec.rb +956 -522
  230. data/spec/core/dataset_spec.rb +1631 -1242
  231. data/spec/core/expression_filters_spec.rb +690 -334
  232. data/spec/core/mock_adapter_spec.rb +453 -0
  233. data/spec/core/object_graph_spec.rb +88 -129
  234. data/spec/core/schema_generator_spec.rb +4 -4
  235. data/spec/core/schema_spec.rb +556 -53
  236. data/spec/core/spec_helper.rb +7 -48
  237. data/spec/core_extensions_spec.rb +626 -0
  238. data/spec/extensions/active_model_spec.rb +13 -0
  239. data/spec/extensions/arbitrary_servers_spec.rb +110 -0
  240. data/spec/extensions/association_autoreloading_spec.rb +18 -10
  241. data/spec/extensions/association_dependencies_spec.rb +15 -25
  242. data/spec/extensions/association_pks_spec.rb +66 -32
  243. data/spec/extensions/association_proxies_spec.rb +4 -4
  244. data/spec/extensions/boolean_readers_spec.rb +25 -25
  245. data/spec/extensions/caching_spec.rb +47 -51
  246. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  247. data/spec/extensions/columns_introspection_spec.rb +91 -0
  248. data/spec/extensions/composition_spec.rb +18 -13
  249. data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
  250. data/spec/extensions/constraint_validations_spec.rb +316 -0
  251. data/spec/extensions/dataset_associations_spec.rb +199 -0
  252. data/spec/extensions/defaults_setter_spec.rb +88 -0
  253. data/spec/extensions/dirty_spec.rb +155 -0
  254. data/spec/extensions/eager_each_spec.rb +34 -0
  255. data/spec/extensions/eval_inspect_spec.rb +67 -0
  256. data/spec/extensions/force_encoding_spec.rb +4 -2
  257. data/spec/extensions/hook_class_methods_spec.rb +97 -128
  258. data/spec/extensions/identity_map_spec.rb +142 -24
  259. data/spec/extensions/inflector_spec.rb +0 -4
  260. data/spec/extensions/instance_filters_spec.rb +11 -21
  261. data/spec/extensions/instance_hooks_spec.rb +72 -0
  262. data/spec/extensions/json_serializer_spec.rb +49 -12
  263. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  264. data/spec/extensions/list_spec.rb +49 -40
  265. data/spec/extensions/looser_typecasting_spec.rb +7 -7
  266. data/spec/extensions/many_through_many_spec.rb +368 -254
  267. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  268. data/spec/extensions/migration_spec.rb +140 -35
  269. data/spec/extensions/named_timezones_spec.rb +29 -11
  270. data/spec/extensions/nested_attributes_spec.rb +268 -89
  271. data/spec/extensions/null_dataset_spec.rb +85 -0
  272. data/spec/extensions/optimistic_locking_spec.rb +24 -21
  273. data/spec/extensions/pg_array_ops_spec.rb +112 -0
  274. data/spec/extensions/pg_array_spec.rb +320 -0
  275. data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
  276. data/spec/extensions/pg_hstore_ops_spec.rb +140 -0
  277. data/spec/extensions/pg_hstore_spec.rb +194 -0
  278. data/spec/extensions/pg_inet_spec.rb +47 -0
  279. data/spec/extensions/pg_interval_spec.rb +72 -0
  280. data/spec/extensions/pg_json_spec.rb +99 -0
  281. data/spec/extensions/pg_range_ops_spec.rb +56 -0
  282. data/spec/extensions/pg_range_spec.rb +395 -0
  283. data/spec/extensions/pg_row_ops_spec.rb +58 -0
  284. data/spec/extensions/pg_row_plugin_spec.rb +49 -0
  285. data/spec/extensions/pg_row_spec.rb +323 -0
  286. data/spec/extensions/pg_statement_cache_spec.rb +208 -0
  287. data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
  288. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  289. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  290. data/spec/extensions/prepared_statements_spec.rb +87 -0
  291. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  292. data/spec/extensions/pretty_table_spec.rb +7 -6
  293. data/spec/extensions/query_literals_spec.rb +167 -0
  294. data/spec/extensions/query_spec.rb +9 -3
  295. data/spec/extensions/rcte_tree_spec.rb +50 -43
  296. data/spec/extensions/schema_caching_spec.rb +41 -0
  297. data/spec/extensions/schema_dumper_spec.rb +434 -49
  298. data/spec/extensions/schema_spec.rb +30 -49
  299. data/spec/extensions/select_remove_spec.rb +38 -0
  300. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  301. data/spec/extensions/serialization_spec.rb +86 -48
  302. data/spec/extensions/server_block_spec.rb +90 -0
  303. data/spec/extensions/sharding_spec.rb +69 -143
  304. data/spec/extensions/single_table_inheritance_spec.rb +23 -29
  305. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  306. data/spec/extensions/spec_helper.rb +34 -67
  307. data/spec/extensions/split_array_nil_spec.rb +24 -0
  308. data/spec/extensions/sql_expr_spec.rb +29 -60
  309. data/spec/extensions/static_cache_spec.rb +145 -0
  310. data/spec/extensions/subclasses_spec.rb +14 -0
  311. data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
  312. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  313. data/spec/extensions/timestamps_spec.rb +6 -6
  314. data/spec/extensions/to_dot_spec.rb +8 -11
  315. data/spec/extensions/touch_spec.rb +13 -14
  316. data/spec/extensions/tree_spec.rb +11 -26
  317. data/spec/extensions/typecast_on_load_spec.rb +9 -6
  318. data/spec/extensions/update_primary_key_spec.rb +30 -24
  319. data/spec/extensions/validation_class_methods_spec.rb +58 -67
  320. data/spec/extensions/validation_helpers_spec.rb +31 -37
  321. data/spec/extensions/xml_serializer_spec.rb +29 -4
  322. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
  323. data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
  324. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
  325. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
  326. data/spec/integration/associations_test.rb +659 -21
  327. data/spec/integration/database_test.rb +11 -5
  328. data/spec/integration/dataset_test.rb +717 -129
  329. data/spec/integration/eager_loader_test.rb +38 -54
  330. data/spec/integration/migrator_test.rb +2 -3
  331. data/spec/integration/model_test.rb +81 -2
  332. data/spec/integration/plugin_test.rb +604 -147
  333. data/spec/integration/prepared_statement_test.rb +272 -128
  334. data/spec/integration/schema_test.rb +367 -57
  335. data/spec/integration/spec_helper.rb +42 -32
  336. data/spec/integration/timezone_test.rb +38 -12
  337. data/spec/integration/transaction_test.rb +183 -8
  338. data/spec/integration/type_test.rb +31 -8
  339. data/spec/model/association_reflection_spec.rb +207 -8
  340. data/spec/model/associations_spec.rb +1206 -693
  341. data/spec/model/base_spec.rb +334 -100
  342. data/spec/model/dataset_methods_spec.rb +45 -27
  343. data/spec/model/eager_loading_spec.rb +828 -692
  344. data/spec/model/hooks_spec.rb +355 -67
  345. data/spec/model/model_spec.rb +251 -179
  346. data/spec/model/plugins_spec.rb +24 -13
  347. data/spec/model/record_spec.rb +506 -232
  348. data/spec/model/spec_helper.rb +16 -77
  349. data/spec/model/validations_spec.rb +38 -2
  350. data/spec/rcov.opts +2 -0
  351. metadata +209 -80
  352. data/spec/core/core_sql_spec.rb +0 -451
@@ -14,10 +14,6 @@ INTEGRATION_DB = MYSQL_DB unless defined?(INTEGRATION_DB)
14
14
 
15
15
  MYSQL_URI = URI.parse(MYSQL_DB.uri)
16
16
 
17
- MYSQL_DB.create_table! :test2 do
18
- text :name
19
- integer :value
20
- end
21
17
  def MYSQL_DB.sqls
22
18
  (@sqls ||= [])
23
19
  end
@@ -26,9 +22,7 @@ def logger.method_missing(m, msg)
26
22
  MYSQL_DB.sqls << msg
27
23
  end
28
24
  MYSQL_DB.loggers = [logger]
29
- MYSQL_DB.drop_table(:items) rescue nil
30
- MYSQL_DB.drop_table(:dolls) rescue nil
31
- MYSQL_DB.drop_table(:booltest) rescue nil
25
+ MYSQL_DB.drop_table?(:items, :dolls, :booltest)
32
26
 
33
27
  SQL_BEGIN = 'BEGIN'
34
28
  SQL_ROLLBACK = 'ROLLBACK'
@@ -40,29 +34,29 @@ describe "MySQL", '#create_table' do
40
34
  MYSQL_DB.sqls.clear
41
35
  end
42
36
  after do
43
- @db.drop_table(:dolls) rescue nil
37
+ @db.drop_table?(:dolls)
44
38
  end
45
-
39
+
46
40
  specify "should allow to specify options for MySQL" do
47
41
  @db.create_table(:dolls, :engine => 'MyISAM', :charset => 'latin2'){text :name}
48
- @db.sqls.should == ["CREATE TABLE dolls (name text) ENGINE=MyISAM DEFAULT CHARSET=latin2"]
42
+ @db.sqls.should == ["CREATE TABLE `dolls` (`name` text) ENGINE=MyISAM DEFAULT CHARSET=latin2"]
49
43
  end
50
-
44
+
51
45
  specify "should create a temporary table" do
52
46
  @db.create_table(:tmp_dolls, :temp => true, :engine => 'MyISAM', :charset => 'latin2'){text :name}
53
- @db.sqls.should == ["CREATE TEMPORARY TABLE tmp_dolls (name text) ENGINE=MyISAM DEFAULT CHARSET=latin2"]
47
+ @db.sqls.should == ["CREATE TEMPORARY TABLE `tmp_dolls` (`name` text) ENGINE=MyISAM DEFAULT CHARSET=latin2"]
54
48
  end
55
-
49
+
56
50
  specify "should not use a default for a String :text=>true type" do
57
51
  @db.create_table(:dolls){String :name, :text=>true, :default=>'blah'}
58
- @db.sqls.should == ["CREATE TABLE dolls (name text)"]
52
+ @db.sqls.should == ["CREATE TABLE `dolls` (`name` text)"]
59
53
  end
60
-
54
+
61
55
  specify "should not use a default for a File type" do
62
56
  @db.create_table(:dolls){File :name, :default=>'blah'}
63
- @db.sqls.should == ["CREATE TABLE dolls (name blob)"]
57
+ @db.sqls.should == ["CREATE TABLE `dolls` (`name` blob)"]
64
58
  end
65
-
59
+
66
60
  specify "should respect the size option for File type" do
67
61
  @db.create_table(:dolls) do
68
62
  File :n1
@@ -82,42 +76,41 @@ describe "MySQL", '#create_table' do
82
76
  end
83
77
  @db.schema(:dolls).map{|k, v| v[:auto_increment]}.should == [nil, nil, true]
84
78
  end
85
- end
86
79
 
87
- describe "A MySQL database" do
88
- specify "should provide the server version" do
89
- MYSQL_DB.server_version.should >= 40000
90
- end
91
-
92
- specify "should handle the creation and dropping of an InnoDB table with foreign keys" do
93
- proc{MYSQL_DB.create_table!(:test_innodb, :engine=>:InnoDB){primary_key :id; foreign_key :fk, :test_innodb, :key=>:id}}.should_not raise_error
80
+ specify "should support collate with various other column options" do
81
+ @db.create_table!(:dolls){ String :name, :size=>128, :collate=>:utf8_bin, :default=>'foo', :null=>false, :unique=>true}
82
+ @db[:dolls].insert
83
+ @db[:dolls].select_map(:name).should == ["foo"]
94
84
  end
95
-
96
- specify "should support for_share" do
97
- MYSQL_DB.transaction{MYSQL_DB[:test2].for_share.all.should == []}
85
+
86
+ specify "should be able to parse the default value for set and enum types" do
87
+ @db.create_table!(:dolls){column :t, "set('a', 'b', 'c', 'd')", :default=>'a,b'}
88
+ @db.schema(:dolls).first.last[:ruby_default].should == 'a,b'
89
+ @db.create_table!(:dolls){column :t, "enum('a', 'b', 'c', 'd')", :default=>'b'}
90
+ @db.schema(:dolls).first.last[:ruby_default].should == 'b'
98
91
  end
99
92
  end
100
93
 
101
- if MYSQL_DB.adapter_scheme == :mysql
102
- describe "Sequel::MySQL.convert_tinyint_to_bool" do
94
+ if [:mysql, :mysql2].include?(MYSQL_DB.adapter_scheme)
95
+ describe "Sequel::MySQL::Database#convert_tinyint_to_bool" do
103
96
  before do
104
97
  @db = MYSQL_DB
105
98
  @db.create_table(:booltest){column :b, 'tinyint(1)'; column :i, 'tinyint(4)'}
106
99
  @ds = @db[:booltest]
107
100
  end
108
101
  after do
109
- Sequel::MySQL.convert_tinyint_to_bool = true
110
- @db.drop_table(:booltest)
102
+ @db.convert_tinyint_to_bool = true
103
+ @db.drop_table?(:booltest)
111
104
  end
112
-
105
+
113
106
  specify "should consider tinyint(1) datatypes as boolean if set, but not larger tinyints" do
114
107
  @db.schema(:booltest, :reload=>true).should == [[:b, {:type=>:boolean, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(1)"}, ], [:i, {:type=>:integer, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(4)"}, ]]
115
- Sequel::MySQL.convert_tinyint_to_bool = false
108
+ @db.convert_tinyint_to_bool = false
116
109
  @db.schema(:booltest, :reload=>true).should == [[:b, {:type=>:integer, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(1)"}, ], [:i, {:type=>:integer, :allow_null=>true, :primary_key=>false, :default=>nil, :ruby_default=>nil, :db_type=>"tinyint(4)"}, ]]
117
110
  end
118
-
111
+
119
112
  specify "should return tinyint(1)s as bools and tinyint(4)s as integers when set" do
120
- Sequel::MySQL.convert_tinyint_to_bool = true
113
+ @db.convert_tinyint_to_bool = true
121
114
  @ds.delete
122
115
  @ds << {:b=>true, :i=>10}
123
116
  @ds.all.should == [{:b=>true, :i=>10}]
@@ -130,14 +123,14 @@ if MYSQL_DB.adapter_scheme == :mysql
130
123
  end
131
124
 
132
125
  specify "should return all tinyints as integers when unset" do
133
- Sequel::MySQL.convert_tinyint_to_bool = false
126
+ @db.convert_tinyint_to_bool = false
134
127
  @ds.delete
135
128
  @ds << {:b=>true, :i=>10}
136
129
  @ds.all.should == [{:b=>1, :i=>10}]
137
130
  @ds.delete
138
131
  @ds << {:b=>false, :i=>0}
139
132
  @ds.all.should == [{:b=>0, :i=>0}]
140
-
133
+
141
134
  @ds.delete
142
135
  @ds << {:b=>1, :i=>10}
143
136
  @ds.all.should == [{:b=>1, :i=>10}]
@@ -145,6 +138,17 @@ if MYSQL_DB.adapter_scheme == :mysql
145
138
  @ds << {:b=>0, :i=>0}
146
139
  @ds.all.should == [{:b=>0, :i=>0}]
147
140
  end
141
+
142
+ specify "should allow disabling the conversion on a per-dataset basis" do
143
+ @db.convert_tinyint_to_bool = true
144
+ ds = @ds.clone
145
+ ds.meta_def(:cast_tinyint_integer?){|f| true} # mysql
146
+ ds.meta_def(:convert_tinyint_to_bool?){false} # mysql2
147
+ ds.delete
148
+ ds << {:b=>true, :i=>10}
149
+ ds.all.should == [{:b=>1, :i=>10}]
150
+ @ds.all.should == [{:b=>true, :i=>10}]
151
+ end
148
152
  end
149
153
  end
150
154
 
@@ -155,106 +159,86 @@ describe "A MySQL dataset" do
155
159
  MYSQL_DB.sqls.clear
156
160
  end
157
161
  after do
158
- MYSQL_DB.drop_table(:items)
162
+ MYSQL_DB.drop_table?(:items)
159
163
  end
160
-
164
+
161
165
  specify "should quote columns and tables using back-ticks if quoting identifiers" do
162
166
  @d.quote_identifiers = true
163
- @d.select(:name).sql.should == \
164
- 'SELECT `name` FROM `items`'
165
-
166
- @d.select('COUNT(*)'.lit).sql.should == \
167
- 'SELECT COUNT(*) FROM `items`'
168
-
169
- @d.select(:max.sql_function(:value)).sql.should == \
170
- 'SELECT max(`value`) FROM `items`'
171
-
172
- @d.select(:NOW.sql_function).sql.should == \
173
- 'SELECT NOW() FROM `items`'
174
-
175
- @d.select(:max.sql_function(:items__value)).sql.should == \
176
- 'SELECT max(`items`.`value`) FROM `items`'
177
-
178
- @d.order(:name.desc).sql.should == \
179
- 'SELECT * FROM `items` ORDER BY `name` DESC'
180
-
181
- @d.select('items.name AS item_name'.lit).sql.should == \
182
- 'SELECT items.name AS item_name FROM `items`'
183
-
184
- @d.select('`name`'.lit).sql.should == \
185
- 'SELECT `name` FROM `items`'
186
-
187
- @d.select('max(items.`name`) AS `max_name`'.lit).sql.should == \
188
- 'SELECT max(items.`name`) AS `max_name` FROM `items`'
189
-
190
- @d.select(:test.sql_function(:abc, 'hello')).sql.should == \
191
- "SELECT test(`abc`, 'hello') FROM `items`"
192
-
193
- @d.select(:test.sql_function(:abc__def, 'hello')).sql.should == \
194
- "SELECT test(`abc`.`def`, 'hello') FROM `items`"
195
-
196
- @d.select(:test.sql_function(:abc__def, 'hello').as(:x2)).sql.should == \
197
- "SELECT test(`abc`.`def`, 'hello') AS `x2` FROM `items`"
198
-
199
- @d.insert_sql(:value => 333).should == \
200
- 'INSERT INTO `items` (`value`) VALUES (333)'
201
-
202
- @d.insert_sql(:x => :y).should == \
203
- 'INSERT INTO `items` (`x`) VALUES (`y`)'
167
+ @d.select(:name).sql.should == 'SELECT `name` FROM `items`'
168
+ @d.select(Sequel.lit('COUNT(*)')).sql.should == 'SELECT COUNT(*) FROM `items`'
169
+ @d.select(Sequel.function(:max, :value)).sql.should == 'SELECT max(`value`) FROM `items`'
170
+ @d.select(Sequel.function(:NOW)).sql.should == 'SELECT NOW() FROM `items`'
171
+ @d.select(Sequel.function(:max, :items__value)).sql.should == 'SELECT max(`items`.`value`) FROM `items`'
172
+ @d.order(Sequel.expr(:name).desc).sql.should == 'SELECT * FROM `items` ORDER BY `name` DESC'
173
+ @d.select(Sequel.lit('items.name AS item_name')).sql.should == 'SELECT items.name AS item_name FROM `items`'
174
+ @d.select(Sequel.lit('`name`')).sql.should == 'SELECT `name` FROM `items`'
175
+ @d.select(Sequel.lit('max(items.`name`) AS `max_name`')).sql.should == 'SELECT max(items.`name`) AS `max_name` FROM `items`'
176
+ @d.select(Sequel.function(:test, :abc, 'hello')).sql.should == "SELECT test(`abc`, 'hello') FROM `items`"
177
+ @d.select(Sequel.function(:test, :abc__def, 'hello')).sql.should == "SELECT test(`abc`.`def`, 'hello') FROM `items`"
178
+ @d.select(Sequel.function(:test, :abc__def, 'hello').as(:x2)).sql.should == "SELECT test(`abc`.`def`, 'hello') AS `x2` FROM `items`"
179
+ @d.insert_sql(:value => 333).should == 'INSERT INTO `items` (`value`) VALUES (333)'
180
+ @d.insert_sql(:x => :y).should == 'INSERT INTO `items` (`x`) VALUES (`y`)'
204
181
  end
205
-
182
+
206
183
  specify "should quote fields correctly when reversing the order" do
207
184
  @d.quote_identifiers = true
208
- @d.reverse_order(:name).sql.should == \
209
- 'SELECT * FROM `items` ORDER BY `name` DESC'
210
-
211
- @d.reverse_order(:name.desc).sql.should == \
212
- 'SELECT * FROM `items` ORDER BY `name` ASC'
213
-
214
- @d.reverse_order(:name, :test.desc).sql.should == \
215
- 'SELECT * FROM `items` ORDER BY `name` DESC, `test` ASC'
216
-
217
- @d.reverse_order(:name.desc, :test).sql.should == \
218
- 'SELECT * FROM `items` ORDER BY `name` ASC, `test` DESC'
185
+ @d.reverse_order(:name).sql.should == 'SELECT * FROM `items` ORDER BY `name` DESC'
186
+ @d.reverse_order(Sequel.desc(:name)).sql.should == 'SELECT * FROM `items` ORDER BY `name` ASC'
187
+ @d.reverse_order(:name, Sequel.desc(:test)).sql.should == 'SELECT * FROM `items` ORDER BY `name` DESC, `test` ASC'
188
+ @d.reverse_order(Sequel.desc(:name), :test).sql.should == 'SELECT * FROM `items` ORDER BY `name` ASC, `test` DESC'
219
189
  end
220
-
190
+
221
191
  specify "should support ORDER clause in UPDATE statements" do
222
- @d.order(:name).update_sql(:value => 1).should == \
223
- 'UPDATE items SET value = 1 ORDER BY name'
192
+ @d.order(:name).update_sql(:value => 1).should == 'UPDATE `items` SET `value` = 1 ORDER BY `name`'
224
193
  end
225
-
194
+
226
195
  specify "should support LIMIT clause in UPDATE statements" do
227
- @d.limit(10).update_sql(:value => 1).should == \
228
- 'UPDATE items SET value = 1 LIMIT 10'
196
+ @d.limit(10).update_sql(:value => 1).should == 'UPDATE `items` SET `value` = 1 LIMIT 10'
229
197
  end
230
-
198
+
231
199
  specify "should support regexps" do
232
200
  @d << {:name => 'abc', :value => 1}
233
201
  @d << {:name => 'bcd', :value => 2}
234
202
  @d.filter(:name => /bc/).count.should == 2
235
203
  @d.filter(:name => /^bc/).count.should == 1
236
204
  end
237
-
205
+
206
+ specify "should have explain output" do
207
+ @d.explain.should be_a_kind_of(String)
208
+ @d.explain(:extended=>true).should be_a_kind_of(String)
209
+ @d.explain.should_not == @d.explain(:extended=>true)
210
+ end
211
+
238
212
  specify "should correctly literalize strings with comment backslashes in them" do
239
213
  @d.delete
240
214
  proc {@d << {:name => ':\\'}}.should_not raise_error
241
-
215
+
242
216
  @d.first[:name].should == ':\\'
243
217
  end
218
+
219
+ specify "should handle prepared statements with on_duplicate_key_update" do
220
+ @d.db.add_index :items, :value, :unique=>true
221
+ ds = @d.on_duplicate_key_update
222
+ ps = ds.prepare(:insert, :insert_user_id_feature_name, :value => :$v, :name => :$n)
223
+ ps.call(:v => 1, :n => 'a')
224
+ ds.all.should == [{:value=>1, :name=>'a'}]
225
+ ps.call(:v => 1, :n => 'b')
226
+ ds.all.should == [{:value=>1, :name=>'b'}]
227
+ end
244
228
  end
245
229
 
246
230
  describe "MySQL datasets" do
247
231
  before do
248
232
  @d = MYSQL_DB[:orders]
249
233
  end
250
-
234
+
251
235
  specify "should correctly quote column references" do
252
236
  @d.quote_identifiers = true
253
237
  market = 'ICE'
254
238
  ack_stamp = Time.now - 15 * 60 # 15 minutes ago
255
- @d.select(:market, :minute.sql_function(:from_unixtime.sql_function(:ack)).as(:minute)).
256
- where{|o|(:ack.sql_number > ack_stamp) & {:market => market}}.
257
- group_by(:minute.sql_function(:from_unixtime.sql_function(:ack))).sql.should == \
239
+ @d.select(:market, Sequel.function(:minute, Sequel.function(:from_unixtime, :ack)).as(:minute)).
240
+ where{(ack > ack_stamp) & {:market => market}}.
241
+ group_by(Sequel.function(:minute, Sequel.function(:from_unixtime, :ack))).sql.should == \
258
242
  "SELECT `market`, minute(from_unixtime(`ack`)) AS `minute` FROM `orders` WHERE ((`ack` > #{@d.literal(ack_stamp)}) AND (`market` = 'ICE')) GROUP BY minute(from_unixtime(`ack`))"
259
243
  end
260
244
  end
@@ -269,14 +253,14 @@ describe "Dataset#distinct" do
269
253
  @ds = @db[:a]
270
254
  end
271
255
  after do
272
- @db.drop_table(:a)
256
+ @db.drop_table?(:a)
273
257
  end
274
-
258
+
275
259
  it "#distinct with arguments should return results distinct on those arguments" do
276
260
  @ds.insert(20, 10)
277
261
  @ds.insert(30, 10)
278
262
  @ds.order(:b, :a).distinct.map(:a).should == [20, 30]
279
- @ds.order(:b, :a.desc).distinct.map(:a).should == [30, 20]
263
+ @ds.order(:b, Sequel.desc(:a)).distinct.map(:a).should == [30, 20]
280
264
  # MySQL doesn't respect orders when using the nonstandard GROUP BY
281
265
  [[20], [30]].should include(@ds.order(:b, :a).distinct(:b).map(:a))
282
266
  end
@@ -285,7 +269,6 @@ end
285
269
  describe "MySQL join expressions" do
286
270
  before do
287
271
  @ds = MYSQL_DB[:nodes]
288
- @ds.db.meta_def(:server_version) {50014}
289
272
  end
290
273
 
291
274
  specify "should raise error for :full_outer join requests." do
@@ -293,43 +276,43 @@ describe "MySQL join expressions" do
293
276
  end
294
277
  specify "should support natural left joins" do
295
278
  @ds.join_table(:natural_left, :nodes).sql.should == \
296
- 'SELECT * FROM nodes NATURAL LEFT JOIN nodes'
279
+ 'SELECT * FROM `nodes` NATURAL LEFT JOIN `nodes`'
297
280
  end
298
281
  specify "should support natural right joins" do
299
282
  @ds.join_table(:natural_right, :nodes).sql.should == \
300
- 'SELECT * FROM nodes NATURAL RIGHT JOIN nodes'
283
+ 'SELECT * FROM `nodes` NATURAL RIGHT JOIN `nodes`'
301
284
  end
302
285
  specify "should support natural left outer joins" do
303
286
  @ds.join_table(:natural_left_outer, :nodes).sql.should == \
304
- 'SELECT * FROM nodes NATURAL LEFT OUTER JOIN nodes'
287
+ 'SELECT * FROM `nodes` NATURAL LEFT OUTER JOIN `nodes`'
305
288
  end
306
289
  specify "should support natural right outer joins" do
307
290
  @ds.join_table(:natural_right_outer, :nodes).sql.should == \
308
- 'SELECT * FROM nodes NATURAL RIGHT OUTER JOIN nodes'
291
+ 'SELECT * FROM `nodes` NATURAL RIGHT OUTER JOIN `nodes`'
309
292
  end
310
293
  specify "should support natural inner joins" do
311
294
  @ds.join_table(:natural_inner, :nodes).sql.should == \
312
- 'SELECT * FROM nodes NATURAL LEFT JOIN nodes'
295
+ 'SELECT * FROM `nodes` NATURAL LEFT JOIN `nodes`'
313
296
  end
314
297
  specify "should support cross joins" do
315
298
  @ds.join_table(:cross, :nodes).sql.should == \
316
- 'SELECT * FROM nodes CROSS JOIN nodes'
299
+ 'SELECT * FROM `nodes` CROSS JOIN `nodes`'
317
300
  end
318
301
  specify "should support cross joins as inner joins if conditions are used" do
319
302
  @ds.join_table(:cross, :nodes, :id=>:id).sql.should == \
320
- 'SELECT * FROM nodes INNER JOIN nodes ON (nodes.id = nodes.id)'
303
+ 'SELECT * FROM `nodes` INNER JOIN `nodes` ON (`nodes`.`id` = `nodes`.`id`)'
321
304
  end
322
305
  specify "should support straight joins (force left table to be read before right)" do
323
306
  @ds.join_table(:straight, :nodes).sql.should == \
324
- 'SELECT * FROM nodes STRAIGHT_JOIN nodes'
307
+ 'SELECT * FROM `nodes` STRAIGHT_JOIN `nodes`'
325
308
  end
326
309
  specify "should support natural joins on multiple tables." do
327
310
  @ds.join_table(:natural_left_outer, [:nodes, :branches]).sql.should == \
328
- 'SELECT * FROM nodes NATURAL LEFT OUTER JOIN (nodes, branches)'
311
+ 'SELECT * FROM `nodes` NATURAL LEFT OUTER JOIN (`nodes`, `branches`)'
329
312
  end
330
313
  specify "should support straight joins on multiple tables." do
331
314
  @ds.join_table(:straight, [:nodes,:branches]).sql.should == \
332
- 'SELECT * FROM nodes STRAIGHT_JOIN (nodes, branches)'
315
+ 'SELECT * FROM `nodes` STRAIGHT_JOIN (`nodes`, `branches`)'
333
316
  end
334
317
  end
335
318
 
@@ -337,46 +320,79 @@ describe "Joined MySQL dataset" do
337
320
  before do
338
321
  @ds = MYSQL_DB[:nodes]
339
322
  end
340
-
323
+
341
324
  specify "should quote fields correctly" do
342
325
  @ds.quote_identifiers = true
343
326
  @ds.join(:attributes, :node_id => :id).sql.should == \
344
327
  "SELECT * FROM `nodes` INNER JOIN `attributes` ON (`attributes`.`node_id` = `nodes`.`id`)"
345
328
  end
346
-
329
+
347
330
  specify "should allow a having clause on ungrouped datasets" do
348
331
  proc {@ds.having('blah')}.should_not raise_error
349
332
 
350
333
  @ds.having('blah').sql.should == \
351
- "SELECT * FROM nodes HAVING (blah)"
334
+ "SELECT * FROM `nodes` HAVING (blah)"
352
335
  end
353
-
336
+
354
337
  specify "should put a having clause before an order by clause" do
355
338
  @ds.order(:aaa).having(:bbb => :ccc).sql.should == \
356
- "SELECT * FROM nodes HAVING (bbb = ccc) ORDER BY aaa"
339
+ "SELECT * FROM `nodes` HAVING (`bbb` = `ccc`) ORDER BY `aaa`"
357
340
  end
358
341
  end
359
342
 
360
343
  describe "A MySQL database" do
361
- before do
344
+ after do
345
+ MYSQL_DB.drop_table?(:test_innodb)
346
+ end
347
+
348
+ specify "should handle the creation and dropping of an InnoDB table with foreign keys" do
349
+ proc{MYSQL_DB.create_table!(:test_innodb, :engine=>:InnoDB){primary_key :id; foreign_key :fk, :test_innodb, :key=>:id}}.should_not raise_error
350
+ end
351
+ end
352
+
353
+ describe "A MySQL database" do
354
+ before(:all) do
362
355
  @db = MYSQL_DB
356
+ @db.create_table! :test2 do
357
+ text :name
358
+ integer :value
359
+ end
360
+ end
361
+ after(:all) do
362
+ @db.drop_table?(:test2)
363
+ end
364
+
365
+ specify "should provide the server version" do
366
+ @db.server_version.should >= 40000
367
+ end
368
+
369
+ specify "should cache the server version" do
370
+ # warm cache:
371
+ @db.server_version
372
+ @db.sqls.clear
373
+ 3.times{@db.server_version}
374
+ @db.sqls.should be_empty
375
+ end
376
+
377
+ specify "should support for_share" do
378
+ @db.transaction{@db[:test2].for_share.all.should == []}
363
379
  end
364
380
 
365
381
  specify "should support add_column operations" do
366
382
  @db.add_column :test2, :xyz, :text
367
-
383
+
368
384
  @db[:test2].columns.should == [:name, :value, :xyz]
369
385
  @db[:test2] << {:name => 'mmm', :value => 111, :xyz => '000'}
370
386
  @db[:test2].first[:xyz].should == '000'
371
387
  end
372
-
388
+
373
389
  specify "should support drop_column operations" do
374
390
  @db[:test2].columns.should == [:name, :value, :xyz]
375
391
  @db.drop_column :test2, :xyz
376
-
392
+
377
393
  @db[:test2].columns.should == [:name, :value]
378
394
  end
379
-
395
+
380
396
  specify "should support rename_column operations" do
381
397
  @db[:test2].delete
382
398
  @db.add_column :test2, :xyz, :text
@@ -387,7 +403,7 @@ describe "A MySQL database" do
387
403
  @db[:test2].columns.should == [:name, :value, :zyx]
388
404
  @db[:test2].first[:zyx].should == 'qqqq'
389
405
  end
390
-
406
+
391
407
  specify "should support rename_column operations with types like varchar(255)" do
392
408
  @db[:test2].delete
393
409
  @db.add_column :test2, :tre, :text
@@ -398,26 +414,27 @@ describe "A MySQL database" do
398
414
  @db[:test2].columns.should == [:name, :value, :zyx, :ert]
399
415
  @db[:test2].first[:ert].should == 'qqqq'
400
416
  end
401
-
417
+
402
418
  specify "should support set_column_type operations" do
403
419
  @db.add_column :test2, :xyz, :float
404
420
  @db[:test2].delete
405
421
  @db[:test2] << {:name => 'mmm', :value => 111, :xyz => 56.78}
406
422
  @db.set_column_type :test2, :xyz, :integer
407
-
423
+
408
424
  @db[:test2].first[:xyz].should == 57
409
425
  end
410
-
426
+
411
427
  specify "should support add_index" do
412
428
  @db.add_index :test2, :value
413
429
  end
414
-
430
+
415
431
  specify "should support drop_index" do
416
432
  @db.drop_index :test2, :value
417
433
  end
418
-
434
+
419
435
  specify "should support add_foreign_key" do
420
436
  @db.alter_table :test2 do
437
+ add_index :value, :unique=>true
421
438
  add_foreign_key :value2, :test2, :key=>:value
422
439
  end
423
440
  @db[:test2].columns.should == [:name, :value, :zyx, :ert, :xyz, :value2]
@@ -427,79 +444,82 @@ end
427
444
  describe "A MySQL database with table options" do
428
445
  before do
429
446
  @options = {:engine=>'MyISAM', :charset=>'latin1', :collate => 'latin1_swedish_ci'}
430
-
447
+
431
448
  Sequel::MySQL.default_engine = 'InnoDB'
432
449
  Sequel::MySQL.default_charset = 'utf8'
433
450
  Sequel::MySQL.default_collate = 'utf8_general_ci'
434
-
451
+
435
452
  @db = MYSQL_DB
436
- @db.drop_table(:items) rescue nil
437
-
453
+ @db.drop_table?(:items)
454
+
438
455
  MYSQL_DB.sqls.clear
439
456
  end
440
457
  after do
441
- @db.drop_table(:items) rescue nil
458
+ @db.drop_table?(:items)
442
459
 
443
460
  Sequel::MySQL.default_engine = nil
444
461
  Sequel::MySQL.default_charset = nil
445
462
  Sequel::MySQL.default_collate = nil
446
463
  end
447
-
464
+
448
465
  specify "should allow to pass custom options (engine, charset, collate) for table creation" do
449
466
  @db.create_table(:items, @options){Integer :size; text :name}
450
- @db.sqls.should == ["CREATE TABLE items (size integer, name text) ENGINE=MyISAM DEFAULT CHARSET=latin1 DEFAULT COLLATE=latin1_swedish_ci"]
467
+ @db.sqls.should == ["CREATE TABLE `items` (`size` integer, `name` text) ENGINE=MyISAM DEFAULT CHARSET=latin1 DEFAULT COLLATE=latin1_swedish_ci"]
451
468
  end
452
-
469
+
453
470
  specify "should use default options if specified (engine, charset, collate) for table creation" do
454
471
  @db.create_table(:items){Integer :size; text :name}
455
- @db.sqls.should == ["CREATE TABLE items (size integer, name text) ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_general_ci"]
472
+ @db.sqls.should == ["CREATE TABLE `items` (`size` integer, `name` text) ENGINE=InnoDB DEFAULT CHARSET=utf8 DEFAULT COLLATE=utf8_general_ci"]
456
473
  end
457
-
474
+
458
475
  specify "should not use default if option has a nil value" do
459
476
  @db.create_table(:items, :engine=>nil, :charset=>nil, :collate=>nil){Integer :size; text :name}
460
- @db.sqls.should == ["CREATE TABLE items (size integer, name text)"]
477
+ @db.sqls.should == ["CREATE TABLE `items` (`size` integer, `name` text)"]
461
478
  end
462
479
  end
463
480
 
464
481
  describe "A MySQL database" do
465
482
  before do
466
483
  @db = MYSQL_DB
467
- @db.drop_table(:items) rescue nil
484
+ @db.drop_table?(:items)
468
485
  MYSQL_DB.sqls.clear
469
486
  end
470
487
  after do
471
- @db.drop_table(:items) rescue nil
488
+ @db.drop_table?(:items, :users)
472
489
  end
473
-
490
+
474
491
  specify "should support defaults for boolean columns" do
475
492
  @db.create_table(:items){TrueClass :active1, :default=>true; FalseClass :active2, :default => false}
476
- @db.sqls.should == ["CREATE TABLE items (active1 tinyint(1) DEFAULT 1, active2 tinyint(1) DEFAULT 0)"]
493
+ @db.sqls.should == ["CREATE TABLE `items` (`active1` tinyint(1) DEFAULT 1, `active2` tinyint(1) DEFAULT 0)"]
477
494
  end
478
-
495
+
479
496
  specify "should correctly format CREATE TABLE statements with foreign keys" do
480
- @db.create_table(:items){Integer :id; foreign_key :p_id, :items, :key => :id, :null => false, :on_delete => :cascade}
481
- @db.sqls.should == ["CREATE TABLE items (id integer, p_id integer NOT NULL, FOREIGN KEY (p_id) REFERENCES items(id) ON DELETE CASCADE)"]
497
+ @db.create_table(:items){primary_key :id; foreign_key :p_id, :items, :key => :id, :null => false, :on_delete => :cascade}
498
+ @db.sqls.should == ["CREATE TABLE `items` (`id` integer PRIMARY KEY AUTO_INCREMENT, `p_id` integer NOT NULL, UNIQUE (`id`), FOREIGN KEY (`p_id`) REFERENCES `items`(`id`) ON DELETE CASCADE)"]
482
499
  end
483
-
500
+
484
501
  specify "should correctly format ALTER TABLE statements with foreign keys" do
485
502
  @db.create_table(:items){Integer :id}
503
+ @db.create_table(:users){primary_key :id}
486
504
  @db.alter_table(:items){add_foreign_key :p_id, :users, :key => :id, :null => false, :on_delete => :cascade}
487
- @db.sqls.should == ["CREATE TABLE items (id integer)", "ALTER TABLE items ADD COLUMN p_id integer NOT NULL", "ALTER TABLE items ADD FOREIGN KEY (p_id) REFERENCES users(id) ON DELETE CASCADE"]
505
+ @db.sqls.should == ["CREATE TABLE `items` (`id` integer)",
506
+ "CREATE TABLE `users` (`id` integer PRIMARY KEY AUTO_INCREMENT)",
507
+ "ALTER TABLE `items` ADD COLUMN `p_id` integer NOT NULL, ADD FOREIGN KEY (`p_id`) REFERENCES `users`(`id`) ON DELETE CASCADE"]
488
508
  end
489
-
509
+
490
510
  specify "should have rename_column support keep existing options" do
491
511
  @db.create_table(:items){String :id, :null=>false, :default=>'blah'}
492
512
  @db.alter_table(:items){rename_column :id, :nid}
493
- @db.sqls.should == ["CREATE TABLE items (id varchar(255) NOT NULL DEFAULT 'blah')", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id nid varchar(255) NOT NULL DEFAULT 'blah'"]
513
+ @db.sqls.should == ["CREATE TABLE `items` (`id` varchar(255) NOT NULL DEFAULT 'blah')", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `nid` varchar(255) NOT NULL DEFAULT 'blah'"]
494
514
  @db[:items].insert
495
515
  @db[:items].all.should == [{:nid=>'blah'}]
496
516
  proc{@db[:items].insert(:nid=>nil)}.should raise_error(Sequel::DatabaseError)
497
517
  end
498
-
518
+
499
519
  specify "should have set_column_type support keep existing options" do
500
520
  @db.create_table(:items){Integer :id, :null=>false, :default=>5}
501
521
  @db.alter_table(:items){set_column_type :id, Bignum}
502
- @db.sqls.should == ["CREATE TABLE items (id integer NOT NULL DEFAULT 5)", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id bigint NOT NULL DEFAULT 5"]
522
+ @db.sqls.should == ["CREATE TABLE `items` (`id` integer NOT NULL DEFAULT 5)", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `id` bigint NOT NULL DEFAULT 5"]
503
523
  @db[:items].insert
504
524
  @db[:items].all.should == [{:id=>5}]
505
525
  proc{@db[:items].insert(:id=>nil)}.should raise_error(Sequel::DatabaseError)
@@ -511,35 +531,35 @@ describe "A MySQL database" do
511
531
  specify "should have set_column_type pass through options" do
512
532
  @db.create_table(:items){integer :id; enum :list, :elements=>%w[one]}
513
533
  @db.alter_table(:items){set_column_type :id, :int, :unsigned=>true, :size=>8; set_column_type :list, :enum, :elements=>%w[two]}
514
- @db.sqls.should == ["CREATE TABLE items (id integer, list enum('one'))", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id int(8) UNSIGNED NULL", "ALTER TABLE items CHANGE COLUMN list list enum('two') NULL"]
534
+ @db.sqls.should == ["CREATE TABLE `items` (`id` integer, `list` enum('one'))", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `id` int(8) UNSIGNED NULL, CHANGE COLUMN `list` `list` enum('two') NULL"]
515
535
  end
516
-
536
+
517
537
  specify "should have set_column_default support keep existing options" do
518
538
  @db.create_table(:items){Integer :id, :null=>false, :default=>5}
519
539
  @db.alter_table(:items){set_column_default :id, 6}
520
- @db.sqls.should == ["CREATE TABLE items (id integer NOT NULL DEFAULT 5)", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id int(11) NOT NULL DEFAULT 6"]
540
+ @db.sqls.should == ["CREATE TABLE `items` (`id` integer NOT NULL DEFAULT 5)", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `id` int(11) NOT NULL DEFAULT 6"]
521
541
  @db[:items].insert
522
542
  @db[:items].all.should == [{:id=>6}]
523
543
  proc{@db[:items].insert(:id=>nil)}.should raise_error(Sequel::DatabaseError)
524
544
  end
525
-
545
+
526
546
  specify "should have set_column_allow_null support keep existing options" do
527
547
  @db.create_table(:items){Integer :id, :null=>false, :default=>5}
528
548
  @db.alter_table(:items){set_column_allow_null :id, true}
529
- @db.sqls.should == ["CREATE TABLE items (id integer NOT NULL DEFAULT 5)", "DESCRIBE items", "ALTER TABLE items CHANGE COLUMN id id int(11) NULL DEFAULT 5"]
549
+ @db.sqls.should == ["CREATE TABLE `items` (`id` integer NOT NULL DEFAULT 5)", "DESCRIBE `items`", "ALTER TABLE `items` CHANGE COLUMN `id` `id` int(11) NULL DEFAULT 5"]
530
550
  @db[:items].insert
531
551
  @db[:items].all.should == [{:id=>5}]
532
552
  proc{@db[:items].insert(:id=>nil)}.should_not
533
553
  end
534
-
554
+
535
555
  specify "should accept repeated raw sql statements using Database#<<" do
536
556
  @db.create_table(:items){String :name; Integer :value}
537
557
  @db << 'DELETE FROM items'
538
558
  @db[:items].count.should == 0
539
-
559
+
540
560
  @db << "INSERT INTO items (name, value) VALUES ('tutu', 1234)"
541
561
  @db[:items].first.should == {:name => 'tutu', :value => 1234}
542
-
562
+
543
563
  @db << 'DELETE FROM items'
544
564
  @db[:items].first.should == nil
545
565
  end
@@ -552,12 +572,12 @@ if %w'localhost 127.0.0.1 ::1'.include?(MYSQL_URI.host) and MYSQL_DB.adapter_sch
552
572
  db = Sequel.mysql(MYSQL_DB.opts[:database], :host => 'localhost', :user => MYSQL_DB.opts[:user], :password => MYSQL_DB.opts[:password], :socket => MYSQL_SOCKET_FILE)
553
573
  proc {db.test_connection}.should_not raise_error
554
574
  end
555
-
575
+
556
576
  specify "should accept a socket option without host option" do
557
577
  db = Sequel.mysql(MYSQL_DB.opts[:database], :user => MYSQL_DB.opts[:user], :password => MYSQL_DB.opts[:password], :socket => MYSQL_SOCKET_FILE)
558
578
  proc {db.test_connection}.should_not raise_error
559
579
  end
560
-
580
+
561
581
  specify "should fail to connect with invalid socket" do
562
582
  db = Sequel.mysql(MYSQL_DB.opts[:database], :user => MYSQL_DB.opts[:user], :password => MYSQL_DB.opts[:password], :socket =>'blah')
563
583
  proc {db.test_connection}.should raise_error
@@ -577,9 +597,58 @@ describe "A MySQL database" do
577
597
  end
578
598
  end
579
599
 
600
+ describe "MySQL foreign key support" do
601
+ after do
602
+ MYSQL_DB.drop_table?(:testfk, :testpk)
603
+ end
604
+
605
+ specify "should create table without :key" do
606
+ MYSQL_DB.create_table!(:testpk){primary_key :id}
607
+ MYSQL_DB.create_table!(:testfk){foreign_key :fk, :testpk}
608
+ end
609
+
610
+ specify "should create table with composite keys without :key" do
611
+ MYSQL_DB.create_table!(:testpk){Integer :id; Integer :id2; primary_key([:id, :id2])}
612
+ MYSQL_DB.create_table!(:testfk){Integer :fk; Integer :fk2; foreign_key([:fk, :fk2], :testpk)}
613
+ end
614
+
615
+ specify "should create table with self referential without :key" do
616
+ MYSQL_DB.create_table!(:testfk){primary_key :id; foreign_key :fk, :testfk}
617
+ end
618
+
619
+ specify "should create table with self referential with composite keys without :key" do
620
+ MYSQL_DB.create_table!(:testfk){Integer :id; Integer :id2; Integer :fk; Integer :fk2; primary_key([:id, :id2]); foreign_key([:fk, :fk2], :testfk)}
621
+ end
622
+
623
+ specify "should alter table without :key" do
624
+ MYSQL_DB.create_table!(:testpk){primary_key :id}
625
+ MYSQL_DB.create_table!(:testfk){Integer :id}
626
+ MYSQL_DB.alter_table(:testfk){add_foreign_key :fk, :testpk}
627
+ end
628
+
629
+ specify "should alter table with composite keys without :key" do
630
+ MYSQL_DB.create_table!(:testpk){Integer :id; Integer :id2; primary_key([:id, :id2])}
631
+ MYSQL_DB.create_table!(:testfk){Integer :fk; Integer :fk2}
632
+ MYSQL_DB.alter_table(:testfk){add_foreign_key([:fk, :fk2], :testpk)}
633
+ end
634
+
635
+ specify "should alter table with self referential without :key" do
636
+ MYSQL_DB.create_table!(:testfk){primary_key :id}
637
+ MYSQL_DB.alter_table(:testfk){add_foreign_key :fk, :testfk}
638
+ end
639
+
640
+ specify "should alter table with self referential with composite keys without :key" do
641
+ MYSQL_DB.create_table!(:testfk){Integer :id; Integer :id2; Integer :fk; Integer :fk2; primary_key([:id, :id2])}
642
+ MYSQL_DB.alter_table(:testfk){add_foreign_key [:fk, :fk2], :testfk}
643
+ end
644
+ end
645
+
580
646
  describe "A grouped MySQL dataset" do
581
647
  before do
582
- MYSQL_DB[:test2].delete
648
+ MYSQL_DB.create_table! :test2 do
649
+ text :name
650
+ integer :value
651
+ end
583
652
  MYSQL_DB[:test2] << {:name => '11', :value => 10}
584
653
  MYSQL_DB[:test2] << {:name => '11', :value => 20}
585
654
  MYSQL_DB[:test2] << {:name => '11', :value => 30}
@@ -587,12 +656,15 @@ describe "A grouped MySQL dataset" do
587
656
  MYSQL_DB[:test2] << {:name => '12', :value => 20}
588
657
  MYSQL_DB[:test2] << {:name => '13', :value => 10}
589
658
  end
590
-
659
+ after do
660
+ MYSQL_DB.drop_table?(:test2)
661
+ end
662
+
591
663
  specify "should return the correct count for raw sql query" do
592
664
  ds = MYSQL_DB["select name FROM test2 WHERE name = '11' GROUP BY name"]
593
665
  ds.count.should == 1
594
666
  end
595
-
667
+
596
668
  specify "should return the correct count for a normal dataset" do
597
669
  ds = MYSQL_DB[:test2].select(:name).where(:name => '11').group(:name)
598
670
  ds.count.should == 1
@@ -602,21 +674,21 @@ end
602
674
  describe "A MySQL database" do
603
675
  before do
604
676
  @db = MYSQL_DB
605
- @db.drop_table(:posts) rescue nil
677
+ @db.drop_table?(:posts)
606
678
  @db.sqls.clear
607
679
  end
608
680
  after do
609
- @db.drop_table(:posts) rescue nil
681
+ @db.drop_table?(:posts)
610
682
  end
611
-
683
+
612
684
  specify "should support fulltext indexes and full_text_search" do
613
- @db.create_table(:posts){text :title; text :body; full_text_index :title; full_text_index [:title, :body]}
685
+ @db.create_table(:posts, :engine=>:MyISAM){text :title; text :body; full_text_index :title; full_text_index [:title, :body]}
614
686
  @db.sqls.should == [
615
- "CREATE TABLE posts (title text, body text)",
616
- "CREATE FULLTEXT INDEX posts_title_index ON posts (title)",
617
- "CREATE FULLTEXT INDEX posts_title_body_index ON posts (title, body)"
687
+ "CREATE TABLE `posts` (`title` text, `body` text) ENGINE=MyISAM",
688
+ "CREATE FULLTEXT INDEX `posts_title_index` ON `posts` (`title`)",
689
+ "CREATE FULLTEXT INDEX `posts_title_body_index` ON `posts` (`title`, `body`)"
618
690
  ]
619
-
691
+
620
692
  @db[:posts].insert(:title=>'ruby rails', :body=>'y')
621
693
  @db[:posts].insert(:title=>'sequel', :body=>'ruby')
622
694
  @db[:posts].insert(:title=>'ruby scooby', :body=>'x')
@@ -626,32 +698,35 @@ describe "A MySQL database" do
626
698
  @db[:posts].full_text_search([:title, :body], ['sequel', 'ruby']).all.should == [{:title=>'sequel', :body=>'ruby'}]
627
699
  @db[:posts].full_text_search(:title, '+ruby -rails', :boolean => true).all.should == [{:title=>'ruby scooby', :body=>'x'}]
628
700
  @db.sqls.should == [
629
- "SELECT * FROM posts WHERE (MATCH (title) AGAINST ('rails'))",
630
- "SELECT * FROM posts WHERE (MATCH (title, body) AGAINST ('sequel ruby'))",
631
- "SELECT * FROM posts WHERE (MATCH (title) AGAINST ('+ruby -rails' IN BOOLEAN MODE))"]
701
+ "SELECT * FROM `posts` WHERE (MATCH (`title`) AGAINST ('rails'))",
702
+ "SELECT * FROM `posts` WHERE (MATCH (`title`, `body`) AGAINST ('sequel ruby'))",
703
+ "SELECT * FROM `posts` WHERE (MATCH (`title`) AGAINST ('+ruby -rails' IN BOOLEAN MODE))"]
704
+
705
+ @db[:posts].full_text_search(:title, :$n).call(:select, :n=>'rails').should == [{:title=>'ruby rails', :body=>'y'}]
706
+ @db[:posts].full_text_search(:title, :$n).prepare(:select, :fts_select).call(:n=>'rails').should == [{:title=>'ruby rails', :body=>'y'}]
632
707
  end
633
708
 
634
709
  specify "should support spatial indexes" do
635
- @db.create_table(:posts){point :geom, :null=>false; spatial_index [:geom]}
710
+ @db.create_table(:posts, :engine=>:MyISAM){point :geom, :null=>false; spatial_index [:geom]}
636
711
  @db.sqls.should == [
637
- "CREATE TABLE posts (geom point NOT NULL)",
638
- "CREATE SPATIAL INDEX posts_geom_index ON posts (geom)"
712
+ "CREATE TABLE `posts` (`geom` point NOT NULL) ENGINE=MyISAM",
713
+ "CREATE SPATIAL INDEX `posts_geom_index` ON `posts` (`geom`)"
639
714
  ]
640
715
  end
641
716
 
642
717
  specify "should support indexes with index type" do
643
718
  @db.create_table(:posts){Integer :id; index :id, :type => :btree}
644
719
  @db.sqls.should == [
645
- "CREATE TABLE posts (id integer)",
646
- "CREATE INDEX posts_id_index USING btree ON posts (id)"
720
+ "CREATE TABLE `posts` (`id` integer)",
721
+ "CREATE INDEX `posts_id_index` USING btree ON `posts` (`id`)"
647
722
  ]
648
723
  end
649
724
 
650
725
  specify "should support unique indexes with index type" do
651
726
  @db.create_table(:posts){Integer :id; index :id, :type => :btree, :unique => true}
652
727
  @db.sqls.should == [
653
- "CREATE TABLE posts (id integer)",
654
- "CREATE UNIQUE INDEX posts_id_index USING btree ON posts (id)"
728
+ "CREATE TABLE `posts` (`id` integer)",
729
+ "CREATE UNIQUE INDEX `posts_id_index` USING btree ON `posts` (`id`)"
655
730
  ]
656
731
  end
657
732
 
@@ -675,43 +750,25 @@ describe "MySQL::Dataset#insert and related methods" do
675
750
  MYSQL_DB.sqls.clear
676
751
  end
677
752
  after do
678
- MYSQL_DB.drop_table(:items)
753
+ MYSQL_DB.drop_table?(:items)
679
754
  end
680
755
 
681
756
  specify "#insert should insert record with default values when no arguments given" do
682
757
  @d.insert
683
-
684
- MYSQL_DB.sqls.should == [
685
- "INSERT INTO items () VALUES ()"
686
- ]
687
-
688
- @d.all.should == [
689
- {:name => nil, :value => nil}
690
- ]
758
+ MYSQL_DB.sqls.should == ["INSERT INTO `items` () VALUES ()"]
759
+ @d.all.should == [{:name => nil, :value => nil}]
691
760
  end
692
761
 
693
762
  specify "#insert should insert record with default values when empty hash given" do
694
763
  @d.insert({})
695
-
696
- MYSQL_DB.sqls.should == [
697
- "INSERT INTO items () VALUES ()"
698
- ]
699
-
700
- @d.all.should == [
701
- {:name => nil, :value => nil}
702
- ]
764
+ MYSQL_DB.sqls.should == ["INSERT INTO `items` () VALUES ()"]
765
+ @d.all.should == [{:name => nil, :value => nil}]
703
766
  end
704
767
 
705
768
  specify "#insert should insert record with default values when empty array given" do
706
769
  @d.insert []
707
-
708
- MYSQL_DB.sqls.should == [
709
- "INSERT INTO items () VALUES ()"
710
- ]
711
-
712
- @d.all.should == [
713
- {:name => nil, :value => nil}
714
- ]
770
+ MYSQL_DB.sqls.should == ["INSERT INTO `items` () VALUES ()"]
771
+ @d.all.should == [{:name => nil, :value => nil}]
715
772
  end
716
773
 
717
774
  specify "#on_duplicate_key_update should work with regular inserts" do
@@ -722,19 +779,75 @@ describe "MySQL::Dataset#insert and related methods" do
722
779
  @d.on_duplicate_key_update(:name, :value => 6).insert(:name => 'def', :value => 2)
723
780
 
724
781
  MYSQL_DB.sqls.length.should == 3
725
- MYSQL_DB.sqls[0].should =~ /\AINSERT INTO items \((name|value), (name|value)\) VALUES \(('abc'|1), (1|'abc')\)\z/
726
- MYSQL_DB.sqls[1].should =~ /\AINSERT INTO items \((name|value), (name|value)\) VALUES \(('abc'|1), (1|'abc')\) ON DUPLICATE KEY UPDATE name=VALUES\(name\), value=6\z/
727
- MYSQL_DB.sqls[2].should =~ /\AINSERT INTO items \((name|value), (name|value)\) VALUES \(('def'|2), (2|'def')\) ON DUPLICATE KEY UPDATE name=VALUES\(name\), value=6\z/
782
+ MYSQL_DB.sqls[0].should =~ /\AINSERT INTO `items` \(`(name|value)`, `(name|value)`\) VALUES \(('abc'|1), (1|'abc')\)\z/
783
+ MYSQL_DB.sqls[1].should =~ /\AINSERT INTO `items` \(`(name|value)`, `(name|value)`\) VALUES \(('abc'|1), (1|'abc')\) ON DUPLICATE KEY UPDATE `name`=VALUES\(`name`\), `value`=6\z/
784
+ MYSQL_DB.sqls[2].should =~ /\AINSERT INTO `items` \(`(name|value)`, `(name|value)`\) VALUES \(('def'|2), (2|'def')\) ON DUPLICATE KEY UPDATE `name`=VALUES\(`name`\), `value`=6\z/
728
785
 
729
786
  @d.all.should == [{:name => 'abc', :value => 6}, {:name => 'def', :value => 2}]
730
787
  end
731
788
 
789
+ specify "#multi_replace should insert multiple records in a single statement" do
790
+ @d.multi_replace([{:name => 'abc'}, {:name => 'def'}])
791
+
792
+ MYSQL_DB.sqls.should == [
793
+ SQL_BEGIN,
794
+ "REPLACE INTO `items` (`name`) VALUES ('abc'), ('def')",
795
+ SQL_COMMIT
796
+ ]
797
+
798
+ @d.all.should == [
799
+ {:name => 'abc', :value => nil}, {:name => 'def', :value => nil}
800
+ ]
801
+ end
802
+
803
+ specify "#multi_replace should split the list of records into batches if :commit_every option is given" do
804
+ @d.multi_replace([{:value => 1}, {:value => 2}, {:value => 3}, {:value => 4}],
805
+ :commit_every => 2)
806
+
807
+ MYSQL_DB.sqls.should == [
808
+ SQL_BEGIN,
809
+ "REPLACE INTO `items` (`value`) VALUES (1), (2)",
810
+ SQL_COMMIT,
811
+ SQL_BEGIN,
812
+ "REPLACE INTO `items` (`value`) VALUES (3), (4)",
813
+ SQL_COMMIT
814
+ ]
815
+
816
+ @d.all.should == [
817
+ {:name => nil, :value => 1},
818
+ {:name => nil, :value => 2},
819
+ {:name => nil, :value => 3},
820
+ {:name => nil, :value => 4}
821
+ ]
822
+ end
823
+
824
+ specify "#multi_replace should split the list of records into batches if :slice option is given" do
825
+ @d.multi_replace([{:value => 1}, {:value => 2}, {:value => 3}, {:value => 4}],
826
+ :slice => 2)
827
+
828
+ MYSQL_DB.sqls.should == [
829
+ SQL_BEGIN,
830
+ "REPLACE INTO `items` (`value`) VALUES (1), (2)",
831
+ SQL_COMMIT,
832
+ SQL_BEGIN,
833
+ "REPLACE INTO `items` (`value`) VALUES (3), (4)",
834
+ SQL_COMMIT
835
+ ]
836
+
837
+ @d.all.should == [
838
+ {:name => nil, :value => 1},
839
+ {:name => nil, :value => 2},
840
+ {:name => nil, :value => 3},
841
+ {:name => nil, :value => 4}
842
+ ]
843
+ end
844
+
732
845
  specify "#multi_insert should insert multiple records in a single statement" do
733
846
  @d.multi_insert([{:name => 'abc'}, {:name => 'def'}])
734
-
847
+
735
848
  MYSQL_DB.sqls.should == [
736
849
  SQL_BEGIN,
737
- "INSERT INTO items (name) VALUES ('abc'), ('def')",
850
+ "INSERT INTO `items` (`name`) VALUES ('abc'), ('def')",
738
851
  SQL_COMMIT
739
852
  ]
740
853
 
@@ -749,13 +862,13 @@ describe "MySQL::Dataset#insert and related methods" do
749
862
 
750
863
  MYSQL_DB.sqls.should == [
751
864
  SQL_BEGIN,
752
- "INSERT INTO items (value) VALUES (1), (2)",
865
+ "INSERT INTO `items` (`value`) VALUES (1), (2)",
753
866
  SQL_COMMIT,
754
867
  SQL_BEGIN,
755
- "INSERT INTO items (value) VALUES (3), (4)",
868
+ "INSERT INTO `items` (`value`) VALUES (3), (4)",
756
869
  SQL_COMMIT
757
870
  ]
758
-
871
+
759
872
  @d.all.should == [
760
873
  {:name => nil, :value => 1},
761
874
  {:name => nil, :value => 2},
@@ -770,13 +883,13 @@ describe "MySQL::Dataset#insert and related methods" do
770
883
 
771
884
  MYSQL_DB.sqls.should == [
772
885
  SQL_BEGIN,
773
- "INSERT INTO items (value) VALUES (1), (2)",
886
+ "INSERT INTO `items` (`value`) VALUES (1), (2)",
774
887
  SQL_COMMIT,
775
888
  SQL_BEGIN,
776
- "INSERT INTO items (value) VALUES (3), (4)",
889
+ "INSERT INTO `items` (`value`) VALUES (3), (4)",
777
890
  SQL_COMMIT
778
891
  ]
779
-
892
+
780
893
  @d.all.should == [
781
894
  {:name => nil, :value => 1},
782
895
  {:name => nil, :value => 2},
@@ -784,28 +897,28 @@ describe "MySQL::Dataset#insert and related methods" do
784
897
  {:name => nil, :value => 4}
785
898
  ]
786
899
  end
787
-
900
+
788
901
  specify "#import should support inserting using columns and values arrays" do
789
902
  @d.import([:name, :value], [['abc', 1], ['def', 2]])
790
903
 
791
904
  MYSQL_DB.sqls.should == [
792
905
  SQL_BEGIN,
793
- "INSERT INTO items (name, value) VALUES ('abc', 1), ('def', 2)",
906
+ "INSERT INTO `items` (`name`, `value`) VALUES ('abc', 1), ('def', 2)",
794
907
  SQL_COMMIT
795
908
  ]
796
-
909
+
797
910
  @d.all.should == [
798
911
  {:name => 'abc', :value => 1},
799
912
  {:name => 'def', :value => 2}
800
913
  ]
801
914
  end
802
-
915
+
803
916
  specify "#insert_ignore should add the IGNORE keyword when inserting" do
804
917
  @d.insert_ignore.multi_insert([{:name => 'abc'}, {:name => 'def'}])
805
-
918
+
806
919
  MYSQL_DB.sqls.should == [
807
920
  SQL_BEGIN,
808
- "INSERT IGNORE INTO items (name) VALUES ('abc'), ('def')",
921
+ "INSERT IGNORE INTO `items` (`name`) VALUES ('abc'), ('def')",
809
922
  SQL_COMMIT
810
923
  ]
811
924
 
@@ -813,20 +926,20 @@ describe "MySQL::Dataset#insert and related methods" do
813
926
  {:name => 'abc', :value => nil}, {:name => 'def', :value => nil}
814
927
  ]
815
928
  end
816
-
929
+
817
930
  specify "#insert_ignore should add the IGNORE keyword for single inserts" do
818
931
  @d.insert_ignore.insert(:name => 'ghi')
819
- MYSQL_DB.sqls.should == ["INSERT IGNORE INTO items (name) VALUES ('ghi')"]
932
+ MYSQL_DB.sqls.should == ["INSERT IGNORE INTO `items` (`name`) VALUES ('ghi')"]
820
933
  @d.all.should == [{:name => 'ghi', :value => nil}]
821
934
  end
822
-
935
+
823
936
  specify "#on_duplicate_key_update should add the ON DUPLICATE KEY UPDATE and ALL columns when no args given" do
824
937
  @d.on_duplicate_key_update.import([:name,:value], [['abc', 1], ['def',2]])
825
-
938
+
826
939
  MYSQL_DB.sqls.should == [
827
- "SELECT * FROM items LIMIT 1",
940
+ "SELECT * FROM `items` LIMIT 1",
828
941
  SQL_BEGIN,
829
- "INSERT INTO items (name, value) VALUES ('abc', 1), ('def', 2) ON DUPLICATE KEY UPDATE name=VALUES(name), value=VALUES(value)",
942
+ "INSERT INTO `items` (`name`, `value`) VALUES ('abc', 1), ('def', 2) ON DUPLICATE KEY UPDATE `name`=VALUES(`name`), `value`=VALUES(`value`)",
830
943
  SQL_COMMIT
831
944
  ]
832
945
 
@@ -834,15 +947,15 @@ describe "MySQL::Dataset#insert and related methods" do
834
947
  {:name => 'abc', :value => 1}, {:name => 'def', :value => 2}
835
948
  ]
836
949
  end
837
-
950
+
838
951
  specify "#on_duplicate_key_update should add the ON DUPLICATE KEY UPDATE and columns specified when args are given" do
839
952
  @d.on_duplicate_key_update(:value).import([:name,:value],
840
953
  [['abc', 1], ['def',2]]
841
954
  )
842
-
955
+
843
956
  MYSQL_DB.sqls.should == [
844
957
  SQL_BEGIN,
845
- "INSERT INTO items (name, value) VALUES ('abc', 1), ('def', 2) ON DUPLICATE KEY UPDATE value=VALUES(value)",
958
+ "INSERT INTO `items` (`name`, `value`) VALUES ('abc', 1), ('def', 2) ON DUPLICATE KEY UPDATE `value`=VALUES(`value`)",
846
959
  SQL_COMMIT
847
960
  ]
848
961
 
@@ -850,7 +963,27 @@ describe "MySQL::Dataset#insert and related methods" do
850
963
  {:name => 'abc', :value => 1}, {:name => 'def', :value => 2}
851
964
  ]
852
965
  end
853
-
966
+
967
+ end
968
+
969
+ describe "MySQL::Dataset#update and related methods" do
970
+ before do
971
+ MYSQL_DB.create_table(:items){String :name; Integer :value; index :name, :unique=>true}
972
+ @d = MYSQL_DB[:items]
973
+ end
974
+ after do
975
+ MYSQL_DB.drop_table?(:items)
976
+ end
977
+
978
+ specify "#update_ignore should not raise error where normal update would fail" do
979
+ @d.insert(:name => 'cow', :value => 0)
980
+ @d.insert(:name => 'cat', :value => 1)
981
+ proc{@d.where(:value => 1).update(:name => 'cow')}.should raise_error(Sequel::DatabaseError)
982
+ MYSQL_DB.sqls.clear
983
+ @d.update_ignore.where(:value => 1).update(:name => 'cow')
984
+ MYSQL_DB.sqls.should == ["UPDATE IGNORE `items` SET `name` = 'cow' WHERE (`value` = 1)"]
985
+ @d.order(:name).all.should == [{:name => 'cat', :value => 1}, {:name => 'cow', :value => 0}]
986
+ end
854
987
  end
855
988
 
856
989
  describe "MySQL::Dataset#replace" do
@@ -860,9 +993,9 @@ describe "MySQL::Dataset#replace" do
860
993
  MYSQL_DB.sqls.clear
861
994
  end
862
995
  after do
863
- MYSQL_DB.drop_table(:items)
996
+ MYSQL_DB.drop_table?(:items)
864
997
  end
865
-
998
+
866
999
  specify "should use default values if they exist" do
867
1000
  MYSQL_DB.alter_table(:items){set_column_default :id, 1; set_column_default :value, 2}
868
1001
  @d.replace
@@ -872,7 +1005,7 @@ describe "MySQL::Dataset#replace" do
872
1005
  @d.replace({})
873
1006
  @d.all.should == [{:id=>1, :value=>2}]
874
1007
  end
875
-
1008
+
876
1009
  specify "should use support arrays, datasets, and multiple values" do
877
1010
  @d.replace([1, 2])
878
1011
  @d.all.should == [{:id=>1, :value=>2}]
@@ -881,12 +1014,12 @@ describe "MySQL::Dataset#replace" do
881
1014
  @d.replace(@d)
882
1015
  @d.all.should == [{:id=>1, :value=>2}]
883
1016
  end
884
-
1017
+
885
1018
  specify "should create a record if the condition is not met" do
886
1019
  @d.replace(:id => 111, :value => 333)
887
1020
  @d.all.should == [{:id => 111, :value => 333}]
888
1021
  end
889
-
1022
+
890
1023
  specify "should update a record if the condition is met" do
891
1024
  @d << {:id => 111}
892
1025
  @d.all.should == [{:id => 111, :value => nil}]
@@ -901,25 +1034,25 @@ describe "MySQL::Dataset#complex_expression_sql" do
901
1034
  end
902
1035
 
903
1036
  specify "should handle pattern matches correctly" do
904
- @d.literal(:x.like('a')).should == "(x LIKE BINARY 'a')"
905
- @d.literal(~:x.like('a')).should == "(x NOT LIKE BINARY 'a')"
906
- @d.literal(:x.ilike('a')).should == "(x LIKE 'a')"
907
- @d.literal(~:x.ilike('a')).should == "(x NOT LIKE 'a')"
908
- @d.literal(:x.like(/a/)).should == "(x REGEXP BINARY 'a')"
909
- @d.literal(~:x.like(/a/)).should == "(x NOT REGEXP BINARY 'a')"
910
- @d.literal(:x.like(/a/i)).should == "(x REGEXP 'a')"
911
- @d.literal(~:x.like(/a/i)).should == "(x NOT REGEXP 'a')"
1037
+ @d.literal(Sequel.expr(:x).like('a')).should == "(`x` LIKE BINARY 'a')"
1038
+ @d.literal(~Sequel.expr(:x).like('a')).should == "(`x` NOT LIKE BINARY 'a')"
1039
+ @d.literal(Sequel.expr(:x).ilike('a')).should == "(`x` LIKE 'a')"
1040
+ @d.literal(~Sequel.expr(:x).ilike('a')).should == "(`x` NOT LIKE 'a')"
1041
+ @d.literal(Sequel.expr(:x).like(/a/)).should == "(`x` REGEXP BINARY 'a')"
1042
+ @d.literal(~Sequel.expr(:x).like(/a/)).should == "(`x` NOT REGEXP BINARY 'a')"
1043
+ @d.literal(Sequel.expr(:x).like(/a/i)).should == "(`x` REGEXP 'a')"
1044
+ @d.literal(~Sequel.expr(:x).like(/a/i)).should == "(`x` NOT REGEXP 'a')"
912
1045
  end
913
1046
 
914
1047
  specify "should handle string concatenation with CONCAT if more than one record" do
915
- @d.literal([:x, :y].sql_string_join).should == "CONCAT(x, y)"
916
- @d.literal([:x, :y].sql_string_join(' ')).should == "CONCAT(x, ' ', y)"
917
- @d.literal([:x.sql_function(:y), 1, 'z'.lit].sql_string_join(:y.sql_subscript(1))).should == "CONCAT(x(y), y[1], '1', y[1], z)"
1048
+ @d.literal(Sequel.join([:x, :y])).should == "CONCAT(`x`, `y`)"
1049
+ @d.literal(Sequel.join([:x, :y], ' ')).should == "CONCAT(`x`, ' ', `y`)"
1050
+ @d.literal(Sequel.join([Sequel.function(:x, :y), 1, Sequel.lit('z')], Sequel.subscript(:y, 1))).should == "CONCAT(x(`y`), `y`[1], '1', `y`[1], z)"
918
1051
  end
919
1052
 
920
1053
  specify "should handle string concatenation as simple string if just one record" do
921
- @d.literal([:x].sql_string_join).should == "x"
922
- @d.literal([:x].sql_string_join(' ')).should == "x"
1054
+ @d.literal(Sequel.join([:x])).should == "`x`"
1055
+ @d.literal(Sequel.join([:x], ' ')).should == "`x`"
923
1056
  end
924
1057
  end
925
1058
 
@@ -928,12 +1061,12 @@ describe "MySQL::Dataset#calc_found_rows" do
928
1061
  MYSQL_DB.create_table!(:items){Integer :a}
929
1062
  end
930
1063
  after do
931
- MYSQL_DB.drop_table(:items)
1064
+ MYSQL_DB.drop_table?(:items)
932
1065
  end
933
1066
 
934
1067
  specify "should add the SQL_CALC_FOUND_ROWS keyword when selecting" do
935
1068
  MYSQL_DB[:items].select(:a).calc_found_rows.limit(1).sql.should == \
936
- 'SELECT SQL_CALC_FOUND_ROWS a FROM items LIMIT 1'
1069
+ 'SELECT SQL_CALC_FOUND_ROWS `a` FROM `items` LIMIT 1'
937
1070
  end
938
1071
 
939
1072
  specify "should count matching rows disregarding LIMIT clause" do
@@ -941,16 +1074,16 @@ describe "MySQL::Dataset#calc_found_rows" do
941
1074
  MYSQL_DB.sqls.clear
942
1075
 
943
1076
  MYSQL_DB[:items].calc_found_rows.filter(:a => 1).limit(1).all.should == [{:a => 1}]
944
- MYSQL_DB.dataset.select(:FOUND_ROWS.sql_function.as(:rows)).all.should == [{:rows => 2 }]
1077
+ MYSQL_DB.dataset.select(Sequel.function(:FOUND_ROWS).as(:rows)).all.should == [{:rows => 2 }]
945
1078
 
946
1079
  MYSQL_DB.sqls.should == [
947
- 'SELECT SQL_CALC_FOUND_ROWS * FROM items WHERE (a = 1) LIMIT 1',
948
- 'SELECT FOUND_ROWS() AS rows',
1080
+ 'SELECT SQL_CALC_FOUND_ROWS * FROM `items` WHERE (`a` = 1) LIMIT 1',
1081
+ 'SELECT FOUND_ROWS() AS `rows`',
949
1082
  ]
950
1083
  end
951
1084
  end
952
1085
 
953
- if MYSQL_DB.adapter_scheme == :mysql or MYSQL_DB.adapter_scheme == :jdbc
1086
+ if MYSQL_DB.adapter_scheme == :mysql or MYSQL_DB.adapter_scheme == :jdbc or MYSQL_DB.adapter_scheme == :mysql2
954
1087
  describe "MySQL Stored Procedures" do
955
1088
  before do
956
1089
  MYSQL_DB.create_table(:items){Integer :id; Integer :value}
@@ -958,10 +1091,10 @@ if MYSQL_DB.adapter_scheme == :mysql or MYSQL_DB.adapter_scheme == :jdbc
958
1091
  MYSQL_DB.sqls.clear
959
1092
  end
960
1093
  after do
961
- MYSQL_DB.drop_table(:items)
1094
+ MYSQL_DB.drop_table?(:items)
962
1095
  MYSQL_DB.execute('DROP PROCEDURE test_sproc')
963
1096
  end
964
-
1097
+
965
1098
  specify "should be callable on the database object" do
966
1099
  MYSQL_DB.execute_ddl('CREATE PROCEDURE test_sproc() BEGIN DELETE FROM items; END')
967
1100
  MYSQL_DB[:items].delete
@@ -970,27 +1103,38 @@ if MYSQL_DB.adapter_scheme == :mysql or MYSQL_DB.adapter_scheme == :jdbc
970
1103
  MYSQL_DB.call_sproc(:test_sproc)
971
1104
  MYSQL_DB[:items].count.should == 0
972
1105
  end
973
-
974
- specify "should be callable on the dataset object" do
975
- MYSQL_DB.execute_ddl('CREATE PROCEDURE test_sproc(a INTEGER) BEGIN SELECT *, a AS b FROM items; END')
976
- MYSQL_DB[:items].delete
977
- @d = MYSQL_DB[:items]
978
- @d.call_sproc(:select, :test_sproc, 3).should == []
979
- @d.insert(:value=>1)
980
- @d.call_sproc(:select, :test_sproc, 4).should == [{:id=>nil, :value=>1, :b=>4}]
981
- @d.row_proc = proc{|r| r.keys.each{|k| r[k] *= 2 if r[k].is_a?(Integer)}; r}
982
- @d.call_sproc(:select, :test_sproc, 3).should == [{:id=>nil, :value=>2, :b=>6}]
1106
+
1107
+ # Mysql2 doesn't support stored procedures that return result sets, probably because
1108
+ # CLIENT_MULTI_RESULTS is not set.
1109
+ unless MYSQL_DB.adapter_scheme == :mysql2
1110
+ specify "should be callable on the dataset object" do
1111
+ MYSQL_DB.execute_ddl('CREATE PROCEDURE test_sproc(a INTEGER) BEGIN SELECT *, a AS b FROM items; END')
1112
+ MYSQL_DB[:items].delete
1113
+ @d = MYSQL_DB[:items]
1114
+ @d.call_sproc(:select, :test_sproc, 3).should == []
1115
+ @d.insert(:value=>1)
1116
+ @d.call_sproc(:select, :test_sproc, 4).should == [{:id=>nil, :value=>1, :b=>4}]
1117
+ @d.row_proc = proc{|r| r.keys.each{|k| r[k] *= 2 if r[k].is_a?(Integer)}; r}
1118
+ @d.call_sproc(:select, :test_sproc, 3).should == [{:id=>nil, :value=>2, :b=>6}]
1119
+ end
1120
+
1121
+ specify "should be callable on the dataset object with multiple arguments" do
1122
+ MYSQL_DB.execute_ddl('CREATE PROCEDURE test_sproc(a INTEGER, c INTEGER) BEGIN SELECT *, a AS b, c AS d FROM items; END')
1123
+ MYSQL_DB[:items].delete
1124
+ @d = MYSQL_DB[:items]
1125
+ @d.call_sproc(:select, :test_sproc, 3, 4).should == []
1126
+ @d.insert(:value=>1)
1127
+ @d.call_sproc(:select, :test_sproc, 4, 5).should == [{:id=>nil, :value=>1, :b=>4, :d=>5}]
1128
+ @d.row_proc = proc{|r| r.keys.each{|k| r[k] *= 2 if r[k].is_a?(Integer)}; r}
1129
+ @d.call_sproc(:select, :test_sproc, 3, 4).should == [{:id=>nil, :value=>2, :b=>6, :d => 8}]
1130
+ end
983
1131
  end
984
-
985
- specify "should be callable on the dataset object with multiple arguments" do
986
- MYSQL_DB.execute_ddl('CREATE PROCEDURE test_sproc(a INTEGER, c INTEGER) BEGIN SELECT *, a AS b, c AS d FROM items; END')
1132
+
1133
+ specify "should deal with nil values" do
1134
+ MYSQL_DB.execute_ddl('CREATE PROCEDURE test_sproc(i INTEGER, v INTEGER) BEGIN INSERT INTO items VALUES (i, v); END')
987
1135
  MYSQL_DB[:items].delete
988
- @d = MYSQL_DB[:items]
989
- @d.call_sproc(:select, :test_sproc, 3, 4).should == []
990
- @d.insert(:value=>1)
991
- @d.call_sproc(:select, :test_sproc, 4, 5).should == [{:id=>nil, :value=>1, :b=>4, :d=>5}]
992
- @d.row_proc = proc{|r| r.keys.each{|k| r[k] *= 2 if r[k].is_a?(Integer)}; r}
993
- @d.call_sproc(:select, :test_sproc, 3, 4).should == [{:id=>nil, :value=>2, :b=>6, :d => 8}]
1136
+ MYSQL_DB.call_sproc(:test_sproc, :args=>[1, nil])
1137
+ MYSQL_DB[:items].all.should == [{:id=>1, :value=>nil}]
994
1138
  end
995
1139
  end
996
1140
  end
@@ -998,35 +1142,35 @@ end
998
1142
  if MYSQL_DB.adapter_scheme == :mysql
999
1143
  describe "MySQL bad date/time conversions" do
1000
1144
  after do
1001
- Sequel::MySQL.convert_invalid_date_time = false
1145
+ MYSQL_DB.convert_invalid_date_time = false
1002
1146
  end
1003
-
1147
+
1004
1148
  specify "should raise an exception when a bad date/time is used and convert_invalid_date_time is false" do
1005
- Sequel::MySQL.convert_invalid_date_time = false
1149
+ MYSQL_DB.convert_invalid_date_time = false
1006
1150
  proc{MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value}.should raise_error(Sequel::InvalidValue)
1007
1151
  proc{MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value}.should raise_error(Sequel::InvalidValue)
1008
1152
  proc{MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value}.should raise_error(Sequel::InvalidValue)
1009
1153
  end
1010
-
1154
+
1011
1155
  specify "should not use a nil value bad date/time is used and convert_invalid_date_time is nil or :nil" do
1012
- Sequel::MySQL.convert_invalid_date_time = nil
1156
+ MYSQL_DB.convert_invalid_date_time = nil
1013
1157
  MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value.should == nil
1014
1158
  MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value.should == nil
1015
1159
  MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value.should == nil
1016
- Sequel::MySQL.convert_invalid_date_time = :nil
1160
+ MYSQL_DB.convert_invalid_date_time = :nil
1017
1161
  MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value.should == nil
1018
1162
  MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value.should == nil
1019
1163
  MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value.should == nil
1020
1164
  end
1021
-
1165
+
1022
1166
  specify "should not use a nil value bad date/time is used and convert_invalid_date_time is :string" do
1023
- Sequel::MySQL.convert_invalid_date_time = :string
1167
+ MYSQL_DB.convert_invalid_date_time = :string
1024
1168
  MYSQL_DB["SELECT CAST('0000-00-00' AS date)"].single_value.should == '0000-00-00'
1025
1169
  MYSQL_DB["SELECT CAST('0000-00-00 00:00:00' AS datetime)"].single_value.should == '0000-00-00 00:00:00'
1026
1170
  MYSQL_DB["SELECT CAST('25:00:00' AS time)"].single_value.should == '25:00:00'
1027
1171
  end
1028
1172
  end
1029
-
1173
+
1030
1174
  describe "MySQL multiple result sets" do
1031
1175
  before do
1032
1176
  MYSQL_DB.create_table!(:a){Integer :a}
@@ -1038,43 +1182,68 @@ if MYSQL_DB.adapter_scheme == :mysql
1038
1182
  MYSQL_DB[:b].insert(25)
1039
1183
  end
1040
1184
  after do
1041
- MYSQL_DB.drop_table(:a, :b)
1185
+ MYSQL_DB.drop_table?(:a, :b)
1042
1186
  end
1043
-
1187
+
1044
1188
  specify "should combine all results by default" do
1045
1189
  @ds.all.should == [{:a=>10}, {:a=>15}, {:b=>20}, {:b=>25}]
1046
1190
  end
1047
-
1191
+
1048
1192
  specify "should work with Database#run" do
1049
1193
  proc{MYSQL_DB.run('SELECT * FROM a; SELECT * FROM b')}.should_not raise_error
1050
1194
  proc{MYSQL_DB.run('SELECT * FROM a; SELECT * FROM b')}.should_not raise_error
1051
1195
  end
1052
-
1196
+
1053
1197
  specify "should work with Database#run and other statements" do
1054
1198
  proc{MYSQL_DB.run('UPDATE a SET a = 1; SELECT * FROM a; DELETE FROM b')}.should_not raise_error
1055
1199
  MYSQL_DB[:a].select_order_map(:a).should == [1, 1]
1056
1200
  MYSQL_DB[:b].all.should == []
1057
1201
  end
1058
-
1202
+
1059
1203
  specify "should split results returned into arrays if split_multiple_result_sets is used" do
1060
1204
  @ds.split_multiple_result_sets.all.should == [[{:a=>10}, {:a=>15}], [{:b=>20}, {:b=>25}]]
1061
1205
  end
1062
-
1206
+
1063
1207
  specify "should have regular row_procs work when splitting multiple result sets" do
1064
1208
  @ds.row_proc = proc{|x| x[x.keys.first] *= 2; x}
1065
1209
  @ds.split_multiple_result_sets.all.should == [[{:a=>20}, {:a=>30}], [{:b=>40}, {:b=>50}]]
1066
1210
  end
1067
-
1211
+
1068
1212
  specify "should use the columns from the first result set when splitting result sets" do
1069
1213
  @ds.split_multiple_result_sets.columns.should == [:a]
1070
1214
  end
1071
-
1215
+
1072
1216
  specify "should not allow graphing a dataset that splits multiple statements" do
1073
1217
  proc{@ds.split_multiple_result_sets.graph(:b, :b=>:a)}.should raise_error(Sequel::Error)
1074
1218
  end
1075
-
1219
+
1076
1220
  specify "should not allow splitting a graphed dataset" do
1077
1221
  proc{MYSQL_DB[:a].graph(:b, :b=>:a).split_multiple_result_sets}.should raise_error(Sequel::Error)
1078
1222
  end
1079
1223
  end
1080
1224
  end
1225
+
1226
+ if MYSQL_DB.adapter_scheme == :mysql2
1227
+ describe "Mysql2 streaming" do
1228
+ before(:all) do
1229
+ MYSQL_DB.create_table!(:a){Integer :a}
1230
+ MYSQL_DB.transaction do
1231
+ 1000.times do |i|
1232
+ MYSQL_DB[:a].insert(i)
1233
+ end
1234
+ end
1235
+ @ds = MYSQL_DB[:a].stream.order(:a)
1236
+ end
1237
+ after(:all) do
1238
+ MYSQL_DB.drop_table?(:a)
1239
+ end
1240
+
1241
+ specify "should correctly stream results" do
1242
+ @ds.map(:a).should == (0...1000).to_a
1243
+ end
1244
+
1245
+ specify "should correctly handle early returning when streaming results" do
1246
+ 3.times{@ds.each{|r| break r[:a]}.should == 0}
1247
+ end
1248
+ end if false
1249
+ end