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,140 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "Sequel::Postgres::HStoreOp" do
4
+ before do
5
+ @ds = Sequel.connect('mock://postgres', :quote_identifiers=>false).dataset
6
+ @h = Sequel.hstore_op(:h)
7
+ end
8
+
9
+ it "#- should use the - operator" do
10
+ @ds.literal(@h - 'a').should == "(h - 'a')"
11
+ end
12
+
13
+ it "#- should return an HStoreOp" do
14
+ @ds.literal((@h - 'a')['a']).should == "((h - 'a') -> 'a')"
15
+ end
16
+
17
+ it "#[] should use the -> operator" do
18
+ @ds.literal(@h['a']).should == "(h -> 'a')"
19
+ end
20
+
21
+ it "#[] should return a string expression" do
22
+ @ds.literal(@h['a'] + 'b').should == "((h -> 'a') || 'b')"
23
+ end
24
+
25
+ it "#concat and #merge should use the || operator" do
26
+ @ds.literal(@h.concat(:h1)).should == "(h || h1)"
27
+ @ds.literal(@h.merge(:h1)).should == "(h || h1)"
28
+ end
29
+
30
+ it "#concat should return an HStoreOp" do
31
+ @ds.literal(@h.concat(:h1)['a']).should == "((h || h1) -> 'a')"
32
+ end
33
+
34
+ it "#contain_all should use the ?& operator" do
35
+ @ds.literal(@h.contain_all(:h1)).should == "(h ?& h1)"
36
+ end
37
+
38
+ it "#contain_any should use the ?| operator" do
39
+ @ds.literal(@h.contain_any(:h1)).should == "(h ?| h1)"
40
+ end
41
+
42
+ it "#contains should use the @> operator" do
43
+ @ds.literal(@h.contains(:h1)).should == "(h @> h1)"
44
+ end
45
+
46
+ it "#contained_by should use the <@ operator" do
47
+ @ds.literal(@h.contained_by(:h1)).should == "(h <@ h1)"
48
+ end
49
+
50
+ it "#defined should use the defined function" do
51
+ @ds.literal(@h.defined('a')).should == "defined(h, 'a')"
52
+ end
53
+
54
+ it "#delete should use the delete function" do
55
+ @ds.literal(@h.delete('a')).should == "delete(h, 'a')"
56
+ end
57
+
58
+ it "#delete should return an HStoreOp" do
59
+ @ds.literal(@h.delete('a')['a']).should == "(delete(h, 'a') -> 'a')"
60
+ end
61
+
62
+ it "#each should use the each function" do
63
+ @ds.literal(@h.each).should == "each(h)"
64
+ end
65
+
66
+ it "#has_key? and aliases should use the ? operator" do
67
+ @ds.literal(@h.has_key?('a')).should == "(h ? 'a')"
68
+ @ds.literal(@h.key?('a')).should == "(h ? 'a')"
69
+ @ds.literal(@h.member?('a')).should == "(h ? 'a')"
70
+ @ds.literal(@h.include?('a')).should == "(h ? 'a')"
71
+ @ds.literal(@h.exist?('a')).should == "(h ? 'a')"
72
+ end
73
+
74
+ it "#hstore should return the receiver" do
75
+ @h.hstore.should equal(@h)
76
+ end
77
+
78
+ it "#keys and #akeys should use the akeys function" do
79
+ @ds.literal(@h.keys).should == "akeys(h)"
80
+ @ds.literal(@h.akeys).should == "akeys(h)"
81
+ end
82
+
83
+ it "#populate should use the populate_record function" do
84
+ @ds.literal(@h.populate(:a)).should == "populate_record(a, h)"
85
+ end
86
+
87
+ it "#record_set should use the #= operator" do
88
+ @ds.literal(@h.record_set(:a)).should == "(a #= h)"
89
+ end
90
+
91
+ it "#skeys should use the skeys function" do
92
+ @ds.literal(@h.skeys).should == "skeys(h)"
93
+ end
94
+
95
+ it "#slice should should use the slice function" do
96
+ @ds.literal(@h.slice(:a)).should == "slice(h, a)"
97
+ end
98
+
99
+ it "#slice should return an HStoreOp" do
100
+ @ds.literal(@h.slice(:a)['a']).should == "(slice(h, a) -> 'a')"
101
+ end
102
+
103
+ it "#svals should use the svals function" do
104
+ @ds.literal(@h.svals).should == "svals(h)"
105
+ end
106
+
107
+ it "#to_array should use the hstore_to_array function" do
108
+ @ds.literal(@h.to_array).should == "hstore_to_array(h)"
109
+ end
110
+
111
+ it "#to_matrix should use the hstore_to_matrix function" do
112
+ @ds.literal(@h.to_matrix).should == "hstore_to_matrix(h)"
113
+ end
114
+
115
+ it "#values and #avals should use the avals function" do
116
+ @ds.literal(@h.values).should == "avals(h)"
117
+ @ds.literal(@h.avals).should == "avals(h)"
118
+ end
119
+
120
+ it "should have Sequel.hstore_op return HStoreOp instances as-is" do
121
+ Sequel.hstore_op(@h).should equal(@h)
122
+ end
123
+
124
+ it "should have Sequel.hstore return HStoreOp instances" do
125
+ Sequel.hstore(:h).should == @h
126
+ end
127
+
128
+ it "should be able to turn expressions into hstore ops using hstore" do
129
+ @ds.literal(Sequel.qualify(:b, :a).hstore['a']).should == "(b.a -> 'a')"
130
+ @ds.literal(Sequel.function(:a, :b).hstore['a']).should == "(a(b) -> 'a')"
131
+ end
132
+
133
+ it "should be able to turn literal strings into hstore ops using hstore" do
134
+ @ds.literal(Sequel.lit('a').hstore['a']).should == "(a -> 'a')"
135
+ end
136
+
137
+ it "should allow transforming HStore instances into HStoreOp instances" do
138
+ @ds.literal(Sequel.hstore('a'=>'b').op['a']).should == "('\"a\"=>\"b\"'::hstore -> 'a')"
139
+ end
140
+ end
@@ -0,0 +1,200 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "pg_hstore extension" do
4
+ before do
5
+ @db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
6
+ @m = Sequel::Postgres
7
+ @c = @m::HStore
8
+ @db.extension :pg_hstore
9
+ end
10
+
11
+ it "should parse hstore strings correctly" do
12
+ @c.parse('').to_hash.should == {}
13
+ @c.parse('"a"=>"b"').to_hash.should == {'a'=>'b'}
14
+ @c.parse('"a"=>"b", "c"=>NULL').to_hash.should == {'a'=>'b', 'c'=>nil}
15
+ @c.parse('"a"=>"b", "c"=>"NULL"').to_hash.should == {'a'=>'b', 'c'=>'NULL'}
16
+ @c.parse('"a"=>"b", "c"=>"\\\\ \\"\'=>"').to_hash.should == {'a'=>'b', 'c'=>'\ "\'=>'}
17
+ end
18
+
19
+ it "should cache parse results" do
20
+ r = @c::Parser.new('')
21
+ o = r.parse
22
+ o.should == {}
23
+ r.parse.should equal(o)
24
+ end
25
+
26
+ it "should literalize HStores to strings correctly" do
27
+ @db.literal(Sequel.hstore({})).should == '\'\'::hstore'
28
+ @db.literal(Sequel.hstore("a"=>"b")).should == '\'"a"=>"b"\'::hstore'
29
+ @db.literal(Sequel.hstore("c"=>nil)).should == '\'"c"=>NULL\'::hstore'
30
+ @db.literal(Sequel.hstore("c"=>'NULL')).should == '\'"c"=>"NULL"\'::hstore'
31
+ @db.literal(Sequel.hstore('c'=>'\ "\'=>')).should == '\'"c"=>"\\\\ \\"\'\'=>"\'::hstore'
32
+ ['\'"a"=>"b","c"=>"d"\'::hstore', '\'"c"=>"d","a"=>"b"\'::hstore'].should include(@db.literal(Sequel.hstore("a"=>"b","c"=>"d")))
33
+ end
34
+
35
+ it "should have Sequel.hstore method for creating HStore instances" do
36
+ Sequel.hstore({}).should be_a_kind_of(@c)
37
+ end
38
+
39
+ it "should have Sequel.hstore return HStores as-is" do
40
+ a = Sequel.hstore({})
41
+ Sequel.hstore(a).should equal(a)
42
+ end
43
+
44
+ it "should HStore#to_hash method for getting underlying hash" do
45
+ Sequel.hstore({}).to_hash.should be_a_kind_of(Hash)
46
+ end
47
+
48
+ it "should convert keys and values to strings on creation" do
49
+ Sequel.hstore(1=>2).to_hash.should == {"1"=>"2"}
50
+ end
51
+
52
+ it "should convert keys and values to strings on assignment" do
53
+ v = Sequel.hstore({})
54
+ v[1] = 2
55
+ v.to_hash.should == {"1"=>"2"}
56
+ v.store(:'1', 3)
57
+ v.to_hash.should == {"1"=>"3"}
58
+ end
59
+
60
+ it "should not convert nil values to strings on creation" do
61
+ Sequel.hstore(:foo=>nil).to_hash.should == {"foo"=>nil}
62
+ end
63
+
64
+ it "should not convert nil values to strings on assignment" do
65
+ v = Sequel.hstore({})
66
+ v[:foo] = nil
67
+ v.to_hash.should == {"foo"=>nil}
68
+ end
69
+
70
+ it "should convert lookups by key to string" do
71
+ Sequel.hstore('foo'=>'bar')[:foo].should == 'bar'
72
+ Sequel.hstore('1'=>'bar')[1].should == 'bar'
73
+
74
+ Sequel.hstore('foo'=>'bar').fetch(:foo).should == 'bar'
75
+ Sequel.hstore('foo'=>'bar').fetch(:foo2, 2).should == 2
76
+ k = nil
77
+ Sequel.hstore('foo2'=>'bar').fetch(:foo){|key| k = key }.should == 'foo'
78
+ k.should == 'foo'
79
+
80
+ Sequel.hstore('foo'=>'bar').has_key?(:foo).should be_true
81
+ Sequel.hstore('foo'=>'bar').has_key?(:bar).should be_false
82
+ Sequel.hstore('foo'=>'bar').key?(:foo).should be_true
83
+ Sequel.hstore('foo'=>'bar').key?(:bar).should be_false
84
+ Sequel.hstore('foo'=>'bar').member?(:foo).should be_true
85
+ Sequel.hstore('foo'=>'bar').member?(:bar).should be_false
86
+ Sequel.hstore('foo'=>'bar').include?(:foo).should be_true
87
+ Sequel.hstore('foo'=>'bar').include?(:bar).should be_false
88
+
89
+ Sequel.hstore('foo'=>'bar', '1'=>'2').values_at(:foo3, :foo, :foo2, 1).should == [nil, 'bar', nil, '2']
90
+
91
+ if RUBY_VERSION >= '1.9.0'
92
+ Sequel.hstore('foo'=>'bar').assoc(:foo).should == ['foo', 'bar']
93
+ Sequel.hstore('foo'=>'bar').assoc(:foo2).should == nil
94
+ end
95
+ end
96
+
97
+ it "should convert has_value?/value? lookups to string" do
98
+ Sequel.hstore('foo'=>'bar').has_value?(:bar).should be_true
99
+ Sequel.hstore('foo'=>'bar').has_value?(:foo).should be_false
100
+ Sequel.hstore('foo'=>'bar').value?(:bar).should be_true
101
+ Sequel.hstore('foo'=>'bar').value?(:foo).should be_false
102
+ end
103
+
104
+ it "should handle nil values in has_value?/value? lookups" do
105
+ Sequel.hstore('foo'=>'').has_value?('').should be_true
106
+ Sequel.hstore('foo'=>'').has_value?(nil).should be_false
107
+ Sequel.hstore('foo'=>nil).has_value?(nil).should be_true
108
+ end
109
+
110
+ it "should have underlying hash convert lookups by key to string" do
111
+ Sequel.hstore('foo'=>'bar').to_hash[:foo].should == 'bar'
112
+ Sequel.hstore('1'=>'bar').to_hash[1].should == 'bar'
113
+ end
114
+
115
+ if RUBY_VERSION >= '1.9.0'
116
+ it "should convert key lookups to string" do
117
+ Sequel.hstore('foo'=>'bar').key(:bar).should == 'foo'
118
+ Sequel.hstore('foo'=>'bar').key(:bar2).should be_nil
119
+ end
120
+
121
+ it "should handle nil values in key lookups" do
122
+ Sequel.hstore('foo'=>'').key('').should == 'foo'
123
+ Sequel.hstore('foo'=>'').key(nil).should == nil
124
+ Sequel.hstore('foo'=>nil).key(nil).should == 'foo'
125
+ end
126
+
127
+ it "should convert rassoc lookups to string" do
128
+ Sequel.hstore('foo'=>'bar').rassoc(:bar).should == ['foo', 'bar']
129
+ Sequel.hstore('foo'=>'bar').rassoc(:bar2).should be_nil
130
+ end
131
+
132
+ it "should handle nil values in rassoc lookups" do
133
+ Sequel.hstore('foo'=>'').rassoc('').should == ['foo', '']
134
+ Sequel.hstore('foo'=>'').rassoc(nil).should == nil
135
+ Sequel.hstore('foo'=>nil).rassoc(nil).should == ['foo', nil]
136
+ end
137
+ end
138
+
139
+ it "should have delete convert key to string" do
140
+ v = Sequel.hstore('foo'=>'bar')
141
+ v.delete(:foo).should == 'bar'
142
+ v.to_hash.should == {}
143
+ end
144
+
145
+ it "should handle #replace with hashes that do not use strings" do
146
+ v = Sequel.hstore('foo'=>'bar')
147
+ v.replace(:bar=>1)
148
+ v.should be_a_kind_of(@c)
149
+ v.should == {'bar'=>'1'}
150
+ v.to_hash[:bar].should == '1'
151
+ end
152
+
153
+ it "should handle #merge with hashes that do not use strings" do
154
+ v = Sequel.hstore('foo'=>'bar').merge(:bar=>1)
155
+ v.should be_a_kind_of(@c)
156
+ v.should == {'foo'=>'bar', 'bar'=>'1'}
157
+ end
158
+
159
+ it "should handle #merge/#update with hashes that do not use strings" do
160
+ v = Sequel.hstore('foo'=>'bar')
161
+ v.merge!(:bar=>1)
162
+ v.should be_a_kind_of(@c)
163
+ v.should == {'foo'=>'bar', 'bar'=>'1'}
164
+
165
+ v = Sequel.hstore('foo'=>'bar')
166
+ v.update(:bar=>1)
167
+ v.should be_a_kind_of(@c)
168
+ v.should == {'foo'=>'bar', 'bar'=>'1'}
169
+ end
170
+
171
+ it "should support using hstores as bound variables" do
172
+ @db.bound_variable_arg(1, nil).should == 1
173
+ @db.bound_variable_arg({'1'=>'2'}, nil).should == '"1"=>"2"'
174
+ @db.bound_variable_arg(Sequel.hstore('1'=>'2'), nil).should == '"1"=>"2"'
175
+ @db.bound_variable_arg(Sequel.hstore('1'=>nil), nil).should == '"1"=>NULL'
176
+ @db.bound_variable_arg(Sequel.hstore('1'=>"NULL"), nil).should == '"1"=>"NULL"'
177
+ @db.bound_variable_arg(Sequel.hstore('1'=>"'\\ \"=>"), nil).should == '"1"=>"\'\\\\ \\"=>"'
178
+ ['"a"=>"b","c"=>"d"', '"c"=>"d","a"=>"b"'].should include(@db.bound_variable_arg(Sequel.hstore("a"=>"b","c"=>"d"), nil))
179
+ end
180
+
181
+ it "should parse hstore type from the schema correctly" do
182
+ @db.fetch = [{:name=>'id', :db_type=>'integer'}, {:name=>'i', :db_type=>'hstore'}]
183
+ @db.schema(:items).map{|e| e[1][:type]}.should == [:integer, :hstore]
184
+ end
185
+
186
+ it "should support typecasting for the hstore type" do
187
+ h = Sequel.hstore(1=>2)
188
+ @db.typecast_value(:hstore, h).should equal(h)
189
+ @db.typecast_value(:hstore, {}).should be_a_kind_of(@c)
190
+ @db.typecast_value(:hstore, {}).should == Sequel.hstore({})
191
+ @db.typecast_value(:hstore, {'a'=>'b'}).should == Sequel.hstore("a"=>"b")
192
+ proc{@db.typecast_value(:hstore, [])}.should raise_error(Sequel::InvalidValue)
193
+ end
194
+
195
+ it "should be serializable" do
196
+ v = Sequel.hstore('foo'=>'bar')
197
+ dump = Marshal.dump(v)
198
+ Marshal.load(dump).should == v
199
+ end
200
+ end
@@ -0,0 +1,47 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "pg_inet extension" do
4
+ ipv6_broken = (IPAddr.new('::1'); false) rescue true
5
+ before do
6
+ @db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
7
+ @db.extension(:pg_array, :pg_inet)
8
+ end
9
+
10
+ it "should literalize IPAddr v4 instances to strings correctly" do
11
+ @db.literal(IPAddr.new('127.0.0.1')).should == "'127.0.0.1/32'"
12
+ @db.literal(IPAddr.new('127.0.0.0/8')).should == "'127.0.0.0/8'"
13
+ end
14
+
15
+ it "should literalize IPAddr v6 instances to strings correctly" do
16
+ @db.literal(IPAddr.new('2001:4f8:3:ba::/64')).should == "'2001:4f8:3:ba::/64'"
17
+ @db.literal(IPAddr.new('2001:4f8:3:ba:2e0:81ff:fe22:d1f1')).should == "'2001:4f8:3:ba:2e0:81ff:fe22:d1f1/128'"
18
+ end unless ipv6_broken
19
+
20
+ it "should not affect literalization of custom objects" do
21
+ o = Object.new
22
+ def o.sql_literal(ds) 'v' end
23
+ @db.literal(o).should == 'v'
24
+ end
25
+
26
+ it "should support using IPAddr as bound variables" do
27
+ @db.bound_variable_arg(1, nil).should == 1
28
+ @db.bound_variable_arg(IPAddr.new('127.0.0.1'), nil).should == '127.0.0.1/32'
29
+ end
30
+
31
+ it "should support using IPAddr instances in array types in bound variables" do
32
+ @db.bound_variable_arg(Sequel.pg_array([IPAddr.new('127.0.0.1')]), nil).should == '{"127.0.0.1/32"}'
33
+ end
34
+
35
+ it "should parse inet/cidr type from the schema correctly" do
36
+ @db.fetch = [{:name=>'id', :db_type=>'integer'}, {:name=>'i', :db_type=>'inet'}, {:name=>'c', :db_type=>'cidr'}]
37
+ @db.schema(:items).map{|e| e[1][:type]}.should == [:integer, :ipaddr, :ipaddr]
38
+ end
39
+
40
+ it "should support typecasting for the ipaddr type" do
41
+ ip = IPAddr.new('127.0.0.1')
42
+ @db.typecast_value(:ipaddr, ip).should equal(ip)
43
+ @db.typecast_value(:ipaddr, ip.to_s).should == ip
44
+ proc{@db.typecast_value(:ipaddr, '')}.should raise_error(Sequel::InvalidValue)
45
+ proc{@db.typecast_value(:ipaddr, 1)}.should raise_error(Sequel::InvalidValue)
46
+ end
47
+ end
@@ -0,0 +1,72 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ begin
4
+ require 'active_support/duration'
5
+ rescue LoadError => e
6
+ skip_warn "pg_interval plugin: can't load active_support/duration (#{e.class}: #{e})"
7
+ else
8
+ describe "pg_interval extension" do
9
+ before do
10
+ @db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
11
+ @db.extension(:pg_array, :pg_interval)
12
+ end
13
+
14
+ it "should literalize ActiveSupport::Duration instances to strings correctly" do
15
+ @db.literal(ActiveSupport::Duration.new(0, [])).should == "'0'::interval"
16
+ @db.literal(ActiveSupport::Duration.new(0, [[:seconds, 0]])).should == "'0'::interval"
17
+ @db.literal(ActiveSupport::Duration.new(0, [[:seconds, 10], [:minutes, 20], [:days, 3], [:months, 4], [:years, 6]])).should == "'6 years 4 months 3 days 20 minutes 10 seconds '::interval"
18
+ @db.literal(ActiveSupport::Duration.new(0, [[:seconds, -10.000001], [:minutes, -20], [:days, -3], [:months, -4], [:years, -6]])).should == "'-6 years -4 months -3 days -20 minutes -10.000001 seconds '::interval"
19
+ end
20
+
21
+ it "should literalize ActiveSupport::Duration instances with repeated parts correctly" do
22
+ @db.literal(ActiveSupport::Duration.new(0, [[:seconds, 2], [:seconds, 1]])).should == "'3 seconds '::interval"
23
+ @db.literal(ActiveSupport::Duration.new(0, [[:seconds, 2], [:seconds, 1], [:days, 1], [:days, 4]])).should == "'5 days 3 seconds '::interval"
24
+ end
25
+
26
+ it "should not affect literalization of custom objects" do
27
+ o = Object.new
28
+ def o.sql_literal(ds) 'v' end
29
+ @db.literal(o).should == 'v'
30
+ end
31
+
32
+ it "should support using ActiveSupport::Duration instances as bound variables" do
33
+ @db.bound_variable_arg(1, nil).should == 1
34
+ @db.bound_variable_arg(ActiveSupport::Duration.new(0, [[:seconds, 0]]), nil).should == '0'
35
+ @db.bound_variable_arg(ActiveSupport::Duration.new(0, [[:seconds, -10.000001], [:minutes, -20], [:days, -3], [:months, -4], [:years, -6]]), nil).should == '-6 years -4 months -3 days -20 minutes -10.000001 seconds '
36
+ end
37
+
38
+ it "should support using ActiveSupport::Duration instances in array types in bound variables" do
39
+ @db.bound_variable_arg(Sequel.pg_array([ActiveSupport::Duration.new(0, [[:seconds, 0]])]), nil).should == '{"0"}'
40
+ @db.bound_variable_arg(Sequel.pg_array([ActiveSupport::Duration.new(0, [[:seconds, -10.000001], [:minutes, -20], [:days, -3], [:months, -4], [:years, -6]])]), nil).should == '{"-6 years -4 months -3 days -20 minutes -10.000001 seconds "}'
41
+ end
42
+
43
+ it "should parse interval type from the schema correctly" do
44
+ @db.fetch = [{:name=>'id', :db_type=>'integer'}, {:name=>'i', :db_type=>'interval'}]
45
+ @db.schema(:items).map{|e| e[1][:type]}.should == [:integer, :interval]
46
+ end
47
+
48
+ it "should support typecasting for the interval type" do
49
+ ip = IPAddr.new('127.0.0.1')
50
+ d = ActiveSupport::Duration.new(31557600 + 2*86400*30 + 3*86400*7 + 4*86400 + 5*3600 + 6*60 + 7, [[:years, 1], [:months, 2], [:days, 25], [:seconds, 18367]])
51
+ @db.typecast_value(:interval, d).object_id.should == d.object_id
52
+
53
+ @db.typecast_value(:interval, "1 year 2 mons 25 days 05:06:07").is_a?(ActiveSupport::Duration).should be_true
54
+ @db.typecast_value(:interval, "1 year 2 mons 25 days 05:06:07").should == d
55
+ @db.typecast_value(:interval, "1 year 2 mons 25 days 05:06:07").parts.sort_by{|k,v| k.to_s}.should == d.parts.sort_by{|k,v| k.to_s}
56
+ @db.typecast_value(:interval, "1 year 2 mons 25 days 05:06:07.0").parts.sort_by{|k,v| k.to_s}.should == d.parts.sort_by{|k,v| k.to_s}
57
+
58
+ @db.typecast_value(:interval, "1 year 2 mons 25 days 5 hours 6 mins 7 secs").is_a?(ActiveSupport::Duration).should be_true
59
+ @db.typecast_value(:interval, "1 year 2 mons 25 days 5 hours 6 mins 7 secs").should == d
60
+ @db.typecast_value(:interval, "1 year 2 mons 25 days 5 hours 6 mins 7 secs").parts.sort_by{|k,v| k.to_s}.should == d.parts.sort_by{|k,v| k.to_s}
61
+ @db.typecast_value(:interval, "1 year 2 mons 25 days 5 hours 6 mins 7.0 secs").parts.sort_by{|k,v| k.to_s}.should == d.parts.sort_by{|k,v| k.to_s}
62
+
63
+ d2 = ActiveSupport::Duration.new(1, [[:seconds, 1]])
64
+ @db.typecast_value(:interval, 1).is_a?(ActiveSupport::Duration).should be_true
65
+ @db.typecast_value(:interval, 1).should == d2
66
+ @db.typecast_value(:interval, 1).parts.sort_by{|k,v| k.to_s}.should == d2.parts.sort_by{|k,v| k.to_s}
67
+
68
+ proc{@db.typecast_value(:interval, 'foo')}.should raise_error(Sequel::InvalidValue)
69
+ proc{@db.typecast_value(:interval, Object.new)}.should raise_error(Sequel::InvalidValue)
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,99 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "pg_json extension" do
4
+ before(:all) do
5
+ m = Sequel::Postgres
6
+ @m = m::JSONDatabaseMethods
7
+ @hc = m::JSONHash
8
+ @ac = m::JSONArray
9
+
10
+ # Create subclass in correct namespace for easily overriding methods
11
+ j = m::JSON = JSON.dup
12
+ j.instance_eval do
13
+ Parser = JSON::Parser
14
+ alias old_parse parse
15
+ def parse(s)
16
+ return 1 if s == '1'
17
+ old_parse(s)
18
+ end
19
+ end
20
+ end
21
+ before do
22
+ @db = Sequel.connect('mock://postgres', :quote_identifiers=>false)
23
+ @db.extension(:pg_array, :pg_json)
24
+ end
25
+
26
+ it "should parse json strings correctly" do
27
+ @m.parse_json('[]').should be_a_kind_of(@ac)
28
+ @m.parse_json('[]').to_a.should == []
29
+ @m.parse_json('[1]').to_a.should == [1]
30
+ @m.parse_json('[1, 2]').to_a.should == [1, 2]
31
+ @m.parse_json('[1, [2], {"a": "b"}]').to_a.should == [1, [2], {'a'=>'b'}]
32
+ @m.parse_json('{}').should be_a_kind_of(@hc)
33
+ @m.parse_json('{}').to_hash.should == {}
34
+ @m.parse_json('{"a": "b"}').to_hash.should == {'a'=>'b'}
35
+ @m.parse_json('{"a": "b", "c": [1, 2, 3]}').to_hash.should == {'a'=>'b', 'c'=>[1, 2, 3]}
36
+ @m.parse_json('{"a": "b", "c": {"d": "e"}}').to_hash.should == {'a'=>'b', 'c'=>{'d'=>'e'}}
37
+ end
38
+
39
+ it "should raise an error when attempting to parse invalid json" do
40
+ proc{@m.parse_json('')}.should raise_error(Sequel::InvalidValue)
41
+ proc{@m.parse_json('1')}.should raise_error(Sequel::InvalidValue)
42
+ end
43
+
44
+ it "should literalize HStores to strings correctly" do
45
+ @db.literal(Sequel.pg_json([])).should == "'[]'::json"
46
+ @db.literal(Sequel.pg_json([1, [2], {'a'=>'b'}])).should == "'[1,[2],{\"a\":\"b\"}]'::json"
47
+ @db.literal(Sequel.pg_json({})).should == "'{}'::json"
48
+ @db.literal(Sequel.pg_json('a'=>'b')).should == "'{\"a\":\"b\"}'::json"
49
+ end
50
+
51
+ it "should have Sequel.pg_json return JSONHash and JSONArray as is" do
52
+ a = Sequel.pg_json({})
53
+ Sequel.pg_json(a).should equal(a)
54
+ a = Sequel.pg_json([])
55
+ Sequel.pg_json(a).should equal(a)
56
+ end
57
+
58
+ it "should have Sequel.pg_json raise an Error if called with a non-hash or array" do
59
+ proc{Sequel.pg_json(:a)}.should raise_error(Sequel::Error)
60
+ end
61
+
62
+ it "should have JSONHash#to_hash method for getting underlying hash" do
63
+ Sequel.pg_json({}).to_hash.should be_a_kind_of(Hash)
64
+ end
65
+
66
+ it "should have JSONArray#to_a method for getting underlying array" do
67
+ Sequel.pg_json([]).to_a.should be_a_kind_of(Array)
68
+ end
69
+
70
+ it "should support using JSONHash and JSONArray as bound variables" do
71
+ @db.bound_variable_arg(1, nil).should == 1
72
+ @db.bound_variable_arg(Sequel.pg_json([1]), nil).should == '[1]'
73
+ @db.bound_variable_arg(Sequel.pg_json('a'=>'b'), nil).should == '{"a":"b"}'
74
+ end
75
+
76
+ it "should support using json[] types in bound variables" do
77
+ @db.bound_variable_arg(Sequel.pg_array([Sequel.pg_json([{"a"=>1}]), Sequel.pg_json("b"=>[1, 2])]), nil).should == '{"[{\\"a\\":1}]","{\\"b\\":[1,2]}"}'
78
+ end
79
+
80
+ it "should parse json type from the schema correctly" do
81
+ @db.fetch = [{:name=>'id', :db_type=>'integer'}, {:name=>'i', :db_type=>'json'}]
82
+ @db.schema(:items).map{|e| e[1][:type]}.should == [:integer, :json]
83
+ end
84
+
85
+ it "should support typecasting for the json type" do
86
+ h = Sequel.pg_json(1=>2)
87
+ a = Sequel.pg_json([1])
88
+ @db.typecast_value(:json, h).should equal(h)
89
+ @db.typecast_value(:json, h.to_hash).should == h
90
+ @db.typecast_value(:json, h.to_hash).should be_a_kind_of(@hc)
91
+ @db.typecast_value(:json, a).should equal(a)
92
+ @db.typecast_value(:json, a.to_a).should == a
93
+ @db.typecast_value(:json, a.to_a).should be_a_kind_of(@ac)
94
+ @db.typecast_value(:json, '[]').should == Sequel.pg_json([])
95
+ @db.typecast_value(:json, '{"a": "b"}').should == Sequel.pg_json("a"=>"b")
96
+ proc{@db.typecast_value(:json, '')}.should raise_error(Sequel::InvalidValue)
97
+ proc{@db.typecast_value(:json, 1)}.should raise_error(Sequel::InvalidValue)
98
+ end
99
+ end
@@ -0,0 +1,56 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ describe "Sequel::Postgres::RangeOp" do
4
+ before do
5
+ @ds = Sequel.connect('mock://postgres', :quote_identifiers=>false).dataset
6
+ @h = Sequel.pg_range_op(:h)
7
+ end
8
+
9
+ it "#pg_range should return self" do
10
+ @h.pg_range.should equal(@h)
11
+ end
12
+
13
+ it "Sequel.pg_range_op should return argument if already a RangeOp" do
14
+ Sequel.pg_range_op(@h).should equal(@h)
15
+ end
16
+
17
+ it "Sequel.pg_range should return a new RangeOp if not given a range" do
18
+ @ds.literal(Sequel.pg_range(:h).lower).should == "lower(h)"
19
+ end
20
+
21
+ it "#pg_range should return a RangeOp for literal strings, and expressions" do
22
+ @ds.literal(Sequel.function(:b, :h).pg_range.lower).should == "lower(b(h))"
23
+ @ds.literal(Sequel.lit('h').pg_range.lower).should == "lower(h)"
24
+ end
25
+
26
+ it "PGRange#op should return a RangeOp" do
27
+ @ds.literal(Sequel.pg_range(1..2, :numrange).op.lower).should == "lower('[1,2]'::numrange)"
28
+ end
29
+
30
+ it "should define methods for all of the the PostgreSQL range operators" do
31
+ @ds.literal(@h.contains(@h)).should == "(h @> h)"
32
+ @ds.literal(@h.contained_by(@h)).should == "(h <@ h)"
33
+ @ds.literal(@h.overlaps(@h)).should == "(h && h)"
34
+ @ds.literal(@h.left_of(@h)).should == "(h << h)"
35
+ @ds.literal(@h.right_of(@h)).should == "(h >> h)"
36
+ @ds.literal(@h.starts_before(@h)).should == "(h &< h)"
37
+ @ds.literal(@h.ends_after(@h)).should == "(h &> h)"
38
+ @ds.literal(@h.adjacent_to(@h)).should == "(h -|- h)"
39
+ end
40
+
41
+ it "should define methods for all of the the PostgreSQL range functions" do
42
+ @ds.literal(@h.lower).should == "lower(h)"
43
+ @ds.literal(@h.upper).should == "upper(h)"
44
+ @ds.literal(@h.isempty).should == "isempty(h)"
45
+ @ds.literal(@h.lower_inc).should == "lower_inc(h)"
46
+ @ds.literal(@h.upper_inc).should == "upper_inc(h)"
47
+ @ds.literal(@h.lower_inf).should == "lower_inf(h)"
48
+ @ds.literal(@h.upper_inf).should == "upper_inf(h)"
49
+ end
50
+
51
+ it "+ - * operators should be defined and return a RangeOp" do
52
+ @ds.literal((@h + @h).lower).should == "lower((h + h))"
53
+ @ds.literal((@h * @h).lower).should == "lower((h * h))"
54
+ @ds.literal((@h - @h).lower).should == "lower((h - h))"
55
+ end
56
+ end