sequel 3.21.0 → 3.41.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 (363) hide show
  1. data/CHANGELOG +1131 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +106 -65
  4. data/Rakefile +59 -27
  5. data/bin/sequel +50 -26
  6. data/doc/active_record.rdoc +68 -52
  7. data/doc/advanced_associations.rdoc +201 -75
  8. data/doc/association_basics.rdoc +327 -79
  9. data/doc/bin_sequel.rdoc +144 -0
  10. data/doc/cheat_sheet.rdoc +21 -21
  11. data/doc/core_extensions.rdoc +374 -0
  12. data/doc/dataset_basics.rdoc +10 -10
  13. data/doc/dataset_filtering.rdoc +54 -42
  14. data/doc/mass_assignment.rdoc +56 -0
  15. data/doc/migration.rdoc +89 -557
  16. data/doc/model_hooks.rdoc +80 -29
  17. data/doc/object_model.rdoc +576 -0
  18. data/doc/opening_databases.rdoc +121 -53
  19. data/doc/prepared_statements.rdoc +41 -15
  20. data/doc/querying.rdoc +137 -56
  21. data/doc/reflection.rdoc +36 -10
  22. data/doc/release_notes/3.22.0.txt +39 -0
  23. data/doc/release_notes/3.23.0.txt +172 -0
  24. data/doc/release_notes/3.24.0.txt +420 -0
  25. data/doc/release_notes/3.25.0.txt +88 -0
  26. data/doc/release_notes/3.26.0.txt +88 -0
  27. data/doc/release_notes/3.27.0.txt +82 -0
  28. data/doc/release_notes/3.28.0.txt +304 -0
  29. data/doc/release_notes/3.29.0.txt +459 -0
  30. data/doc/release_notes/3.30.0.txt +135 -0
  31. data/doc/release_notes/3.31.0.txt +146 -0
  32. data/doc/release_notes/3.32.0.txt +202 -0
  33. data/doc/release_notes/3.33.0.txt +157 -0
  34. data/doc/release_notes/3.34.0.txt +671 -0
  35. data/doc/release_notes/3.35.0.txt +144 -0
  36. data/doc/release_notes/3.36.0.txt +245 -0
  37. data/doc/release_notes/3.37.0.txt +338 -0
  38. data/doc/release_notes/3.38.0.txt +234 -0
  39. data/doc/release_notes/3.39.0.txt +237 -0
  40. data/doc/release_notes/3.40.0.txt +73 -0
  41. data/doc/release_notes/3.41.0.txt +155 -0
  42. data/doc/schema_modification.rdoc +585 -0
  43. data/doc/sharding.rdoc +99 -8
  44. data/doc/sql.rdoc +154 -112
  45. data/doc/testing.rdoc +169 -0
  46. data/doc/thread_safety.rdoc +17 -0
  47. data/doc/transactions.rdoc +137 -0
  48. data/doc/validations.rdoc +1 -1
  49. data/doc/virtual_rows.rdoc +78 -43
  50. data/lib/sequel/adapters/ado/access.rb +334 -0
  51. data/lib/sequel/adapters/ado/mssql.rb +18 -12
  52. data/lib/sequel/adapters/ado.rb +69 -21
  53. data/lib/sequel/adapters/amalgalite.rb +17 -14
  54. data/lib/sequel/adapters/cubrid.rb +143 -0
  55. data/lib/sequel/adapters/db2.rb +178 -85
  56. data/lib/sequel/adapters/dbi.rb +19 -21
  57. data/lib/sequel/adapters/do/mysql.rb +17 -11
  58. data/lib/sequel/adapters/do/postgres.rb +2 -61
  59. data/lib/sequel/adapters/do/sqlite.rb +0 -10
  60. data/lib/sequel/adapters/do.rb +20 -39
  61. data/lib/sequel/adapters/firebird.rb +33 -210
  62. data/lib/sequel/adapters/ibmdb.rb +452 -0
  63. data/lib/sequel/adapters/informix.rb +6 -29
  64. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  65. data/lib/sequel/adapters/jdbc/cubrid.rb +52 -0
  66. data/lib/sequel/adapters/jdbc/db2.rb +78 -0
  67. data/lib/sequel/adapters/jdbc/derby.rb +325 -0
  68. data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
  69. data/lib/sequel/adapters/jdbc/h2.rb +68 -31
  70. data/lib/sequel/adapters/jdbc/hsqldb.rb +189 -0
  71. data/lib/sequel/adapters/jdbc/informix.rb +21 -0
  72. data/lib/sequel/adapters/jdbc/jtds.rb +40 -0
  73. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  74. data/lib/sequel/adapters/jdbc/mysql.rb +16 -28
  75. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  76. data/lib/sequel/adapters/jdbc/postgresql.rb +77 -52
  77. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  78. data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
  79. data/lib/sequel/adapters/jdbc/sqlserver.rb +72 -0
  80. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  81. data/lib/sequel/adapters/jdbc.rb +308 -114
  82. data/lib/sequel/adapters/mock.rb +372 -0
  83. data/lib/sequel/adapters/mysql.rb +130 -230
  84. data/lib/sequel/adapters/mysql2.rb +64 -63
  85. data/lib/sequel/adapters/odbc/mssql.rb +17 -9
  86. data/lib/sequel/adapters/odbc.rb +29 -10
  87. data/lib/sequel/adapters/openbase.rb +7 -11
  88. data/lib/sequel/adapters/oracle.rb +364 -57
  89. data/lib/sequel/adapters/postgres.rb +379 -145
  90. data/lib/sequel/adapters/shared/access.rb +236 -11
  91. data/lib/sequel/adapters/shared/cubrid.rb +216 -0
  92. data/lib/sequel/adapters/shared/db2.rb +353 -0
  93. data/lib/sequel/adapters/shared/firebird.rb +231 -0
  94. data/lib/sequel/adapters/shared/informix.rb +53 -0
  95. data/lib/sequel/adapters/shared/mssql.rb +412 -116
  96. data/lib/sequel/adapters/shared/mysql.rb +396 -89
  97. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +166 -0
  98. data/lib/sequel/adapters/shared/oracle.rb +262 -45
  99. data/lib/sequel/adapters/shared/postgres.rb +688 -279
  100. data/lib/sequel/adapters/shared/progress.rb +5 -8
  101. data/lib/sequel/adapters/shared/sqlite.rb +317 -96
  102. data/lib/sequel/adapters/sqlite.rb +109 -46
  103. data/lib/sequel/adapters/swift/mysql.rb +10 -12
  104. data/lib/sequel/adapters/swift/postgres.rb +13 -79
  105. data/lib/sequel/adapters/swift/sqlite.rb +9 -6
  106. data/lib/sequel/adapters/swift.rb +31 -27
  107. data/lib/sequel/adapters/tinytds.rb +177 -25
  108. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +77 -0
  109. data/lib/sequel/adapters/utils/pg_types.rb +81 -0
  110. data/lib/sequel/adapters/utils/split_alter_table.rb +36 -0
  111. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  112. data/lib/sequel/ast_transformer.rb +194 -0
  113. data/lib/sequel/connection_pool/sharded_single.rb +23 -13
  114. data/lib/sequel/connection_pool/sharded_threaded.rb +64 -13
  115. data/lib/sequel/connection_pool/single.rb +11 -3
  116. data/lib/sequel/connection_pool/threaded.rb +69 -20
  117. data/lib/sequel/connection_pool.rb +20 -18
  118. data/lib/sequel/core.rb +143 -11
  119. data/lib/sequel/database/connecting.rb +66 -29
  120. data/lib/sequel/database/dataset.rb +4 -4
  121. data/lib/sequel/database/dataset_defaults.rb +63 -2
  122. data/lib/sequel/database/logging.rb +7 -2
  123. data/lib/sequel/database/misc.rb +192 -51
  124. data/lib/sequel/database/query.rb +299 -114
  125. data/lib/sequel/database/schema_generator.rb +103 -36
  126. data/lib/sequel/database/schema_methods.rb +310 -69
  127. data/lib/sequel/dataset/actions.rb +344 -90
  128. data/lib/sequel/dataset/features.rb +101 -8
  129. data/lib/sequel/dataset/graph.rb +42 -15
  130. data/lib/sequel/dataset/misc.rb +52 -25
  131. data/lib/sequel/dataset/mutation.rb +12 -7
  132. data/lib/sequel/dataset/prepared_statements.rb +68 -30
  133. data/lib/sequel/dataset/query.rb +322 -68
  134. data/lib/sequel/dataset/sql.rb +716 -293
  135. data/lib/sequel/dataset.rb +8 -0
  136. data/lib/sequel/exceptions.rb +4 -0
  137. data/lib/sequel/extensions/_pretty_table.rb +83 -0
  138. data/lib/sequel/extensions/arbitrary_servers.rb +109 -0
  139. data/lib/sequel/extensions/blank.rb +4 -0
  140. data/lib/sequel/extensions/columns_introspection.rb +72 -0
  141. data/lib/sequel/extensions/connection_validator.rb +109 -0
  142. data/lib/sequel/extensions/constraint_validations.rb +451 -0
  143. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +30 -46
  144. data/lib/sequel/extensions/eval_inspect.rb +173 -0
  145. data/lib/sequel/extensions/inflector.rb +4 -0
  146. data/lib/sequel/extensions/looser_typecasting.rb +5 -4
  147. data/lib/sequel/extensions/migration.rb +100 -11
  148. data/lib/sequel/extensions/named_timezones.rb +9 -0
  149. data/lib/sequel/extensions/null_dataset.rb +94 -0
  150. data/lib/sequel/extensions/pagination.rb +4 -0
  151. data/lib/sequel/extensions/pg_array.rb +539 -0
  152. data/lib/sequel/extensions/pg_array_ops.rb +263 -0
  153. data/lib/sequel/extensions/pg_auto_parameterize.rb +175 -0
  154. data/lib/sequel/extensions/pg_hstore.rb +334 -0
  155. data/lib/sequel/extensions/pg_hstore_ops.rb +293 -0
  156. data/lib/sequel/extensions/pg_inet.rb +113 -0
  157. data/lib/sequel/extensions/pg_interval.rb +191 -0
  158. data/lib/sequel/extensions/pg_json.rb +212 -0
  159. data/lib/sequel/extensions/pg_range.rb +513 -0
  160. data/lib/sequel/extensions/pg_range_ops.rb +150 -0
  161. data/lib/sequel/extensions/pg_row.rb +576 -0
  162. data/lib/sequel/extensions/pg_row_ops.rb +182 -0
  163. data/lib/sequel/extensions/pg_statement_cache.rb +317 -0
  164. data/lib/sequel/extensions/pretty_table.rb +17 -72
  165. data/lib/sequel/extensions/query.rb +8 -4
  166. data/lib/sequel/extensions/query_literals.rb +79 -0
  167. data/lib/sequel/extensions/schema_caching.rb +76 -0
  168. data/lib/sequel/extensions/schema_dumper.rb +282 -76
  169. data/lib/sequel/extensions/select_remove.rb +39 -0
  170. data/lib/sequel/extensions/server_block.rb +140 -0
  171. data/lib/sequel/extensions/split_array_nil.rb +65 -0
  172. data/lib/sequel/extensions/sql_expr.rb +8 -110
  173. data/lib/sequel/extensions/string_date_time.rb +4 -0
  174. data/lib/sequel/extensions/thread_local_timezones.rb +10 -4
  175. data/lib/sequel/extensions/to_dot.rb +99 -83
  176. data/lib/sequel/model/associations.rb +1263 -409
  177. data/lib/sequel/model/base.rb +624 -171
  178. data/lib/sequel/model/errors.rb +1 -1
  179. data/lib/sequel/model/exceptions.rb +24 -2
  180. data/lib/sequel/model/inflections.rb +1 -1
  181. data/lib/sequel/model.rb +30 -11
  182. data/lib/sequel/no_core_ext.rb +2 -0
  183. data/lib/sequel/plugins/active_model.rb +13 -1
  184. data/lib/sequel/plugins/association_pks.rb +137 -16
  185. data/lib/sequel/plugins/caching.rb +25 -18
  186. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  187. data/lib/sequel/plugins/composition.rb +44 -12
  188. data/lib/sequel/plugins/constraint_validations.rb +198 -0
  189. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  190. data/lib/sequel/plugins/defaults_setter.rb +72 -0
  191. data/lib/sequel/plugins/dirty.rb +214 -0
  192. data/lib/sequel/plugins/eager_each.rb +59 -0
  193. data/lib/sequel/plugins/force_encoding.rb +6 -6
  194. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  195. data/lib/sequel/plugins/identity_map.rb +134 -15
  196. data/lib/sequel/plugins/instance_filters.rb +10 -0
  197. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  198. data/lib/sequel/plugins/json_serializer.rb +77 -6
  199. data/lib/sequel/plugins/list.rb +13 -2
  200. data/lib/sequel/plugins/many_through_many.rb +103 -51
  201. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  202. data/lib/sequel/plugins/nested_attributes.rb +150 -66
  203. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  204. data/lib/sequel/plugins/pg_row.rb +121 -0
  205. data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
  206. data/lib/sequel/plugins/prepared_statements.rb +168 -0
  207. data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
  208. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  209. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  210. data/lib/sequel/plugins/rcte_tree.rb +31 -17
  211. data/lib/sequel/plugins/schema.rb +8 -3
  212. data/lib/sequel/plugins/serialization.rb +98 -49
  213. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  214. data/lib/sequel/plugins/sharding.rb +21 -54
  215. data/lib/sequel/plugins/single_table_inheritance.rb +57 -12
  216. data/lib/sequel/plugins/static_cache.rb +99 -0
  217. data/lib/sequel/plugins/subclasses.rb +29 -3
  218. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  219. data/lib/sequel/plugins/timestamps.rb +1 -1
  220. data/lib/sequel/plugins/touch.rb +18 -6
  221. data/lib/sequel/plugins/tree.rb +3 -3
  222. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  223. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  224. data/lib/sequel/plugins/validation_class_methods.rb +2 -1
  225. data/lib/sequel/plugins/validation_helpers.rb +57 -4
  226. data/lib/sequel/plugins/xml_serializer.rb +15 -4
  227. data/lib/sequel/sql.rb +721 -141
  228. data/lib/sequel/timezones.rb +67 -40
  229. data/lib/sequel/version.rb +1 -1
  230. data/spec/adapters/db2_spec.rb +146 -0
  231. data/spec/adapters/firebird_spec.rb +53 -39
  232. data/spec/adapters/mssql_spec.rb +261 -66
  233. data/spec/adapters/mysql_spec.rb +597 -352
  234. data/spec/adapters/oracle_spec.rb +92 -117
  235. data/spec/adapters/postgres_spec.rb +2103 -341
  236. data/spec/adapters/spec_helper.rb +16 -6
  237. data/spec/adapters/sqlite_spec.rb +237 -76
  238. data/spec/core/connection_pool_spec.rb +270 -141
  239. data/spec/core/database_spec.rb +980 -524
  240. data/spec/core/dataset_spec.rb +1658 -1243
  241. data/spec/core/expression_filters_spec.rb +741 -334
  242. data/spec/core/mock_adapter_spec.rb +453 -0
  243. data/spec/core/object_graph_spec.rb +88 -129
  244. data/spec/core/schema_generator_spec.rb +4 -4
  245. data/spec/core/schema_spec.rb +556 -53
  246. data/spec/core/spec_helper.rb +7 -48
  247. data/spec/core_extensions_spec.rb +626 -0
  248. data/spec/extensions/active_model_spec.rb +13 -0
  249. data/spec/extensions/arbitrary_servers_spec.rb +110 -0
  250. data/spec/extensions/association_autoreloading_spec.rb +18 -10
  251. data/spec/extensions/association_dependencies_spec.rb +15 -25
  252. data/spec/extensions/association_pks_spec.rb +227 -33
  253. data/spec/extensions/association_proxies_spec.rb +4 -4
  254. data/spec/extensions/boolean_readers_spec.rb +25 -25
  255. data/spec/extensions/caching_spec.rb +47 -51
  256. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  257. data/spec/extensions/columns_introspection_spec.rb +91 -0
  258. data/spec/extensions/composition_spec.rb +18 -13
  259. data/spec/extensions/connection_validator_spec.rb +118 -0
  260. data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
  261. data/spec/extensions/constraint_validations_spec.rb +316 -0
  262. data/spec/extensions/dataset_associations_spec.rb +199 -0
  263. data/spec/extensions/defaults_setter_spec.rb +88 -0
  264. data/spec/extensions/dirty_spec.rb +155 -0
  265. data/spec/extensions/eager_each_spec.rb +34 -0
  266. data/spec/extensions/eval_inspect_spec.rb +67 -0
  267. data/spec/extensions/force_encoding_spec.rb +4 -2
  268. data/spec/extensions/hook_class_methods_spec.rb +97 -128
  269. data/spec/extensions/identity_map_spec.rb +142 -24
  270. data/spec/extensions/inflector_spec.rb +0 -4
  271. data/spec/extensions/instance_filters_spec.rb +11 -21
  272. data/spec/extensions/instance_hooks_spec.rb +72 -0
  273. data/spec/extensions/json_serializer_spec.rb +49 -12
  274. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  275. data/spec/extensions/list_spec.rb +49 -40
  276. data/spec/extensions/looser_typecasting_spec.rb +7 -7
  277. data/spec/extensions/many_through_many_spec.rb +368 -254
  278. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  279. data/spec/extensions/migration_spec.rb +140 -35
  280. data/spec/extensions/named_timezones_spec.rb +29 -11
  281. data/spec/extensions/nested_attributes_spec.rb +268 -89
  282. data/spec/extensions/null_dataset_spec.rb +85 -0
  283. data/spec/extensions/optimistic_locking_spec.rb +24 -21
  284. data/spec/extensions/pg_array_ops_spec.rb +112 -0
  285. data/spec/extensions/pg_array_spec.rb +324 -0
  286. data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
  287. data/spec/extensions/pg_hstore_ops_spec.rb +140 -0
  288. data/spec/extensions/pg_hstore_spec.rb +200 -0
  289. data/spec/extensions/pg_inet_spec.rb +47 -0
  290. data/spec/extensions/pg_interval_spec.rb +72 -0
  291. data/spec/extensions/pg_json_spec.rb +99 -0
  292. data/spec/extensions/pg_range_ops_spec.rb +56 -0
  293. data/spec/extensions/pg_range_spec.rb +395 -0
  294. data/spec/extensions/pg_row_ops_spec.rb +58 -0
  295. data/spec/extensions/pg_row_plugin_spec.rb +49 -0
  296. data/spec/extensions/pg_row_spec.rb +340 -0
  297. data/spec/extensions/pg_statement_cache_spec.rb +208 -0
  298. data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
  299. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  300. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  301. data/spec/extensions/prepared_statements_spec.rb +87 -0
  302. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  303. data/spec/extensions/pretty_table_spec.rb +7 -6
  304. data/spec/extensions/query_literals_spec.rb +167 -0
  305. data/spec/extensions/query_spec.rb +9 -3
  306. data/spec/extensions/rcte_tree_spec.rb +50 -43
  307. data/spec/extensions/schema_caching_spec.rb +41 -0
  308. data/spec/extensions/schema_dumper_spec.rb +434 -49
  309. data/spec/extensions/schema_spec.rb +30 -49
  310. data/spec/extensions/select_remove_spec.rb +38 -0
  311. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  312. data/spec/extensions/serialization_spec.rb +86 -48
  313. data/spec/extensions/server_block_spec.rb +90 -0
  314. data/spec/extensions/sharding_spec.rb +69 -143
  315. data/spec/extensions/single_table_inheritance_spec.rb +65 -29
  316. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  317. data/spec/extensions/spec_helper.rb +34 -67
  318. data/spec/extensions/split_array_nil_spec.rb +24 -0
  319. data/spec/extensions/sql_expr_spec.rb +29 -60
  320. data/spec/extensions/static_cache_spec.rb +145 -0
  321. data/spec/extensions/subclasses_spec.rb +14 -0
  322. data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
  323. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  324. data/spec/extensions/timestamps_spec.rb +6 -6
  325. data/spec/extensions/to_dot_spec.rb +8 -11
  326. data/spec/extensions/touch_spec.rb +53 -14
  327. data/spec/extensions/tree_spec.rb +11 -26
  328. data/spec/extensions/typecast_on_load_spec.rb +9 -6
  329. data/spec/extensions/update_primary_key_spec.rb +30 -24
  330. data/spec/extensions/validation_class_methods_spec.rb +77 -68
  331. data/spec/extensions/validation_helpers_spec.rb +48 -37
  332. data/spec/extensions/xml_serializer_spec.rb +29 -4
  333. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
  334. data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
  335. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
  336. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
  337. data/spec/integration/associations_test.rb +659 -21
  338. data/spec/integration/database_test.rb +25 -5
  339. data/spec/integration/dataset_test.rb +729 -141
  340. data/spec/integration/eager_loader_test.rb +38 -54
  341. data/spec/integration/migrator_test.rb +2 -3
  342. data/spec/integration/model_test.rb +81 -2
  343. data/spec/integration/plugin_test.rb +871 -160
  344. data/spec/integration/prepared_statement_test.rb +272 -128
  345. data/spec/integration/schema_test.rb +377 -57
  346. data/spec/integration/spec_helper.rb +49 -32
  347. data/spec/integration/timezone_test.rb +38 -12
  348. data/spec/integration/transaction_test.rb +183 -8
  349. data/spec/integration/type_test.rb +40 -8
  350. data/spec/model/association_reflection_spec.rb +207 -8
  351. data/spec/model/associations_spec.rb +1206 -693
  352. data/spec/model/base_spec.rb +334 -100
  353. data/spec/model/dataset_methods_spec.rb +45 -27
  354. data/spec/model/eager_loading_spec.rb +828 -692
  355. data/spec/model/hooks_spec.rb +355 -67
  356. data/spec/model/model_spec.rb +251 -179
  357. data/spec/model/plugins_spec.rb +24 -13
  358. data/spec/model/record_spec.rb +506 -232
  359. data/spec/model/spec_helper.rb +16 -77
  360. data/spec/model/validations_spec.rb +38 -2
  361. data/spec/rcov.opts +2 -0
  362. metadata +223 -81
  363. data/spec/core/core_sql_spec.rb +0 -451
@@ -2,16 +2,16 @@ require File.join(File.dirname(File.expand_path(__FILE__)), 'spec_helper.rb')
2
2
 
3
3
  describe "Simple Dataset operations" do
4
4
  before do
5
- INTEGRATION_DB.create_table!(:items) do
5
+ @db = INTEGRATION_DB
6
+ @db.create_table!(:items) do
6
7
  primary_key :id
7
8
  Integer :number
8
9
  end
9
- @ds = INTEGRATION_DB[:items]
10
+ @ds = @db[:items]
10
11
  @ds.insert(:number=>10)
11
- clear_sqls
12
12
  end
13
13
  after do
14
- INTEGRATION_DB.drop_table(:items)
14
+ @db.drop_table?(:items)
15
15
  end
16
16
 
17
17
  specify "should support sequential primary keys" do
@@ -23,7 +23,17 @@ describe "Simple Dataset operations" do
23
23
  {:id => 3, :number=>30} ]
24
24
  end
25
25
 
26
- cspecify "should insert with a primary key specified", :mssql do
26
+ specify "should support sequential primary keys with a Bignum" do
27
+ @db.create_table!(:items) do
28
+ primary_key :id, :type=>Bignum
29
+ Integer :number
30
+ end
31
+ @ds << {:number=>20}
32
+ @ds << {:number=>30}
33
+ @ds.order(:number).all.should == [{:id => 1, :number=>20}, {:id => 2, :number=>30}]
34
+ end
35
+
36
+ cspecify "should insert with a primary key specified", :db2, :mssql do
27
37
  @ds.insert(:id=>100, :number=>20)
28
38
  @ds.count.should == 2
29
39
  @ds.order(:id).all.should == [{:id=>1, :number=>10}, {:id=>100, :number=>20}]
@@ -34,17 +44,54 @@ describe "Simple Dataset operations" do
34
44
  @ds.filter(:id=>2).first[:number].should == 20
35
45
  end
36
46
 
47
+ specify "should have insert work correctly with static SQL" do
48
+ @db["INSERT INTO #{@ds.literal(:items)} (#{@ds.literal(:number)}) VALUES (20)"].insert
49
+ @ds.filter(:id=>2).first[:number].should == 20
50
+ end
51
+
52
+ specify "should have insert_multiple return primary key values" do
53
+ @ds.insert_multiple([{:number=>20}, {:number=>30}]).should == [2, 3]
54
+ @ds.filter(:id=>2).get(:number).should == 20
55
+ @ds.filter(:id=>3).get(:number).should == 30
56
+ end
57
+
58
+ specify "should join correctly" do
59
+ @ds.join(:items___b, :id=>:id).select_all(:items).all.should == [{:id=>1, :number=>10}]
60
+ end
61
+
62
+ specify "should correctly deal with qualified columns and subselects" do
63
+ @ds.from_self(:alias=>:a).select(:a__id, Sequel.qualify(:a, :number)).all.should == [{:id=>1, :number=>10}]
64
+ @ds.join(@ds.as(:a), :id=>:id).select(:a__id, Sequel.qualify(:a, :number)).all.should == [{:id=>1, :number=>10}]
65
+ end
66
+
67
+ specify "should graph correctly" do
68
+ @ds.graph(:items, {:id=>:id}, :table_alias=>:b).all.should == [{:items=>{:id=>1, :number=>10}, :b=>{:id=>1, :number=>10}}]
69
+ end
70
+
71
+ specify "should graph correctly with a subselect" do
72
+ @ds.from_self(:alias=>:items).graph(@ds.from_self, {:id=>:id}, :table_alias=>:b).all.should == [{:items=>{:id=>1, :number=>10}, :b=>{:id=>1, :number=>10}}]
73
+ end
74
+
75
+ cspecify "should have insert work correctly when inserting a row with all NULL values", :hsqldb do
76
+ @db.create_table!(:items) do
77
+ String :name
78
+ Integer :number
79
+ end
80
+ proc{@ds.insert}.should_not raise_error
81
+ @ds.all.should == [{:name=>nil, :number=>nil}]
82
+ end
83
+
37
84
  specify "should delete correctly" do
38
85
  @ds.filter(1=>1).delete.should == 1
39
86
  @ds.count.should == 0
40
87
  end
41
88
 
42
89
  specify "should update correctly" do
43
- @ds.update(:number=>:number+1).should == 1
90
+ @ds.update(:number=>Sequel.expr(:number)+1).should == 1
44
91
  @ds.all.should == [{:id=>1, :number=>11}]
45
92
  end
46
93
 
47
- cspecify "should have update return the number of matched rows", [:mysql, :mysql], [:do, :mysql], [:mysql2], [:ado] do
94
+ cspecify "should have update return the number of matched rows", [:do, :mysql], [:ado] do
48
95
  @ds.update(:number=>:number).should == 1
49
96
  @ds.filter(:id=>1).update(:number=>:number).should == 1
50
97
  @ds.filter(:id=>2).update(:number=>:number).should == 0
@@ -79,13 +126,87 @@ describe "Simple Dataset operations" do
79
126
  @ds.order(:id).limit(2, 1).all.should == [{:id=>2, :number=>20}]
80
127
  end
81
128
 
82
- cspecify "should fetch correctly with a limit and offset without an order", :mssql do
129
+ specify "should provide correct columns when using a limit and offset" do
130
+ ds = @ds.order(:id).limit(1, 1)
131
+ ds.all
132
+ ds.columns.should == [:id, :number]
133
+ @ds.order(:id).limit(1, 1).columns.should == [:id, :number]
134
+ end
135
+
136
+ specify "should fetch correctly with a limit and offset for different combinations of from and join tables" do
137
+ @db.create_table!(:items2){primary_key :id2; Integer :number2}
138
+ @db[:items2].insert(:number2=>10)
139
+ @ds.from(:items, :items2).order(:id).limit(2, 0).all.should == [{:id=>1, :number=>10, :id2=>1, :number2=>10}]
140
+ @ds.from(:items___i, :items2___i2).order(:id).limit(2, 0).all.should == [{:id=>1, :number=>10, :id2=>1, :number2=>10}]
141
+ @ds.cross_join(:items2).order(:id).limit(2, 0).all.should ==[{:id=>1, :number=>10, :id2=>1, :number2=>10}]
142
+ @ds.from(:items___i).cross_join(:items2___i2).order(:id).limit(2, 0).all.should == [{:id=>1, :number=>10, :id2=>1, :number2=>10}]
143
+ @ds.cross_join(:items2___i).cross_join(@db[:items2].select(:id2___id3, :number2___number3)).order(:id).limit(2, 0).all.should == [{:id=>1, :number=>10, :id2=>1, :number2=>10, :id3=>1, :number3=>10}]
144
+
145
+ @ds.from(:items, :items2).order(:id).limit(2, 1).all.should == []
146
+ @ds.from(:items___i, :items2___i2).order(:id).limit(2, 1).all.should == []
147
+ @ds.cross_join(:items2).order(:id).limit(2, 1).all.should == []
148
+ @ds.from(:items___i).cross_join(:items2___i2).order(:id).limit(2, 1).all.should == []
149
+ @ds.cross_join(:items2___i).cross_join(@db[:items2].select(:id2___id3, :number2___number3)).order(:id).limit(2, 1).all.should == []
150
+ @db.drop_table(:items2)
151
+ end
152
+
153
+ specify "should fetch correctly with a limit and offset without an order" do
83
154
  @ds.limit(2, 1).all.should == []
84
155
  end
85
156
 
157
+ specify "should fetch correctly with a limit in an IN subselect" do
158
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(2)).all.should == [{:id=>1, :number=>10}]
159
+ @ds.insert(:number=>20)
160
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(1)).all.should == [{:id=>1, :number=>10}]
161
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(2)).order(:id).all.should == [{:id=>1, :number=>10}, {:id=>2, :number=>20}]
162
+ end
163
+
164
+ specify "should fetch correctly with a limit and offset in an IN subselect" do
165
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(2, 0)).all.should == [{:id=>1, :number=>10}]
166
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(2, 1)).all.should == []
167
+ @ds.insert(:number=>20)
168
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(1, 1)).all.should == [{:id=>2, :number=>20}]
169
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(2, 0)).order(:id).all.should == [{:id=>1, :number=>10}, {:id=>2, :number=>20}]
170
+ @ds.where(:id=>@ds.select(:id).order(:id).limit(2, 1)).all.should == [{:id=>2, :number=>20}]
171
+ end
172
+
86
173
  specify "should alias columns correctly" do
87
174
  @ds.select(:id___x, :number___n).first.should == {:x=>1, :n=>10}
88
175
  end
176
+
177
+ specify "should handle true/false properly" do
178
+ @ds.filter(Sequel::TRUE).select_map(:number).should == [10]
179
+ @ds.filter(Sequel::FALSE).select_map(:number).should == []
180
+ @ds.filter(true).select_map(:number).should == [10]
181
+ @ds.filter(false).select_map(:number).should == []
182
+ end
183
+ end
184
+
185
+ describe "Simple dataset operations with nasty table names" do
186
+ before do
187
+ @db = INTEGRATION_DB
188
+ @table = :"i`t' [e]\"m\\s"
189
+ @qi = @db.quote_identifiers?
190
+ @db.quote_identifiers = true
191
+ end
192
+ after do
193
+ @db.quote_identifiers = @qi
194
+ end
195
+
196
+ cspecify "should work correctly", :mssql, :oracle do
197
+ @db.create_table!(@table) do
198
+ primary_key :id
199
+ Integer :number
200
+ end
201
+ @ds = @db[@table]
202
+ @ds.insert(:number=>10).should == 1
203
+ @ds.all.should == [{:id=>1, :number=>10}]
204
+ @ds.update(:number=>20).should == 1
205
+ @ds.all.should == [{:id=>1, :number=>20}]
206
+ @ds.delete.should == 1
207
+ @ds.count.should == 0
208
+ proc{@db.drop_table?(@table)}.should_not raise_error
209
+ end
89
210
  end
90
211
 
91
212
  describe Sequel::Dataset do
@@ -95,10 +216,9 @@ describe Sequel::Dataset do
95
216
  Integer :value
96
217
  end
97
218
  @d = INTEGRATION_DB[:test]
98
- clear_sqls
99
219
  end
100
220
  after do
101
- INTEGRATION_DB.drop_table(:test)
221
+ INTEGRATION_DB.drop_table?(:test)
102
222
  end
103
223
 
104
224
  specify "should return the correct record count" do
@@ -171,23 +291,38 @@ end
171
291
 
172
292
  describe Sequel::Database do
173
293
  specify "should correctly escape strings" do
174
- INTEGRATION_DB.get("\\dingo".as(:a)) == "\\dingo"
175
- end
176
-
177
- specify "should correctly escape strings with quotes" do
178
- INTEGRATION_DB.get("\\'dingo".as(:a)) == "\\'dingo"
294
+ ["\\\n",
295
+ "\\\\\n",
296
+ "\\\r\n",
297
+ "\\\\\r\n",
298
+ "\\\\\n\n",
299
+ "\\\\\r\n\r\n",
300
+ "\\dingo",
301
+ "\\'dingo",
302
+ "\\\\''dingo",
303
+ ].each do |str|
304
+ INTEGRATION_DB.get(Sequel.cast(str, String)).should == str
305
+ str = "1#{str}1"
306
+ INTEGRATION_DB.get(Sequel.cast(str, String)).should == str
307
+ str = "#{str}#{str}"
308
+ INTEGRATION_DB.get(Sequel.cast(str, String)).should == str
309
+ end
179
310
  end
180
311
 
181
- specify "should properly escape binary data" do
182
- INTEGRATION_DB.get("\1\2\3".to_sequel_blob.as(:a)) == "\1\2\3"
312
+ cspecify "should properly escape binary data", [:odbc], [:jdbc, :hsqldb], :oracle do
313
+ INTEGRATION_DB.get(Sequel.cast(Sequel.blob("\1\2\3"), File).as(:a)).should == "\1\2\3"
183
314
  end
184
315
 
185
316
  specify "should have a working table_exists?" do
186
317
  t = :basdfdsafsaddsaf
187
- INTEGRATION_DB.drop_table(t) rescue nil
318
+ INTEGRATION_DB.drop_table?(t)
188
319
  INTEGRATION_DB.table_exists?(t).should == false
189
320
  INTEGRATION_DB.create_table(t){Integer :a}
190
- INTEGRATION_DB.table_exists?(t).should == true
321
+ begin
322
+ INTEGRATION_DB.table_exists?(t).should == true
323
+ ensure
324
+ INTEGRATION_DB.drop_table(t)
325
+ end
191
326
  end
192
327
  end
193
328
 
@@ -203,7 +338,7 @@ describe Sequel::Dataset do
203
338
  @d << {:value => 789}
204
339
  end
205
340
  after do
206
- INTEGRATION_DB.drop_table(:items)
341
+ INTEGRATION_DB.drop_table?(:items)
207
342
  end
208
343
 
209
344
  specify "should correctly return avg" do
@@ -232,7 +367,7 @@ describe "Simple Dataset operations" do
232
367
  @ds = INTEGRATION_DB[:items]
233
368
  end
234
369
  after do
235
- INTEGRATION_DB.drop_table(:items)
370
+ INTEGRATION_DB.drop_table?(:items)
236
371
  end
237
372
 
238
373
  specify "should deal with boolean conditions correctly" do
@@ -251,18 +386,17 @@ end
251
386
 
252
387
  describe "Simple Dataset operations in transactions" do
253
388
  before do
254
- INTEGRATION_DB.create_table!(:items_insert_in_transaction) do
389
+ INTEGRATION_DB.create_table!(:items) do
255
390
  primary_key :id
256
391
  integer :number
257
392
  end
258
- @ds = INTEGRATION_DB[:items_insert_in_transaction]
259
- clear_sqls
393
+ @ds = INTEGRATION_DB[:items]
260
394
  end
261
395
  after do
262
- INTEGRATION_DB.drop_table(:items_insert_in_transaction)
396
+ INTEGRATION_DB.drop_table?(:items)
263
397
  end
264
398
 
265
- cspecify "should insert correctly with a primary key specified inside a transaction", :mssql do
399
+ cspecify "should insert correctly with a primary key specified inside a transaction", :db2, :mssql do
266
400
  INTEGRATION_DB.transaction do
267
401
  @ds.insert(:id=>100, :number=>20)
268
402
  @ds.count.should == 1
@@ -293,7 +427,9 @@ describe "Dataset UNION, EXCEPT, and INTERSECT" do
293
427
  @ds2 = INTEGRATION_DB[:i2]
294
428
  @ds2.insert(:number=>10)
295
429
  @ds2.insert(:number=>30)
296
- clear_sqls
430
+ end
431
+ after do
432
+ INTEGRATION_DB.drop_table?(:i1, :i2, :i3)
297
433
  end
298
434
 
299
435
  specify "should give the correct results for simple UNION, EXCEPT, and INTERSECT" do
@@ -310,20 +446,20 @@ describe "Dataset UNION, EXCEPT, and INTERSECT" do
310
446
  @ds1.insert(:number=>38)
311
447
  @ds2.insert(:number=>39)
312
448
 
313
- @ds1.order(:number.desc).union(@ds2).order(:number).map{|x| x[:number].to_s}.should == %w'8 9 10 20 30 38 39'
314
- @ds1.union(@ds2.order(:number.desc)).order(:number).map{|x| x[:number].to_s}.should == %w'8 9 10 20 30 38 39'
449
+ @ds1.reverse_order(:number).union(@ds2).order(:number).map{|x| x[:number].to_s}.should == %w'8 9 10 20 30 38 39'
450
+ @ds1.union(@ds2.reverse_order(:number)).order(:number).map{|x| x[:number].to_s}.should == %w'8 9 10 20 30 38 39'
315
451
 
316
- @ds1.order(:number.desc).limit(1).union(@ds2).order(:number).map{|x| x[:number].to_s}.should == %w'9 10 30 38 39'
317
- @ds2.order(:number.desc).limit(1).union(@ds1).order(:number).map{|x| x[:number].to_s}.should == %w'8 10 20 38 39'
452
+ @ds1.reverse_order(:number).limit(1).union(@ds2).order(:number).map{|x| x[:number].to_s}.should == %w'9 10 30 38 39'
453
+ @ds2.reverse_order(:number).limit(1).union(@ds1).order(:number).map{|x| x[:number].to_s}.should == %w'8 10 20 38 39'
318
454
 
319
455
  @ds1.union(@ds2.order(:number).limit(1)).order(:number).map{|x| x[:number].to_s}.should == %w'8 9 10 20 38'
320
456
  @ds2.union(@ds1.order(:number).limit(1)).order(:number).map{|x| x[:number].to_s}.should == %w'8 9 10 30 39'
321
457
 
322
458
  @ds1.union(@ds2).limit(2).order(:number).map{|x| x[:number].to_s}.should == %w'8 9'
323
- @ds2.union(@ds1).order(:number.desc).limit(2).map{|x| x[:number].to_s}.should == %w'39 38'
459
+ @ds2.union(@ds1).reverse_order(:number).limit(2).map{|x| x[:number].to_s}.should == %w'39 38'
324
460
 
325
- @ds1.order(:number.desc).limit(2).union(@ds2.order(:number.desc).limit(2)).order(:number).limit(3).map{|x| x[:number].to_s}.should == %w'20 30 38'
326
- @ds2.order(:number).limit(2).union(@ds1.order(:number).limit(2)).order(:number.desc).limit(3).map{|x| x[:number].to_s}.should == %w'10 9 8'
461
+ @ds1.reverse_order(:number).limit(2).union(@ds2.reverse_order(:number).limit(2)).order(:number).limit(3).map{|x| x[:number].to_s}.should == %w'20 30 38'
462
+ @ds2.order(:number).limit(2).union(@ds1.order(:number).limit(2)).reverse_order(:number).limit(3).map{|x| x[:number].to_s}.should == %w'10 9 8'
327
463
  end
328
464
 
329
465
  specify "should give the correct results for compound UNION, EXCEPT, and INTERSECT" do
@@ -359,7 +495,7 @@ end
359
495
 
360
496
  if INTEGRATION_DB.dataset.supports_cte?
361
497
  describe "Common Table Expressions" do
362
- before do
498
+ before(:all) do
363
499
  @db = INTEGRATION_DB
364
500
  @db.create_table!(:i1){Integer :id; Integer :parent_id}
365
501
  @ds = @db[:i1]
@@ -370,15 +506,15 @@ if INTEGRATION_DB.dataset.supports_cte?
370
506
  @ds.insert(:id=>5, :parent_id=>3)
371
507
  @ds.insert(:id=>6, :parent_id=>5)
372
508
  end
373
- after do
374
- @db.drop_table(:i1)
509
+ after(:all) do
510
+ @db.drop_table?(:i1)
375
511
  end
376
512
 
377
513
  specify "should give correct results for WITH" do
378
514
  @db[:t].with(:t, @ds.filter(:parent_id=>nil).select(:id)).order(:id).map(:id).should == [1, 2]
379
515
  end
380
516
 
381
- specify "should give correct results for recursive WITH" do
517
+ cspecify "should give correct results for recursive WITH", :db2 do
382
518
  ds = @db[:t].select(:i___id, :pi___parent_id).with_recursive(:t, @ds.filter(:parent_id=>nil), @ds.join(:t, :i=>:parent_id).select(:i1__id, :i1__parent_id), :args=>[:i, :pi])
383
519
  ds.all.should == [{:parent_id=>nil, :id=>1}, {:parent_id=>nil, :id=>2}, {:parent_id=>1, :id=>3}, {:parent_id=>1, :id=>4}, {:parent_id=>3, :id=>5}, {:parent_id=>5, :id=>6}]
384
520
  ps = @db[:t].select(:i___id, :pi___parent_id).with_recursive(:t, @ds.filter(:parent_id=>:$n), @ds.join(:t, :i=>:parent_id).filter(:t__i=>:parent_id).select(:i1__id, :i1__parent_id), :args=>[:i, :pi]).prepare(:select, :cte_sel)
@@ -391,12 +527,116 @@ if INTEGRATION_DB.dataset.supports_cte?
391
527
  @ds.inner_join(@db[:t].with(:t, @ds.filter(:parent_id=>nil)), :id => :id).select(:i1__id).order(:i1__id).map(:id).should == [1,2]
392
528
  @db[:t].with(:t, @ds).inner_join(@db[:s].with(:s, @ds.filter(:parent_id=>nil)), :id => :id).select(:t__id).order(:t__id).map(:id).should == [1,2]
393
529
  end
530
+
531
+ specify "should support a subselect in the FROM clause with a CTE" do
532
+ @ds.from(@db[:t].with(:t, @ds)).select_order_map(:id).should == [1,2,3,4,5,6]
533
+ @db[:t].with(:t, @ds).from_self.select_order_map(:id).should == [1,2,3,4,5,6]
534
+ end
535
+
536
+ specify "should support using a CTE inside a CTE" do
537
+ @db[:s].with(:s, @db[:t].with(:t, @ds)).select_order_map(:id).should == [1,2,3,4,5,6]
538
+ @db[:s].with_recursive(:s, @db[:t].with(:t, @ds), @db[:t2].with(:t2, @ds)).select_order_map(:id).should == [1,1,2,2,3,3,4,4,5,5,6,6]
539
+ end
540
+
541
+ specify "should support using a CTE inside UNION/EXCEPT/INTERSECT" do
542
+ @ds.union(@db[:t].with(:t, @ds)).select_order_map(:id).should == [1,2,3,4,5,6]
543
+ if @ds.supports_intersect_except?
544
+ @ds.intersect(@db[:t].with(:t, @ds)).select_order_map(:id).should == [1,2,3,4,5,6]
545
+ @ds.except(@db[:t].with(:t, @ds)).select_order_map(:id).should == []
546
+ end
547
+ end
548
+ end
549
+ end
550
+
551
+ if INTEGRATION_DB.dataset.supports_cte?(:update) # Assume INSERT and DELETE support as well
552
+ describe "Common Table Expressions in INSERT/UPDATE/DELETE" do
553
+ before do
554
+ @db = INTEGRATION_DB
555
+ @db.create_table!(:i1){Integer :id}
556
+ @ds = @db[:i1]
557
+ @ds2 = @ds.with(:t, @ds)
558
+ @ds.insert(:id=>1)
559
+ @ds.insert(:id=>2)
560
+ end
561
+ after do
562
+ @db.drop_table?(:i1)
563
+ end
564
+
565
+ specify "should give correct results for WITH" do
566
+ @ds2.insert(@db[:t])
567
+ @ds.select_order_map(:id).should == [1, 1, 2, 2]
568
+ @ds2.filter(:id=>@db[:t].select{max(id)}).update(:id=>Sequel.+(:id, 1))
569
+ @ds.select_order_map(:id).should == [1, 1, 3, 3]
570
+ @ds2.filter(:id=>@db[:t].select{max(id)}).delete
571
+ @ds.select_order_map(:id).should == [1, 1]
572
+ end
573
+ end
574
+ end
575
+
576
+ if INTEGRATION_DB.dataset.supports_returning?(:insert)
577
+ describe "RETURNING clauses in INSERT" do
578
+ before do
579
+ @db = INTEGRATION_DB
580
+ @db.create_table!(:i1){Integer :id; Integer :foo}
581
+ @ds = @db[:i1]
582
+ end
583
+ after do
584
+ @db.drop_table?(:i1)
585
+ end
586
+
587
+ specify "should give correct results" do
588
+ h = {}
589
+ @ds.returning(:foo).insert(1, 2){|r| h = r}
590
+ h.should == {:foo=>2}
591
+ @ds.returning(:id).insert(3, 4){|r| h = r}
592
+ h.should == {:id=>3}
593
+ @ds.returning.insert(5, 6){|r| h = r}
594
+ h.should == {:id=>5, :foo=>6}
595
+ @ds.returning(:id___foo, :foo___id).insert(7, 8){|r| h = r}
596
+ h.should == {:id=>8, :foo=>7}
597
+ end
598
+ end
599
+ end
600
+
601
+ if INTEGRATION_DB.dataset.supports_returning?(:update) # Assume DELETE support as well
602
+ describe "RETURNING clauses in UPDATE/DELETE" do
603
+ before do
604
+ @db = INTEGRATION_DB
605
+ @db.create_table!(:i1){Integer :id; Integer :foo}
606
+ @ds = @db[:i1]
607
+ @ds.insert(1, 2)
608
+ end
609
+ after do
610
+ @db.drop_table?(:i1)
611
+ end
612
+
613
+ specify "should give correct results" do
614
+ h = []
615
+ @ds.returning(:foo).update(:id=>Sequel.+(:id, 1), :foo=>Sequel.*(:foo, 2)){|r| h << r}
616
+ h.should == [{:foo=>4}]
617
+ h.clear
618
+ @ds.returning(:id).update(:id=>Sequel.+(:id, 1), :foo=>Sequel.*(:foo, 2)){|r| h << r}
619
+ h.should == [{:id=>3}]
620
+ h.clear
621
+ @ds.returning.update(:id=>Sequel.+(:id, 1), :foo=>Sequel.*(:foo, 2)){|r| h << r}
622
+ h.should == [{:id=>4, :foo=>16}]
623
+ h.clear
624
+ @ds.returning(:id___foo, :foo___id).update(:id=>Sequel.+(:id, 1), :foo=>Sequel.*(:foo, 2)){|r| h << r}
625
+ h.should == [{:id=>32, :foo=>5}]
626
+ h.clear
627
+
628
+ @ds.returning.delete{|r| h << r}
629
+ h.should == [{:id=>5, :foo=>32}]
630
+ h.clear
631
+ @ds.returning.delete{|r| h << r}
632
+ h.should == []
633
+ end
394
634
  end
395
635
  end
396
636
 
397
637
  if INTEGRATION_DB.dataset.supports_window_functions?
398
638
  describe "Window Functions" do
399
- before do
639
+ before(:all) do
400
640
  @db = INTEGRATION_DB
401
641
  @db.create_table!(:i1){Integer :id; Integer :group_id; Integer :amount}
402
642
  @ds = @db[:i1].order(:id)
@@ -407,8 +647,8 @@ if INTEGRATION_DB.dataset.supports_window_functions?
407
647
  @ds.insert(:id=>5, :group_id=>2, :amount=>10000)
408
648
  @ds.insert(:id=>6, :group_id=>2, :amount=>100000)
409
649
  end
410
- after do
411
- @db.drop_table(:i1)
650
+ after(:all) do
651
+ @db.drop_table?(:i1)
412
652
  end
413
653
 
414
654
  specify "should give correct results for aggregate window functions" do
@@ -435,21 +675,13 @@ if INTEGRATION_DB.dataset.supports_window_functions?
435
675
  cspecify "should give correct results for aggregate window functions with frames", :mssql do
436
676
  @ds.select(:id){sum(:over, :args=>amount, :partition=>group_id, :order=>id, :frame=>:all){}.as(:sum)}.all.should ==
437
677
  [{:sum=>111, :id=>1}, {:sum=>111, :id=>2}, {:sum=>111, :id=>3}, {:sum=>111000, :id=>4}, {:sum=>111000, :id=>5}, {:sum=>111000, :id=>6}]
438
- @ds.select(:id){sum(:over, :args=>amount, :partition=>group_id, :frame=>:all){}.as(:sum)}.all.should ==
439
- [{:sum=>111, :id=>1}, {:sum=>111, :id=>2}, {:sum=>111, :id=>3}, {:sum=>111000, :id=>4}, {:sum=>111000, :id=>5}, {:sum=>111000, :id=>6}]
440
678
  @ds.select(:id){sum(:over, :args=>amount, :order=>id, :frame=>:all){}.as(:sum)}.all.should ==
441
679
  [{:sum=>111111, :id=>1}, {:sum=>111111, :id=>2}, {:sum=>111111, :id=>3}, {:sum=>111111, :id=>4}, {:sum=>111111, :id=>5}, {:sum=>111111, :id=>6}]
442
- @ds.select(:id){sum(:over, :args=>amount, :frame=>:all){}.as(:sum)}.all.should ==
443
- [{:sum=>111111, :id=>1}, {:sum=>111111, :id=>2}, {:sum=>111111, :id=>3}, {:sum=>111111, :id=>4}, {:sum=>111111, :id=>5}, {:sum=>111111, :id=>6}]
444
680
 
445
681
  @ds.select(:id){sum(:over, :args=>amount, :partition=>group_id, :order=>id, :frame=>:rows){}.as(:sum)}.all.should ==
446
682
  [{:sum=>1, :id=>1}, {:sum=>11, :id=>2}, {:sum=>111, :id=>3}, {:sum=>1000, :id=>4}, {:sum=>11000, :id=>5}, {:sum=>111000, :id=>6}]
447
- @ds.select(:id){sum(:over, :args=>amount, :partition=>group_id, :frame=>:rows){}.as(:sum)}.all.should ==
448
- [{:sum=>1, :id=>1}, {:sum=>11, :id=>2}, {:sum=>111, :id=>3}, {:sum=>1000, :id=>4}, {:sum=>11000, :id=>5}, {:sum=>111000, :id=>6}]
449
683
  @ds.select(:id){sum(:over, :args=>amount, :order=>id, :frame=>:rows){}.as(:sum)}.all.should ==
450
684
  [{:sum=>1, :id=>1}, {:sum=>11, :id=>2}, {:sum=>111, :id=>3}, {:sum=>1111, :id=>4}, {:sum=>11111, :id=>5}, {:sum=>111111, :id=>6}]
451
- @ds.select(:id){sum(:over, :args=>amount, :frame=>:rows){}.as(:sum)}.all.should ==
452
- [{:sum=>1, :id=>1}, {:sum=>11, :id=>2}, {:sum=>111, :id=>3}, {:sum=>1111, :id=>4}, {:sum=>11111, :id=>5}, {:sum=>111111, :id=>6}]
453
685
  end
454
686
  end
455
687
  end
@@ -471,10 +703,10 @@ describe Sequel::SQL::Constants do
471
703
  @c2 = proc{|v| v.is_a?(Date) ? v : Date.parse(v) }
472
704
  end
473
705
  after do
474
- @db.drop_table(:constants)
706
+ @db.drop_table?(:constants)
475
707
  end
476
708
 
477
- cspecify "should have working CURRENT_DATE", [:odbc, :mssql], [:jdbc, :sqlite] do
709
+ cspecify "should have working CURRENT_DATE", [:odbc, :mssql], [:jdbc, :sqlite], :oracle do
478
710
  @db.create_table!(:constants){Date :d}
479
711
  @ds.insert(:d=>Sequel::CURRENT_DATE)
480
712
  d = @c2[@ds.get(:d)]
@@ -485,26 +717,33 @@ describe Sequel::SQL::Constants do
485
717
  cspecify "should have working CURRENT_TIME", [:do, :mysql], [:jdbc, :sqlite], [:mysql2] do
486
718
  @db.create_table!(:constants){Time :t, :only_time=>true}
487
719
  @ds.insert(:t=>Sequel::CURRENT_TIME)
488
- (Time.now - @c[@ds.get(:t)]).should be_within(1).of(0)
720
+ (Time.now - @c[@ds.get(:t)]).should be_within(60).of(0)
489
721
  end
490
722
 
491
- cspecify "should have working CURRENT_TIMESTAMP", [:jdbc, :sqlite] do
723
+ cspecify "should have working CURRENT_TIMESTAMP", [:jdbc, :sqlite], [:swift] do
492
724
  @db.create_table!(:constants){DateTime :ts}
493
725
  @ds.insert(:ts=>Sequel::CURRENT_TIMESTAMP)
494
- (Time.now - @c[@ds.get(:ts)]).should be_within(1).of(0)
726
+ (Time.now - @c[@ds.get(:ts)]).should be_within(60).of(0)
727
+ end
728
+
729
+ cspecify "should have working CURRENT_TIMESTAMP when used as a column default", [:jdbc, :sqlite], [:swift] do
730
+ @db.create_table!(:constants){DateTime :ts, :default=>Sequel::CURRENT_TIMESTAMP}
731
+ @ds.insert
732
+ (Time.now - @c[@ds.get(:ts)]).should be_within(60).of(0)
495
733
  end
496
734
  end
497
735
 
498
736
  describe "Sequel::Dataset#import and #multi_insert" do
499
- before do
737
+ before(:all) do
500
738
  @db = INTEGRATION_DB
501
739
  @db.create_table!(:imp){Integer :i}
502
- @db.create_table!(:exp2){Integer :i}
503
740
  @ids = @db[:imp].order(:i)
504
- @eds = @db[:exp2]
505
741
  end
506
- after do
507
- @db.drop_table(:imp, :exp2)
742
+ before do
743
+ @ids.delete
744
+ end
745
+ after(:all) do
746
+ @db.drop_table?(:imp)
508
747
  end
509
748
 
510
749
  it "should import with multi_insert and an array of hashes" do
@@ -518,9 +757,11 @@ describe "Sequel::Dataset#import and #multi_insert" do
518
757
  end
519
758
 
520
759
  it "should import with a dataset" do
521
- @eds.import([:i], [[10], [20]])
522
- @ids.import([:i], @eds)
760
+ @db.create_table!(:exp2){Integer :i}
761
+ @db[:exp2].import([:i], [[10], [20]])
762
+ @ids.import([:i], @db[:exp2])
523
763
  @ids.all.should == [{:i=>10}, {:i=>20}]
764
+ @db.drop_table(:exp2)
524
765
  end
525
766
 
526
767
  it "should have import work with the :slice_size option" do
@@ -535,14 +776,66 @@ describe "Sequel::Dataset#import and #multi_insert" do
535
776
  end
536
777
  end
537
778
 
538
- describe "Sequel::Dataset convenience methods" do
779
+ describe "Sequel::Dataset#import and #multi_insert :return=>:primary_key " do
539
780
  before do
781
+ @db = INTEGRATION_DB
782
+ @db.create_table!(:imp){primary_key :id; Integer :i}
783
+ @ds = @db[:imp]
784
+ end
785
+ after do
786
+ @db.drop_table?(:imp)
787
+ end
788
+
789
+ specify "should return primary key values" do
790
+ @ds.multi_insert([{:i=>10}, {:i=>20}, {:i=>30}], :return=>:primary_key).should == [1, 2, 3]
791
+ @ds.import([:i], [[40], [50], [60]], :return=>:primary_key).should == [4, 5, 6]
792
+ @ds.order(:id).map([:id, :i]).should == [[1, 10], [2, 20], [3, 30], [4, 40], [5, 50], [6, 60]]
793
+ end
794
+
795
+ specify "should return primary key values when :slice is used" do
796
+ @ds.multi_insert([{:i=>10}, {:i=>20}, {:i=>30}], :return=>:primary_key, :slice=>2).should == [1, 2, 3]
797
+ @ds.import([:i], [[40], [50], [60]], :return=>:primary_key, :slice=>2).should == [4, 5, 6]
798
+ @ds.order(:id).map([:id, :i]).should == [[1, 10], [2, 20], [3, 30], [4, 40], [5, 50], [6, 60]]
799
+ end
800
+ end
801
+
802
+ describe "Sequel::Dataset convenience methods" do
803
+ before(:all) do
804
+ @db = INTEGRATION_DB
805
+ @db.create_table!(:a){Integer :a; Integer :b; Integer :c}
806
+ @ds = @db[:a]
807
+ @ds.insert(1, 3, 5)
808
+ @ds.insert(1, 3, 6)
809
+ @ds.insert(1, 4, 5)
810
+ @ds.insert(2, 3, 5)
811
+ @ds.insert(2, 4, 6)
812
+ end
813
+ after(:all) do
814
+ @db.drop_table?(:a)
815
+ end
816
+
817
+ it "#group_rollup should include hierarchy of groupings" do
818
+ @ds.group_by(:a).group_rollup.select_map([:a, Sequel.function(:sum, :b).cast(Integer).as(:b), Sequel.function(:sum, :c).cast(Integer).as(:c)]).sort_by{|x| x.inspect}.should == [[1, 10, 16], [2, 7, 11], [nil, 17, 27]]
819
+ @ds.group_by(:a, :b).group_rollup.select_map([:a, :b, Sequel.function(:sum, :c).cast(Integer).as(:c)]).sort_by{|x| x.inspect}.should == [[1, 3, 11], [1, 4, 5], [1, nil, 16], [2, 3, 5], [2, 4, 6], [2, nil, 11], [nil, nil, 27]]
820
+ end if INTEGRATION_DB.dataset.supports_group_rollup?
821
+
822
+ it "#group_cube should include all combinations of groupings" do
823
+ @ds.group_by(:a).group_cube.select_map([:a, Sequel.function(:sum, :b).cast(Integer).as(:b), Sequel.function(:sum, :c).cast(Integer).as(:c)]).sort_by{|x| x.inspect}.should == [[1, 10, 16], [2, 7, 11], [nil, 17, 27]]
824
+ @ds.group_by(:a, :b).group_cube.select_map([:a, :b, Sequel.function(:sum, :c).cast(Integer).as(:c)]).sort_by{|x| x.inspect}.should == [[1, 3, 11], [1, 4, 5], [1, nil, 16], [2, 3, 5], [2, 4, 6], [2, nil, 11], [nil, 3, 16], [nil, 4, 11], [nil, nil, 27]]
825
+ end if INTEGRATION_DB.dataset.supports_group_cube?
826
+ end
827
+
828
+ describe "Sequel::Dataset convenience methods" do
829
+ before(:all) do
540
830
  @db = INTEGRATION_DB
541
831
  @db.create_table!(:a){Integer :a; Integer :b}
542
832
  @ds = @db[:a].order(:a)
543
833
  end
544
- after do
545
- @db.drop_table(:a)
834
+ before do
835
+ @ds.delete
836
+ end
837
+ after(:all) do
838
+ @db.drop_table?(:a)
546
839
  end
547
840
 
548
841
  it "#[]= should update matching rows" do
@@ -557,27 +850,43 @@ describe "Sequel::Dataset convenience methods" do
557
850
  @ds.empty?.should == false
558
851
  end
559
852
 
853
+ it "#empty? should work correctly for datasets with limits" do
854
+ ds = @ds.limit(1)
855
+ ds.empty?.should == true
856
+ ds.insert(20, 10)
857
+ ds.empty?.should == false
858
+ end
859
+
860
+ it "#empty? should work correctly for datasets with limits and offsets" do
861
+ ds = @ds.limit(1, 1)
862
+ ds.empty?.should == true
863
+ ds.insert(20, 10)
864
+ ds.empty?.should == true
865
+ ds.insert(20, 10)
866
+ ds.empty?.should == false
867
+ end
868
+
560
869
  it "#group_and_count should return a grouping by count" do
561
- @ds.group_and_count(:a).order(:count).all.should == []
870
+ @ds.group_and_count(:a).order{count(:a)}.all.should == []
562
871
  @ds.insert(20, 10)
563
- @ds.group_and_count(:a).order(:count).all.each{|h| h[:count] = h[:count].to_i}.should == [{:a=>20, :count=>1}]
872
+ @ds.group_and_count(:a).order{count(:a)}.all.each{|h| h[:count] = h[:count].to_i}.should == [{:a=>20, :count=>1}]
564
873
  @ds.insert(20, 30)
565
- @ds.group_and_count(:a).order(:count).all.each{|h| h[:count] = h[:count].to_i}.should == [{:a=>20, :count=>2}]
874
+ @ds.group_and_count(:a).order{count(:a)}.all.each{|h| h[:count] = h[:count].to_i}.should == [{:a=>20, :count=>2}]
566
875
  @ds.insert(30, 30)
567
- @ds.group_and_count(:a).order(:count).all.each{|h| h[:count] = h[:count].to_i}.should == [{:a=>30, :count=>1}, {:a=>20, :count=>2}]
876
+ @ds.group_and_count(:a).order{count(:a)}.all.each{|h| h[:count] = h[:count].to_i}.should == [{:a=>30, :count=>1}, {:a=>20, :count=>2}]
568
877
  end
569
878
 
570
879
  it "#group_and_count should support column aliases" do
571
- @ds.group_and_count(:a___c).order(:count).all.should == []
880
+ @ds.group_and_count(:a___c).order{count(:a)}.all.should == []
572
881
  @ds.insert(20, 10)
573
- @ds.group_and_count(:a___c).order(:count).all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>20, :count=>1}]
882
+ @ds.group_and_count(:a___c).order{count(:a)}.all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>20, :count=>1}]
574
883
  @ds.insert(20, 30)
575
- @ds.group_and_count(:a___c).order(:count).all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>20, :count=>2}]
884
+ @ds.group_and_count(:a___c).order{count(:a)}.all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>20, :count=>2}]
576
885
  @ds.insert(30, 30)
577
- @ds.group_and_count(:a___c).order(:count).all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>30, :count=>1}, {:c=>20, :count=>2}]
886
+ @ds.group_and_count(:a___c).order{count(:a)}.all.each{|h| h[:count] = h[:count].to_i}.should == [{:c=>30, :count=>1}, {:c=>20, :count=>2}]
578
887
  end
579
888
 
580
- cspecify "#range should return the range between the maximum and minimum values", :sqlite do
889
+ specify "#range should return the range between the maximum and minimum values" do
581
890
  @ds = @ds.unordered
582
891
  @ds.insert(20, 10)
583
892
  @ds.insert(30, 10)
@@ -595,20 +904,23 @@ describe "Sequel::Dataset convenience methods" do
595
904
  end
596
905
 
597
906
  describe "Sequel::Dataset main SQL methods" do
598
- before do
907
+ before(:all) do
599
908
  @db = INTEGRATION_DB
600
- @db.create_table!(:a){Integer :a; Integer :b}
601
- @ds = @db[:a].order(:a)
909
+ @db.create_table!(:d){Integer :a; Integer :b}
910
+ @ds = @db[:d].order(:a)
602
911
  end
603
- after do
604
- @db.drop_table(:a)
912
+ before do
913
+ @ds.delete
914
+ end
915
+ after(:all) do
916
+ @db.drop_table?(:d)
605
917
  end
606
918
 
607
919
  it "#exists should return a usable exists clause" do
608
- @ds.filter(@db[:a___c].filter(:c__a=>:a__b).exists).all.should == []
920
+ @ds.filter(@db[:d___c].filter(:c__a=>:d__b).exists).all.should == []
609
921
  @ds.insert(20, 30)
610
922
  @ds.insert(10, 20)
611
- @ds.filter(@db[:a___c].filter(:c__a=>:a__b).exists).all.should == [{:a=>10, :b=>20}]
923
+ @ds.filter(@db[:d___c].filter(:c__a=>:d__b).exists).all.should == [{:a=>10, :b=>20}]
612
924
  end
613
925
 
614
926
  it "#filter and #exclude should work with placeholder strings" do
@@ -625,6 +937,23 @@ describe "Sequel::Dataset main SQL methods" do
625
937
  @ds.filter(:a=>20).or(:b=>15).all.should == [{:a=>20, :b=>30}]
626
938
  @ds.filter(:a=>10).or(:b=>15).all.should == []
627
939
  end
940
+
941
+ it "#select_group should work correctly" do
942
+ @ds.unordered!
943
+ @ds.select_group(:a).all.should == []
944
+ @ds.insert(20, 30)
945
+ @ds.select_group(:a).all.should == [{:a=>20}]
946
+ @ds.select_group(:b).all.should == [{:b=>30}]
947
+ @ds.insert(20, 40)
948
+ @ds.select_group(:a).all.should == [{:a=>20}]
949
+ @ds.order(:b).select_group(:b).all.should == [{:b=>30}, {:b=>40}]
950
+ end
951
+
952
+ it "#select_group should work correctly when aliasing" do
953
+ @ds.unordered!
954
+ @ds.insert(20, 30)
955
+ @ds.select_group(:b___c).all.should == [{:c=>30}]
956
+ end
628
957
 
629
958
  it "#having should work correctly" do
630
959
  @ds.unordered!
@@ -645,14 +974,119 @@ describe "Sequel::Dataset main SQL methods" do
645
974
  end
646
975
  end
647
976
 
648
- describe "Sequel::Dataset DSL support" do
977
+ describe "Sequel::Dataset convenience methods" do
978
+ before(:all) do
979
+ @db = INTEGRATION_DB
980
+ @db.create_table!(:a){Integer :a; Integer :b; Integer :c; Integer :d}
981
+ @ds = @db[:a].order(:a)
982
+ end
649
983
  before do
984
+ @ds.delete
985
+ @ds.insert(1, 2, 3, 4)
986
+ @ds.insert(5, 6, 7, 8)
987
+ end
988
+ after(:all) do
989
+ @db.drop_table?(:a)
990
+ end
991
+
992
+ specify "should have working #map" do
993
+ @ds.map(:a).should == [1, 5]
994
+ @ds.map(:b).should == [2, 6]
995
+ @ds.map([:a, :b]).should == [[1, 2], [5, 6]]
996
+ end
997
+
998
+ specify "should have working #to_hash" do
999
+ @ds.to_hash(:a).should == {1=>{:a=>1, :b=>2, :c=>3, :d=>4}, 5=>{:a=>5, :b=>6, :c=>7, :d=>8}}
1000
+ @ds.to_hash(:b).should == {2=>{:a=>1, :b=>2, :c=>3, :d=>4}, 6=>{:a=>5, :b=>6, :c=>7, :d=>8}}
1001
+ @ds.to_hash([:a, :b]).should == {[1, 2]=>{:a=>1, :b=>2, :c=>3, :d=>4}, [5, 6]=>{:a=>5, :b=>6, :c=>7, :d=>8}}
1002
+
1003
+ @ds.to_hash(:a, :b).should == {1=>2, 5=>6}
1004
+ @ds.to_hash([:a, :c], :b).should == {[1, 3]=>2, [5, 7]=>6}
1005
+ @ds.to_hash(:a, [:b, :c]).should == {1=>[2, 3], 5=>[6, 7]}
1006
+ @ds.to_hash([:a, :c], [:b, :d]).should == {[1, 3]=>[2, 4], [5, 7]=>[6, 8]}
1007
+ end
1008
+
1009
+ specify "should have working #to_hash_groups" do
1010
+ ds = @ds.order(*@ds.columns)
1011
+ ds.insert(1, 2, 3, 9)
1012
+ ds.to_hash_groups(:a).should == {1=>[{:a=>1, :b=>2, :c=>3, :d=>4}, {:a=>1, :b=>2, :c=>3, :d=>9}], 5=>[{:a=>5, :b=>6, :c=>7, :d=>8}]}
1013
+ ds.to_hash_groups(:b).should == {2=>[{:a=>1, :b=>2, :c=>3, :d=>4}, {:a=>1, :b=>2, :c=>3, :d=>9}], 6=>[{:a=>5, :b=>6, :c=>7, :d=>8}]}
1014
+ ds.to_hash_groups([:a, :b]).should == {[1, 2]=>[{:a=>1, :b=>2, :c=>3, :d=>4}, {:a=>1, :b=>2, :c=>3, :d=>9}], [5, 6]=>[{:a=>5, :b=>6, :c=>7, :d=>8}]}
1015
+
1016
+ ds.to_hash_groups(:a, :d).should == {1=>[4, 9], 5=>[8]}
1017
+ ds.to_hash_groups([:a, :c], :d).should == {[1, 3]=>[4, 9], [5, 7]=>[8]}
1018
+ ds.to_hash_groups(:a, [:b, :d]).should == {1=>[[2, 4], [2, 9]], 5=>[[6, 8]]}
1019
+ ds.to_hash_groups([:a, :c], [:b, :d]).should == {[1, 3]=>[[2, 4], [2, 9]], [5, 7]=>[[6, 8]]}
1020
+ end
1021
+
1022
+ specify "should have working #select_map" do
1023
+ @ds.select_map(:a).should == [1, 5]
1024
+ @ds.select_map(:b).should == [2, 6]
1025
+ @ds.select_map([:a]).should == [[1], [5]]
1026
+ @ds.select_map([:a, :b]).should == [[1, 2], [5, 6]]
1027
+
1028
+ @ds.select_map(:a___e).should == [1, 5]
1029
+ @ds.select_map(:b___e).should == [2, 6]
1030
+ @ds.select_map([:a___e, :b___f]).should == [[1, 2], [5, 6]]
1031
+ @ds.select_map([:a__a___e, :a__b___f]).should == [[1, 2], [5, 6]]
1032
+ @ds.select_map([Sequel.expr(:a__a).as(:e), Sequel.expr(:a__b).as(:f)]).should == [[1, 2], [5, 6]]
1033
+ @ds.select_map([Sequel.qualify(:a, :a).as(:e), Sequel.qualify(:a, :b).as(:f)]).should == [[1, 2], [5, 6]]
1034
+ @ds.select_map([Sequel.identifier(:a).qualify(:a).as(:e), Sequel.qualify(:a, :b).as(:f)]).should == [[1, 2], [5, 6]]
1035
+ end
1036
+
1037
+ specify "should have working #select_order_map" do
1038
+ @ds.select_order_map(:a).should == [1, 5]
1039
+ @ds.select_order_map(Sequel.desc(:a__b)).should == [6, 2]
1040
+ @ds.select_order_map(Sequel.desc(:a__b___e)).should == [6, 2]
1041
+ @ds.select_order_map(Sequel.qualify(:a, :b).as(:e)).should == [2, 6]
1042
+ @ds.select_order_map([:a]).should == [[1], [5]]
1043
+ @ds.select_order_map([Sequel.desc(:a), :b]).should == [[5, 6], [1, 2]]
1044
+
1045
+ @ds.select_order_map(:a___e).should == [1, 5]
1046
+ @ds.select_order_map(:b___e).should == [2, 6]
1047
+ @ds.select_order_map([Sequel.desc(:a___e), :b___f]).should == [[5, 6], [1, 2]]
1048
+ @ds.select_order_map([Sequel.desc(:a__a___e), :a__b___f]).should == [[5, 6], [1, 2]]
1049
+ @ds.select_order_map([Sequel.desc(:a__a), Sequel.expr(:a__b).as(:f)]).should == [[5, 6], [1, 2]]
1050
+ @ds.select_order_map([Sequel.qualify(:a, :a).desc, Sequel.qualify(:a, :b).as(:f)]).should == [[5, 6], [1, 2]]
1051
+ @ds.select_order_map([Sequel.identifier(:a).qualify(:a).desc, Sequel.qualify(:a, :b).as(:f)]).should == [[5, 6], [1, 2]]
1052
+ end
1053
+
1054
+ specify "should have working #select_hash" do
1055
+ @ds.select_hash(:a, :b).should == {1=>2, 5=>6}
1056
+ @ds.select_hash(:a__a___e, :b).should == {1=>2, 5=>6}
1057
+ @ds.select_hash(Sequel.expr(:a__a).as(:e), :b).should == {1=>2, 5=>6}
1058
+ @ds.select_hash(Sequel.qualify(:a, :a).as(:e), :b).should == {1=>2, 5=>6}
1059
+ @ds.select_hash(Sequel.identifier(:a).qualify(:a).as(:e), :b).should == {1=>2, 5=>6}
1060
+ @ds.select_hash([:a, :c], :b).should == {[1, 3]=>2, [5, 7]=>6}
1061
+ @ds.select_hash(:a, [:b, :c]).should == {1=>[2, 3], 5=>[6, 7]}
1062
+ @ds.select_hash([:a, :c], [:b, :d]).should == {[1, 3]=>[2, 4], [5, 7]=>[6, 8]}
1063
+ end
1064
+
1065
+ specify "should have working #select_hash_groups" do
1066
+ ds = @ds.order(*@ds.columns)
1067
+ ds.insert(1, 2, 3, 9)
1068
+ ds.select_hash_groups(:a, :d).should == {1=>[4, 9], 5=>[8]}
1069
+ ds.select_hash_groups(:a__a___e, :d).should == {1=>[4, 9], 5=>[8]}
1070
+ ds.select_hash_groups(Sequel.expr(:a__a).as(:e), :d).should == {1=>[4, 9], 5=>[8]}
1071
+ ds.select_hash_groups(Sequel.qualify(:a, :a).as(:e), :d).should == {1=>[4, 9], 5=>[8]}
1072
+ ds.select_hash_groups(Sequel.identifier(:a).qualify(:a).as(:e), :d).should == {1=>[4, 9], 5=>[8]}
1073
+ ds.select_hash_groups([:a, :c], :d).should == {[1, 3]=>[4, 9], [5, 7]=>[8]}
1074
+ ds.select_hash_groups(:a, [:b, :d]).should == {1=>[[2, 4], [2, 9]], 5=>[[6, 8]]}
1075
+ ds.select_hash_groups([:a, :c], [:b, :d]).should == {[1, 3]=>[[2, 4], [2, 9]], [5, 7]=>[[6, 8]]}
1076
+ end
1077
+ end
1078
+
1079
+ describe "Sequel::Dataset DSL support" do
1080
+ before(:all) do
650
1081
  @db = INTEGRATION_DB
651
1082
  @db.create_table!(:a){Integer :a; Integer :b}
652
1083
  @ds = @db[:a].order(:a)
653
1084
  end
654
- after do
655
- @db.drop_table(:a)
1085
+ before do
1086
+ @ds.delete
1087
+ end
1088
+ after(:all) do
1089
+ @db.drop_table?(:a)
656
1090
  end
657
1091
 
658
1092
  it "should work with standard mathematical operators" do
@@ -663,31 +1097,43 @@ describe "Sequel::Dataset DSL support" do
663
1097
  @ds.get{a / b}.to_i.should == 2
664
1098
  end
665
1099
 
666
- specify "should work with bitwise shift operators" do
1100
+ cspecify "should work with bitwise shift operators", :derby do
667
1101
  @ds.insert(3, 2)
668
1102
  @ds.get{a.sql_number << b}.to_i.should == 12
669
1103
  @ds.get{a.sql_number >> b}.to_i.should == 0
1104
+ @ds.get{a.sql_number << b << 1}.to_i.should == 24
670
1105
  @ds.delete
671
1106
  @ds.insert(3, 1)
672
1107
  @ds.get{a.sql_number << b}.to_i.should == 6
673
1108
  @ds.get{a.sql_number >> b}.to_i.should == 1
1109
+ @ds.get{a.sql_number >> b >> 1}.to_i.should == 0
674
1110
  end
675
1111
 
676
- specify "should work with bitwise AND and OR operators" do
1112
+ cspecify "should work with bitwise AND and OR operators", :derby do
677
1113
  @ds.insert(3, 5)
678
1114
  @ds.get{a.sql_number | b}.to_i.should == 7
679
1115
  @ds.get{a.sql_number & b}.to_i.should == 1
1116
+ @ds.get{a.sql_number | b | 8}.to_i.should == 15
1117
+ @ds.get{a.sql_number & b & 8}.to_i.should == 0
680
1118
  end
681
1119
 
682
- cspecify "should work with the bitwise compliment operator", :h2 do
1120
+ specify "should work with the bitwise compliment operator" do
683
1121
  @ds.insert(-3, 3)
684
1122
  @ds.get{~a.sql_number}.to_i.should == 2
685
1123
  @ds.get{~b.sql_number}.to_i.should == -4
686
1124
  end
687
1125
 
688
- cspecify "should work with the bitwise xor operator", :sqlite do
1126
+ cspecify "should work with the bitwise xor operator", :derby do
689
1127
  @ds.insert(3, 5)
690
1128
  @ds.get{a.sql_number ^ b}.to_i.should == 6
1129
+ @ds.get{a.sql_number ^ b ^ 1}.to_i.should == 7
1130
+ end
1131
+
1132
+ specify "should work with the modulus operator" do
1133
+ @ds.insert(3, 5)
1134
+ @ds.get{a.sql_number % 4}.to_i.should == 3
1135
+ @ds.get{b.sql_number % 4}.to_i.should == 1
1136
+ @ds.get{a.sql_number % 4 % 2}.to_i.should == 1
691
1137
  end
692
1138
 
693
1139
  specify "should work with inequality operators" do
@@ -703,35 +1149,35 @@ describe "Sequel::Dataset DSL support" do
703
1149
 
704
1150
  specify "should work with casting and string concatentation" do
705
1151
  @ds.insert(20, 20)
706
- @ds.get{a.cast_string + b.cast_string}.should == '2020'
1152
+ @ds.get{Sequel.cast(a, String).sql_string + Sequel.cast(b, String)}.should == '2020'
707
1153
  end
708
1154
 
709
1155
  it "should work with ordering" do
710
1156
  @ds.insert(10, 20)
711
1157
  @ds.insert(20, 10)
712
1158
  @ds.order(:a, :b).all.should == [{:a=>10, :b=>20}, {:a=>20, :b=>10}]
713
- @ds.order(:a.asc, :b.asc).all.should == [{:a=>10, :b=>20}, {:a=>20, :b=>10}]
714
- @ds.order(:a.desc, :b.desc).all.should == [{:a=>20, :b=>10}, {:a=>10, :b=>20}]
1159
+ @ds.order(Sequel.asc(:a), Sequel.asc(:b)).all.should == [{:a=>10, :b=>20}, {:a=>20, :b=>10}]
1160
+ @ds.order(Sequel.desc(:a), Sequel.desc(:b)).all.should == [{:a=>20, :b=>10}, {:a=>10, :b=>20}]
715
1161
  end
716
1162
 
717
1163
  it "should work with qualifying" do
718
1164
  @ds.insert(10, 20)
719
1165
  @ds.get(:a__b).should == 20
720
1166
  @ds.get{a__b}.should == 20
721
- @ds.get(:b.qualify(:a)).should == 20
1167
+ @ds.get(Sequel.qualify(:a, :b)).should == 20
722
1168
  end
723
1169
 
724
1170
  it "should work with aliasing" do
725
1171
  @ds.insert(10, 20)
726
1172
  @ds.get(:a__b___c).should == 20
727
1173
  @ds.get{a__b.as(c)}.should == 20
728
- @ds.get(:b.qualify(:a).as(:c)).should == 20
729
- @ds.get(:b.as(:c)).should == 20
1174
+ @ds.get(Sequel.qualify(:a, :b).as(:c)).should == 20
1175
+ @ds.get(Sequel.as(:b, :c)).should == 20
730
1176
  end
731
1177
 
732
1178
  it "should work with selecting all columns of a table" do
733
1179
  @ds.insert(20, 10)
734
- @ds.select(:a.*).all.should == [{:a=>20, :b=>10}]
1180
+ @ds.select_all(:a).all.should == [{:a=>20, :b=>10}]
735
1181
  end
736
1182
 
737
1183
  it "should work with ranges as hash values" do
@@ -772,24 +1218,24 @@ describe "Sequel::Dataset DSL support" do
772
1218
 
773
1219
  it "should work with CASE statements" do
774
1220
  @ds.insert(20, 10)
775
- @ds.filter({{:a=>20}=>20}.case(0) > 0).all.should == [{:a=>20, :b=>10}]
776
- @ds.filter({{:a=>15}=>20}.case(0) > 0).all.should == []
777
- @ds.filter({20=>20}.case(0, :a) > 0).all.should == [{:a=>20, :b=>10}]
778
- @ds.filter({15=>20}.case(0, :a) > 0).all.should == []
1221
+ @ds.filter(Sequel.case({{:a=>20}=>20}, 0) > 0).all.should == [{:a=>20, :b=>10}]
1222
+ @ds.filter(Sequel.case({{:a=>15}=>20}, 0) > 0).all.should == []
1223
+ @ds.filter(Sequel.case({20=>20}, 0, :a) > 0).all.should == [{:a=>20, :b=>10}]
1224
+ @ds.filter(Sequel.case({15=>20}, 0, :a) > 0).all.should == []
779
1225
  end
780
1226
 
781
- it "should work with multiple value arrays" do
1227
+ specify "should work with multiple value arrays" do
782
1228
  @ds.insert(20, 10)
783
1229
  @ds.quote_identifiers = false
784
- @ds.filter([:a, :b]=>[[20, 10]].sql_array).all.should == [{:a=>20, :b=>10}]
785
- @ds.filter([:a, :b]=>[[10, 20]].sql_array).all.should == []
786
- @ds.filter([:a, :b]=>[[20, 10], [1, 2]].sql_array).all.should == [{:a=>20, :b=>10}]
787
- @ds.filter([:a, :b]=>[[10, 10], [20, 20]].sql_array).all.should == []
1230
+ @ds.filter([:a, :b]=>[[20, 10]]).all.should == [{:a=>20, :b=>10}]
1231
+ @ds.filter([:a, :b]=>[[10, 20]]).all.should == []
1232
+ @ds.filter([:a, :b]=>[[20, 10], [1, 2]]).all.should == [{:a=>20, :b=>10}]
1233
+ @ds.filter([:a, :b]=>[[10, 10], [20, 20]]).all.should == []
788
1234
 
789
- @ds.exclude([:a, :b]=>[[20, 10]].sql_array).all.should == []
790
- @ds.exclude([:a, :b]=>[[10, 20]].sql_array).all.should == [{:a=>20, :b=>10}]
791
- @ds.exclude([:a, :b]=>[[20, 10], [1, 2]].sql_array).all.should == []
792
- @ds.exclude([:a, :b]=>[[10, 10], [20, 20]].sql_array).all.should == [{:a=>20, :b=>10}]
1235
+ @ds.exclude([:a, :b]=>[[20, 10]]).all.should == []
1236
+ @ds.exclude([:a, :b]=>[[10, 20]]).all.should == [{:a=>20, :b=>10}]
1237
+ @ds.exclude([:a, :b]=>[[20, 10], [1, 2]]).all.should == []
1238
+ @ds.exclude([:a, :b]=>[[10, 10], [20, 20]]).all.should == [{:a=>20, :b=>10}]
793
1239
  end
794
1240
 
795
1241
  it "should work with IN/NOT in with datasets" do
@@ -822,18 +1268,49 @@ describe "Sequel::Dataset DSL support" do
822
1268
  specify "should work empty arrays with nulls" do
823
1269
  @ds.insert(nil, nil)
824
1270
  @ds.filter(:a=>[]).all.should == []
825
- @ds.exclude(:a=>[]).all.should == [{:a=>nil, :b=>nil}]
1271
+ @ds.exclude(:a=>[]).all.should == []
826
1272
  @ds.filter([:a, :b]=>[]).all.should == []
827
- @ds.exclude([:a, :b]=>[]).all.should == [{:a=>nil, :b=>nil}]
1273
+ @ds.exclude([:a, :b]=>[]).all.should == []
1274
+
1275
+ unless Sequel.guarded?(:mssql, :oracle, :db2)
1276
+ # Some databases don't like boolean results in the select list
1277
+ pr = proc{|r| r.is_a?(Integer) ? (r != 0) : r}
1278
+ pr[@ds.get(Sequel.expr(:a=>[]))].should == nil
1279
+ pr[@ds.get(~Sequel.expr(:a=>[]))].should == nil
1280
+ pr[@ds.get(Sequel.expr([:a, :b]=>[]))].should == nil
1281
+ pr[@ds.get(~Sequel.expr([:a, :b]=>[]))].should == nil
1282
+ end
828
1283
  end
829
1284
 
1285
+ specify "should work empty arrays with nulls and Sequel.empty_array_null_handling = true" do
1286
+ begin
1287
+ Sequel.empty_array_handle_nulls = false
1288
+ @ds.insert(nil, nil)
1289
+ @ds.filter(:a=>[]).all.should == []
1290
+ @ds.exclude(:a=>[]).all.should == [{:a=>nil, :b=>nil}]
1291
+ @ds.filter([:a, :b]=>[]).all.should == []
1292
+ @ds.exclude([:a, :b]=>[]).all.should == [{:a=>nil, :b=>nil}]
1293
+
1294
+ unless Sequel.guarded?(:mssql, :oracle, :db2)
1295
+ # Some databases don't like boolean results in the select list
1296
+ pr = proc{|r| r.is_a?(Integer) ? (r != 0) : r}
1297
+ pr[@ds.get(Sequel.expr(:a=>[]))].should == false
1298
+ pr[@ds.get(~Sequel.expr(:a=>[]))].should == true
1299
+ pr[@ds.get(Sequel.expr([:a, :b]=>[]))].should == false
1300
+ pr[@ds.get(~Sequel.expr([:a, :b]=>[]))].should == true
1301
+ end
1302
+ ensure
1303
+ Sequel.empty_array_handle_nulls = true
1304
+ end
1305
+ end
1306
+
830
1307
  it "should work multiple conditions" do
831
1308
  @ds.insert(20, 10)
832
1309
  @ds.filter(:a=>20, :b=>10).all.should == [{:a=>20, :b=>10}]
833
1310
  @ds.filter([[:a, 20], [:b, 10]]).all.should == [{:a=>20, :b=>10}]
834
- @ds.filter({:a=>20} & {:b=>10}).all.should == [{:a=>20, :b=>10}]
835
- @ds.filter({:a=>20} | {:b=>5}).all.should == [{:a=>20, :b=>10}]
836
- @ds.filter(~{:a=>10}).all.should == [{:a=>20, :b=>10}]
1311
+ @ds.filter({:a=>20}, {:b=>10}).all.should == [{:a=>20, :b=>10}]
1312
+ @ds.filter(Sequel.|({:a=>20}, {:b=>5})).all.should == [{:a=>20, :b=>10}]
1313
+ @ds.filter(Sequel.~(:a=>10)).all.should == [{:a=>20, :b=>10}]
837
1314
  end
838
1315
  end
839
1316
 
@@ -844,26 +1321,40 @@ describe "SQL Extract Function" do
844
1321
  @ds = @db[:a].order(:a)
845
1322
  end
846
1323
  after do
847
- @db.drop_table(:a)
1324
+ @db.drop_table?(:a)
848
1325
  end
849
1326
 
850
- cspecify "should return the part of the datetime asked for", :sqlite, :mssql do
1327
+ specify "should return the part of the datetime asked for" do
851
1328
  t = Time.now
1329
+ def @ds.supports_timestamp_timezones?() false end
852
1330
  @ds.insert(t)
853
1331
  @ds.get{a.extract(:year)}.should == t.year
854
1332
  @ds.get{a.extract(:month)}.should == t.month
855
1333
  @ds.get{a.extract(:day)}.should == t.day
1334
+ @ds.get{a.extract(:hour)}.should == t.hour
1335
+ @ds.get{a.extract(:minute)}.should == t.min
1336
+ @ds.get{a.extract(:second)}.to_i.should == t.sec
856
1337
  end
857
1338
  end
858
1339
 
859
1340
  describe "Dataset string methods" do
860
- before do
1341
+ before(:all) do
861
1342
  @db = INTEGRATION_DB
862
- @db.create_table!(:a){String :a; String :b}
1343
+ csc = {}
1344
+ cic = {}
1345
+ csc[:collate] = @db.dataset_class::CASE_SENSITIVE_COLLATION if defined? @db.dataset_class::CASE_SENSITIVE_COLLATION
1346
+ cic[:collate] = @db.dataset_class::CASE_INSENSITIVE_COLLATION if defined? @db.dataset_class::CASE_INSENSITIVE_COLLATION
1347
+ @db.create_table!(:a) do
1348
+ String :a, csc
1349
+ String :b, cic
1350
+ end
863
1351
  @ds = @db[:a].order(:a)
864
1352
  end
865
- after do
866
- @db.drop_table(:a)
1353
+ before do
1354
+ @ds.delete
1355
+ end
1356
+ after(:all) do
1357
+ @db.drop_table?(:a)
867
1358
  end
868
1359
 
869
1360
  it "#grep should return matching rows" do
@@ -877,15 +1368,15 @@ describe "Dataset string methods" do
877
1368
  end
878
1369
 
879
1370
  it "#grep should work with :all_patterns and :all_columns options" do
880
- @ds.insert('foo bar', '')
1371
+ @ds.insert('foo bar', ' ')
881
1372
  @ds.insert('foo d', 'bar')
882
- @ds.insert('foo e', '')
883
- @ds.insert('', 'bar')
1373
+ @ds.insert('foo e', ' ')
1374
+ @ds.insert(' ', 'bar')
884
1375
  @ds.insert('foo f', 'baz')
885
1376
  @ds.insert('foo baz', 'bar baz')
886
1377
  @ds.insert('foo boo', 'boo foo')
887
1378
 
888
- @ds.grep([:a, :b], %w'%foo% %bar%', :all_patterns=>true).all.should == [{:a=>'foo bar', :b=>''}, {:a=>'foo baz', :b=>'bar baz'}, {:a=>'foo d', :b=>'bar'}]
1379
+ @ds.grep([:a, :b], %w'%foo% %bar%', :all_patterns=>true).all.should == [{:a=>'foo bar', :b=>' '}, {:a=>'foo baz', :b=>'bar baz'}, {:a=>'foo d', :b=>'bar'}]
889
1380
  @ds.grep([:a, :b], %w'%foo% %bar% %blob%', :all_patterns=>true).all.should == []
890
1381
 
891
1382
  @ds.grep([:a, :b], %w'%bar% %foo%', :all_columns=>true).all.should == [{:a=>"foo baz", :b=>"bar baz"}, {:a=>"foo boo", :b=>"boo foo"}, {:a=>"foo d", :b=>"bar"}]
@@ -897,27 +1388,82 @@ describe "Dataset string methods" do
897
1388
 
898
1389
  it "#like should return matching rows" do
899
1390
  @ds.insert('foo', 'bar')
900
- @ds.filter(:a.like('foo')).all.should == [{:a=>'foo', :b=>'bar'}]
901
- @ds.filter(:a.like('bar')).all.should == []
902
- @ds.filter(:a.like('foo', 'bar')).all.should == [{:a=>'foo', :b=>'bar'}]
1391
+ @ds.filter(Sequel.expr(:a).like('foo')).all.should == [{:a=>'foo', :b=>'bar'}]
1392
+ @ds.filter(Sequel.expr(:a).like('bar')).all.should == []
1393
+ @ds.filter(Sequel.expr(:a).like('foo', 'bar')).all.should == [{:a=>'foo', :b=>'bar'}]
1394
+ @ds.exclude(Sequel.expr(:a).like('foo')).all.should == []
1395
+ @ds.exclude(Sequel.expr(:a).like('bar')).all.should == [{:a=>'foo', :b=>'bar'}]
1396
+ @ds.exclude(Sequel.expr(:a).like('foo', 'bar')).all.should == []
1397
+ end
1398
+
1399
+ it "#like should be case sensitive" do
1400
+ @ds.insert('foo', 'bar')
1401
+ @ds.filter(Sequel.expr(:a).like('Foo')).all.should == []
1402
+ @ds.filter(Sequel.expr(:b).like('baR')).all.should == []
1403
+ @ds.filter(Sequel.expr(:a).like('FOO', 'BAR')).all.should == []
1404
+ @ds.exclude(Sequel.expr(:a).like('Foo')).all.should == [{:a=>'foo', :b=>'bar'}]
1405
+ @ds.exclude(Sequel.expr(:b).like('baR')).all.should == [{:a=>'foo', :b=>'bar'}]
1406
+ @ds.exclude(Sequel.expr(:a).like('FOO', 'BAR')).all.should == [{:a=>'foo', :b=>'bar'}]
903
1407
  end
904
1408
 
905
1409
  it "#ilike should return matching rows, in a case insensitive manner" do
906
1410
  @ds.insert('foo', 'bar')
907
- @ds.filter(:a.ilike('Foo')).all.should == [{:a=>'foo', :b=>'bar'}]
908
- @ds.filter(:a.ilike('baR')).all.should == []
909
- @ds.filter(:a.ilike('FOO', 'BAR')).all.should == [{:a=>'foo', :b=>'bar'}]
1411
+ @ds.filter(Sequel.expr(:a).ilike('Foo')).all.should == [{:a=>'foo', :b=>'bar'}]
1412
+ @ds.filter(Sequel.expr(:a).ilike('baR')).all.should == []
1413
+ @ds.filter(Sequel.expr(:a).ilike('FOO', 'BAR')).all.should == [{:a=>'foo', :b=>'bar'}]
1414
+ @ds.exclude(Sequel.expr(:a).ilike('Foo')).all.should == []
1415
+ @ds.exclude(Sequel.expr(:a).ilike('baR')).all.should == [{:a=>'foo', :b=>'bar'}]
1416
+ @ds.exclude(Sequel.expr(:a).ilike('FOO', 'BAR')).all.should == []
910
1417
  end
911
1418
 
912
- it "should work with strings created with sql_string_join" do
1419
+ if INTEGRATION_DB.dataset.supports_regexp?
1420
+ it "#like with regexp return matching rows" do
1421
+ @ds.insert('foo', 'bar')
1422
+ @ds.filter(Sequel.expr(:a).like(/fo/)).all.should == [{:a=>'foo', :b=>'bar'}]
1423
+ @ds.filter(Sequel.expr(:a).like(/fo$/)).all.should == []
1424
+ @ds.filter(Sequel.expr(:a).like(/fo/, /ar/)).all.should == [{:a=>'foo', :b=>'bar'}]
1425
+ @ds.exclude(Sequel.expr(:a).like(/fo/)).all.should == []
1426
+ @ds.exclude(Sequel.expr(:a).like(/fo$/)).all.should == [{:a=>'foo', :b=>'bar'}]
1427
+ @ds.exclude(Sequel.expr(:a).like(/fo/, /ar/)).all.should == []
1428
+ end
1429
+
1430
+ it "#like with regexp should be case sensitive if regexp is case sensitive" do
1431
+ @ds.insert('foo', 'bar')
1432
+ @ds.filter(Sequel.expr(:a).like(/Fo/)).all.should == []
1433
+ @ds.filter(Sequel.expr(:b).like(/baR/)).all.should == []
1434
+ @ds.filter(Sequel.expr(:a).like(/FOO/, /BAR/)).all.should == []
1435
+ @ds.exclude(Sequel.expr(:a).like(/Fo/)).all.should == [{:a=>'foo', :b=>'bar'}]
1436
+ @ds.exclude(Sequel.expr(:b).like(/baR/)).all.should == [{:a=>'foo', :b=>'bar'}]
1437
+ @ds.exclude(Sequel.expr(:a).like(/FOO/, /BAR/)).all.should == [{:a=>'foo', :b=>'bar'}]
1438
+
1439
+ @ds.filter(Sequel.expr(:a).like(/Fo/i)).all.should == [{:a=>'foo', :b=>'bar'}]
1440
+ @ds.filter(Sequel.expr(:b).like(/baR/i)).all.should == [{:a=>'foo', :b=>'bar'}]
1441
+ @ds.filter(Sequel.expr(:a).like(/FOO/i, /BAR/i)).all.should == [{:a=>'foo', :b=>'bar'}]
1442
+ @ds.exclude(Sequel.expr(:a).like(/Fo/i)).all.should == []
1443
+ @ds.exclude(Sequel.expr(:b).like(/baR/i)).all.should == []
1444
+ @ds.exclude(Sequel.expr(:a).like(/FOO/i, /BAR/i)).all.should == []
1445
+ end
1446
+
1447
+ it "#ilike with regexp should return matching rows, in a case insensitive manner" do
1448
+ @ds.insert('foo', 'bar')
1449
+ @ds.filter(Sequel.expr(:a).ilike(/Fo/)).all.should == [{:a=>'foo', :b=>'bar'}]
1450
+ @ds.filter(Sequel.expr(:b).ilike(/baR/)).all.should == [{:a=>'foo', :b=>'bar'}]
1451
+ @ds.filter(Sequel.expr(:a).ilike(/FOO/, /BAR/)).all.should == [{:a=>'foo', :b=>'bar'}]
1452
+ @ds.exclude(Sequel.expr(:a).ilike(/Fo/)).all.should == []
1453
+ @ds.exclude(Sequel.expr(:b).ilike(/baR/)).all.should == []
1454
+ @ds.exclude(Sequel.expr(:a).ilike(/FOO/, /BAR/)).all.should == []
1455
+ end
1456
+ end
1457
+
1458
+ it "should work with strings created with Sequel.join" do
913
1459
  @ds.insert('foo', 'bar')
914
- @ds.get([:a, :b].sql_string_join).should == 'foobar'
915
- @ds.get([:a, :b].sql_string_join(' ')).should == 'foo bar'
1460
+ @ds.get(Sequel.join([:a, "bar"])).should == 'foobar'
1461
+ @ds.get(Sequel.join(["foo", :b], ' ')).should == 'foo bar'
916
1462
  end
917
1463
  end
918
1464
 
919
1465
  describe "Dataset identifier methods" do
920
- before do
1466
+ before(:all) do
921
1467
  class ::String
922
1468
  def uprev
923
1469
  upcase.reverse
@@ -925,20 +1471,27 @@ describe "Dataset identifier methods" do
925
1471
  end
926
1472
  @db = INTEGRATION_DB
927
1473
  @db.create_table!(:a){Integer :ab}
1474
+ @db[:a].insert(1)
1475
+ end
1476
+ before do
928
1477
  @ds = @db[:a].order(:ab)
929
- @ds.insert(1)
930
1478
  end
931
- after do
932
- @db.drop_table(:a)
1479
+ after(:all) do
1480
+ @db.drop_table?(:a)
933
1481
  end
934
1482
 
935
- cspecify "#identifier_output_method should change how identifiers are output", [:mysql2], [:swift] do
1483
+ specify "#identifier_output_method should change how identifiers are output" do
936
1484
  @ds.identifier_output_method = :upcase
937
1485
  @ds.first.should == {:AB=>1}
938
1486
  @ds.identifier_output_method = :uprev
939
1487
  @ds.first.should == {:BA=>1}
940
1488
  end
941
1489
 
1490
+ it "should work with a nil identifier_output_method" do
1491
+ @ds.identifier_output_method = nil
1492
+ [{:ab=>1}, {:AB=>1}].should include(@ds.first)
1493
+ end
1494
+
942
1495
  it "should work when not quoting identifiers" do
943
1496
  @ds.quote_identifiers = false
944
1497
  @ds.first.should == {:ab=>1}
@@ -946,13 +1499,16 @@ describe "Dataset identifier methods" do
946
1499
  end
947
1500
 
948
1501
  describe "Dataset defaults and overrides" do
949
- before do
1502
+ before(:all) do
950
1503
  @db = INTEGRATION_DB
951
1504
  @db.create_table!(:a){Integer :a}
952
1505
  @ds = @db[:a].order(:a)
953
1506
  end
954
- after do
955
- @db.drop_table(:a)
1507
+ before do
1508
+ @ds.delete
1509
+ end
1510
+ after(:all) do
1511
+ @db.drop_table?(:a)
956
1512
  end
957
1513
 
958
1514
  it "#set_defaults should set defaults that can be overridden" do
@@ -977,7 +1533,7 @@ if INTEGRATION_DB.dataset.supports_modifying_joins?
977
1533
  @db.create_table!(:a){Integer :a; Integer :d}
978
1534
  @db.create_table!(:b){Integer :b; Integer :e}
979
1535
  @db.create_table!(:c){Integer :c; Integer :f}
980
- @ds = @db.from(:a, :b).join(:c, :c=>:e.identifier).where(:d=>:b, :f=>6)
1536
+ @ds = @db.from(:a, :b).join(:c, :c=>Sequel.identifier(:e)).where(:d=>:b, :f=>6)
981
1537
  @db[:a].insert(1, 2)
982
1538
  @db[:a].insert(3, 4)
983
1539
  @db[:b].insert(2, 5)
@@ -986,7 +1542,7 @@ if INTEGRATION_DB.dataset.supports_modifying_joins?
986
1542
  @db[:c].insert(7, 8)
987
1543
  end
988
1544
  after do
989
- @db.drop_table(:a, :b, :c)
1545
+ @db.drop_table?(:a, :b, :c)
990
1546
  end
991
1547
 
992
1548
  it "#update should allow updating joined datasets" do
@@ -1006,3 +1562,35 @@ if INTEGRATION_DB.dataset.supports_modifying_joins?
1006
1562
  end
1007
1563
  end
1008
1564
  end
1565
+
1566
+ describe "Emulated functions" do
1567
+ before(:all) do
1568
+ @db = INTEGRATION_DB
1569
+ @db.create_table!(:a){String :a}
1570
+ @ds = @db[:a]
1571
+ end
1572
+ after(:all) do
1573
+ @db.drop_table?(:a)
1574
+ end
1575
+ after do
1576
+ @ds.delete
1577
+ end
1578
+
1579
+ specify "Sequel.char_length should return the length of characters in the string" do
1580
+ @ds.get(Sequel.char_length(:a)).should == nil
1581
+ @ds.insert(:a=>'foo')
1582
+ @ds.get(Sequel.char_length(:a)).should == 3
1583
+ # Check behavior with leading/trailing blanks
1584
+ @ds.update(:a=>' foo22 ')
1585
+ @ds.get(Sequel.char_length(:a)).should == 7
1586
+ end
1587
+
1588
+ specify "Sequel.trim should return the string with spaces trimmed from both sides" do
1589
+ @ds.get(Sequel.trim(:a)).should == nil
1590
+ @ds.insert(:a=>'foo')
1591
+ @ds.get(Sequel.trim(:a)).should == 'foo'
1592
+ # Check behavior with leading/trailing blanks
1593
+ @ds.update(:a=>' foo22 ')
1594
+ @ds.get(Sequel.trim(:a)).should == 'foo22'
1595
+ end
1596
+ end