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/MIT-LICENSE CHANGED
@@ -1,5 +1,5 @@
1
1
  Copyright (c) 2007-2008 Sharon Rosner
2
- Copyright (c) 2008-2011 Jeremy Evans
2
+ Copyright (c) 2008-2012 Jeremy Evans
3
3
 
4
4
  Permission is hereby granted, free of charge, to any person obtaining a copy
5
5
  of this software and associated documentation files (the "Software"), to
data/README.rdoc CHANGED
@@ -11,16 +11,17 @@ toolkit for Ruby.
11
11
  statements, bound variables, stored procedures, savepoints,
12
12
  two-phase commit, transaction isolation, master/slave
13
13
  configurations, and database sharding.
14
- * Sequel currently has adapters for ADO, Amalgalite, DataObjects,
15
- DB2, DBI, Firebird, Informix, JDBC, MySQL, Mysql2, ODBC, OpenBase,
16
- Oracle, PostgreSQL, SQLite3, Swift, and TinyTDS.
14
+ * Sequel currently has adapters for ADO, Amalgalite, CUBRID,
15
+ DataObjects, DB2, DBI, Firebird, IBM_DB, Informix, JDBC, MySQL,
16
+ Mysql2, ODBC, OpenBase, Oracle, PostgreSQL, SQLite3, Swift, and
17
+ TinyTDS.
17
18
 
18
19
  == Resources
19
20
 
20
21
  * {Website}[http://sequel.rubyforge.org]
21
22
  * {Blog}[http://sequel.heroku.com]
22
23
  * {Source code}[http://github.com/jeremyevans/sequel]
23
- * {Bug tracking}[http://code.google.com/p/ruby-sequel/issues/list]
24
+ * {Bug tracking}[http://github.com/jeremyevans/sequel/issues]
24
25
  * {Google group}[http://groups.google.com/group/sequel-talk]
25
26
  * {RDoc}[http://sequel.rubyforge.org/rdoc]
26
27
 
@@ -64,12 +65,14 @@ If you have any comments or suggestions please post to the Google group.
64
65
 
65
66
  == The Sequel Console
66
67
 
67
- Sequel includes an IRB console for quick access to databases. You can use it like this:
68
+ Sequel includes an IRB console for quick access to databases (usually referred to as <tt>bin/sequel</tt>). You can use it like this:
68
69
 
69
70
  sequel sqlite://test.db # test.db in current directory
70
71
 
71
72
  You get an IRB session with the database object stored in DB.
72
73
 
74
+ In addition to providing an IRB shell (the default behavior), bin/sequel also has support for migrating databases, dumping schema migrations, and copying databases. See the {bin/sequel guide}[link:files/doc/bin_sequel_rdoc.html] for more details.
75
+
73
76
  == An Introduction
74
77
 
75
78
  Sequel is designed to take the hassle away from connecting to databases and manipulating them. Sequel deals with all the boring stuff like maintaining connections, formatting SQL correctly and fetching records so you can concentrate on your application.
@@ -91,11 +94,11 @@ Since datasets retrieve records only when needed, they can be stored and later r
91
94
 
92
95
  Sequel also offers convenience methods for extracting data from Datasets, such as an extended +map+ method:
93
96
 
94
- middle_east.map(:name) #=> ['Egypt', 'Greece', 'Israel', ...]
97
+ middle_east.map(:name) #=> ['Egypt', 'Turkey', 'Israel', ...]
95
98
 
96
99
  Or getting results as a hash via +to_hash+, with one column as key and another as value:
97
100
 
98
- middle_east.to_hash(:name, :area) #=> {'Israel' => 20000, 'Greece' => 120000, ...}
101
+ middle_east.to_hash(:name, :area) #=> {'Israel' => 20000, 'Turkey' => 120000, ...}
99
102
 
100
103
  == Getting Started
101
104
 
@@ -169,7 +172,7 @@ You can also iterate through records one at a time using +each+:
169
172
 
170
173
  Or perform more advanced stuff:
171
174
 
172
- names_and_dates = posts.map{|r| [r[:name], r[:date]]}
175
+ names_and_dates = posts.map([:name, :date])
173
176
  old_posts, recent_posts = posts.partition{|r| r[:date] < Date.today - 7}
174
177
 
175
178
  You can also retrieve the first record in a dataset:
@@ -189,29 +192,29 @@ If the dataset is ordered, you can also ask for the last record:
189
192
 
190
193
  === Filtering Records
191
194
 
192
- An easy way to filter records is to provide a hash of values to match to +filter+:
195
+ An easy way to filter records is to provide a hash of values to match to +where+:
193
196
 
194
- my_posts = posts.filter(:category => 'ruby', :author => 'david')
197
+ my_posts = posts.where(:category => 'ruby', :author => 'david')
195
198
  # WHERE category = 'ruby' AND author = 'david'
196
199
 
197
200
  You can also specify ranges:
198
201
 
199
- my_posts = posts.filter(:stamp => (Date.today - 14)..(Date.today - 7))
202
+ my_posts = posts.where(:stamp => (Date.today - 14)..(Date.today - 7))
200
203
  # WHERE stamp >= '2010-06-30' AND stamp <= '2010-07-07'
201
204
 
202
205
  Or arrays of values:
203
206
 
204
- my_posts = posts.filter(:category => ['ruby', 'postgres', 'linux'])
207
+ my_posts = posts.where(:category => ['ruby', 'postgres', 'linux'])
205
208
  # WHERE category IN ('ruby', 'postgres', 'linux')
206
209
 
207
210
  Sequel also accepts expressions:
208
211
 
209
- my_posts = posts.filter{stamp > Date.today << 1}
212
+ my_posts = posts.where{stamp > Date.today << 1}
210
213
  # WHERE stamp > '2010-06-14'
211
214
 
212
215
  Some adapters will also let you specify Regexps:
213
216
 
214
- my_posts = posts.filter(:category => /ruby/i)
217
+ my_posts = posts.where(:category => /ruby/i)
215
218
  # WHERE category ~* 'ruby'
216
219
 
217
220
  You can also use an inverse filter via +exclude+:
@@ -221,32 +224,31 @@ You can also use an inverse filter via +exclude+:
221
224
 
222
225
  You can also specify a custom WHERE clause using a string:
223
226
 
224
- posts.filter('stamp IS NOT NULL')
227
+ posts.where('stamp IS NOT NULL')
225
228
  # WHERE stamp IS NOT NULL
226
229
 
227
230
  You can use parameters in your string, as well:
228
231
 
229
232
  author_name = 'JKR'
230
- posts.filter('(stamp < ?) AND (author != ?)', Date.today - 3, author_name)
233
+ posts.where('(stamp < ?) AND (author != ?)', Date.today - 3, author_name)
231
234
  # WHERE (stamp < '2010-07-11') AND (author != 'JKR')
232
- posts.filter{(stamp < Date.today - 3) & ~{:author => author_name}} # same as above
233
235
 
234
236
  Datasets can also be used as subqueries:
235
237
 
236
- DB[:items].filter('price > ?', DB[:items].select{avg(price) + 100})
238
+ DB[:items].where('price > ?', DB[:items].select{avg(price) + 100})
237
239
  # WHERE price > (SELECT avg(price) + 100 FROM items)
238
240
 
239
- After filtering you can retrieve the matching records by using any of the retrieval methods:
241
+ After filtering, you can retrieve the matching records by using any of the retrieval methods:
240
242
 
241
243
  my_posts.each{|row| p row}
242
244
 
243
- See the doc/dataset_filtering.rdoc file for more details.
245
+ See the {Dataset Filtering}[link:files/doc/dataset_filtering_rdoc.html] file for more details.
244
246
 
245
247
  === Summarizing Records
246
248
 
247
249
  Counting records is easy using +count+:
248
250
 
249
- posts.filter(:category.like('%ruby%')).count
251
+ posts.where(:category.like('%ruby%')).count
250
252
  # SELECT COUNT(*) FROM posts WHERE category LIKE '%ruby%'
251
253
 
252
254
  And you can also query maximum/minimum values via +max+ and +min+:
@@ -273,7 +275,7 @@ Ordering datasets is simple using +order+:
273
275
  posts.order(:stamp, :name)
274
276
  # ORDER BY stamp, name
275
277
 
276
- Chaining +order+ doesn't work the same as +filter+:
278
+ Chaining +order+ doesn't work the same as +where+:
277
279
 
278
280
  posts.order(:stamp).order(:name)
279
281
  # ORDER BY name
@@ -283,10 +285,27 @@ The +order_append+ method chains this way, though:
283
285
  posts.order(:stamp).order_append(:name)
284
286
  # ORDER BY stamp, name
285
287
 
288
+ The +order_prepend+ method can be used as well:
289
+
290
+ posts.order(:stamp).order_prepend(:name)
291
+ # ORDER BY name, stamp
292
+
286
293
  You can also specify descending order:
287
294
 
288
- posts.order(:stamp.desc)
295
+ posts.reverse_order(:stamp)
289
296
  # ORDER BY stamp DESC
297
+ posts.order(Sequel.desc(:stamp))
298
+ # ORDER BY stamp DESC
299
+
300
+ === Core Extensions
301
+
302
+ Note the use of <tt>Sequel.desc(:stamp)</tt> in the above example. Much of Sequel's DSL uses this style, calling methods on the Sequel module that return SQL expression objects. Sequel also ships with a {core_extensions extension}[link:files/doc/core_extensions_rdoc.html]) that integrates Sequel's DSL better into the ruby language, allowing you to write:
303
+
304
+ :stamp.desc
305
+
306
+ instead of:
307
+
308
+ Sequel.desc(:stamp)
290
309
 
291
310
  === Selecting Columns
292
311
 
@@ -297,7 +316,7 @@ Selecting specific columns to be returned is also simple using +select+:
297
316
  posts.select(:stamp, :name)
298
317
  # SELECT stamp, name FROM posts
299
318
 
300
- Chaining +select+ works like +order+, not +filter+:
319
+ Chaining +select+ works like +order+, not +where+:
301
320
 
302
321
  posts.select(:stamp).select(:name)
303
322
  # SELECT name FROM posts
@@ -311,16 +330,16 @@ As you might expect, there is an +order_append+ equivalent for +select+ called +
311
330
 
312
331
  Deleting records from the table is done with +delete+:
313
332
 
314
- posts.filter('stamp < ?', Date.today - 3).delete
333
+ posts.where('stamp < ?', Date.today - 3).delete
315
334
  # DELETE FROM posts WHERE stamp < '2010-07-11'
316
335
 
317
336
  Be very careful when deleting, as +delete+ affects all rows in the dataset.
318
- +filter+ first, +delete+ second, unless you want to empty the table:
337
+ Call +where+ first and +delete+ second:
319
338
 
320
339
  # DO THIS:
321
- posts.filter('stamp < ?', Date.today - 7).delete
340
+ posts.where('stamp < ?', Date.today - 7).delete
322
341
  # NOT THIS:
323
- posts.delete.filter('stamp < ?', Date.today - 7)
342
+ posts.delete.where('stamp < ?', Date.today - 7)
324
343
 
325
344
  === Inserting Records
326
345
 
@@ -333,21 +352,21 @@ Inserting records into the table is done with +insert+:
333
352
 
334
353
  Updating records in the table is done with +update+:
335
354
 
336
- posts.filter('stamp < ?', Date.today - 7).update(:state => 'archived')
355
+ posts.where('stamp < ?', Date.today - 7).update(:state => 'archived')
337
356
  # UPDATE posts SET state = 'archived' WHERE stamp < '2010-07-07'
338
357
 
339
358
  You can reference table columns when choosing what values to set:
340
359
 
341
- posts.filter{|o| o.stamp < Date.today - 7}.update(:backup_number => :backup_number + 1)
360
+ posts.where{|o| o.stamp < Date.today - 7}.update(:backup_number => :backup_number + 1)
342
361
  # UPDATE posts SET backup_number = backup_number + 1 WHERE stamp < '2010-07-07'
343
362
 
344
- As with +delete+, +update+ affects all rows in the dataset, so +filter+ first,
345
- +update+ second, unless you want to update all rows:
363
+ As with +delete+, +update+ affects all rows in the dataset, so +where+ first,
364
+ +update+ second:
346
365
 
347
366
  # DO THIS:
348
- posts.filter('stamp < ?', Date.today - 7).update(:state => 'archived')
367
+ posts.where('stamp < ?', Date.today - 7).update(:state => 'archived')
349
368
  # NOT THIS:
350
- posts.update(:state => 'archived').filter('stamp < ?', Date.today - 7)
369
+ posts.update(:state => 'archived').where('stamp < ?', Date.today - 7)
351
370
 
352
371
  === Transactions
353
372
 
@@ -355,7 +374,7 @@ You can wrap some code in a database transaction using the <tt>Database#transact
355
374
 
356
375
  DB.transaction do
357
376
  posts.insert(:category => 'ruby', :author => 'david')
358
- posts.filter('stamp < ?', Date.today - 7).update(:state => 'archived')
377
+ posts.where('stamp < ?', Date.today - 7).update(:state => 'archived')
359
378
  end
360
379
 
361
380
  If the block does not raise an exception, the transaction will be committed.
@@ -376,11 +395,15 @@ and not raise an exception outside the block, you can raise the
376
395
  Sequel makes it easy to join tables:
377
396
 
378
397
  order_items = DB[:items].join(:order_items, :item_id => :id).
379
- filter(:order_items__order_id => 1234)
398
+ where(:order_items__order_id => 1234)
380
399
  # SELECT * FROM items INNER JOIN order_items
381
400
  # ON order_items.item_id = items.id
382
401
  # WHERE order_items.order_id = 1234
383
402
 
403
+ The important thing to note here is that item_id is automatically qualified with
404
+ the table being joined, and id is automatically qualified with the last table
405
+ joined.
406
+
384
407
  You can then do anything you like with the dataset:
385
408
 
386
409
  order_total = order_items.sum(:price)
@@ -404,14 +427,14 @@ Using +graph+, you can split the result hashes into subhashes, one per join:
404
427
 
405
428
  Sequel expects column names to be specified using symbols. In addition, returned hashes always use symbols as their keys. This allows you to freely mix literal values and column references in many cases. For example, the two following lines produce equivalent SQL:
406
429
 
407
- items.filter(:x => 1)
430
+ items.where(:x => 1)
408
431
  # SELECT * FROM items WHERE (x = 1)
409
- items.filter(1 => :x)
432
+ items.where(1 => :x)
410
433
  # SELECT * FROM items WHERE (1 = x)"
411
434
 
412
435
  Ruby strings are generally treated as SQL strings:
413
436
 
414
- items.filter(:x => 'x')
437
+ items.where(:x => 'x')
415
438
  # SELECT * FROM items WHERE (x = 'x')
416
439
 
417
440
  === Qualifying column names
@@ -421,9 +444,9 @@ Column references can be qualified by using the double underscore special notati
421
444
  items.literal(:items__price)
422
445
  # items.price
423
446
 
424
- Another way to qualify columns is to use the +qualify+ method:
447
+ Another way to qualify columns is to use the <tt>Sequel.qualify</tt> method:
425
448
 
426
- items.literal(:price.qualify(:items))
449
+ items.literal(Sequel.qualify(:items, :price))
427
450
  # items.price
428
451
 
429
452
  === Column aliases
@@ -435,9 +458,9 @@ You can also alias columns by using the triple undersecore special notation <tt>
435
458
  items.literal(:items__price___p)
436
459
  # items.price AS p
437
460
 
438
- Another way to alias columns is to use the +as+ method:
461
+ Another way to alias columns is to use the <tt>Sequel.as</tt> method:
439
462
 
440
- items.literal(:price.as(:p))
463
+ items.literal(Sequel.as(:price, :p))
441
464
  # price AS p
442
465
 
443
466
  == Sequel Models
@@ -463,7 +486,7 @@ You can explicitly set the table name or even the dataset used:
463
486
 
464
487
  If you call +set_dataset+ with a symbol, it assumes you are referring to the table with the same name. You can also call it with a dataset, which will set the defaults for all retrievals for that model:
465
488
 
466
- Post.set_dataset DB[:my_posts].filter(:category => 'ruby')
489
+ Post.set_dataset DB[:my_posts].where(:category => 'ruby')
467
490
  Post.set_dataset DB[:my_posts].select(:id, :name).order(:date)
468
491
 
469
492
  === Model instances
@@ -498,12 +521,12 @@ A single model instance can also be fetched by specifying a condition:
498
521
 
499
522
  A model class lets you iterate over subsets of records by proxying many methods to the underlying dataset. This means that you can use most of the +Dataset+ API to create customized queries that return model instances, e.g.:
500
523
 
501
- Post.filter(:category => 'ruby').each{|post| p post}
524
+ Post.where(:category => 'ruby').each{|post| p post}
502
525
 
503
526
  You can also manipulate the records in the dataset:
504
527
 
505
- Post.filter{num_comments < 7}.delete
506
- Post.filter(:title.like(/ruby/)).update(:category => 'ruby')
528
+ Post.where{num_comments < 7}.delete
529
+ Post.where(Sequel.like(:title, /ruby/)).update(:category => 'ruby')
507
530
 
508
531
  === Accessing record values
509
532
 
@@ -521,10 +544,12 @@ If the record's attributes names are not valid columns in the model's dataset (m
521
544
  post[:id] #=> 123
522
545
  post[:title] #=> 'hello world'
523
546
 
524
- You can also modify record values using attribute setters or the +set+ method:
547
+ You can also modify record values using attribute setters, the <tt>[]=</tt> method, or the +set+ method:
525
548
 
526
549
  post.title = 'hey there'
527
550
  # or
551
+ post[:title] = 'hey there'
552
+ # or
528
553
  post.set(:title=>'hey there')
529
554
 
530
555
  That will just change the value for the object, it will not update the row in the database. To update the database row, call the +save+ method:
@@ -573,7 +598,7 @@ You can execute custom code when creating, updating, or deleting records by defi
573
598
 
574
599
  Note the use of +super+ if you define your own hook methods. Almost all <tt>Sequel::Model</tt> class and instance methods (not just hook methods) can be overridden safely, but you have to make sure to call +super+ when doing so, otherwise you risk breaking things.
575
600
 
576
- For the example above, you should probably use a database trigger if you can. Hooks can be used for data integrity, but they will only enforce that integrity when you are modifying the database through model instances. If you plan on allowing any other access to the database, it's best to use database triggers for data integrity.
601
+ For the example above, you should probably use a database trigger if you can. Hooks can be used for data integrity, but they will only enforce that integrity when you are modifying the database through model instances, and even then they are often subject to race conditions. It's best to use database triggers and constraints to enforce data integrity.
577
602
 
578
603
  === Deleting records
579
604
 
@@ -584,8 +609,8 @@ You can delete individual records by calling +delete+ or +destroy+. The only dif
584
609
 
585
610
  Records can also be deleted en-masse by calling <tt>Model.delete</tt> and <tt>Model.destroy</tt>. As stated above, you can specify filters for the deleted records:
586
611
 
587
- Post.filter(:category => 32).delete # => bypasses hooks
588
- Post.filter(:category => 32).destroy # => runs hooks
612
+ Post.where(:category => 32).delete # => bypasses hooks
613
+ Post.where(:category => 32).destroy # => runs hooks
589
614
 
590
615
  Please note that if <tt>Model.destroy</tt> is called, each record is deleted
591
616
  separately, but <tt>Model.delete</tt> deletes all matching records with a single
@@ -630,7 +655,7 @@ All associations add a dataset method that can be used to further filter or reor
630
655
  post.comments_dataset.destroy
631
656
 
632
657
  # Return all tags related to this post with no subscribers, ordered by the tag's name
633
- post.tags_dataset.filter(:subscribers=>0).order(:name).all
658
+ post.tags_dataset.where(:subscribers=>0).order(:name).all
634
659
 
635
660
  === Eager Loading
636
661
 
@@ -661,7 +686,7 @@ Associations can be eagerly loaded via +eager+ and the <tt>:eager</tt> associati
661
686
  Post.eager(:person).all
662
687
 
663
688
  # eager is a dataset method, so it works with filters/orders/limits/etc.
664
- Post.filter{topic > 'M'}.order(:date).limit(5).eager(:person).all
689
+ Post.where{topic > 'M'}.order(:date).limit(5).eager(:person).all
665
690
 
666
691
  person = Person.first
667
692
  # Eager loading via :eager (will eagerly load the tags for this person's posts)
@@ -681,9 +706,23 @@ Associations can be eagerly loaded via +eager+ and the <tt>:eager</tt> associati
681
706
  # Loads all people, their posts, their posts' tags, replies to those posts,
682
707
  # the person for each reply, the tag for each reply, and all posts and
683
708
  # replies that have that tag. Uses a total of 8 queries.
684
- Person.eager(:posts=>{:replies=>[:person, {:tags=>{:posts, :replies}}]}).all
709
+ Person.eager(:posts=>{:replies=>[:person, {:tags=>[:posts, :replies]}]}).all
710
+
711
+ In addition to using +eager+, you can also use +eager_graph+, which will use a single query to get the object and all associated objects. This may be necessary if you want to filter or order the result set based on columns in associated tables. It works with cascading as well, the API is very similar. Note that using +eager_graph+ to eagerly load multiple <tt>*_to_many</tt> associations will cause the result set to be a cartesian product, so you should be very careful with your filters when using it in that case.
712
+
713
+ You can dynamically customize the eagerly loaded dataset by using using a proc. This proc is passed the dataset used for eager loading, and should return a modified copy of that dataset:
714
+
715
+ # Eagerly load only replies containing 'foo'
716
+ Post.eager(:replies=>proc{|ds| ds.where(Sequel.like(text, '%foo%'))}).all
717
+
718
+ This also works when using +eager_graph+, in which case the proc is called with dataset to graph into the current dataset:
685
719
 
686
- In addition to using +eager+, you can also use +eager_graph+, which will use a single query to get the object and all associated objects. This may be necessary if you want to filter or order the result set based on columns in associated tables. It works with cascading as well, the syntax is exactly the same. Note that using eager_graph to eagerly load multiple *_to_many associations will cause the result set to be a cartesian product, so you should be very careful with your filters when using it in that case.
720
+ Post.eager_graph(:replies=>proc{|ds| ds.where(Sequel.like(text, '%foo%'))}).all
721
+
722
+ You can dynamically customize eager loads for both +eager+ and +eager_graph+ while also cascading, by making the value a single entry hash with the proc as a key, and the cascaded associations as the value:
723
+
724
+ # Eagerly load only replies containing 'foo', and the person and tags for those replies
725
+ Post.eager(:replies=>{proc{|ds| ds.where(Sequel.like(text, '%foo%'))}=>[:person, :tags]}).all
687
726
 
688
727
  === Extending the underlying dataset
689
728
 
@@ -691,7 +730,7 @@ The obvious way to add table-wide logic is to define class methods to the model
691
730
 
692
731
  class Post < Sequel::Model
693
732
  def self.posts_with_few_comments
694
- filter{num_comments < 30}
733
+ where{num_comments < 30}
695
734
  end
696
735
 
697
736
  def self.clean_posts_with_few_comments
@@ -699,27 +738,29 @@ The obvious way to add table-wide logic is to define class methods to the model
699
738
  end
700
739
  end
701
740
 
702
- You can also implement table-wide logic by defining methods on the dataset using +def_dataset_method+:
741
+ You can also implement table-wide logic by defining methods on the dataset using +dataset_module+:
703
742
 
704
743
  class Post < Sequel::Model
705
- def_dataset_method(:posts_with_few_comments) do
706
- filter{num_comments < 30}
707
- end
708
-
709
- def_dataset_method(:clean_posts_with_few_comments) do
710
- posts_with_few_comments.delete
744
+ dataset_module do
745
+ def posts_with_few_comments
746
+ where{num_comments < 30}
747
+ end
748
+
749
+ def clean_posts_with_few_comments
750
+ posts_with_few_comments.delete
751
+ end
711
752
  end
712
753
  end
713
754
 
714
755
  This is the recommended way of implementing table-wide operations, and allows you to have access to your model API from filtered datasets as well:
715
756
 
716
- Post.filter(:category => 'ruby').clean_posts_with_few_comments
757
+ Post.where(:category => 'ruby').clean_posts_with_few_comments
717
758
 
718
759
  Sequel models also provide a +subset+ class method that creates a dataset method with a simple filter:
719
760
 
720
761
  class Post < Sequel::Model
721
762
  subset(:posts_with_few_comments){num_comments < 30}
722
- subset :invisible, ~:visible
763
+ subset :invisible, Sequel.~(:visible)
723
764
  end
724
765
 
725
766
  === Model Validations
data/Rakefile CHANGED
@@ -1,11 +1,5 @@
1
1
  require "rake"
2
2
  require "rake/clean"
3
- require "rake/gempackagetask"
4
- begin
5
- require "hanna/rdoctask"
6
- rescue LoadError
7
- require "rake/rdoctask"
8
- end
9
3
 
10
4
  NAME = 'sequel'
11
5
  VERS = lambda do
@@ -13,34 +7,47 @@ VERS = lambda do
13
7
  Sequel.version
14
8
  end
15
9
  CLEAN.include ["**/.*.sw?", "sequel-*.gem", ".config", "rdoc", "coverage", "www/public/*.html", "www/public/rdoc*", '**/*.rbc']
16
- RDOC_DEFAULT_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', 'Sequel: The Database Toolkit for Ruby']
17
- RDOC_OPTS = RDOC_DEFAULT_OPTS + ['--main', 'README.rdoc']
10
+ SUDO = ENV['SUDO'] || 'sudo'
18
11
 
19
12
  # Gem Packaging and Release
20
13
 
21
14
  desc "Packages sequel"
22
15
  task :package=>[:clean] do |p|
23
- sh %{gem build sequel.gemspec}
16
+ load './sequel.gemspec'
17
+ Gem::Builder.new(SEQUEL_GEMSPEC).build
24
18
  end
25
19
 
26
20
  desc "Install sequel gem"
27
21
  task :install=>[:package] do
28
- sh %{sudo gem install ./#{NAME}-#{VERS.call} --local}
22
+ sh %{#{SUDO} gem install ./#{NAME}-#{VERS.call} --local}
29
23
  end
30
24
 
31
25
  desc "Uninstall sequel gem"
32
26
  task :uninstall=>[:clean] do
33
- sh %{sudo gem uninstall #{NAME}}
27
+ sh %{#{SUDO} gem uninstall #{NAME}}
34
28
  end
35
29
 
36
30
  desc "Upload sequel gem to gemcutter"
37
31
  task :release=>[:package] do
38
- sh %{gem push ./#{NAME}-#{VERS.call}.gem}
32
+ sh %{gem push ./#{NAME}-#{VERS.call}.gem}
39
33
  end
40
34
 
41
35
  ### RDoc
42
36
 
43
- Rake::RDocTask.new do |rdoc|
37
+ RDOC_DEFAULT_OPTS = ["--quiet", "--line-numbers", "--inline-source", '--title', 'Sequel: The Database Toolkit for Ruby']
38
+
39
+ rdoc_task_class = begin
40
+ require "rdoc/task"
41
+ RDOC_DEFAULT_OPTS.concat(['-f', 'hanna'])
42
+ RDoc::Task
43
+ rescue LoadError
44
+ require "rake/rdoctask"
45
+ Rake::RDocTask
46
+ end
47
+
48
+ RDOC_OPTS = RDOC_DEFAULT_OPTS + ['--main', 'README.rdoc']
49
+
50
+ rdoc_task_class.new do |rdoc|
44
51
  rdoc.rdoc_dir = "rdoc"
45
52
  rdoc.options += RDOC_OPTS
46
53
  rdoc.rdoc_files.add %w"README.rdoc CHANGELOG MIT-LICENSE lib/**/*.rb doc/*.rdoc doc/release_notes/*.txt"
@@ -50,25 +57,25 @@ end
50
57
 
51
58
  desc "Make local version of website"
52
59
  task :website do
53
- sh %{www/make_www.rb}
60
+ sh %{#{FileUtils::RUBY} www/make_www.rb}
54
61
  end
55
62
 
56
63
  desc "Make rdoc for website"
57
64
  task :website_rdoc=>[:website_rdoc_main, :website_rdoc_adapters, :website_rdoc_plugins]
58
65
 
59
- Rake::RDocTask.new(:website_rdoc_main) do |rdoc|
66
+ rdoc_task_class.new(:website_rdoc_main) do |rdoc|
60
67
  rdoc.rdoc_dir = "www/public/rdoc"
61
68
  rdoc.options += RDOC_OPTS
62
69
  rdoc.rdoc_files.add %w"README.rdoc CHANGELOG MIT-LICENSE lib/*.rb lib/sequel/*.rb lib/sequel/{connection_pool,dataset,database,model}/*.rb doc/*.rdoc doc/release_notes/*.txt lib/sequel/extensions/migration.rb"
63
70
  end
64
71
 
65
- Rake::RDocTask.new(:website_rdoc_adapters) do |rdoc|
72
+ rdoc_task_class.new(:website_rdoc_adapters) do |rdoc|
66
73
  rdoc.rdoc_dir = "www/public/rdoc-adapters"
67
74
  rdoc.options += RDOC_DEFAULT_OPTS + %w'--main Sequel'
68
75
  rdoc.rdoc_files.add %w"lib/sequel/adapters/**/*.rb"
69
76
  end
70
77
 
71
- Rake::RDocTask.new(:website_rdoc_plugins) do |rdoc|
78
+ rdoc_task_class.new(:website_rdoc_plugins) do |rdoc|
72
79
  rdoc.rdoc_dir = "www/public/rdoc-plugins"
73
80
  rdoc.options += RDOC_DEFAULT_OPTS + %w'--main Sequel'
74
81
  rdoc.rdoc_files.add %w"lib/sequel/{extensions,plugins}/**/*.rb"
@@ -92,11 +99,13 @@ begin
92
99
  require "spec/rake/spectask"
93
100
  spec_class = Spec::Rake::SpecTask
94
101
  spec_files_meth = :spec_files=
102
+ spec_opts_meth = :spec_opts=
95
103
  rescue LoadError
96
104
  # RSpec 2
97
105
  require "rspec/core/rake_task"
98
106
  spec_class = RSpec::Core::RakeTask
99
107
  spec_files_meth = :pattern=
108
+ spec_opts_meth = :rspec_opts=
100
109
  end
101
110
 
102
111
  spec = lambda do |name, files, d|
@@ -105,26 +114,49 @@ begin
105
114
  desc d
106
115
  spec_class.new(name) do |t|
107
116
  t.send spec_files_meth, files
108
- t.spec_opts = ENV['SEQUEL_SPEC_OPTS'].split if ENV['SEQUEL_SPEC_OPTS']
117
+ t.send spec_opts_meth, ENV['SEQUEL_SPEC_OPTS'].split if ENV['SEQUEL_SPEC_OPTS']
109
118
  end
110
119
  end
111
120
 
112
- spec_with_cov = lambda do |name, files, d|
121
+ spec_with_cov = lambda do |name, files, d, &b|
113
122
  spec.call(name, files, d)
114
123
  t = spec.call("#{name}_cov", files, "#{d} with coverage")
115
124
  t.rcov = true
116
125
  t.rcov_opts = File.read("spec/rcov.opts").split("\n")
126
+ b.call(t) if b
127
+ t
117
128
  end
118
-
129
+
119
130
  task :default => [:spec]
120
- spec_with_cov.call("spec", Dir["spec/{core,model}/*_spec.rb"], "Run core and model specs")
131
+ spec_with_cov.call("spec", Dir["spec/{core,model}/*_spec.rb"], "Run core and model specs"){|t| t.rcov_opts.concat(%w'--exclude "lib/sequel/(adapters/([a-ln-z]|m[a-np-z])|extensions/core_extensions)"')}
121
132
  spec.call("spec_core", Dir["spec/core/*_spec.rb"], "Run core specs")
122
133
  spec.call("spec_model", Dir["spec/model/*_spec.rb"], "Run model specs")
123
- spec_with_cov.call("spec_plugin", Dir["spec/extensions/*_spec.rb"], "Run extension/plugin specs")
134
+ spec.call("_spec_model_no_assoc", Dir["spec/model/*_spec.rb"].delete_if{|f| f =~ /association|eager_loading/}, '')
135
+ spec_with_cov.call("spec_core_ext", ["spec/core_extensions_spec.rb"], "Run core extensions specs"){|t| t.rcov_opts.concat(%w'--exclude "lib/sequel/([a-z_]+\.rb|adapters|connection_pool|database|dataset|model)"')}
136
+ spec_with_cov.call("spec_plugin", Dir["spec/extensions/*_spec.rb"], "Run extension/plugin specs"){|t| t.rcov_opts.concat(%w'--exclude "lib/sequel/([a-z_]+\.rb|adapters|connection_pool|database|dataset|model)"')}
124
137
  spec_with_cov.call("spec_integration", Dir["spec/integration/*_test.rb"], "Run integration tests")
125
-
126
- %w'postgres sqlite mysql informix oracle firebird mssql'.each do |adapter|
127
- spec_with_cov.call("spec_#{adapter}", ["spec/adapters/#{adapter}_spec.rb"] + Dir["spec/integration/*_test.rb"], "Run #{adapter} specs")
138
+
139
+ %w'postgres sqlite mysql informix oracle firebird mssql db2'.each do |adapter|
140
+ spec_with_cov.call("spec_#{adapter}", ["spec/adapters/#{adapter}_spec.rb"] + Dir["spec/integration/*_test.rb"], "Run #{adapter} specs"){|t| t.rcov_opts.concat(%w'--exclude "lib/sequel/([a-z_]+\.rb|connection_pool|database|dataset|model|extensions|plugins)"')}
141
+ end
142
+
143
+ task :spec_travis=>[:spec, :spec_plugin, :spec_core_ext, :spec_sqlite] do
144
+ if defined?(RUBY_ENGINE) && RUBY_ENGINE == 'jruby'
145
+ ENV['SEQUEL_PG_SPEC_DB'] = "jdbc:postgresql://localhost/sequel_test?user=postgres"
146
+ ENV['SEQUEL_MY_SPEC_DB'] = "jdbc:mysql://localhost/sequel_test?user=root"
147
+ else
148
+ ENV['SEQUEL_PG_SPEC_DB'] = "postgres://localhost/sequel_test?user=postgres"
149
+ ENV['SEQUEL_MY_SPEC_DB'] = "mysql2://localhost/sequel_test?user=root"
150
+ end
151
+
152
+ Rake::Task['spec_postgres'].invoke
153
+ Rake::Task['spec_mysql'].invoke
154
+ end
155
+
156
+ desc "Run model specs without the associations code"
157
+ task :spec_model_no_assoc do
158
+ ENV['SEQUEL_NO_ASSOCIATIONS'] = '1'
159
+ Rake::Task['_spec_model_no_assoc'].invoke
128
160
  end
129
161
  rescue LoadError
130
162
  task :default do
@@ -142,7 +174,7 @@ end
142
174
  desc "Report code statistics (KLOCs, etc) from the application"
143
175
  task :stats do
144
176
  STATS_DIRECTORIES = [%w(Code lib/), %w(Spec spec)].map{|name, dir| [ name, "./#{dir}" ] }.select { |name, dir| File.directory?(dir)}
145
- require "extra/stats"
177
+ require "./extra/stats"
146
178
  verbose = true
147
179
  CodeStatistics.new(*STATS_DIRECTORIES).to_s
148
180
  end
@@ -154,5 +186,5 @@ end
154
186
 
155
187
  desc "Check syntax of all .rb files"
156
188
  task :check_syntax do
157
- Dir['**/*.rb'].each{|file| print `#{ENV['RUBY'] || :ruby} -c #{file} | fgrep -v "Syntax OK"`}
189
+ Dir['**/*.rb'].each{|file| print `#{FileUtils::RUBY} -c #{file} | fgrep -v "Syntax OK"`}
158
190
  end