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
data/doc/sharding.rdoc CHANGED
@@ -8,9 +8,25 @@ that ship with Sequel.
8
8
 
9
9
  == The :servers Database option
10
10
 
11
- Both features use the :servers Database option. The :servers option should
12
- be a hash with symbol keys and values that are either hashes or procs that
13
- return hashes. Note that all servers should have the same schema for all
11
+ Sharding and read_only support are both enabled via the :servers database
12
+ option. Using the :servers database option makes Sequel use a connection pool
13
+ class that supports sharding, and the minimum required to enable sharding
14
+ support is to use the empty hash:
15
+
16
+ DB=Sequel.connect('postgres://master_server/database', :servers=>{})
17
+
18
+ In most cases, you are probably not going to want to use an empty hash,
19
+ so you'll want to have entries in the hash. Keys in the server hash are
20
+ not restricted to type, but the general recommendation is to use a symbol
21
+ unless you have special requirements. Values in the server hash should be
22
+ either hashes or procs that return hashes. These hashes are merged into
23
+ the Database object's default options hash to get the connection options
24
+ for the shard, so you don't need to override all options, just the ones
25
+ that need to be modified. For example, if you are using the same user,
26
+ password, and database name and just the host is changing, you only need
27
+ a :host entry in each shard's hash.
28
+
29
+ Note that all servers should have the same schema for all
14
30
  tables you are accessing, unless you really know what you are doing.
15
31
 
16
32
  == Master and Slave Database Configurations
@@ -93,7 +109,7 @@ schemas, so you should always have a default server that works.
93
109
 
94
110
  To set the shard for a given query, you use the Dataset#server method:
95
111
 
96
- DB[:hashes].server(:a).filter(:hash=>/31337/)
112
+ DB[:hashes].server(:a).where(:hash=>/31337/)
97
113
 
98
114
  That will return all matching rows on the hash_host_a shard that have a hash
99
115
  column that contains 31337.
@@ -103,10 +119,11 @@ work, you might want to add a method to the dataset that automatically sets
103
119
  the shard to use. This is fairly easy using a Sequel::Model:
104
120
 
105
121
  class Rainbow < Sequel::Model(:hashes)
106
- def_dataset_method(:plaintext_for_hash) do |hash|
107
- raise(ArgumentError, 'Invalid SHA-1 Hash') unless /\A[0-9a-f]{40}\z/.match(hash)
108
- row = self.server(hash[0...1].to_sym).first(:hash=>hash)
109
- row[:plaintext] if row
122
+ dataset_module do
123
+ def plaintext_for_hash(hash)
124
+ raise(ArgumentError, 'Invalid SHA-1 Hash') unless /\A[0-9a-f]{40}\z/.match(hash)
125
+ server(hash[0...1].to_sym).where(:hash=>hash).get(:plaintext)
126
+ end
110
127
  end
111
128
  end
112
129
 
@@ -153,3 +170,77 @@ work well with shards. You just need to remember to set to model to use the plu
153
170
  If all of your models are sharded, you can set all models to use the plugin via:
154
171
 
155
172
  Sequel::Model.plugin :sharding
173
+
174
+ === server_block Extension
175
+
176
+ By default, you must specify the server/shard you want to use for every dataset/action,
177
+ or Sequel will use the default shard. If you have a group of queries that should use the
178
+ same shard, it can get a bit redundent to specify the same shard for all of them.
179
+
180
+ The server_block extension adds a Database#with_server method that scopes all database
181
+ access inside the block to the given shard by default:
182
+
183
+ DB.extension :server_block
184
+ DB.with_server(:a) do
185
+ # this SELECT query uses the "a" shard
186
+ if r = Rainbow.first(:hash=>/31337/)
187
+ r.count += 1
188
+ # this UPDATE query also uses the "a" shard
189
+ r.save
190
+ end
191
+ end
192
+
193
+ The server_block extension doesn't currently integrate with the sharding plugin, as it
194
+ ties into the Dataset#server method. This shouldn't present a problem in practice as
195
+ long as you just access the models inside the with_server block, since they will use
196
+ the shard set by with_server by default. However, you will probably have issues if
197
+ you retrieve the models inside the block and save them outside of the block. If you
198
+ need to do that, call the server method explicitly on the dataset used to retrieve the
199
+ model objects.
200
+
201
+ === arbitrary_servers Extension
202
+
203
+ By default, Sequel's sharding support is designed to work with predefined shards. It ships
204
+ with Database#add_servers and Database#remove_servers methods to modify these predefined
205
+ shards on the fly, but it is a bit cumbersome to work with truly arbitrary servers
206
+ (requiring you to call add_servers before use, then remove_servers after use).
207
+
208
+ The arbitrary_servers extension allows you to pass a server/shard options hash as the
209
+ server to use, and those options will be merged directly into the database's default options:
210
+
211
+ DB.extension :arbitrary_servers
212
+ DB[:rainbows].server(:host=>'hash_host_a').all
213
+ # or
214
+ DB[:rainbows].server(:host=>'hash_host_b', :database=>'backup').all
215
+
216
+ arbitrary_servers is designed to work well in conjunction with the server_block extension:
217
+
218
+ DB.with_server(:host=>'hash_host_b', :database=>'backup') do
219
+ DB.synchronize do
220
+ # All queries here default to the backup database on hash_host_b
221
+ end
222
+ end
223
+
224
+ If you are using arbitrary_servers with server_block, you may want to
225
+ define the following method (or something similar) so that you don't
226
+ need to call synchronize separately:
227
+
228
+ def DB.with_server(*)
229
+ super{synchronize{yield}}
230
+ end
231
+
232
+ The reason for the synchronize method is that it checks out a connection
233
+ and makes the same connection available for the duration of the block.
234
+ If you don't do that, Sequel will probably disconnect from the database
235
+ and reconnect to the database on each request, since connections to
236
+ arbitrary servers are not cached.
237
+
238
+ Note that this extension only works with the sharded threaded connection
239
+ pool. If you are using the sharded single connection pool, you need
240
+ to switch to the sharded threaded connection pool before using this
241
+ extension. If you are passing the :single_threaded option to
242
+ the Database, just remove that option. If you are setting:
243
+
244
+ Sequel.single_threaded = true
245
+
246
+ just remove or comment out that code.
data/doc/sql.rdoc CHANGED
@@ -73,10 +73,14 @@ You can also use <tt>Database#<<</tt>:
73
73
 
74
74
  === Other Places
75
75
 
76
- Almost everywhere in Sequel, you can drop down to literal SQL by providing a literal string, which you can create with <tt>String#lit</tt>:
76
+ Almost everywhere in Sequel, you can drop down to literal SQL by providing a literal string, which you can create with <tt>Sequel.lit</tt>:
77
77
 
78
78
  DB[:albums].select('name') # SELECT 'name' FROM albums
79
- DB[:albums].select('name'.lit) # SELECT name FROM albums
79
+ DB[:albums].select(Sequel.lit('name')) # SELECT name FROM albums
80
+
81
+ For a simpler way of creating literal strings, you can also use the {core_extensions extension}[link:files/doc/core_extensions_rdoc.html], which adds the <tt>String#lit</tt> method, and other methods that integrate Sequel's DSL with the ruby language:
82
+
83
+ DB[:albums].select('name'.lit)
80
84
 
81
85
  So you can use Sequel's DSL everywhere you find it helpful, and fallback to literal SQL if the DSL can't do what you want or you just find literal SQL easier.
82
86
 
@@ -129,9 +133,9 @@ Also note that specifying the period inside the symbol doesn't work if you are q
129
133
 
130
134
  :"table.column" # "table.column"
131
135
 
132
- The other way to qualify an identifier is to use the +qualify+ method on the column symbol with the table symbol:
136
+ The other way to qualify an identifier is to use the <tt>Sequel.qualify</tt> with the table and column symbols:
133
137
 
134
- :column.qualify(:table) # "table"."column"
138
+ Sequel.qualify(:table, :column) # "table"."column"
135
139
 
136
140
  Another way to generate identifiers is to use Sequel's {virtual row support}[link:files/doc/virtual_rows_rdoc.html]:
137
141
 
@@ -169,37 +173,37 @@ You can combine this with implicit qualification:
169
173
 
170
174
  :table__column___alias # "table"."column" AS "alias"
171
175
 
172
- You can also use the +as+ method on symbols and most Sequel-specific expression objects:
176
+ You can also use the <tt>Sequel.as</tt> method to create an alias, and the +as+ method on most Sequel-specific expression objects:
173
177
 
174
- :column.as(:alias) # "column" AS "alias"
175
- :column.qualify(:table).as(:alias) # "table"."column" AS "alias"
178
+ Sequel.as(:column, :alias) # "column" AS "alias"
179
+ Sequel.qualify(:table, :column).as(:alias) # "table"."column" AS "alias"
176
180
 
177
181
  === Functions
178
182
 
179
183
  The easiest way to use SQL functions is via a virtual row:
180
184
 
181
- DB[:albums].select{function{}} # SELECT function() FROM "albums"
182
- DB[:albums].select{function(col1, col2)} # SELECT function("col1", "col2") FROM "albums"
185
+ DB[:albums].select{func{}} # SELECT func() FROM "albums"
186
+ DB[:albums].select{func(col1, col2)} # SELECT func("col1", "col2") FROM "albums"
183
187
 
184
- You can also use the +sql_function+ method on the symbol that contains the function name:
188
+ You can also use the <tt>Sequel.function</tt> method on the symbol that contains the function name:
185
189
 
186
- :function.sql_function # function()
187
- :function.sql_function(:col1, :col2) # function("col1", "col2")
190
+ Sequel.function(:func) # func()
191
+ Sequel.function(:func, :col1, :col2) # func("col1", "col2")
188
192
 
189
193
  === Aggregate Functions
190
194
 
191
195
  Aggregate functions work the same way as normal functions, since they share the same syntax:
192
196
 
193
- :sum.sql_function(:column) # sum(column)
197
+ Sequel.function(:sum, :column) # sum(column)
194
198
 
195
199
  However, if you want to use the DISTINCT modifier to an aggregate function, you either have to use literal SQL or a virtual row block:
196
200
 
197
- :sum.sql_function('DISTINCT column'.lit) # sum(DISTINCT column)
201
+ Sequel.function(:sum, Sequel.lit('DISTINCT column')) # sum(DISTINCT column)
198
202
  DB[:albums].select{sum(:distinct, :column){}} # SELECT sum(DISTINCT column) FROM albums
199
203
 
200
204
  If you want to use the wildcard as the sole argument of the aggregate function, you again have to use literal SQL or a virtual row block:
201
205
 
202
- :count.sql_function('*'.lit) # count(*)
206
+ Sequel.function(:count, Sequel.lit('*')) # count(*)
203
207
  DB[:albums].select{count(:*){}} # SELECT count(*) FROM albums
204
208
 
205
209
  Note that Sequel provides helper methods for aggregate functions such as +count+, +sum+, +min+, +max+, +avg+, and +group_and_count+, which handle common uses of aggregate functions.
@@ -232,28 +236,35 @@ You can also specify this as an array of two element arrays:
232
236
 
233
237
  === Not Equal Operator (!=)
234
238
 
235
- You can specify a not equals condition by inverting the hash or array of two element arrays using +sql_negate+ or ~:
239
+ You can specify a not equals condition by inverting the hash or array of two element arrays using <tt>Sequel.negate</tt> or <tt>Sequel.~</tt>:
240
+
241
+ Sequel.negate(:column => 1) # ("column" != 1)
242
+ Sequel.negate([[:column, 1]]) # ("column" != 1)
243
+ Sequel.~(:column => 1) # ("column" != 1)
244
+ Sequel.~([[:column, 1]]) # ("column" != 1)
236
245
 
237
- {:column => 1}.sql_negate # ("column" != 1)
238
- [[:column, 1]].sql_negate # ("column" != 1)
239
- ~{:column => 1} # ("column" != 1)
240
- ~[[:column, 1]] # ("column" != 1)
246
+ The difference between the two is that negate only works on hashes and arrays of element arrays, and it negates all entries in the, while ~ does a general inversion. This is best shown by an example with multiple entries:
247
+
248
+ Sequel.negate(:column => 1, :foo => 2) # (("column" != 1) AND (foo != 2))
249
+ Sequel.~(:column => 1, :foo => 2) # (("column" != 1) OR (foo != 2))
241
250
 
242
251
  The most common need for not equals is in filters, in which case you can use the +exclude+ method:
243
252
 
244
253
  DB[:albums].exclude(:column=>1) # SELECT * FROM "albums" WHERE ("column" != 1)
245
254
 
255
+ Note that +exclude+ does a generalized inversion, similar to <tt>Sequel.~</tt>.
256
+
246
257
  === Inclusion and Exclusion Operators (IN, NOT IN)
247
258
 
248
259
  Sequel also uses hashes to specify inclusion, and inversions of those hashes to specify exclusion:
249
260
 
250
261
  {:column=>[1, 2, 3]} # ("column" IN (1, 2, 3))
251
- ~{:column=>[1, 2, 3]} # ("column" NOT IN (1, 2, 3))
262
+ Sequel.~(:column=>[1, 2, 3]) # ("column" NOT IN (1, 2, 3))
252
263
 
253
264
  As you may have guessed, Sequel switches from an = to an IN when the hash value is an array. It also does this for datasets, which easily allows you to test for inclusion and exclusion in a subselect:
254
265
 
255
266
  {:column=>DB[:albums].select(:id)} # ("column" IN (SELECT "id" FROM "albums"))
256
- ~{:column=>DB[:albums].select(:id)} # ("column" NOT IN (SELECT "id" FROM "albums"))
267
+ Sequel.~(:column=>DB[:albums].select(:id)) # ("column" NOT IN (SELECT "id" FROM "albums"))
257
268
 
258
269
  Sequel also supports the SQL EXISTS operator using <tt>Dataset#exists</tt>:
259
270
 
@@ -269,19 +280,19 @@ Hashes in Sequel use IS if the value is true, false, or nil:
269
280
 
270
281
  Negation works the same way as it does for equality and inclusion:
271
282
 
272
- {:column=>nil).sql_negate # ("column" IS NOT NULL)
273
- {:column=>true).sql_negate # ("column" IS NOT TRUE)
274
- {:column=>false).sql_negate # ("column" IS NOT FALSE)
283
+ Sequel.~(:column=>nil) # ("column" IS NOT NULL)
284
+ Sequel.~(:column=>true) # ("column" IS NOT TRUE)
285
+ Sequel.~(:column=>false) # ("column" IS NOT FALSE)
275
286
 
276
287
  === Inversion Operator (NOT)
277
288
 
278
289
  Sequel's general inversion operator is ~, which works on symbols and most Sequel-specific expression objects:
279
290
 
280
- ~:column # NOT "column"
291
+ Sequel.~(:column) # NOT "column"
281
292
 
282
293
  Note that ~ will actually apply the inversion operation to the underlying object, which is why
283
294
 
284
- ~{:column=>1}
295
+ Sequel.~(:column=>1)
285
296
 
286
297
  produces <tt>(column != 1)</tt> instead of <tt>NOT (column = 1)</tt>.
287
298
 
@@ -289,198 +300,229 @@ produces <tt>(column != 1)</tt> instead of <tt>NOT (column = 1)</tt>.
289
300
 
290
301
  Sequel defines the inequality operators directly on most Sequel-specific expression objects:
291
302
 
292
- :column.qualify(:table) > 1 # ("table"."column" > 1)
293
- :column.qualify(:table) < 1 # ("table"."column" < 1)
294
- :function.sql_function >= 1 # (function() >= 1)
295
- :function.sql_function(:column) <= 1 # (function("column") <= 1)
303
+ Sequel.qualify(:table, :column) > 1 # ("table"."column" > 1)
304
+ Sequel.qualify(:table, :column) < 1 # ("table"."column" < 1)
305
+ Sequel.function(:func) >= 1 # (func() >= 1)
306
+ Sequel.function(:func, :column) <= 1 # (func("column") <= 1)
296
307
 
297
- If you want to use them on a symbol, you should call +identifier+ on the symbol:
308
+ If you want to use them on a symbol, you should call <tt>Sequel.expr</tt> with the symbol:
298
309
 
299
- :column.identifier > 1 # ("column" > 1)
310
+ Sequel.expr(:column) > 1 # ("column" > 1)
300
311
 
301
312
  A common use of virtual rows is to handle inequality operators:
302
313
 
303
- DB[:albums].filter{col1 > col2} # SELECT * FROM "albums" WHERE ("col1" > "col2")
314
+ DB[:albums].where{col1 > col2} # SELECT * FROM "albums" WHERE ("col1" > "col2")
304
315
 
305
316
  === Standard Mathematical Operators (+ - * /)
306
317
 
307
- The standard mathematical operates are defined on symbol and most Sequel-specific expression objects:
318
+ The standard mathematical operates are defined on most Sequel-specific expression objects:
319
+
320
+ Sequel.expr(:column) + 1 # "column" + 1
321
+ Sequel.expr(:table__column) - 1 # "table"."column" - 1
322
+ Sequel.qualify(:table, :column) * 1 # "table"."column" * 1
323
+ Sequel.expr(:column) / 1 # "column" / 1
308
324
 
309
- :column + 1 # "column" + 1
310
- :table__column - 1 # "table"."column" - 1
311
- :column.qualify(:table) * 1 # "table"."column" * 1
312
- :column / 1 # "column" / 1
325
+ You can also call the operator methods directly on the Sequel module:
326
+
327
+ Sequel.+(:column, 1) # "column" + 1
328
+ Sequel.-(:table__column, 1) # "table"."column" - 1
329
+ Sequel.*(Sequel.qualify(:table, :column), 1) # "table"."column" * 1
330
+ Sequel./(:column, 1) # "column" / 1
313
331
 
314
332
  Note that the following does not work:
315
333
 
316
- 1 + :column # raises TypeError
334
+ 1 + Sequel.expr(:column) # raises TypeError
317
335
 
318
- For commutative operates such as + and *, this isn't a problem as you can just reorder, but non-commutative operators such as - and / cannot be expressed directly. However, Sequel comes with an +sql_expr+ extension that adds an +sql_expr+ method to all objects, allowing you to do:
336
+ For commutative operates such as + and *, this isn't a problem as you can just reorder, but non-commutative operators such as - and / cannot be expressed directly. The solution is to use one of the methods on the Sequel module:
319
337
 
320
- Sequel.extension :sql_expr
321
- 1.sql_expr / :column # (1 / "column")
338
+ Sequel.expr(1) / :column # (1 / "column")
339
+ Sequel./(1, :column) # (1 / "column")
322
340
 
323
341
  === Boolean Operators (AND OR)
324
342
 
325
- Sequel defines the & and | methods on symbols, hashes, and most Sequel-specific expression objects to handle AND and OR:
343
+ Sequel defines the & and | methods on most Sequel-specific expression objects to handle AND and OR:
326
344
 
327
- :column1 & :column2 # ("column1" AND "column2")
328
- {:column1=>1} | {:column2=>2} # (("column1" = 1) OR ("column2" = 2))
329
- (:function.sql_function > 1) & :column3 # ((function() > 1) AND "column3")
345
+ Sequel.expr(:column1) & :column2 # ("column1" AND "column2")
346
+ Sequel.expr(:column1=>1) | {:column2=>2} # (("column1" = 1) OR ("column2" = 2))
347
+ (Sequel.function(:func) > 1) & :column3 # ((func() > 1) AND "column3")
330
348
 
331
349
  Note the use of parentheses in the last statement. If you omit them, you won't get what you expect:
332
350
 
333
- :function.sql_function > 1 & :column3 # (function() > 1)
351
+ Sequel.function(:func) > 1 & :column3 # (func() > 1)
334
352
 
335
353
  This is because & has higher precedence than >, so it is parsed as:
336
354
 
337
- :function.sql_function > (1 & :column3)
355
+ Sequel.function(:func) > (1 & :column3)
338
356
 
339
357
  In this case, <tt>:column3.to_int</tt> returns an odd integer, so:
340
358
 
341
359
  1 & :column3 # => 1
342
360
 
361
+ You and also use the <tt>Sequel.&</tt> and <tt>Sequel.|</tt> methods:
362
+
363
+ Sequel.&(:column1, :column2) # ("column1" AND "column2")
364
+ Sequel.|({:column1=>1}, {:column2=>2}) # (("column1" = 1) OR ("column2" = 2))
365
+
343
366
  You can use hashes and arrays of two element arrays to specify AND and OR with equality conditions:
344
367
 
345
368
  {:column1=>1, :column2=>2} # (("column1" = 1) AND ("column2" = 2))
346
369
  [[:column1, 1], [:column2, 2]] # (("column1" = 1) AND ("column2" = 2))
347
370
 
348
- As you can see, these literalize with ANDs by default. You can use the +sql_or+ method to use OR instead:
371
+ As you can see, these literalize with ANDs by default. You can use the <tt>Sequel.or</tt> method to use OR instead:
349
372
 
350
- {:column1=>1, :column2=>2}.sql_or # (("column1" = 1) OR ("column2" = 2))
373
+ Sequel.or(:column1=>1, :column2=>2) # (("column1" = 1) OR ("column2" = 2))
351
374
 
352
- You've already seen the +sql_negate+ method, which will use ANDs if multiple entries are used:
375
+ You've already seen the <tt>Sequel.negate</tt> method, which will use ANDs if multiple entries are used:
353
376
 
354
- {:column1=>1, :column2=>2}.sql_negate # (("column1" != 1) AND ("column2" != 2))
377
+ Sequel.negate(:column1=>1, :column2=>2) # (("column1" != 1) AND ("column2" != 2))
355
378
 
356
- To negate while using ORs, the ~ operator can be used:
379
+ To negate while using ORs, the <tt>Sequel.~</tt> operator can be used:
357
380
 
358
- ~{:column1=>1, :column2=>2} # (("column1" != 1) OR ("column2" != 2))
381
+ Sequel.~(:column1=>1, :column2=>2) # (("column1" != 1) OR ("column2" != 2))
359
382
 
360
- Note that <tt>Dataset#exclude</tt> uses ~, not +sql_negate+:
383
+ Note again that <tt>Dataset#exclude</tt> uses ~, not +negate+:
361
384
 
362
385
  DB[:albums].exclude(:column1=>1, :column2=>2) # SELECT * FROM "albums" WHERE (("column" != 1) OR ("column2" != 2))
363
386
 
364
387
  === Casts
365
388
 
366
- Casting in Sequel is done with the +cast+ method, which is available on strings, symbols, and most of the Sequel-specific expression objects:
389
+ Casting in Sequel is done with the +cast+ method, which is available on most of the Sequel-specific expression objects:
367
390
 
368
- :name.cast(:text) # CAST("name" AS text)
369
- '1'.cast(:integer) # CAST('1' AS integer)
370
- :column.qualify(:table).cast(:date) # CAST("table"."column" AS date)
391
+ Sequel.expr(:name).cast(:text) # CAST("name" AS text)
392
+ Sequel.expr('1').cast(:integer) # CAST('1' AS integer)
393
+ Sequel.qualify(:table, :column).cast(:date) # CAST("table"."column" AS date)
371
394
 
372
- === Bitwise Mathematical Operators (& | ^ << >> ~)
395
+ You can also use the <tt>Sequel.cast</tt> method:
373
396
 
374
- Sequel allows the use of bitwise mathematical operators on Sequel::SQL::NumericExpression objects:
397
+ Sequel.cast(:name, :text) # CAST("name" AS text)
375
398
 
376
- :number + 1 # => #<Sequel::SQL::NumericExpression ...>
377
- (:number + 1) & 5 # (("number" + 1) & 5)
399
+ === Bitwise Mathematical Operators (& | ^ << >> ~)
378
400
 
379
- As you can see, when you use the + operator on a symbol, you get a NumericExpression. You can turn a symbol into a NumericExpression using +sql_number+:
401
+ Sequel allows the use of bitwise mathematical operators on Sequel::SQL::NumericExpression objects:
380
402
 
381
- :number.sql_number | 5 # ("number" | 5)
403
+ Sequel.expr(:number) + 1 # => #<Sequel::SQL::NumericExpression ...>
404
+ (Sequel.expr(:number) + 1) & 5 # (("number" + 1) & 5)
382
405
 
383
- +sql_number+ also works on the many other Sequel-specific expression objects:
406
+ As you can see, when you use the + operator on a symbol, you get a NumericExpression. You can turn an expression a NumericExpression using +sql_number+:
384
407
 
385
- :function.sql_function.sql_number << 7 # (function() << 7)
386
- :name.cast(:integer).sql_number >> 8 # (CAST("name" AS integer) >> 8)
408
+ Sequel.expr(:number).sql_number | 5 # ("number" | 5)
409
+ Sequel.function(:func).sql_number << 7 # (func() << 7)
410
+ Sequel.cast(:name, :integer).sql_number >> 8 # (CAST("name" AS integer) >> 8)
387
411
 
388
412
  Sequel allows you to do the cast and conversion at the same time via +cast_numeric+:
389
413
 
390
- :name.cast_numeric ^ 9 # (CAST("name" AS integer) ^ 9)
414
+ Sequel.expr(:name).cast_numeric ^ 9 # (CAST("name" AS integer) ^ 9)
391
415
 
392
- Note that &, |, and ~ are already defined to do AND, OR, and NOT on most objects, so if you want to use the bitwise operators, you need to make sure that they are converted first:
416
+ Note that &, |, and ~ are already defined to do AND, OR, and NOT on most expressions, so if you want to use the bitwise operators, you need to make sure that they are converted first:
393
417
 
394
- ~:name # NOT "name"
395
- ~:name.sql_number # ~"name"
418
+ ~Sequel.expr(:name) # NOT "name"
419
+ ~Sequel.expr(:name).sql_number # ~"name"
396
420
 
397
421
  === String Operators (||, LIKE, Regexp)
398
422
 
399
- Sequel allows the use of the string concatenation operator on Sequel::SQL::StringExpression objects, which can be created using the +sql_string+ method:
423
+ Sequel allows the use of the string concatenation operator on Sequel::SQL::StringExpression objects, which can be created using the +sql_string+ method on an expression:
400
424
 
401
- :name.sql_string + ' - Name' # ("name" || ' - Name')
425
+ Sequel.expr(:name).sql_string + ' - Name' # ("name" || ' - Name')
402
426
 
403
427
  Just like for the bitwise operators, Sequel allows you do do the cast and conversion at the same time via +cast_string+:
404
428
 
405
- :number.cast_string + ' - Number' # (CAST(number AS varchar(255)) || ' - Number')
429
+ Sequel.expr(:number).cast_string + ' - Number' # (CAST(number AS varchar(255)) || ' - Number')
406
430
 
407
431
  Note that similar to the mathematical operators, you cannot switch the order the expression and have it work:
408
432
 
409
- 'Name - ' + :name.sql_string # raises TypeError
433
+ 'Name - ' + Sequel.expr(:name).sql_string # raises TypeError
410
434
 
411
- Just like for the mathematical operators, you can use the +sql_expr+ extension to work around this:
435
+ Just like for the mathematical operators, you can use <tt>Sequel.expr</tt> to wrap the object:
412
436
 
413
- Sequel.extension :sql_expr
414
- 'Name - '.sql_expr + :name # ('Name - ' || "name")
437
+ Sequel.expr('Name - ') + :name # ('Name - ' || "name")
415
438
 
416
- Sequel also adds an <tt>Array#sql_string_join</tt> method, which concatenates all of the elements in the array:
439
+ The <tt>Sequel.join</tt> method concatenates all of the elements in the array:
417
440
 
418
- ['Name', :name].sql_string_join # ('Name' || "name")
441
+ Sequel.join(['Name', :name]) # ('Name' || "name")
419
442
 
420
443
  Just like ruby's <tt>String#join</tt>, you can provide an argument for a string used to join each element:
421
444
 
422
- ['Name', :name].sql_string_join(' - ') # ('Name' || ' - ' || "name")
445
+ Sequel.join(['Name', :name], ' - ') # ('Name' || ' - ' || "name")
446
+
447
+ For the LIKE operator, Sequel defines the +like+ and +ilike+ methods on most Sequel-specific expression objects:
423
448
 
424
- For the LIKE operator, Sequel defines the +like+ and +ilike+ methods on symbol and most Sequel-specific expression objects:
449
+ Sequel.expr(:name).like('A%') # ("name" LIKE 'A%')
450
+ Sequel.expr(:name).ilike('A%') # ("name" ILIKE 'A%')
425
451
 
426
- :name.like('A%') # ("name" LIKE 'A%')
427
- :name.qualify.ilike('A%') # ("name" ILIKE 'A%')
452
+ You can also use the <tt>Sequel.like</tt> and <tt>Sequel.ilike</tt> methods:
428
453
 
429
- Note the above syntax, while Sequel's default, is specific to PostgreSQL. However, most other adapters override the behavior. For example, on MySQL, Sequel uses LIKE BINARY for +like+, and LIKE for +ilike+. If the database supports both case sensitive and case insensitive LIKE, then +like+ will use a case sensitive LIKE, and +ilike+ will use a case insensitive LIKE. Some databases only support case insensitive behavior, in which case +like+ and +ilike+ will act identically.
454
+ Sequel.like(:name, 'A%') # ("name" LIKE 'A%')
455
+ Sequel.ilike(:name, 'A%') # ("name" ILIKE 'A%')
456
+
457
+ Note the above syntax for ilike, while Sequel's default, is specific to PostgreSQL. However, most other adapters override the behavior. For example, on MySQL, Sequel uses LIKE BINARY for +like+, and LIKE for +ilike+. If the database supports both case sensitive and case insensitive LIKE, then +like+ will use a case sensitive LIKE, and +ilike+ will use a case insensitive LIKE.
430
458
 
431
459
  Inverting the LIKE operator works like other inversions:
432
460
 
433
- ~:name.like('A%') # ("name" NOT LIKE 'A%')
461
+ ~Sequel.like(:name, 'A%') # ("name" NOT LIKE 'A%')
434
462
 
435
- Sequel also supports SQL regular expressions on MySQL and PostgreSQL. You can use these by passing a ruby regular expression to the +like+ or +ilike+ method, or by making the regular expression a hash value:
463
+ Sequel also supports SQL regular expressions on MySQL and PostgreSQL. You can use these by passing a ruby regular expression to +like+ or +ilike+, or by making the regular expression a hash value:
436
464
 
437
- :name.like(/^A/) # ("name" ~ '^A')
438
- ~:name.ilike(/^A/) # ("name" !~* '^A')
465
+ Sequel.like(:name, /^A/) # ("name" ~ '^A')
466
+ ~Sequel.ilike(:name, /^A/) # ("name" !~* '^A')
439
467
  {:name=>/^A/i} # ("name" ~* '^A')
440
- ~{:name=>/^A/} # ("name" !~ '^A')
468
+ Sequel.~(:name=>/^A/) # ("name" !~ '^A')
441
469
 
442
470
  Note that using +ilike+ with a regular expression will always make the regexp case insensitive. If you use +like+ or the hash with regexp value, it will only be case insensitive if the Regexp itself is case insensitive.
443
471
 
444
472
  === Order Specifications (ASC, DESC)
445
473
 
446
- Sequel supports specifying ascending or descending order using the +asc+ and +desc+ method on symbols and most Sequel-specific expression objects:
474
+ Sequel supports specifying ascending or descending order using the asc+ and +desc+ method on most Sequel-specific expression objects:
475
+
476
+ Sequel.expr(:column).asc # "column" ASC
477
+ Sequel.expr(:column).qualify(:table).desc # "table"."column" DESC
447
478
 
448
- :column.asc # "column" ASC
449
- :column.qualify(:table).desc # "table"."column" DESC
479
+ You can also use the <tt>Sequel.asc</tt> and <tt>Sequel.desc</tt> methods:
480
+
481
+ Sequel.asc(:column) # "column" ASC
482
+ Sequel.desc(Sequel.expr(:column).qualify(:table)) # "table"."column" DESC
483
+
484
+ On some databases, you can specify null ordering:
485
+
486
+ Sequel.asc(:column, :nulls=>:first) # "column" ASC NULLS FIRST
487
+ Sequel.desc(Sequel.expr(:column).qualify(:table), :nulls=>:last) # "table"."column" DESC NULLS LAST
450
488
 
451
489
  === All Columns (.*)
452
490
 
453
- To select all columns in a table, Sequel supports the * method on symbols without an argument:
491
+ To select all columns in a table, Sequel supports the * method on identifiers without an argument:
454
492
 
455
- :table.* # "table".*
493
+ Sequel.expr(:table).* # "table".*
456
494
 
457
495
  === CASE statements
458
496
 
459
- Sequel allows the easy production of SQL CASE statements using the +case+ method of hashes and arrays of two element arrays. The argument to +case+ is the default value, the keys of the hash (or first element in each array) is the WHEN condition, and the values of the hash (or second element in each array) is the THEN result. Here are some examples:
497
+ Sequel allows the easy production of SQL CASE statements using the <tt>Sequel.case</tt> method. The first argument is a hash or array of two element arrays representing the conditions, the second argument is the default value (ELSE). The keys of the hash (or first element in each array) is the WHEN condition, and the values of the hash (or second element in each array) is the THEN result. Here are some examples:
460
498
 
461
- {:column=>1}.case(0) # (CASE WHEN "column" THEN 1 ELSE 0 END)
462
- [[column, 1]].case(0) # (CASE WHEN "column" THEN 1 ELSE 0 END)
463
- {{:column=>nil}=>1}.case(0) # (CASE WHEN (column IS NULL) THEN 1 ELSE 0 END)
499
+ Sequel.case({:column=>1, 0) # (CASE WHEN "column" THEN 1 ELSE 0 END)
500
+ Sequel.case([[column, 1]], 0) # (CASE WHEN "column" THEN 1 ELSE 0 END)
501
+ Sequel.case({{:column=>nil}=>1}, 0) # (CASE WHEN (column IS NULL) THEN 1 ELSE 0 END)
464
502
 
465
503
  If the hash or array has multiple arguments, multiple WHEN clauses are used:
466
504
 
467
- {:c=>1, :d=>2}.case(0) # (CASE WHEN "c" THEN 1 WHEN "d" THEN 2 ELSE 0 END)
468
- [[:c, 1], [:d, 2]].case(0) # (CASE WHEN "c" THEN 1 WHEN "d" THEN 2 ELSE 0 END)
505
+ Sequel.case({:c=>1, :d=>2}, 0) # (CASE WHEN "c" THEN 1 WHEN "d" THEN 2 ELSE 0 END)
506
+ Sequel.case([[:c, 1], [:d, 2]], 0) # (CASE WHEN "c" THEN 1 WHEN "d" THEN 2 ELSE 0 END)
469
507
 
470
508
  If you provide a 2nd argument to CASE, it goes between CASE and WHEN:
471
509
 
472
- {2=>1, 3=>5}.case(0, :column) # (CASE column WHEN 2 THEN 1 WHEN 3 THEN 5 ELSE 0 END)
510
+ Sequel.case({2=>1, 3=>5}, 0, :column) # (CASE column WHEN 2 THEN 1 WHEN 3 THEN 5 ELSE 0 END)
473
511
 
474
512
  === Subscripts/Array Access ([])
475
513
 
476
- Sequel supports SQL subscripts using the +sql_subscript+ method on symbols and most Sequel-specific expression objects:
514
+ Sequel supports SQL subscripts using the +sql_subscript+ method on most Sequel-specific expression objects:
515
+
516
+ Sequel.expr(:column).sql_subscript(3) # column[3]
517
+ Sequel.expr(:column).qualify(:table).sql_subscript(3) # table.column[3]
518
+
519
+ You can also use the <tt>Sequel.subscript</tt> method:
477
520
 
478
- :column.sql_subscript(3) # column[3]
479
- :column.qualify(:table).sql_subscript(3) # table.column[3]
521
+ Sequel.subscript(:column, 3) # column[3]
480
522
 
481
523
  Just like in SQL, you can use any expression as a subscript:
482
524
 
483
- :column.sql_subscript(:function.sql_function) # column[function()]
525
+ Sequel.subscript(:column, Sequel.function(:func)) # column[func()]
484
526
 
485
527
  == Building Queries in Sequel
486
528
 
@@ -504,12 +546,12 @@ If you don't want to select from any FROM tables, use no arguments:
504
546
 
505
547
  Once you have your dataset object, you build queries by chaining methods, usually with one method per clause in the query:
506
548
 
507
- DB[:albums].select(:id, :name).where(:name.like('A%')).order(:name)
549
+ DB[:albums].select(:id, :name).where(Sequel.like(:name, 'A%')).order(:name)
508
550
  # SELECT id, name FROM albums WHERE (name LIKE 'A%') ORDER BY name
509
551
 
510
552
  Note that the order of your method chain is not usually important unless you have multiple methods that affect the same clause:
511
553
 
512
- DB[:albums].order(:name).where(:name.like('A%')).select(:id, :name)
554
+ DB[:albums].order(:name).where(Sequel.like(:name, 'A%')).select(:id, :name)
513
555
  # SELECT id, name FROM albums WHERE (name LIKE 'A%') ORDER BY name
514
556
 
515
557
  === Using the Same Dataset for SELECT, INSERT, UPDATE, and DELETE
@@ -524,13 +566,13 @@ Also note that while the SELECT clause is displayed when you look at a dataset,
524
566
 
525
567
  In general, the +insert+, +update+, and +delete+ methods use the appropriate clauses you defined on the dataset:
526
568
 
527
- ds = DB[:albums].filter(:id=>1)
569
+ ds = DB[:albums].where(:id=>1)
528
570
  ds.all # SELECT * FROM albums WHERE (id = 1)
529
571
  ds.insert(:name=>'RF') # INSERT INTO albums (name) VALUES ('RF')
530
572
  ds.update(:name=>'RF') # UPDATE albums SET name = 'RF' WHERE (id = 1)
531
573
  ds.delete # DELETE FROM albums WHERE (id = 1)
532
574
 
533
- Note how +update+ and +delete+ used the +filter+ argument, but that +insert+ did not, because INSERT doesn't use a WHERE clause.
575
+ Note how +update+ and +delete+ used the +where+ argument, but that +insert+ did not, because INSERT doesn't use a WHERE clause.
534
576
 
535
577
  === Methods Used for Each SQL Clause
536
578