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
@@ -0,0 +1,113 @@
1
+ # The pg_inet extension adds support for Sequel to handle
2
+ # PostgreSQL's inet and cidr types using ruby's IPAddr class.
3
+ #
4
+ # This extension integrates with Sequel's native postgres adapter, so
5
+ # that when inet/cidr fields are retrieved, they are returned as
6
+ # IPAddr instances
7
+ #
8
+ # After loading the extension, you should extend your dataset
9
+ # with a module so that it correctly handles the inet/cidr type:
10
+ #
11
+ # DB.extension :pg_inet
12
+ #
13
+ # If you are not using the native postgres adapter, you probably
14
+ # also want to use the typecast_on_load plugin in the model, and
15
+ # set it to typecast the inet/cidr column(s) on load.
16
+ #
17
+ # This extension integrates with the pg_array extension. If you plan
18
+ # to use the inet[] or cidr[] types, load the pg_array extension before
19
+ # the pg_inet extension:
20
+ #
21
+ # DB.extension :pg_array, :pg_inet
22
+ #
23
+ # This extension does not add special support for the macaddr
24
+ # type. Ruby doesn't have a stdlib class that represents mac
25
+ # addresses, so these will still be returned as strings. The exception
26
+ # to this is that the pg_array extension integration will recognize
27
+ # macaddr[] types return them as arrays of strings.
28
+
29
+ require 'ipaddr'
30
+ Sequel.require 'adapters/utils/pg_types'
31
+
32
+ module Sequel
33
+ module Postgres
34
+ # Methods enabling Database object integration with the inet/cidr types.
35
+ module InetDatabaseMethods
36
+
37
+ # Reset the conversion procs when extending the Database object, so
38
+ # it will pick up the inet/cidr converter. Also, extend the datasets
39
+ # with support for literalizing the IPAddr types.
40
+ def self.extended(db)
41
+ db.extend_datasets(InetDatasetMethods)
42
+ end
43
+
44
+ # Convert an IPAddr arg to a string. Probably not necessary, but done
45
+ # for safety.
46
+ def bound_variable_arg(arg, conn)
47
+ case arg
48
+ when IPAddr
49
+ "#{arg.to_s}/#{arg.instance_variable_get(:@mask_addr).to_s(2).count('1')}"
50
+ else
51
+ super
52
+ end
53
+ end
54
+
55
+ # Make the column type detection recognize the inet and cidr types.
56
+ def schema_column_type(db_type)
57
+ case db_type
58
+ when 'inet', 'cidr'
59
+ :ipaddr
60
+ else
61
+ super
62
+ end
63
+ end
64
+
65
+ private
66
+
67
+ # Handle inet[]/cidr[] types in bound variables.
68
+ def bound_variable_array(a)
69
+ case a
70
+ when IPAddr
71
+ "\"#{a.to_s}/#{a.instance_variable_get(:@mask_addr).to_s(2).count('1')}\""
72
+ else
73
+ super
74
+ end
75
+ end
76
+
77
+ # Typecast the given value to an IPAddr object.
78
+ def typecast_value_ipaddr(value)
79
+ case value
80
+ when IPAddr
81
+ value
82
+ when String
83
+ IPAddr.new(value)
84
+ else
85
+ raise Sequel::InvalidValue, "invalid value for inet/cidr: #{value.inspect}"
86
+ end
87
+ end
88
+ end
89
+
90
+ module InetDatasetMethods
91
+ private
92
+
93
+ # Convert IPAddr value to a string and append a literal version
94
+ # of the string to the sql.
95
+ def literal_other_append(sql, value)
96
+ if value.is_a?(IPAddr)
97
+ literal_string_append(sql, "#{value.to_s}/#{value.instance_variable_get(:@mask_addr).to_s(2).count('1')}")
98
+ else
99
+ super
100
+ end
101
+ end
102
+ end
103
+
104
+ PG_TYPES[869] = PG_TYPES[650] = IPAddr.method(:new)
105
+ if defined?(PGArray) && PGArray.respond_to?(:register)
106
+ PGArray.register('inet', :oid=>1041, :scalar_oid=>869)
107
+ PGArray.register('cidr', :oid=>651, :scalar_oid=>650)
108
+ PGArray.register('macaddr', :oid=>1040)
109
+ end
110
+ end
111
+
112
+ Database.register_extension(:pg_inet, Postgres::InetDatabaseMethods)
113
+ end
@@ -0,0 +1,191 @@
1
+ # The pg_interval extension adds support for PostgreSQL's interval type.
2
+ #
3
+ # This extension integrates with Sequel's native postgres adapter, so
4
+ # that when interval type values are retrieved, they are parsed and returned
5
+ # as instances of ActiveSupport::Duration.
6
+ #
7
+ # In addition to the parser, this extension adds literalizers for
8
+ # ActiveSupport::Duration that use the standard Sequel literalization
9
+ # callbacks, so they work on all adapters.
10
+ #
11
+ # If you would like to use interval columns in your model objects, you
12
+ # probably want to modify the typecasting so that it
13
+ # recognizes and correctly handles the interval columns, which you can
14
+ # do by:
15
+ #
16
+ # DB.extension :pg_interval
17
+ #
18
+ # If you are not using the native postgres adapter, you probably
19
+ # also want to use the typecast_on_load plugin in the model, and
20
+ # set it to typecast the interval type column(s) on load.
21
+ #
22
+ # This extension integrates with the pg_array extension. If you plan
23
+ # to use arrays of interval types, load the pg_array extension before the
24
+ # pg_interval extension:
25
+ #
26
+ # DB.extension :pg_array, :pg_interval
27
+ #
28
+ # The parser this extension uses requires that IntervalStyle for PostgreSQL
29
+ # is set to postgres (the default setting). If IntervalStyle is changed from
30
+ # the default setting, the parser will probably not work. The parser used is
31
+ # very simple, and is only designed to parse PostgreSQL's default output
32
+ # format, it is not designed to support all input formats that PostgreSQL
33
+ # supports.
34
+
35
+ require 'active_support/duration'
36
+ Sequel.require 'adapters/utils/pg_types'
37
+
38
+ module Sequel
39
+ module Postgres
40
+ module IntervalDatabaseMethods
41
+ EMPTY_INTERVAL = '0'.freeze
42
+ DURATION_UNITS = [:years, :months, :days, :minutes, :seconds].freeze
43
+
44
+ # Return an unquoted string version of the duration object suitable for
45
+ # use as a bound variable.
46
+ def self.literal_duration(duration)
47
+ h = Hash.new(0)
48
+ duration.parts.each{|unit, value| h[unit] += value}
49
+ s = ''
50
+
51
+ DURATION_UNITS.each do |unit|
52
+ if (v = h[unit]) != 0
53
+ s << "#{v.is_a?(Integer) ? v : sprintf('%0.6f', v)} #{unit} "
54
+ end
55
+ end
56
+
57
+ if s.empty?
58
+ EMPTY_INTERVAL
59
+ else
60
+ s
61
+ end
62
+ end
63
+
64
+ # Creates callable objects that convert strings into ActiveSupport::Duration instances.
65
+ class Parser
66
+ # Regexp that parses the full range of PostgreSQL interval type output.
67
+ PARSER = /\A([+-]?\d+ years?\s?)?([+-]?\d+ mons?\s?)?([+-]?\d+ days?\s?)?(?:(?:([+-])?(\d\d):(\d\d):(\d\d(\.\d+)?))|([+-]?\d+ hours?\s?)?([+-]?\d+ mins?\s?)?([+-]?\d+(\.\d+)? secs?\s?)?)?\z/o
68
+
69
+ # Parse the interval input string into an ActiveSupport::Duration instance.
70
+ def call(string)
71
+ raise(InvalidValue, "invalid or unhandled interval format: #{string.inspect}") unless matches = PARSER.match(string)
72
+
73
+ value = 0
74
+ parts = []
75
+
76
+ if v = matches[1]
77
+ v = v.to_i
78
+ value += 31557600 * v
79
+ parts << [:years, v]
80
+ end
81
+ if v = matches[2]
82
+ v = v.to_i
83
+ value += 2592000 * v
84
+ parts << [:months, v]
85
+ end
86
+ if v = matches[3]
87
+ v = v.to_i
88
+ value += 86400 * v
89
+ parts << [:days, v]
90
+ end
91
+ if matches[5]
92
+ seconds = matches[5].to_i * 3600 + matches[6].to_i * 60
93
+ seconds += matches[8] ? matches[7].to_f : matches[7].to_i
94
+ seconds *= -1 if matches[4] == '-'
95
+ value += seconds
96
+ parts << [:seconds, seconds]
97
+ elsif matches[9] || matches[10] || matches[11]
98
+ seconds = 0
99
+ if v = matches[9]
100
+ seconds += v.to_i * 3600
101
+ end
102
+ if v = matches[10]
103
+ seconds += v.to_i * 60
104
+ end
105
+ if v = matches[11]
106
+ seconds += matches[12] ? v.to_f : v.to_i
107
+ end
108
+ value += seconds
109
+ parts << [:seconds, seconds]
110
+ end
111
+
112
+ ActiveSupport::Duration.new(value, parts)
113
+ end
114
+ end
115
+
116
+ # Single instance of Parser used for parsing, to save on memory (since the parser has no state).
117
+ PARSER = Parser.new
118
+
119
+ # Reset the conversion procs if using the native postgres adapter,
120
+ # and extend the datasets to correctly literalize ActiveSupport::Duration values.
121
+ def self.extended(db)
122
+ db.extend_datasets(IntervalDatasetMethods)
123
+ end
124
+
125
+ # Handle ActiveSupport::Duration values in bound variables.
126
+ def bound_variable_arg(arg, conn)
127
+ case arg
128
+ when ActiveSupport::Duration
129
+ IntervalDatabaseMethods.literal_duration(arg)
130
+ else
131
+ super
132
+ end
133
+ end
134
+
135
+ private
136
+
137
+ # Handle arrays of interval types in bound variables.
138
+ def bound_variable_array(a)
139
+ case a
140
+ when ActiveSupport::Duration
141
+ "\"#{IntervalDatabaseMethods.literal_duration(a)}\""
142
+ else
143
+ super
144
+ end
145
+ end
146
+
147
+ # Typecast value correctly to an ActiveSupport::Duration instance.
148
+ # If already an ActiveSupport::Duration, return it.
149
+ # If a numeric argument is given, assume it represents a number
150
+ # of seconds, and create a new ActiveSupport::Duration instance
151
+ # representing that number of seconds.
152
+ # If a String, assume it is in PostgreSQL interval output format
153
+ # and attempt to parse it.
154
+ def typecast_value_interval(value)
155
+ case value
156
+ when ActiveSupport::Duration
157
+ value
158
+ when Numeric
159
+ ActiveSupport::Duration.new(value, [[:seconds, value]])
160
+ when String
161
+ PARSER.call(value)
162
+ else
163
+ raise Sequel::InvalidValue, "invalid value for interval type: #{value.inspect}"
164
+ end
165
+ end
166
+ end
167
+
168
+ module IntervalDatasetMethods
169
+ CAST_INTERVAL = '::interval'.freeze
170
+
171
+ # Handle literalization of ActiveSupport::Duration objects, treating them as
172
+ # PostgreSQL intervals.
173
+ def literal_other_append(sql, v)
174
+ case v
175
+ when ActiveSupport::Duration
176
+ literal_append(sql, IntervalDatabaseMethods.literal_duration(v))
177
+ sql << CAST_INTERVAL
178
+ else
179
+ super
180
+ end
181
+ end
182
+ end
183
+
184
+ PG_TYPES[1186] = Postgres::IntervalDatabaseMethods::PARSER
185
+ if defined?(PGArray) && PGArray.respond_to?(:register)
186
+ PGArray.register('interval', :oid=>1187, :scalar_oid=>1186)
187
+ end
188
+ end
189
+
190
+ Database.register_extension(:pg_interval, Postgres::IntervalDatabaseMethods)
191
+ end
@@ -0,0 +1,212 @@
1
+ # The pg_json extension adds support for Sequel to handle
2
+ # PostgreSQL's json type. It is slightly more strict than the
3
+ # PostgreSQL json type in that the object returned must be an
4
+ # array or object (PostgreSQL's json type considers plain numbers
5
+ # and strings as valid). This is because Sequel relies completely
6
+ # on the ruby JSON library for parsing, and ruby's JSON library
7
+ # does not accept the values.
8
+ #
9
+ # This extension integrates with Sequel's native postgres adapter, so
10
+ # that when json fields are retrieved, they are parsed and returned
11
+ # as instances of Sequel::Postgres::JSONArray or
12
+ # Sequel::Postgres::JSONHash. JSONArray and JSONHash are
13
+ # DelegateClasses of Array and Hash, so they mostly act the same, but
14
+ # not completely (json_array.is_a?(Array) is false). If you want
15
+ # the actual array for a JSONArray, call JSONArray#to_a. If you want
16
+ # the actual hash for a JSONHash, call JSONHash#to_hash.
17
+ # This is done so that Sequel does not treat JSONArray and JSONHash
18
+ # like Array and Hash by default, which would cause issues.
19
+ #
20
+ # To turn an existing Array or Hash into a JSONArray or JSONHash,
21
+ # use Sequel.pg_json:
22
+ #
23
+ # Sequel.pg_json(array)
24
+ # Sequel.pg_json(hash)
25
+ #
26
+ # If you have loaded the {core_extensions extension}[link:files/doc/core_extensions_rdoc.html]),
27
+ # you can also use Array#pg_json and Hash#pg_json:
28
+ #
29
+ # array.pg_json
30
+ # hash.pg_json
31
+ #
32
+ # So if you want to insert an array or hash into an json database column:
33
+ #
34
+ # DB[:table].insert(:column=>Sequel.pg_json([1, 2, 3]))
35
+ # DB[:table].insert(:column=>Sequel.pg_json({'a'=>1, 'b'=>2}))
36
+ #
37
+ # If you would like to use PostgreSQL json columns in your model
38
+ # objects, you probably want to modify the schema parsing/typecasting
39
+ # so that it recognizes and correctly handles the json type, which
40
+ # you can do by:
41
+ #
42
+ # DB.extension :pg_json
43
+ #
44
+ # If you are not using the native postgres adapter, you probably
45
+ # also want to use the typecast_on_load plugin in the model, and
46
+ # set it to typecast the json column(s) on load.
47
+ #
48
+ # This extension integrates with the pg_array extension. If you plan
49
+ # to use the json[] type, load the pg_array extension before the
50
+ # pg_json extension:
51
+ #
52
+ # DB.extension :pg_array, :pg_json
53
+ #
54
+ # This extension requires both the json and delegate libraries.
55
+
56
+ require 'delegate'
57
+ require 'json'
58
+ Sequel.require 'adapters/utils/pg_types'
59
+
60
+ module Sequel
61
+ module Postgres
62
+ CAST_JSON = '::json'.freeze
63
+
64
+ # Class representating PostgreSQL JSON column array values.
65
+ class JSONArray < DelegateClass(Array)
66
+ include Sequel::SQL::AliasMethods
67
+
68
+ # Convert the array to a string using to_json, append a
69
+ # literalized version of the string to the sql, and explicitly
70
+ # cast the string to json.
71
+ def sql_literal_append(ds, sql)
72
+ ds.literal_append(sql, to_json)
73
+ sql << CAST_JSON
74
+ end
75
+ end
76
+
77
+ # Class representating PostgreSQL JSON column hash/object values.
78
+ class JSONHash < DelegateClass(Hash)
79
+ include Sequel::SQL::AliasMethods
80
+
81
+ # Convert the array to a string using to_json, append a
82
+ # literalized version of the string to the sql, and explicitly
83
+ # cast the string to json.
84
+ def sql_literal_append(ds, sql)
85
+ ds.literal_append(sql, to_json)
86
+ sql << CAST_JSON
87
+ end
88
+
89
+ # Return the object being delegated to.
90
+ alias to_hash __getobj__
91
+ end
92
+
93
+ # Methods enabling Database object integration with the json type.
94
+ module JSONDatabaseMethods
95
+ # Parse the given string as json, returning either a JSONArray
96
+ # or JSONHash instance, and raising an error if the JSON
97
+ # parsing does not yield an array or hash.
98
+ def self.parse_json(s)
99
+ begin
100
+ value = JSON.parse(s)
101
+ rescue JSON::ParserError=>e
102
+ raise Sequel.convert_exception_class(e, Sequel::InvalidValue)
103
+ end
104
+
105
+ case value
106
+ when Array
107
+ JSONArray.new(value)
108
+ when Hash
109
+ JSONHash.new(value)
110
+ else
111
+ raise Sequel::InvalidValue, "unhandled json value: #{value.inspect} (from #{s.inspect})"
112
+ end
113
+ end
114
+
115
+ # Handle JSONArray and JSONHash in bound variables
116
+ def bound_variable_arg(arg, conn)
117
+ case arg
118
+ when JSONArray, JSONHash
119
+ arg.to_json
120
+ else
121
+ super
122
+ end
123
+ end
124
+
125
+ # Make the column type detection recognize the json type.
126
+ def schema_column_type(db_type)
127
+ case db_type
128
+ when 'json'
129
+ :json
130
+ else
131
+ super
132
+ end
133
+ end
134
+
135
+ private
136
+
137
+ # Handle json[] types in bound variables.
138
+ def bound_variable_array(a)
139
+ case a
140
+ when JSONHash, JSONArray
141
+ "\"#{a.to_json.gsub('"', '\\"')}\""
142
+ else
143
+ super
144
+ end
145
+ end
146
+
147
+ # Given a value to typecast to the json column
148
+ # * If given a JSONArray or JSONHash, just return the value
149
+ # * If given an Array, return a JSONArray
150
+ # * If given a Hash, return a JSONHash
151
+ # * If given a String, parse it as would be done during
152
+ # database retrieval.
153
+ def typecast_value_json(value)
154
+ case value
155
+ when JSONArray, JSONHash
156
+ value
157
+ when Array
158
+ JSONArray.new(value)
159
+ when Hash
160
+ JSONHash.new(value)
161
+ when String
162
+ JSONDatabaseMethods.parse_json(value)
163
+ else
164
+ raise Sequel::InvalidValue, "invalid value for json: #{value.inspect}"
165
+ end
166
+ end
167
+ end
168
+
169
+ PG_TYPES[114] = JSONDatabaseMethods.method(:parse_json)
170
+ if defined?(PGArray) && PGArray.respond_to?(:register)
171
+ PGArray.register('json', :oid=>199, :scalar_oid=>114)
172
+ end
173
+ end
174
+
175
+ module SQL::Builders
176
+ # Wrap the array or hash in a Postgres::JSONArray or Postgres::JSONHash.
177
+ def pg_json(v)
178
+ case v
179
+ when Postgres::JSONArray, Postgres::JSONHash
180
+ v
181
+ when Array
182
+ Postgres::JSONArray.new(v)
183
+ when Hash
184
+ Postgres::JSONHash.new(v)
185
+ else
186
+ raise Error, "Sequel.pg_json requires a hash or array argument"
187
+ end
188
+ end
189
+ end
190
+
191
+ Database.register_extension(:pg_json, Postgres::JSONDatabaseMethods)
192
+ end
193
+
194
+ if Sequel.core_extensions?
195
+ class Array
196
+ # Return a Sequel::Postgres::JSONArray proxy to the receiver.
197
+ # This is mostly useful as a short cut for creating JSONArray
198
+ # objects that didn't come from the database.
199
+ def pg_json
200
+ Sequel::Postgres::JSONArray.new(self)
201
+ end
202
+ end
203
+
204
+ class Hash
205
+ # Return a Sequel::Postgres::JSONHash proxy to the receiver.
206
+ # This is mostly useful as a short cut for creating JSONHash
207
+ # objects that didn't come from the database.
208
+ def pg_json
209
+ Sequel::Postgres::JSONHash.new(self)
210
+ end
211
+ end
212
+ end