sequel 3.21.0 → 3.39.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (352) hide show
  1. data/CHANGELOG +1061 -3
  2. data/MIT-LICENSE +1 -1
  3. data/README.rdoc +103 -63
  4. data/Rakefile +59 -27
  5. data/bin/sequel +50 -26
  6. data/doc/active_record.rdoc +67 -51
  7. data/doc/advanced_associations.rdoc +189 -75
  8. data/doc/association_basics.rdoc +327 -79
  9. data/doc/cheat_sheet.rdoc +21 -21
  10. data/doc/core_extensions.rdoc +374 -0
  11. data/doc/dataset_basics.rdoc +10 -10
  12. data/doc/dataset_filtering.rdoc +54 -42
  13. data/doc/mass_assignment.rdoc +56 -0
  14. data/doc/migration.rdoc +89 -557
  15. data/doc/model_hooks.rdoc +80 -29
  16. data/doc/object_model.rdoc +547 -0
  17. data/doc/opening_databases.rdoc +114 -53
  18. data/doc/prepared_statements.rdoc +41 -15
  19. data/doc/querying.rdoc +137 -56
  20. data/doc/reflection.rdoc +36 -10
  21. data/doc/release_notes/3.22.0.txt +39 -0
  22. data/doc/release_notes/3.23.0.txt +172 -0
  23. data/doc/release_notes/3.24.0.txt +420 -0
  24. data/doc/release_notes/3.25.0.txt +88 -0
  25. data/doc/release_notes/3.26.0.txt +88 -0
  26. data/doc/release_notes/3.27.0.txt +82 -0
  27. data/doc/release_notes/3.28.0.txt +304 -0
  28. data/doc/release_notes/3.29.0.txt +459 -0
  29. data/doc/release_notes/3.30.0.txt +135 -0
  30. data/doc/release_notes/3.31.0.txt +146 -0
  31. data/doc/release_notes/3.32.0.txt +202 -0
  32. data/doc/release_notes/3.33.0.txt +157 -0
  33. data/doc/release_notes/3.34.0.txt +671 -0
  34. data/doc/release_notes/3.35.0.txt +144 -0
  35. data/doc/release_notes/3.36.0.txt +245 -0
  36. data/doc/release_notes/3.37.0.txt +338 -0
  37. data/doc/release_notes/3.38.0.txt +234 -0
  38. data/doc/release_notes/3.39.0.txt +237 -0
  39. data/doc/schema_modification.rdoc +585 -0
  40. data/doc/sharding.rdoc +99 -8
  41. data/doc/sql.rdoc +154 -112
  42. data/doc/testing.rdoc +169 -0
  43. data/doc/thread_safety.rdoc +17 -0
  44. data/doc/transactions.rdoc +137 -0
  45. data/doc/validations.rdoc +1 -1
  46. data/doc/virtual_rows.rdoc +78 -43
  47. data/lib/sequel/adapters/ado/mssql.rb +18 -6
  48. data/lib/sequel/adapters/ado.rb +40 -18
  49. data/lib/sequel/adapters/amalgalite.rb +17 -9
  50. data/lib/sequel/adapters/db2.rb +175 -86
  51. data/lib/sequel/adapters/dbi.rb +15 -15
  52. data/lib/sequel/adapters/do/mysql.rb +17 -11
  53. data/lib/sequel/adapters/do/postgres.rb +2 -61
  54. data/lib/sequel/adapters/do/sqlite.rb +0 -10
  55. data/lib/sequel/adapters/do.rb +18 -36
  56. data/lib/sequel/adapters/firebird.rb +27 -208
  57. data/lib/sequel/adapters/ibmdb.rb +453 -0
  58. data/lib/sequel/adapters/informix.rb +6 -23
  59. data/lib/sequel/adapters/jdbc/as400.rb +16 -34
  60. data/lib/sequel/adapters/jdbc/db2.rb +56 -0
  61. data/lib/sequel/adapters/jdbc/derby.rb +325 -0
  62. data/lib/sequel/adapters/jdbc/firebird.rb +24 -0
  63. data/lib/sequel/adapters/jdbc/h2.rb +73 -31
  64. data/lib/sequel/adapters/jdbc/hsqldb.rb +184 -0
  65. data/lib/sequel/adapters/jdbc/informix.rb +21 -0
  66. data/lib/sequel/adapters/jdbc/jtds.rb +40 -0
  67. data/lib/sequel/adapters/jdbc/mssql.rb +3 -33
  68. data/lib/sequel/adapters/jdbc/mysql.rb +7 -24
  69. data/lib/sequel/adapters/jdbc/oracle.rb +88 -25
  70. data/lib/sequel/adapters/jdbc/postgresql.rb +77 -52
  71. data/lib/sequel/adapters/jdbc/progress.rb +21 -0
  72. data/lib/sequel/adapters/jdbc/sqlite.rb +20 -10
  73. data/lib/sequel/adapters/jdbc/sqlserver.rb +66 -0
  74. data/lib/sequel/adapters/jdbc/transactions.rb +83 -0
  75. data/lib/sequel/adapters/jdbc.rb +279 -97
  76. data/lib/sequel/adapters/mock.rb +372 -0
  77. data/lib/sequel/adapters/mysql.rb +125 -222
  78. data/lib/sequel/adapters/mysql2.rb +65 -56
  79. data/lib/sequel/adapters/odbc/mssql.rb +17 -9
  80. data/lib/sequel/adapters/odbc.rb +28 -9
  81. data/lib/sequel/adapters/openbase.rb +3 -5
  82. data/lib/sequel/adapters/oracle.rb +349 -53
  83. data/lib/sequel/adapters/postgres.rb +368 -138
  84. data/lib/sequel/adapters/shared/access.rb +32 -9
  85. data/lib/sequel/adapters/shared/db2.rb +343 -0
  86. data/lib/sequel/adapters/shared/firebird.rb +221 -0
  87. data/lib/sequel/adapters/shared/informix.rb +53 -0
  88. data/lib/sequel/adapters/shared/mssql.rb +401 -116
  89. data/lib/sequel/adapters/shared/mysql.rb +424 -89
  90. data/lib/sequel/adapters/shared/mysql_prepared_statements.rb +155 -0
  91. data/lib/sequel/adapters/shared/oracle.rb +257 -45
  92. data/lib/sequel/adapters/shared/postgres.rb +675 -279
  93. data/lib/sequel/adapters/shared/progress.rb +5 -8
  94. data/lib/sequel/adapters/shared/sqlite.rb +285 -96
  95. data/lib/sequel/adapters/sqlite.rb +101 -39
  96. data/lib/sequel/adapters/swift/mysql.rb +10 -12
  97. data/lib/sequel/adapters/swift/postgres.rb +13 -79
  98. data/lib/sequel/adapters/swift/sqlite.rb +9 -6
  99. data/lib/sequel/adapters/swift.rb +28 -19
  100. data/lib/sequel/adapters/tinytds.rb +174 -22
  101. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +77 -0
  102. data/lib/sequel/adapters/utils/pg_types.rb +81 -0
  103. data/lib/sequel/adapters/utils/stored_procedures.rb +1 -11
  104. data/lib/sequel/ast_transformer.rb +194 -0
  105. data/lib/sequel/connection_pool/sharded_single.rb +11 -1
  106. data/lib/sequel/connection_pool/sharded_threaded.rb +33 -2
  107. data/lib/sequel/connection_pool/single.rb +5 -0
  108. data/lib/sequel/connection_pool/threaded.rb +43 -14
  109. data/lib/sequel/connection_pool.rb +10 -2
  110. data/lib/sequel/core.rb +143 -11
  111. data/lib/sequel/database/connecting.rb +38 -28
  112. data/lib/sequel/database/dataset.rb +4 -4
  113. data/lib/sequel/database/dataset_defaults.rb +63 -2
  114. data/lib/sequel/database/logging.rb +7 -2
  115. data/lib/sequel/database/misc.rb +190 -46
  116. data/lib/sequel/database/query.rb +272 -110
  117. data/lib/sequel/database/schema_generator.rb +103 -36
  118. data/lib/sequel/database/schema_methods.rb +300 -67
  119. data/lib/sequel/dataset/actions.rb +344 -90
  120. data/lib/sequel/dataset/features.rb +101 -8
  121. data/lib/sequel/dataset/graph.rb +42 -15
  122. data/lib/sequel/dataset/misc.rb +52 -25
  123. data/lib/sequel/dataset/mutation.rb +12 -7
  124. data/lib/sequel/dataset/prepared_statements.rb +68 -30
  125. data/lib/sequel/dataset/query.rb +305 -54
  126. data/lib/sequel/dataset/sql.rb +720 -292
  127. data/lib/sequel/dataset.rb +8 -0
  128. data/lib/sequel/exceptions.rb +4 -0
  129. data/lib/sequel/extensions/_pretty_table.rb +83 -0
  130. data/lib/sequel/extensions/arbitrary_servers.rb +109 -0
  131. data/lib/sequel/extensions/blank.rb +4 -0
  132. data/lib/sequel/extensions/columns_introspection.rb +72 -0
  133. data/lib/sequel/extensions/constraint_validations.rb +451 -0
  134. data/lib/sequel/{core_sql.rb → extensions/core_extensions.rb} +30 -46
  135. data/lib/sequel/extensions/eval_inspect.rb +173 -0
  136. data/lib/sequel/extensions/inflector.rb +4 -0
  137. data/lib/sequel/extensions/looser_typecasting.rb +5 -4
  138. data/lib/sequel/extensions/migration.rb +100 -11
  139. data/lib/sequel/extensions/named_timezones.rb +9 -0
  140. data/lib/sequel/extensions/null_dataset.rb +94 -0
  141. data/lib/sequel/extensions/pagination.rb +4 -0
  142. data/lib/sequel/extensions/pg_array.rb +537 -0
  143. data/lib/sequel/extensions/pg_array_ops.rb +263 -0
  144. data/lib/sequel/extensions/pg_auto_parameterize.rb +175 -0
  145. data/lib/sequel/extensions/pg_hstore.rb +313 -0
  146. data/lib/sequel/extensions/pg_hstore_ops.rb +293 -0
  147. data/lib/sequel/extensions/pg_inet.rb +113 -0
  148. data/lib/sequel/extensions/pg_interval.rb +191 -0
  149. data/lib/sequel/extensions/pg_json.rb +208 -0
  150. data/lib/sequel/extensions/pg_range.rb +512 -0
  151. data/lib/sequel/extensions/pg_range_ops.rb +150 -0
  152. data/lib/sequel/extensions/pg_row.rb +572 -0
  153. data/lib/sequel/extensions/pg_row_ops.rb +182 -0
  154. data/lib/sequel/extensions/pg_statement_cache.rb +317 -0
  155. data/lib/sequel/extensions/pretty_table.rb +17 -72
  156. data/lib/sequel/extensions/query.rb +8 -4
  157. data/lib/sequel/extensions/query_literals.rb +79 -0
  158. data/lib/sequel/extensions/schema_caching.rb +76 -0
  159. data/lib/sequel/extensions/schema_dumper.rb +282 -76
  160. data/lib/sequel/extensions/select_remove.rb +39 -0
  161. data/lib/sequel/extensions/server_block.rb +140 -0
  162. data/lib/sequel/extensions/split_array_nil.rb +65 -0
  163. data/lib/sequel/extensions/sql_expr.rb +8 -110
  164. data/lib/sequel/extensions/string_date_time.rb +4 -0
  165. data/lib/sequel/extensions/thread_local_timezones.rb +10 -4
  166. data/lib/sequel/extensions/to_dot.rb +99 -83
  167. data/lib/sequel/model/associations.rb +1263 -409
  168. data/lib/sequel/model/base.rb +624 -171
  169. data/lib/sequel/model/errors.rb +1 -1
  170. data/lib/sequel/model/exceptions.rb +24 -2
  171. data/lib/sequel/model/inflections.rb +1 -1
  172. data/lib/sequel/model.rb +30 -11
  173. data/lib/sequel/no_core_ext.rb +2 -0
  174. data/lib/sequel/plugins/active_model.rb +13 -1
  175. data/lib/sequel/plugins/association_pks.rb +22 -4
  176. data/lib/sequel/plugins/caching.rb +25 -18
  177. data/lib/sequel/plugins/class_table_inheritance.rb +4 -4
  178. data/lib/sequel/plugins/composition.rb +44 -12
  179. data/lib/sequel/plugins/constraint_validations.rb +198 -0
  180. data/lib/sequel/plugins/dataset_associations.rb +100 -0
  181. data/lib/sequel/plugins/defaults_setter.rb +72 -0
  182. data/lib/sequel/plugins/dirty.rb +214 -0
  183. data/lib/sequel/plugins/eager_each.rb +59 -0
  184. data/lib/sequel/plugins/force_encoding.rb +6 -6
  185. data/lib/sequel/plugins/hook_class_methods.rb +1 -1
  186. data/lib/sequel/plugins/identity_map.rb +134 -15
  187. data/lib/sequel/plugins/instance_filters.rb +10 -0
  188. data/lib/sequel/plugins/instance_hooks.rb +1 -1
  189. data/lib/sequel/plugins/json_serializer.rb +58 -6
  190. data/lib/sequel/plugins/list.rb +13 -2
  191. data/lib/sequel/plugins/many_through_many.rb +103 -51
  192. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +71 -0
  193. data/lib/sequel/plugins/nested_attributes.rb +150 -66
  194. data/lib/sequel/plugins/optimistic_locking.rb +8 -0
  195. data/lib/sequel/plugins/pg_row.rb +121 -0
  196. data/lib/sequel/plugins/pg_typecast_on_load.rb +65 -0
  197. data/lib/sequel/plugins/prepared_statements.rb +167 -0
  198. data/lib/sequel/plugins/prepared_statements_associations.rb +87 -0
  199. data/lib/sequel/plugins/prepared_statements_safe.rb +82 -0
  200. data/lib/sequel/plugins/prepared_statements_with_pk.rb +59 -0
  201. data/lib/sequel/plugins/rcte_tree.rb +31 -17
  202. data/lib/sequel/plugins/schema.rb +8 -3
  203. data/lib/sequel/plugins/serialization.rb +98 -49
  204. data/lib/sequel/plugins/serialization_modification_detection.rb +63 -0
  205. data/lib/sequel/plugins/sharding.rb +21 -54
  206. data/lib/sequel/plugins/single_table_inheritance.rb +5 -3
  207. data/lib/sequel/plugins/static_cache.rb +99 -0
  208. data/lib/sequel/plugins/subclasses.rb +29 -3
  209. data/lib/sequel/plugins/tactical_eager_loading.rb +7 -7
  210. data/lib/sequel/plugins/timestamps.rb +1 -1
  211. data/lib/sequel/plugins/tree.rb +3 -3
  212. data/lib/sequel/plugins/typecast_on_load.rb +9 -12
  213. data/lib/sequel/plugins/update_primary_key.rb +2 -2
  214. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  215. data/lib/sequel/plugins/validation_helpers.rb +55 -4
  216. data/lib/sequel/plugins/xml_serializer.rb +15 -4
  217. data/lib/sequel/sql.rb +649 -122
  218. data/lib/sequel/timezones.rb +67 -40
  219. data/lib/sequel/version.rb +1 -1
  220. data/spec/adapters/db2_spec.rb +146 -0
  221. data/spec/adapters/firebird_spec.rb +1 -1
  222. data/spec/adapters/mssql_spec.rb +194 -66
  223. data/spec/adapters/mysql_spec.rb +475 -306
  224. data/spec/adapters/oracle_spec.rb +92 -117
  225. data/spec/adapters/postgres_spec.rb +1982 -325
  226. data/spec/adapters/spec_helper.rb +9 -6
  227. data/spec/adapters/sqlite_spec.rb +203 -75
  228. data/spec/core/connection_pool_spec.rb +218 -93
  229. data/spec/core/database_spec.rb +956 -522
  230. data/spec/core/dataset_spec.rb +1631 -1242
  231. data/spec/core/expression_filters_spec.rb +690 -334
  232. data/spec/core/mock_adapter_spec.rb +453 -0
  233. data/spec/core/object_graph_spec.rb +88 -129
  234. data/spec/core/schema_generator_spec.rb +4 -4
  235. data/spec/core/schema_spec.rb +556 -53
  236. data/spec/core/spec_helper.rb +7 -48
  237. data/spec/core_extensions_spec.rb +626 -0
  238. data/spec/extensions/active_model_spec.rb +13 -0
  239. data/spec/extensions/arbitrary_servers_spec.rb +110 -0
  240. data/spec/extensions/association_autoreloading_spec.rb +18 -10
  241. data/spec/extensions/association_dependencies_spec.rb +15 -25
  242. data/spec/extensions/association_pks_spec.rb +66 -32
  243. data/spec/extensions/association_proxies_spec.rb +4 -4
  244. data/spec/extensions/boolean_readers_spec.rb +25 -25
  245. data/spec/extensions/caching_spec.rb +47 -51
  246. data/spec/extensions/class_table_inheritance_spec.rb +31 -83
  247. data/spec/extensions/columns_introspection_spec.rb +91 -0
  248. data/spec/extensions/composition_spec.rb +18 -13
  249. data/spec/extensions/constraint_validations_plugin_spec.rb +196 -0
  250. data/spec/extensions/constraint_validations_spec.rb +316 -0
  251. data/spec/extensions/dataset_associations_spec.rb +199 -0
  252. data/spec/extensions/defaults_setter_spec.rb +88 -0
  253. data/spec/extensions/dirty_spec.rb +155 -0
  254. data/spec/extensions/eager_each_spec.rb +34 -0
  255. data/spec/extensions/eval_inspect_spec.rb +67 -0
  256. data/spec/extensions/force_encoding_spec.rb +4 -2
  257. data/spec/extensions/hook_class_methods_spec.rb +97 -128
  258. data/spec/extensions/identity_map_spec.rb +142 -24
  259. data/spec/extensions/inflector_spec.rb +0 -4
  260. data/spec/extensions/instance_filters_spec.rb +11 -21
  261. data/spec/extensions/instance_hooks_spec.rb +72 -0
  262. data/spec/extensions/json_serializer_spec.rb +49 -12
  263. data/spec/extensions/lazy_attributes_spec.rb +16 -20
  264. data/spec/extensions/list_spec.rb +49 -40
  265. data/spec/extensions/looser_typecasting_spec.rb +7 -7
  266. data/spec/extensions/many_through_many_spec.rb +368 -254
  267. data/spec/extensions/many_to_one_pk_lookup_spec.rb +140 -0
  268. data/spec/extensions/migration_spec.rb +140 -35
  269. data/spec/extensions/named_timezones_spec.rb +29 -11
  270. data/spec/extensions/nested_attributes_spec.rb +268 -89
  271. data/spec/extensions/null_dataset_spec.rb +85 -0
  272. data/spec/extensions/optimistic_locking_spec.rb +24 -21
  273. data/spec/extensions/pg_array_ops_spec.rb +112 -0
  274. data/spec/extensions/pg_array_spec.rb +320 -0
  275. data/spec/extensions/pg_auto_parameterize_spec.rb +65 -0
  276. data/spec/extensions/pg_hstore_ops_spec.rb +140 -0
  277. data/spec/extensions/pg_hstore_spec.rb +194 -0
  278. data/spec/extensions/pg_inet_spec.rb +47 -0
  279. data/spec/extensions/pg_interval_spec.rb +72 -0
  280. data/spec/extensions/pg_json_spec.rb +99 -0
  281. data/spec/extensions/pg_range_ops_spec.rb +56 -0
  282. data/spec/extensions/pg_range_spec.rb +395 -0
  283. data/spec/extensions/pg_row_ops_spec.rb +58 -0
  284. data/spec/extensions/pg_row_plugin_spec.rb +49 -0
  285. data/spec/extensions/pg_row_spec.rb +323 -0
  286. data/spec/extensions/pg_statement_cache_spec.rb +208 -0
  287. data/spec/extensions/pg_typecast_on_load_spec.rb +58 -0
  288. data/spec/extensions/prepared_statements_associations_spec.rb +111 -0
  289. data/spec/extensions/prepared_statements_safe_spec.rb +61 -0
  290. data/spec/extensions/prepared_statements_spec.rb +87 -0
  291. data/spec/extensions/prepared_statements_with_pk_spec.rb +31 -0
  292. data/spec/extensions/pretty_table_spec.rb +7 -6
  293. data/spec/extensions/query_literals_spec.rb +167 -0
  294. data/spec/extensions/query_spec.rb +9 -3
  295. data/spec/extensions/rcte_tree_spec.rb +50 -43
  296. data/spec/extensions/schema_caching_spec.rb +41 -0
  297. data/spec/extensions/schema_dumper_spec.rb +434 -49
  298. data/spec/extensions/schema_spec.rb +30 -49
  299. data/spec/extensions/select_remove_spec.rb +38 -0
  300. data/spec/extensions/serialization_modification_detection_spec.rb +72 -0
  301. data/spec/extensions/serialization_spec.rb +86 -48
  302. data/spec/extensions/server_block_spec.rb +90 -0
  303. data/spec/extensions/sharding_spec.rb +69 -143
  304. data/spec/extensions/single_table_inheritance_spec.rb +23 -29
  305. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  306. data/spec/extensions/spec_helper.rb +34 -67
  307. data/spec/extensions/split_array_nil_spec.rb +24 -0
  308. data/spec/extensions/sql_expr_spec.rb +29 -60
  309. data/spec/extensions/static_cache_spec.rb +145 -0
  310. data/spec/extensions/subclasses_spec.rb +14 -0
  311. data/spec/extensions/tactical_eager_loading_spec.rb +17 -19
  312. data/spec/extensions/thread_local_timezones_spec.rb +22 -2
  313. data/spec/extensions/timestamps_spec.rb +6 -6
  314. data/spec/extensions/to_dot_spec.rb +8 -11
  315. data/spec/extensions/touch_spec.rb +13 -14
  316. data/spec/extensions/tree_spec.rb +11 -26
  317. data/spec/extensions/typecast_on_load_spec.rb +9 -6
  318. data/spec/extensions/update_primary_key_spec.rb +30 -24
  319. data/spec/extensions/validation_class_methods_spec.rb +58 -67
  320. data/spec/extensions/validation_helpers_spec.rb +31 -37
  321. data/spec/extensions/xml_serializer_spec.rb +29 -4
  322. data/spec/files/transaction_specified_migrations/001_create_alt_basic.rb +4 -0
  323. data/spec/files/transaction_specified_migrations/002_create_basic.rb +4 -0
  324. data/spec/files/transaction_unspecified_migrations/001_create_alt_basic.rb +3 -0
  325. data/spec/files/transaction_unspecified_migrations/002_create_basic.rb +3 -0
  326. data/spec/integration/associations_test.rb +659 -21
  327. data/spec/integration/database_test.rb +11 -5
  328. data/spec/integration/dataset_test.rb +717 -129
  329. data/spec/integration/eager_loader_test.rb +38 -54
  330. data/spec/integration/migrator_test.rb +2 -3
  331. data/spec/integration/model_test.rb +81 -2
  332. data/spec/integration/plugin_test.rb +604 -147
  333. data/spec/integration/prepared_statement_test.rb +272 -128
  334. data/spec/integration/schema_test.rb +367 -57
  335. data/spec/integration/spec_helper.rb +42 -32
  336. data/spec/integration/timezone_test.rb +38 -12
  337. data/spec/integration/transaction_test.rb +183 -8
  338. data/spec/integration/type_test.rb +31 -8
  339. data/spec/model/association_reflection_spec.rb +207 -8
  340. data/spec/model/associations_spec.rb +1206 -693
  341. data/spec/model/base_spec.rb +334 -100
  342. data/spec/model/dataset_methods_spec.rb +45 -27
  343. data/spec/model/eager_loading_spec.rb +828 -692
  344. data/spec/model/hooks_spec.rb +355 -67
  345. data/spec/model/model_spec.rb +251 -179
  346. data/spec/model/plugins_spec.rb +24 -13
  347. data/spec/model/record_spec.rb +506 -232
  348. data/spec/model/spec_helper.rb +16 -77
  349. data/spec/model/validations_spec.rb +38 -2
  350. data/spec/rcov.opts +2 -0
  351. metadata +209 -80
  352. data/spec/core/core_sql_spec.rb +0 -451
@@ -0,0 +1,173 @@
1
+ # The eval_inspect extension changes #inspect for Sequel::SQL::Expression
2
+ # subclasses to return a string suitable for ruby's eval, such that
3
+ #
4
+ # eval(obj.inspect) == obj
5
+ #
6
+ # is true. The above code is true for most of ruby's simple classes such
7
+ # as String, Integer, Float, and Symbol, but it's not true for classes such
8
+ # as Time, Date, and BigDecimal. Sequel attempts to handle situations where
9
+ # instances of these classes are a component of a Sequel expression.
10
+ #
11
+ # To load the extension:
12
+ #
13
+ # Sequel.extension :eval_inspect
14
+
15
+ module Sequel
16
+ module EvalInspect
17
+ # Special case objects where inspect does not generally produce input
18
+ # suitable for eval. Used by Sequel::SQL::Expression#inspect so that
19
+ # it can produce a string suitable for eval even if components of the
20
+ # expression have inspect methods that do not produce strings suitable
21
+ # for eval.
22
+ def eval_inspect(obj)
23
+ case obj
24
+ when Sequel::SQL::Blob, Sequel::LiteralString, Sequel::SQL::ValueList
25
+ "#{obj.class}.new(#{obj.inspect})"
26
+ when Array
27
+ "[#{obj.map{|o| eval_inspect(o)}.join(', ')}]"
28
+ when Hash
29
+ "{#{obj.map{|k, v| "#{eval_inspect(k)} => #{eval_inspect(v)}"}.join(', ')}}"
30
+ when Time
31
+ datepart = "%Y-%m-%dT" unless obj.is_a?(Sequel::SQLTime)
32
+ if RUBY_VERSION < '1.9'
33
+ # Time on 1.8 doesn't handle %N (or %z on Windows), manually set the usec value in the string
34
+ hours, mins = obj.utc_offset.divmod(3600)
35
+ mins /= 60
36
+ "#{obj.class}.parse(#{obj.strftime("#{datepart}%H:%M:%S.#{sprintf('%06i%+03i%02i', obj.usec, hours, mins)}").inspect})#{'.utc' if obj.utc?}"
37
+ else
38
+ "#{obj.class}.parse(#{obj.strftime("#{datepart}%T.%N%z").inspect})#{'.utc' if obj.utc?}"
39
+ end
40
+ when DateTime
41
+ # Ignore date of calendar reform
42
+ "DateTime.parse(#{obj.strftime('%FT%T.%N%z').inspect})"
43
+ when Date
44
+ # Ignore offset and date of calendar reform
45
+ "Date.new(#{obj.year}, #{obj.month}, #{obj.day})"
46
+ when BigDecimal
47
+ "BigDecimal.new(#{obj.to_s.inspect})"
48
+ else
49
+ obj.inspect
50
+ end
51
+ end
52
+ end
53
+
54
+ extend EvalInspect
55
+
56
+ module SQL
57
+ class Expression
58
+ # Attempt to produce a string suitable for eval, such that:
59
+ #
60
+ # eval(obj.inspect) == obj
61
+ def inspect
62
+ # Assume by default that the object can be recreated by calling
63
+ # self.class.new with any attr_reader values defined on the class,
64
+ # in the order they were defined.
65
+ klass = self.class
66
+ args = inspect_args.map do |arg|
67
+ if arg.is_a?(String) && arg =~ /\A\*/
68
+ # Special case string arguments starting with *, indicating that
69
+ # they should return an array to be splatted as the remaining arguments
70
+ send(arg.sub('*', '')).map{|a| Sequel.eval_inspect(a)}.join(', ')
71
+ else
72
+ Sequel.eval_inspect(send(arg))
73
+ end
74
+ end
75
+ "#{klass}.new(#{args.join(', ')})"
76
+ end
77
+
78
+ private
79
+
80
+ # Which attribute values to use in the inspect string.
81
+ def inspect_args
82
+ self.class.comparison_attrs
83
+ end
84
+ end
85
+
86
+ class ComplexExpression
87
+ private
88
+
89
+ # ComplexExpression's initializer uses a splat for the operator arguments.
90
+ def inspect_args
91
+ [:op, "*args"]
92
+ end
93
+ end
94
+
95
+ class Constant
96
+ # Constants to lookup in the Sequel module.
97
+ INSPECT_LOOKUPS = [:CURRENT_DATE, :CURRENT_TIMESTAMP, :CURRENT_TIME, :SQLTRUE, :SQLFALSE, :NULL, :NOTNULL]
98
+
99
+ # Reference the constant in the Sequel module if there is
100
+ # one that matches.
101
+ def inspect
102
+ INSPECT_LOOKUPS.each do |c|
103
+ return "Sequel::#{c}" if Sequel.const_get(c) == self
104
+ end
105
+ super
106
+ end
107
+ end
108
+
109
+ class CaseExpression
110
+ private
111
+
112
+ # CaseExpression's initializer checks whether an argument was
113
+ # provided, to differentiate CASE WHEN from CASE NULL WHEN, so
114
+ # check if an expression was provided, and only include the
115
+ # expression in the inspect output if so.
116
+ def inspect_args
117
+ if expression?
118
+ [:conditions, :default, :expression]
119
+ else
120
+ [:conditions, :default]
121
+ end
122
+ end
123
+ end
124
+
125
+ class Function
126
+ private
127
+
128
+ # Function's initializer uses a splat for the function arguments.
129
+ def inspect_args
130
+ [:f, "*args"]
131
+ end
132
+ end
133
+
134
+ class JoinOnClause
135
+ private
136
+
137
+ # JoinOnClause's initializer takes the on argument as the first argument
138
+ # instead of the last.
139
+ def inspect_args
140
+ [:on, :join_type, :table, :table_alias]
141
+ end
142
+ end
143
+
144
+ class JoinUsingClause
145
+ private
146
+
147
+ # JoinOnClause's initializer takes the using argument as the first argument
148
+ # instead of the last.
149
+ def inspect_args
150
+ [:using, :join_type, :table, :table_alias]
151
+ end
152
+ end
153
+
154
+ class OrderedExpression
155
+ private
156
+
157
+ # OrderedExpression's initializer takes the :nulls information inside a hash,
158
+ # so if a NULL order was given, include a hash with that information.
159
+ def inspect_args
160
+ if nulls
161
+ [:expression, :descending, :opts_hash]
162
+ else
163
+ [:expression, :descending]
164
+ end
165
+ end
166
+
167
+ # A hash of null information suitable for passing to the initializer.
168
+ def opts_hash
169
+ {:nulls=>nulls}
170
+ end
171
+ end
172
+ end
173
+ end
@@ -2,6 +2,10 @@
2
2
  # words from singular to plural, class names to table names, modularized class
3
3
  # names to ones without, and class names to foreign keys. It exists for
4
4
  # backwards compatibility to legacy Sequel code.
5
+ #
6
+ # To load the extension:
7
+ #
8
+ # Sequel.extension :inflector
5
9
 
6
10
  class String
7
11
  # This module acts as a singleton returned/yielded by String.inflections,
@@ -1,10 +1,8 @@
1
1
  # The LooserTypecasting extension changes the float and integer typecasting to
2
2
  # use the looser .to_f and .to_i instead of the more strict Kernel.Float and
3
- # Kernel.Integer. To use it, you should extend the database with the
4
- # Sequel::LooserTypecasting module after loading the extension:
3
+ # Kernel.Integer. To load the extension into the database:
5
4
  #
6
- # Sequel.extension :looser_typecasting
7
- # DB.extend(Sequel::LooserTypecasting)
5
+ # DB.extension :looser_typecasting
8
6
 
9
7
  module Sequel
10
8
  module LooserTypecasting
@@ -18,4 +16,7 @@ module Sequel
18
16
  value.to_i
19
17
  end
20
18
  end
19
+
20
+ Database.register_extension(:looser_typecasting, LooserTypecasting)
21
21
  end
22
+
@@ -1,6 +1,10 @@
1
1
  # Adds the Sequel::Migration and Sequel::Migrator classes, which allow
2
2
  # the user to easily group schema changes and migrate the database
3
3
  # to a newer version or revert to a previous version.
4
+ #
5
+ # To load the extension:
6
+ #
7
+ # Sequel.extension :migration
4
8
 
5
9
  module Sequel
6
10
  # Sequel's older migration class, available for backward compatibility.
@@ -21,7 +25,7 @@ module Sequel
21
25
  #
22
26
  # Part of the +migration+ extension.
23
27
  class Migration
24
- # Creates a new instance of the migration and sets the @db attribute.
28
+ # Set the database associated with this migration.
25
29
  def initialize(db)
26
30
  @db = db
27
31
  end
@@ -42,6 +46,11 @@ module Sequel
42
46
  def self.inherited(base)
43
47
  descendants << base
44
48
  end
49
+
50
+ # Don't allow transaction overriding in old migrations.
51
+ def self.use_transactions
52
+ nil
53
+ end
45
54
 
46
55
  # The default down action does nothing
47
56
  def down
@@ -68,6 +77,15 @@ module Sequel
68
77
  # Proc used for the up action
69
78
  attr_accessor :up
70
79
 
80
+ # Whether to use transactions for this migration, default depends on the
81
+ # database.
82
+ attr_accessor :use_transactions
83
+
84
+ # Don't set transaction use by default.
85
+ def initialize
86
+ @use_transactions = nil
87
+ end
88
+
71
89
  # Apply the appropriate block on the +Database+
72
90
  # instance using instance_eval.
73
91
  def apply(db, direction)
@@ -99,6 +117,16 @@ module Sequel
99
117
  migration.down = block
100
118
  end
101
119
 
120
+ # Disable the use of transactions for the related migration
121
+ def no_transaction
122
+ migration.use_transactions = false
123
+ end
124
+
125
+ # Enable the use of transactions for the related migration
126
+ def transaction
127
+ migration.use_transactions = true
128
+ end
129
+
102
130
  # Defines the migration's up action.
103
131
  def up(&block)
104
132
  migration.up = block
@@ -165,6 +193,10 @@ module Sequel
165
193
  @actions << [:alter_table, table, MigrationAlterTableReverser.new.reverse(&block)]
166
194
  end
167
195
 
196
+ def create_join_table(*args)
197
+ @actions << [:drop_join_table, *args]
198
+ end
199
+
168
200
  def create_table(*args)
169
201
  @actions << [:drop_table, args.first]
170
202
  end
@@ -302,7 +334,7 @@ module Sequel
302
334
  #
303
335
  # Part of the +migration+ extension.
304
336
  class Migrator
305
- MIGRATION_FILE_PATTERN = /\A\d+_.+\.rb\z/i.freeze
337
+ MIGRATION_FILE_PATTERN = /\A(\d+)_.+\.rb\z/i.freeze
306
338
  MIGRATION_SPLITTER = '_'.freeze
307
339
  MINIMUM_TIMESTAMP = 20000101
308
340
 
@@ -311,11 +343,28 @@ module Sequel
311
343
  class Error < Sequel::Error
312
344
  end
313
345
 
346
+ # Exception class raised when Migrator.check_current signals that it is
347
+ # not current.
348
+ class NotCurrentError < Error
349
+ end
350
+
314
351
  # Wrapper for +run+, maintaining backwards API compatibility
315
352
  def self.apply(db, directory, target = nil, current = nil)
316
353
  run(db, directory, :target => target, :current => current)
317
354
  end
318
355
 
356
+ # Raise a NotCurrentError unless the migrator is current, takes the same
357
+ # arguments as #run.
358
+ def self.check_current(*args)
359
+ raise(NotCurrentError, 'migrator is not current') unless is_current?(*args)
360
+ end
361
+
362
+ # Return whether the migrator is current (i.e. it does not need to make
363
+ # any changes). Takes the same arguments as #run.
364
+ def self.is_current?(db, directory, opts={})
365
+ migrator_class(directory).new(db, directory, opts).is_current?
366
+ end
367
+
319
368
  # Migrates the supplied database using the migration files in the the specified directory. Options:
320
369
  # * :column :: The column in the :table argument storing the migration version (default: :version).
321
370
  # * :current :: The current version of the database. If not given, it is retrieved from the database
@@ -336,11 +385,15 @@ module Sequel
336
385
  # if the version number appears to be a unix time integer for a year
337
386
  # after 2005, otherwise uses the IntegerMigrator.
338
387
  def self.migrator_class(directory)
339
- Dir.new(directory).each do |file|
340
- next unless MIGRATION_FILE_PATTERN.match(file)
341
- return TimestampMigrator if file.split(MIGRATION_SPLITTER, 2).first.to_i > MINIMUM_TIMESTAMP
388
+ if self.equal?(Migrator)
389
+ Dir.new(directory).each do |file|
390
+ next unless MIGRATION_FILE_PATTERN.match(file)
391
+ return TimestampMigrator if file.split(MIGRATION_SPLITTER, 2).first.to_i > MINIMUM_TIMESTAMP
392
+ end
393
+ IntegerMigrator
394
+ else
395
+ self
342
396
  end
343
- IntegerMigrator
344
397
  end
345
398
  private_class_method :migrator_class
346
399
 
@@ -375,13 +428,35 @@ module Sequel
375
428
  @db = db
376
429
  @directory = directory
377
430
  @files = get_migration_files
378
- @table = opts[:table] || self.class.const_get(:DEFAULT_SCHEMA_TABLE)
431
+ schema, table = @db.send(:schema_and_table, opts[:table] || self.class.const_get(:DEFAULT_SCHEMA_TABLE))
432
+ @table = schema ? Sequel::SQL::QualifiedIdentifier.new(schema, table) : table
379
433
  @column = opts[:column] || self.class.const_get(:DEFAULT_SCHEMA_COLUMN)
380
434
  @ds = schema_dataset
435
+ @use_transactions = opts[:use_transactions]
381
436
  end
382
437
 
383
438
  private
384
439
 
440
+ # If transactions should be used for the migration, yield to the block
441
+ # inside a transaction. Otherwise, just yield to the block.
442
+ def checked_transaction(migration, &block)
443
+ use_trans = if @use_transactions.nil?
444
+ if migration.use_transactions.nil?
445
+ @db.supports_transactional_ddl?
446
+ else
447
+ migration.use_transactions
448
+ end
449
+ else
450
+ @use_transactions
451
+ end
452
+
453
+ if use_trans
454
+ db.transaction(&block)
455
+ else
456
+ yield
457
+ end
458
+ end
459
+
385
460
  # Remove all migration classes. Done by the migrator to ensure that
386
461
  # the correct migration classes are picked up.
387
462
  def remove_migration_classes
@@ -423,19 +498,24 @@ module Sequel
423
498
  @current = opts[:current] || current_migration_version
424
499
 
425
500
  raise(Error, "No current version available") unless current
426
- raise(Error, "No target version available") unless target
501
+ raise(Error, "No target version available, probably because no migration files found or filenames don't follow the migration filename convention") unless target
427
502
 
428
503
  @direction = current < target ? :up : :down
429
504
  @migrations = get_migrations
430
505
  end
431
506
 
507
+ # The integer migrator is current if the current version is the same as the target version.
508
+ def is_current?
509
+ current_migration_version == target
510
+ end
511
+
432
512
  # Apply all migrations on the database
433
513
  def run
434
514
  migrations.zip(version_numbers).each do |m, v|
435
515
  t = Time.now
436
516
  lv = up? ? v : v + 1
437
517
  db.log_info("Begin applying migration version #{lv}, direction: #{direction}")
438
- db.transaction do
518
+ checked_transaction(m) do
439
519
  m.apply(db, direction)
440
520
  set_migration_version(v)
441
521
  end
@@ -459,6 +539,9 @@ module Sequel
459
539
  Dir.new(directory).each do |file|
460
540
  next unless MIGRATION_FILE_PATTERN.match(file)
461
541
  version = migration_version_from_file(file)
542
+ if version >= 20000101
543
+ raise Migrator::Error, "Migration number too large, must use TimestampMigrator: #{file}"
544
+ end
462
545
  raise(Error, "Duplicate migration version: #{version}") if files[version]
463
546
  files[version] = File.join(directory, file)
464
547
  end
@@ -543,12 +626,18 @@ module Sequel
543
626
  @migration_tuples = get_migration_tuples
544
627
  end
545
628
 
629
+ # The timestamp migrator is current if there are no migrations to apply
630
+ # in either direction.
631
+ def is_current?
632
+ migration_tuples.empty?
633
+ end
634
+
546
635
  # Apply all migration tuples on the database
547
636
  def run
548
637
  migration_tuples.each do |m, f, direction|
549
638
  t = Time.now
550
639
  db.log_info("Begin applying migration #{f}, direction: #{direction}")
551
- db.transaction do
640
+ checked_transaction(m) do
552
641
  m.apply(db, direction)
553
642
  fi = f.downcase
554
643
  direction == :up ? ds.insert(column=>fi) : ds.filter(column=>fi).delete
@@ -588,7 +677,7 @@ module Sequel
588
677
  next unless MIGRATION_FILE_PATTERN.match(file)
589
678
  files << File.join(directory, file)
590
679
  end
591
- files.sort
680
+ files.sort_by{|f| MIGRATION_FILE_PATTERN.match(File.basename(f))[1].to_i}
592
681
  end
593
682
 
594
683
  # Returns tuples of migration, filename, and direction
@@ -8,6 +8,10 @@
8
8
  # typecast_timezone=. If a string is passed, it is converted to a
9
9
  # TZInfo::Timezone using TZInfo::Timezone.get.
10
10
  #
11
+ # To load the extension:
12
+ #
13
+ # Sequel.extension :named_timezones
14
+ #
11
15
  # Let's say you have the database server in New York and the
12
16
  # application server in Los Angeles. For historical reasons, data
13
17
  # is stored in local New York time, but the application server only
@@ -21,6 +25,11 @@
21
25
  # Then, before data is stored in the database, it is converted to New
22
26
  # York time. When data is retrieved from the database, it is
23
27
  # converted to Los Angeles time.
28
+ #
29
+ # Note that typecasting from the database timezone to the application
30
+ # timezone when fetching rows is dependent on the database adapter,
31
+ # and only works on adapters where Sequel itself does the conversion.
32
+ # It should work on mysql, postgres, sqlite, ibmdb, and jdbc.
24
33
 
25
34
  require 'tzinfo'
26
35
 
@@ -0,0 +1,94 @@
1
+ # The null_dataset extension adds the Dataset#nullify method, which
2
+ # returns a cloned dataset that will never issue a query to the
3
+ # database. It implements the null object pattern for datasets.
4
+ #
5
+ # To load the extension:
6
+ #
7
+ # Sequel.extension :null_dataset
8
+ #
9
+ # The most common usage is probably in a method that must return
10
+ # a dataset, where the method knows the dataset shouldn't return
11
+ # anything. With standard Sequel, you'd probably just add a
12
+ # WHERE condition that is always false, but that still results
13
+ # in a query being sent to the database, and can be overridden
14
+ # using #unfiltered, the OR operator, or a UNION.
15
+ #
16
+ # Usage:
17
+ #
18
+ # ds = DB[:items].nullify.where(:a=>:b).select(:c)
19
+ # ds.sql # => "SELECT c FROM items WHERE (a = b)"
20
+ # ds.all # => [] # no query sent to the database
21
+ #
22
+ # Note that there is one case where a null dataset will sent
23
+ # a query to the database. If you call #columns on a nulled
24
+ # dataset and the dataset doesn't have an already cached
25
+ # version of the columns, it will create a new dataset with
26
+ # the same options to get the columns.
27
+
28
+ module Sequel
29
+ class Dataset
30
+ module NullDataset
31
+ # Create a new dataset from the dataset (which won't
32
+ # be nulled) to get the columns if they aren't already cached.
33
+ def columns
34
+ @columns ||= db.dataset(@opts).columns
35
+ end
36
+
37
+ # Return 0 without sending a database query.
38
+ def delete
39
+ 0
40
+ end
41
+
42
+ # Return self without sending a database query, never yielding.
43
+ def each
44
+ self
45
+ end
46
+
47
+ # Return nil without sending a database query, never yielding.
48
+ def fetch_rows(sql)
49
+ nil
50
+ end
51
+
52
+ # Return nil without sending a database query.
53
+ def insert(*)
54
+ nil
55
+ end
56
+
57
+ # Return nil without sending a database query.
58
+ def truncate
59
+ nil
60
+ end
61
+
62
+ # Return 0 without sending a database query.
63
+ def update(v={})
64
+ 0
65
+ end
66
+
67
+ protected
68
+
69
+ # Return nil without sending a database query.
70
+ def _import(columns, values, opts)
71
+ nil
72
+ end
73
+
74
+ private
75
+
76
+ # Just in case these are called directly by some internal code,
77
+ # make them noops. There's nothing we can do if the db
78
+ # is accessed directly to make a change, though.
79
+ (%w'_ddl _dui _insert' << '').each do |m|
80
+ class_eval("private; def execute#{m}(sql, opts={}) end", __FILE__, __LINE__)
81
+ end
82
+ end
83
+
84
+ # Return a cloned nullified dataset.
85
+ def nullify
86
+ clone.nullify!
87
+ end
88
+
89
+ # Nullify the current dataset
90
+ def nullify!
91
+ extend NullDataset
92
+ end
93
+ end
94
+ end
@@ -1,6 +1,10 @@
1
1
  # The pagination extension adds the Sequel::Dataset#paginate and #each_page methods,
2
2
  # which return paginated (limited and offset) datasets with some helpful methods
3
3
  # that make creating a paginated display easier.
4
+ #
5
+ # To load the extension:
6
+ #
7
+ # Sequel.extension :pagination
4
8
 
5
9
  module Sequel
6
10
  class Dataset