sequel 4.49.0 → 5.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (477) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +70 -0
  3. data/README.rdoc +195 -136
  4. data/Rakefile +26 -42
  5. data/bin/sequel +3 -5
  6. data/doc/advanced_associations.rdoc +86 -163
  7. data/doc/association_basics.rdoc +197 -274
  8. data/doc/bin_sequel.rdoc +5 -3
  9. data/doc/cheat_sheet.rdoc +66 -43
  10. data/doc/code_order.rdoc +1 -8
  11. data/doc/core_extensions.rdoc +81 -56
  12. data/doc/dataset_basics.rdoc +8 -17
  13. data/doc/dataset_filtering.rdoc +81 -86
  14. data/doc/extensions.rdoc +3 -10
  15. data/doc/mass_assignment.rdoc +73 -30
  16. data/doc/migration.rdoc +19 -36
  17. data/doc/model_dataset_method_design.rdoc +14 -17
  18. data/doc/model_hooks.rdoc +15 -25
  19. data/doc/model_plugins.rdoc +10 -10
  20. data/doc/mssql_stored_procedures.rdoc +3 -3
  21. data/doc/object_model.rdoc +52 -70
  22. data/doc/opening_databases.rdoc +39 -32
  23. data/doc/postgresql.rdoc +48 -38
  24. data/doc/prepared_statements.rdoc +27 -22
  25. data/doc/querying.rdoc +173 -150
  26. data/doc/reflection.rdoc +5 -6
  27. data/doc/release_notes/5.0.0.txt +159 -0
  28. data/doc/schema_modification.rdoc +63 -60
  29. data/doc/security.rdoc +97 -88
  30. data/doc/sharding.rdoc +43 -30
  31. data/doc/sql.rdoc +53 -65
  32. data/doc/testing.rdoc +3 -5
  33. data/doc/thread_safety.rdoc +2 -4
  34. data/doc/transactions.rdoc +18 -17
  35. data/doc/validations.rdoc +48 -45
  36. data/doc/virtual_rows.rdoc +87 -115
  37. data/lib/sequel.rb +1 -1
  38. data/lib/sequel/adapters/ado.rb +9 -25
  39. data/lib/sequel/adapters/ado/access.rb +7 -13
  40. data/lib/sequel/adapters/ado/mssql.rb +2 -9
  41. data/lib/sequel/adapters/amalgalite.rb +3 -18
  42. data/lib/sequel/adapters/ibmdb.rb +9 -45
  43. data/lib/sequel/adapters/jdbc.rb +13 -73
  44. data/lib/sequel/adapters/jdbc/db2.rb +8 -37
  45. data/lib/sequel/adapters/jdbc/derby.rb +4 -50
  46. data/lib/sequel/adapters/jdbc/h2.rb +4 -25
  47. data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -26
  48. data/lib/sequel/adapters/jdbc/jtds.rb +2 -9
  49. data/lib/sequel/adapters/jdbc/mssql.rb +1 -11
  50. data/lib/sequel/adapters/jdbc/mysql.rb +1 -15
  51. data/lib/sequel/adapters/jdbc/oracle.rb +4 -26
  52. data/lib/sequel/adapters/jdbc/postgresql.rb +2 -31
  53. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +4 -17
  54. data/lib/sequel/adapters/jdbc/sqlite.rb +1 -7
  55. data/lib/sequel/adapters/jdbc/sqlserver.rb +1 -13
  56. data/lib/sequel/adapters/jdbc/transactions.rb +1 -14
  57. data/lib/sequel/adapters/mock.rb +4 -30
  58. data/lib/sequel/adapters/mysql.rb +7 -44
  59. data/lib/sequel/adapters/mysql2.rb +5 -23
  60. data/lib/sequel/adapters/odbc.rb +0 -19
  61. data/lib/sequel/adapters/odbc/db2.rb +1 -1
  62. data/lib/sequel/adapters/odbc/mssql.rb +4 -12
  63. data/lib/sequel/adapters/odbc/oracle.rb +1 -1
  64. data/lib/sequel/adapters/oracle.rb +7 -13
  65. data/lib/sequel/adapters/postgres.rb +13 -57
  66. data/lib/sequel/adapters/postgresql.rb +1 -1
  67. data/lib/sequel/adapters/shared/access.rb +11 -51
  68. data/lib/sequel/adapters/shared/db2.rb +3 -61
  69. data/lib/sequel/adapters/shared/mssql.rb +21 -157
  70. data/lib/sequel/adapters/shared/mysql.rb +23 -224
  71. data/lib/sequel/adapters/shared/oracle.rb +13 -41
  72. data/lib/sequel/adapters/shared/postgres.rb +44 -259
  73. data/lib/sequel/adapters/shared/sqlanywhere.rb +4 -96
  74. data/lib/sequel/adapters/shared/sqlite.rb +12 -101
  75. data/lib/sequel/adapters/sqlanywhere.rb +4 -23
  76. data/lib/sequel/adapters/sqlite.rb +2 -19
  77. data/lib/sequel/adapters/tinytds.rb +5 -15
  78. data/lib/sequel/adapters/utils/emulate_offset_with_row_number.rb +1 -1
  79. data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -4
  80. data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +3 -6
  81. data/lib/sequel/adapters/utils/replace.rb +0 -5
  82. data/lib/sequel/adapters/utils/stored_procedures.rb +0 -2
  83. data/lib/sequel/adapters/utils/unmodified_identifiers.rb +2 -0
  84. data/lib/sequel/ast_transformer.rb +3 -94
  85. data/lib/sequel/connection_pool.rb +26 -28
  86. data/lib/sequel/connection_pool/sharded_single.rb +1 -4
  87. data/lib/sequel/connection_pool/sharded_threaded.rb +97 -95
  88. data/lib/sequel/connection_pool/single.rb +0 -2
  89. data/lib/sequel/connection_pool/threaded.rb +94 -110
  90. data/lib/sequel/core.rb +42 -101
  91. data/lib/sequel/database.rb +12 -2
  92. data/lib/sequel/database/connecting.rb +23 -60
  93. data/lib/sequel/database/dataset.rb +6 -9
  94. data/lib/sequel/database/dataset_defaults.rb +4 -48
  95. data/lib/sequel/database/features.rb +5 -4
  96. data/lib/sequel/database/logging.rb +2 -9
  97. data/lib/sequel/database/misc.rb +23 -55
  98. data/lib/sequel/database/query.rb +8 -13
  99. data/lib/sequel/database/schema_generator.rb +89 -64
  100. data/lib/sequel/database/schema_methods.rb +61 -79
  101. data/lib/sequel/database/transactions.rb +4 -24
  102. data/lib/sequel/dataset.rb +18 -10
  103. data/lib/sequel/dataset/actions.rb +53 -107
  104. data/lib/sequel/dataset/dataset_module.rb +3 -15
  105. data/lib/sequel/dataset/features.rb +30 -30
  106. data/lib/sequel/dataset/graph.rb +40 -49
  107. data/lib/sequel/dataset/misc.rb +12 -37
  108. data/lib/sequel/dataset/placeholder_literalizer.rb +4 -4
  109. data/lib/sequel/dataset/prepared_statements.rb +23 -51
  110. data/lib/sequel/dataset/query.rb +71 -155
  111. data/lib/sequel/dataset/sql.rb +30 -225
  112. data/lib/sequel/deprecated.rb +18 -27
  113. data/lib/sequel/exceptions.rb +1 -17
  114. data/lib/sequel/extensions/_model_pg_row.rb +0 -7
  115. data/lib/sequel/extensions/_pretty_table.rb +1 -3
  116. data/lib/sequel/extensions/arbitrary_servers.rb +10 -10
  117. data/lib/sequel/extensions/connection_expiration.rb +1 -1
  118. data/lib/sequel/extensions/connection_validator.rb +1 -1
  119. data/lib/sequel/extensions/constraint_validations.rb +11 -11
  120. data/lib/sequel/extensions/core_extensions.rb +39 -49
  121. data/lib/sequel/extensions/core_refinements.rb +39 -45
  122. data/lib/sequel/extensions/current_datetime_timestamp.rb +0 -4
  123. data/lib/sequel/extensions/date_arithmetic.rb +7 -7
  124. data/lib/sequel/extensions/duplicate_columns_handler.rb +12 -9
  125. data/lib/sequel/extensions/empty_array_consider_nulls.rb +2 -2
  126. data/lib/sequel/extensions/eval_inspect.rb +4 -11
  127. data/lib/sequel/extensions/freeze_datasets.rb +1 -69
  128. data/lib/sequel/extensions/from_block.rb +1 -35
  129. data/lib/sequel/extensions/graph_each.rb +2 -2
  130. data/lib/sequel/extensions/identifier_mangling.rb +9 -19
  131. data/lib/sequel/extensions/implicit_subquery.rb +2 -2
  132. data/lib/sequel/extensions/inflector.rb +4 -4
  133. data/lib/sequel/extensions/migration.rb +23 -40
  134. data/lib/sequel/extensions/no_auto_literal_strings.rb +2 -84
  135. data/lib/sequel/extensions/null_dataset.rb +2 -8
  136. data/lib/sequel/extensions/pagination.rb +1 -17
  137. data/lib/sequel/extensions/pg_array.rb +20 -189
  138. data/lib/sequel/extensions/pg_hstore.rb +11 -50
  139. data/lib/sequel/extensions/pg_hstore_ops.rb +2 -2
  140. data/lib/sequel/extensions/pg_inet.rb +2 -15
  141. data/lib/sequel/extensions/pg_interval.rb +1 -20
  142. data/lib/sequel/extensions/pg_json.rb +7 -27
  143. data/lib/sequel/extensions/pg_loose_count.rb +1 -1
  144. data/lib/sequel/extensions/pg_range.rb +6 -121
  145. data/lib/sequel/extensions/pg_range_ops.rb +1 -3
  146. data/lib/sequel/extensions/pg_row.rb +5 -77
  147. data/lib/sequel/extensions/pg_row_ops.rb +2 -13
  148. data/lib/sequel/extensions/query.rb +3 -4
  149. data/lib/sequel/extensions/round_timestamps.rb +0 -6
  150. data/lib/sequel/extensions/schema_dumper.rb +13 -13
  151. data/lib/sequel/extensions/select_remove.rb +3 -3
  152. data/lib/sequel/extensions/split_array_nil.rb +2 -2
  153. data/lib/sequel/extensions/sql_comments.rb +2 -2
  154. data/lib/sequel/extensions/string_agg.rb +11 -8
  155. data/lib/sequel/extensions/symbol_aref.rb +6 -20
  156. data/lib/sequel/model.rb +27 -62
  157. data/lib/sequel/model/associations.rb +128 -131
  158. data/lib/sequel/model/base.rb +171 -711
  159. data/lib/sequel/model/default_inflections.rb +1 -1
  160. data/lib/sequel/model/errors.rb +0 -3
  161. data/lib/sequel/model/exceptions.rb +2 -6
  162. data/lib/sequel/model/inflections.rb +1 -26
  163. data/lib/sequel/model/plugins.rb +1 -0
  164. data/lib/sequel/plugins/active_model.rb +2 -5
  165. data/lib/sequel/plugins/association_dependencies.rb +15 -15
  166. data/lib/sequel/plugins/association_pks.rb +14 -28
  167. data/lib/sequel/plugins/association_proxies.rb +6 -7
  168. data/lib/sequel/plugins/auto_validations.rb +4 -4
  169. data/lib/sequel/plugins/before_after_save.rb +0 -43
  170. data/lib/sequel/plugins/blacklist_security.rb +9 -8
  171. data/lib/sequel/plugins/boolean_readers.rb +3 -3
  172. data/lib/sequel/plugins/boolean_subsets.rb +2 -2
  173. data/lib/sequel/plugins/caching.rb +5 -5
  174. data/lib/sequel/plugins/class_table_inheritance.rb +71 -102
  175. data/lib/sequel/plugins/column_conflicts.rb +2 -2
  176. data/lib/sequel/plugins/column_select.rb +2 -2
  177. data/lib/sequel/plugins/composition.rb +15 -24
  178. data/lib/sequel/plugins/constraint_validations.rb +4 -3
  179. data/lib/sequel/plugins/csv_serializer.rb +13 -20
  180. data/lib/sequel/plugins/dataset_associations.rb +2 -2
  181. data/lib/sequel/plugins/def_dataset_method.rb +5 -5
  182. data/lib/sequel/plugins/defaults_setter.rb +1 -1
  183. data/lib/sequel/plugins/delay_add_association.rb +1 -1
  184. data/lib/sequel/plugins/finder.rb +16 -10
  185. data/lib/sequel/plugins/force_encoding.rb +1 -7
  186. data/lib/sequel/plugins/hook_class_methods.rb +4 -106
  187. data/lib/sequel/plugins/input_transformer.rb +10 -11
  188. data/lib/sequel/plugins/insert_returning_select.rb +1 -9
  189. data/lib/sequel/plugins/instance_filters.rb +5 -5
  190. data/lib/sequel/plugins/instance_hooks.rb +7 -52
  191. data/lib/sequel/plugins/inverted_subsets.rb +3 -1
  192. data/lib/sequel/plugins/json_serializer.rb +19 -19
  193. data/lib/sequel/plugins/lazy_attributes.rb +1 -10
  194. data/lib/sequel/plugins/list.rb +6 -6
  195. data/lib/sequel/plugins/many_through_many.rb +11 -8
  196. data/lib/sequel/plugins/mssql_optimistic_locking.rb +3 -3
  197. data/lib/sequel/plugins/nested_attributes.rb +18 -31
  198. data/lib/sequel/plugins/optimistic_locking.rb +3 -3
  199. data/lib/sequel/plugins/pg_array_associations.rb +8 -2
  200. data/lib/sequel/plugins/pg_row.rb +2 -11
  201. data/lib/sequel/plugins/prepared_statements.rb +13 -66
  202. data/lib/sequel/plugins/prepared_statements_safe.rb +1 -1
  203. data/lib/sequel/plugins/rcte_tree.rb +7 -7
  204. data/lib/sequel/plugins/serialization.rb +15 -33
  205. data/lib/sequel/plugins/serialization_modification_detection.rb +1 -1
  206. data/lib/sequel/plugins/sharding.rb +2 -8
  207. data/lib/sequel/plugins/single_table_inheritance.rb +10 -13
  208. data/lib/sequel/plugins/skip_create_refresh.rb +3 -3
  209. data/lib/sequel/plugins/static_cache.rb +8 -9
  210. data/lib/sequel/plugins/string_stripper.rb +3 -3
  211. data/lib/sequel/plugins/subclasses.rb +1 -1
  212. data/lib/sequel/plugins/subset_conditions.rb +2 -2
  213. data/lib/sequel/plugins/table_select.rb +2 -2
  214. data/lib/sequel/plugins/tactical_eager_loading.rb +4 -4
  215. data/lib/sequel/plugins/timestamps.rb +6 -7
  216. data/lib/sequel/plugins/touch.rb +4 -8
  217. data/lib/sequel/plugins/tree.rb +3 -3
  218. data/lib/sequel/plugins/typecast_on_load.rb +2 -2
  219. data/lib/sequel/plugins/unlimited_update.rb +1 -7
  220. data/lib/sequel/plugins/update_or_create.rb +3 -3
  221. data/lib/sequel/plugins/update_refresh.rb +3 -3
  222. data/lib/sequel/plugins/uuid.rb +7 -11
  223. data/lib/sequel/plugins/validation_class_methods.rb +10 -9
  224. data/lib/sequel/plugins/validation_contexts.rb +4 -4
  225. data/lib/sequel/plugins/validation_helpers.rb +26 -25
  226. data/lib/sequel/plugins/whitelist_security.rb +13 -9
  227. data/lib/sequel/plugins/xml_serializer.rb +24 -25
  228. data/lib/sequel/sql.rb +145 -276
  229. data/lib/sequel/timezones.rb +8 -22
  230. data/lib/sequel/version.rb +2 -2
  231. data/spec/adapter_spec.rb +1 -1
  232. data/spec/adapters/db2_spec.rb +2 -103
  233. data/spec/adapters/mssql_spec.rb +89 -68
  234. data/spec/adapters/mysql_spec.rb +101 -480
  235. data/spec/adapters/oracle_spec.rb +1 -9
  236. data/spec/adapters/postgres_spec.rb +312 -565
  237. data/spec/adapters/spec_helper.rb +12 -31
  238. data/spec/adapters/sqlanywhere_spec.rb +2 -77
  239. data/spec/adapters/sqlite_spec.rb +8 -146
  240. data/spec/bin_spec.rb +11 -16
  241. data/spec/core/connection_pool_spec.rb +173 -74
  242. data/spec/core/database_spec.rb +64 -244
  243. data/spec/core/dataset_spec.rb +81 -415
  244. data/spec/core/deprecated_spec.rb +3 -3
  245. data/spec/core/expression_filters_spec.rb +37 -144
  246. data/spec/core/mock_adapter_spec.rb +176 -4
  247. data/spec/core/object_graph_spec.rb +11 -60
  248. data/spec/core/placeholder_literalizer_spec.rb +1 -14
  249. data/spec/core/schema_generator_spec.rb +51 -40
  250. data/spec/core/schema_spec.rb +74 -77
  251. data/spec/core/spec_helper.rb +6 -24
  252. data/spec/core/version_spec.rb +1 -1
  253. data/spec/core_extensions_spec.rb +7 -83
  254. data/spec/core_model_spec.rb +2 -2
  255. data/spec/deprecation_helper.rb +2 -14
  256. data/spec/extensions/accessed_columns_spec.rb +1 -1
  257. data/spec/extensions/active_model_spec.rb +3 -3
  258. data/spec/extensions/after_initialize_spec.rb +1 -1
  259. data/spec/extensions/arbitrary_servers_spec.rb +2 -2
  260. data/spec/extensions/association_dependencies_spec.rb +1 -1
  261. data/spec/extensions/association_pks_spec.rb +4 -59
  262. data/spec/extensions/association_proxies_spec.rb +1 -1
  263. data/spec/extensions/auto_literal_strings_spec.rb +1 -12
  264. data/spec/extensions/auto_validations_spec.rb +1 -1
  265. data/spec/extensions/blacklist_security_spec.rb +1 -1
  266. data/spec/extensions/blank_spec.rb +1 -1
  267. data/spec/extensions/boolean_readers_spec.rb +1 -1
  268. data/spec/extensions/boolean_subsets_spec.rb +1 -1
  269. data/spec/extensions/caching_spec.rb +1 -1
  270. data/spec/extensions/class_table_inheritance_spec.rb +35 -1086
  271. data/spec/extensions/column_conflicts_spec.rb +1 -1
  272. data/spec/extensions/column_select_spec.rb +4 -4
  273. data/spec/extensions/columns_introspection_spec.rb +1 -1
  274. data/spec/extensions/columns_updated_spec.rb +1 -1
  275. data/spec/extensions/composition_spec.rb +1 -7
  276. data/spec/extensions/connection_expiration_spec.rb +3 -3
  277. data/spec/extensions/connection_validator_spec.rb +3 -3
  278. data/spec/extensions/constraint_validations_plugin_spec.rb +1 -1
  279. data/spec/extensions/constraint_validations_spec.rb +1 -1
  280. data/spec/extensions/core_refinements_spec.rb +1 -3
  281. data/spec/extensions/csv_serializer_spec.rb +4 -9
  282. data/spec/extensions/current_datetime_timestamp_spec.rb +1 -1
  283. data/spec/extensions/dataset_associations_spec.rb +2 -1
  284. data/spec/extensions/dataset_source_alias_spec.rb +1 -1
  285. data/spec/extensions/date_arithmetic_spec.rb +3 -3
  286. data/spec/extensions/def_dataset_method_spec.rb +1 -1
  287. data/spec/extensions/defaults_setter_spec.rb +2 -2
  288. data/spec/extensions/delay_add_association_spec.rb +8 -9
  289. data/spec/extensions/dirty_spec.rb +1 -1
  290. data/spec/extensions/duplicate_columns_handler_spec.rb +1 -1
  291. data/spec/extensions/eager_each_spec.rb +2 -2
  292. data/spec/extensions/empty_array_consider_nulls_spec.rb +1 -1
  293. data/spec/extensions/error_splitter_spec.rb +1 -1
  294. data/spec/extensions/error_sql_spec.rb +1 -1
  295. data/spec/extensions/eval_inspect_spec.rb +1 -1
  296. data/spec/extensions/finder_spec.rb +1 -1
  297. data/spec/extensions/force_encoding_spec.rb +2 -5
  298. data/spec/extensions/freeze_datasets_spec.rb +1 -1
  299. data/spec/extensions/graph_each_spec.rb +5 -5
  300. data/spec/extensions/hook_class_methods_spec.rb +1 -194
  301. data/spec/extensions/identifier_mangling_spec.rb +17 -170
  302. data/spec/extensions/implicit_subquery_spec.rb +1 -5
  303. data/spec/extensions/inflector_spec.rb +1 -1
  304. data/spec/extensions/input_transformer_spec.rb +7 -2
  305. data/spec/extensions/insert_returning_select_spec.rb +1 -1
  306. data/spec/extensions/instance_filters_spec.rb +1 -1
  307. data/spec/extensions/instance_hooks_spec.rb +1 -95
  308. data/spec/extensions/inverted_subsets_spec.rb +1 -1
  309. data/spec/extensions/json_serializer_spec.rb +1 -1
  310. data/spec/extensions/lazy_attributes_spec.rb +1 -7
  311. data/spec/extensions/list_spec.rb +1 -1
  312. data/spec/extensions/looser_typecasting_spec.rb +1 -1
  313. data/spec/extensions/many_through_many_spec.rb +1 -1
  314. data/spec/extensions/migration_spec.rb +2 -2
  315. data/spec/extensions/modification_detection_spec.rb +1 -1
  316. data/spec/extensions/mssql_optimistic_locking_spec.rb +1 -1
  317. data/spec/extensions/named_timezones_spec.rb +3 -3
  318. data/spec/extensions/nested_attributes_spec.rb +1 -29
  319. data/spec/extensions/null_dataset_spec.rb +1 -11
  320. data/spec/extensions/optimistic_locking_spec.rb +1 -1
  321. data/spec/extensions/pagination_spec.rb +1 -1
  322. data/spec/extensions/pg_array_associations_spec.rb +4 -1
  323. data/spec/extensions/pg_array_ops_spec.rb +1 -1
  324. data/spec/extensions/pg_array_spec.rb +3 -48
  325. data/spec/extensions/pg_enum_spec.rb +1 -1
  326. data/spec/extensions/pg_hstore_ops_spec.rb +1 -1
  327. data/spec/extensions/pg_hstore_spec.rb +23 -32
  328. data/spec/extensions/pg_inet_ops_spec.rb +1 -1
  329. data/spec/extensions/pg_inet_spec.rb +1 -14
  330. data/spec/extensions/pg_interval_spec.rb +3 -13
  331. data/spec/extensions/pg_json_ops_spec.rb +1 -1
  332. data/spec/extensions/pg_json_spec.rb +1 -13
  333. data/spec/extensions/pg_loose_count_spec.rb +1 -1
  334. data/spec/extensions/pg_range_ops_spec.rb +1 -1
  335. data/spec/extensions/pg_range_spec.rb +3 -88
  336. data/spec/extensions/pg_row_ops_spec.rb +1 -1
  337. data/spec/extensions/pg_row_plugin_spec.rb +1 -1
  338. data/spec/extensions/pg_row_spec.rb +1 -44
  339. data/spec/extensions/pg_static_cache_updater_spec.rb +1 -1
  340. data/spec/extensions/prepared_statements_safe_spec.rb +1 -1
  341. data/spec/extensions/prepared_statements_spec.rb +13 -48
  342. data/spec/extensions/pretty_table_spec.rb +1 -1
  343. data/spec/extensions/query_spec.rb +1 -12
  344. data/spec/extensions/rcte_tree_spec.rb +1 -1
  345. data/spec/extensions/round_timestamps_spec.rb +1 -5
  346. data/spec/extensions/s_spec.rb +1 -1
  347. data/spec/extensions/schema_caching_spec.rb +1 -1
  348. data/spec/extensions/schema_dumper_spec.rb +1 -1
  349. data/spec/extensions/select_remove_spec.rb +1 -1
  350. data/spec/extensions/sequel_4_dataset_methods_spec.rb +1 -1
  351. data/spec/extensions/serialization_modification_detection_spec.rb +1 -1
  352. data/spec/extensions/serialization_spec.rb +2 -14
  353. data/spec/extensions/server_block_spec.rb +1 -1
  354. data/spec/extensions/server_logging_spec.rb +2 -2
  355. data/spec/extensions/sharding_spec.rb +1 -1
  356. data/spec/extensions/shared_caching_spec.rb +1 -28
  357. data/spec/extensions/single_table_inheritance_spec.rb +2 -5
  358. data/spec/extensions/singular_table_names_spec.rb +1 -1
  359. data/spec/extensions/skip_create_refresh_spec.rb +1 -1
  360. data/spec/extensions/spec_helper.rb +5 -27
  361. data/spec/extensions/split_array_nil_spec.rb +1 -1
  362. data/spec/extensions/split_values_spec.rb +1 -1
  363. data/spec/extensions/sql_comments_spec.rb +1 -1
  364. data/spec/extensions/sql_expr_spec.rb +1 -1
  365. data/spec/extensions/static_cache_spec.rb +1 -1
  366. data/spec/extensions/string_agg_spec.rb +2 -2
  367. data/spec/extensions/string_date_time_spec.rb +1 -1
  368. data/spec/extensions/string_stripper_spec.rb +1 -1
  369. data/spec/extensions/subclasses_spec.rb +1 -1
  370. data/spec/extensions/subset_conditions_spec.rb +1 -1
  371. data/spec/extensions/symbol_aref_refinement_spec.rb +1 -1
  372. data/spec/extensions/symbol_as_refinement_spec.rb +1 -1
  373. data/spec/extensions/table_select_spec.rb +4 -4
  374. data/spec/extensions/tactical_eager_loading_spec.rb +1 -6
  375. data/spec/extensions/thread_local_timezones_spec.rb +1 -1
  376. data/spec/extensions/timestamps_spec.rb +3 -3
  377. data/spec/extensions/to_dot_spec.rb +1 -1
  378. data/spec/extensions/touch_spec.rb +1 -1
  379. data/spec/extensions/tree_spec.rb +1 -1
  380. data/spec/extensions/typecast_on_load_spec.rb +1 -1
  381. data/spec/extensions/unlimited_update_spec.rb +1 -1
  382. data/spec/extensions/update_or_create_spec.rb +1 -1
  383. data/spec/extensions/update_primary_key_spec.rb +4 -3
  384. data/spec/extensions/update_refresh_spec.rb +1 -1
  385. data/spec/extensions/uuid_spec.rb +10 -12
  386. data/spec/extensions/validate_associated_spec.rb +1 -1
  387. data/spec/extensions/validation_class_methods_spec.rb +3 -3
  388. data/spec/extensions/validation_contexts_spec.rb +1 -1
  389. data/spec/extensions/validation_helpers_spec.rb +10 -44
  390. data/spec/extensions/whitelist_security_spec.rb +5 -5
  391. data/spec/extensions/xml_serializer_spec.rb +3 -3
  392. data/spec/guards_helper.rb +2 -1
  393. data/spec/integration/associations_test.rb +1 -23
  394. data/spec/integration/database_test.rb +7 -7
  395. data/spec/integration/dataset_test.rb +5 -47
  396. data/spec/integration/eager_loader_test.rb +1 -1
  397. data/spec/integration/migrator_test.rb +1 -1
  398. data/spec/integration/model_test.rb +4 -82
  399. data/spec/integration/plugin_test.rb +6 -22
  400. data/spec/integration/prepared_statement_test.rb +8 -88
  401. data/spec/integration/schema_test.rb +6 -6
  402. data/spec/integration/spec_helper.rb +13 -21
  403. data/spec/integration/timezone_test.rb +5 -5
  404. data/spec/integration/transaction_test.rb +3 -55
  405. data/spec/integration/type_test.rb +9 -9
  406. data/spec/model/association_reflection_spec.rb +24 -9
  407. data/spec/model/associations_spec.rb +124 -303
  408. data/spec/model/base_spec.rb +18 -137
  409. data/spec/model/class_dataset_methods_spec.rb +2 -20
  410. data/spec/model/dataset_methods_spec.rb +1 -20
  411. data/spec/model/eager_loading_spec.rb +17 -11
  412. data/spec/model/hooks_spec.rb +5 -300
  413. data/spec/model/inflector_spec.rb +1 -1
  414. data/spec/model/model_spec.rb +15 -320
  415. data/spec/model/plugins_spec.rb +2 -16
  416. data/spec/model/record_spec.rb +29 -121
  417. data/spec/model/spec_helper.rb +5 -15
  418. data/spec/model/validations_spec.rb +1 -1
  419. data/spec/sequel_warning.rb +1 -12
  420. metadata +8 -64
  421. data/doc/active_record.rdoc +0 -927
  422. data/lib/sequel/adapters/cubrid.rb +0 -160
  423. data/lib/sequel/adapters/do.rb +0 -166
  424. data/lib/sequel/adapters/do/mysql.rb +0 -69
  425. data/lib/sequel/adapters/do/postgres.rb +0 -46
  426. data/lib/sequel/adapters/do/sqlite3.rb +0 -41
  427. data/lib/sequel/adapters/jdbc/as400.rb +0 -92
  428. data/lib/sequel/adapters/jdbc/cubrid.rb +0 -65
  429. data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -37
  430. data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -34
  431. data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -34
  432. data/lib/sequel/adapters/odbc/progress.rb +0 -12
  433. data/lib/sequel/adapters/shared/cubrid.rb +0 -245
  434. data/lib/sequel/adapters/shared/firebird.rb +0 -261
  435. data/lib/sequel/adapters/shared/informix.rb +0 -63
  436. data/lib/sequel/adapters/shared/progress.rb +0 -40
  437. data/lib/sequel/adapters/swift.rb +0 -169
  438. data/lib/sequel/adapters/swift/mysql.rb +0 -50
  439. data/lib/sequel/adapters/swift/postgres.rb +0 -49
  440. data/lib/sequel/adapters/swift/sqlite.rb +0 -48
  441. data/lib/sequel/adapters/utils/pg_types.rb +0 -4
  442. data/lib/sequel/dataset/mutation.rb +0 -98
  443. data/lib/sequel/extensions/_deprecated_identifier_mangling.rb +0 -117
  444. data/lib/sequel/extensions/empty_array_ignore_nulls.rb +0 -8
  445. data/lib/sequel/extensions/filter_having.rb +0 -65
  446. data/lib/sequel/extensions/hash_aliases.rb +0 -51
  447. data/lib/sequel/extensions/meta_def.rb +0 -37
  448. data/lib/sequel/extensions/query_literals.rb +0 -86
  449. data/lib/sequel/extensions/ruby18_symbol_extensions.rb +0 -26
  450. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +0 -133
  451. data/lib/sequel/extensions/set_overrides.rb +0 -82
  452. data/lib/sequel/no_core_ext.rb +0 -4
  453. data/lib/sequel/plugins/association_autoreloading.rb +0 -11
  454. data/lib/sequel/plugins/identifier_columns.rb +0 -49
  455. data/lib/sequel/plugins/many_to_one_pk_lookup.rb +0 -11
  456. data/lib/sequel/plugins/pg_typecast_on_load.rb +0 -90
  457. data/lib/sequel/plugins/prepared_statements_associations.rb +0 -137
  458. data/lib/sequel/plugins/prepared_statements_with_pk.rb +0 -71
  459. data/lib/sequel/plugins/schema.rb +0 -84
  460. data/lib/sequel/plugins/scissors.rb +0 -37
  461. data/spec/core/dataset_mutation_spec.rb +0 -253
  462. data/spec/extensions/_deprecated_identifier_mangling_spec.rb +0 -314
  463. data/spec/extensions/before_after_save_spec.rb +0 -40
  464. data/spec/extensions/filter_having_spec.rb +0 -42
  465. data/spec/extensions/from_block_spec.rb +0 -21
  466. data/spec/extensions/hash_aliases_spec.rb +0 -26
  467. data/spec/extensions/identifier_columns_spec.rb +0 -19
  468. data/spec/extensions/meta_def_spec.rb +0 -35
  469. data/spec/extensions/no_auto_literal_strings_spec.rb +0 -69
  470. data/spec/extensions/pg_typecast_on_load_spec.rb +0 -70
  471. data/spec/extensions/prepared_statements_associations_spec.rb +0 -212
  472. data/spec/extensions/prepared_statements_with_pk_spec.rb +0 -40
  473. data/spec/extensions/query_literals_spec.rb +0 -185
  474. data/spec/extensions/schema_spec.rb +0 -123
  475. data/spec/extensions/scissors_spec.rb +0 -27
  476. data/spec/extensions/sequel_3_dataset_methods_spec.rb +0 -118
  477. data/spec/extensions/set_overrides_spec.rb +0 -75
@@ -2,16 +2,7 @@
2
2
 
3
3
  == Introduction
4
4
 
5
- Datasets are the primary way Sequel uses to access the database. While most database libraries have specific support for updating all records or only a single record, Sequel's ability to represent SQL queries themselves as objects is what gives Sequel most of its power. However, if you haven't been exposed to the dataset concept before, it can be a little disorienting. This document aims to give a basic introduction to datasets and how to use them.
6
-
7
- == What a Dataset Represents
8
-
9
- A Dataset can be thought of representing one of two concepts:
10
-
11
- * An SQL query
12
- * An abstract set of rows and some related behavior
13
-
14
- The first concept is more easily understood, so you should probably start with that assumption.
5
+ Datasets are the primary way Sequel uses to access the database. While most database libraries have specific support for updating all records or only a single record, Sequel's ability to represent SQL queries themselves as datasets is what gives Sequel most of its power. This document aims to give a basic introduction to datasets and how to use them.
15
6
 
16
7
  == Basics
17
8
 
@@ -22,9 +13,9 @@ The most basic dataset is the simple selection of all columns in a table:
22
13
 
23
14
  Here, DB represents your Sequel::Database object, and ds is your dataset, with the SQL query it represents below it.
24
15
 
25
- One of the core dataset ideas that should be understood is that datasets use a functional style of modification, in which methods called on the dataset return modified copies of the dataset, they don't modify the dataset themselves:
16
+ One of the core dataset ideas that should be understood is that datasets are frozen and use a functional style of modification, in which methods called on the dataset return modified copies of the dataset, they don't modify the dataset themselves:
26
17
 
27
- ds2 = ds.where(:id=>1)
18
+ ds2 = ds.where(id: 1)
28
19
  ds2
29
20
  # SELECT * FROM posts WHERE id = 1
30
21
  ds
@@ -35,7 +26,7 @@ Note how ds itself is not modified. This is because ds.where returns a modified
35
26
  # Thread safe:
36
27
  100.times do |i|
37
28
  Thread.new do
38
- ds.where(:id=>i).first
29
+ ds.where(id: i).first
39
30
  end
40
31
  end
41
32
 
@@ -77,7 +68,7 @@ Most dataset methods fall into this category, which can be further broken down b
77
68
  SELECT:: select, select_all, select_append, select_group, select_more
78
69
  FROM:: from, from_self
79
70
  JOIN:: join, left_join, right_join, full_join, natural_join, natural_left_join, natural_right_join, natural_full_join, cross_join, inner_join, left_outer_join, right_outer_join, full_outer_join, join_table
80
- WHERE:: where, filter, exclude, exclude_where, and, or, grep, invert, unfiltered
71
+ WHERE:: where, filter, exclude, or, grep, invert, unfiltered
81
72
  GROUP:: group, group_by, group_and_count, group_append, select_group, ungrouped
82
73
  HAVING:: having, exclude_having, invert, unfiltered
83
74
  ORDER:: order, order_by, order_append, order_prepend, order_more, reverse, reverse_order, unordered
@@ -85,16 +76,16 @@ LIMIT/OFFSET:: limit, offset, unlimited
85
76
  compounds:: union, intersect, except
86
77
  locking:: for_update, lock_style
87
78
  common table expressions:: with, with_recursive
88
- other:: clone, distinct, naked, qualify, server, with_sql
79
+ other:: distinct, naked, qualify, server, with_sql
89
80
 
90
81
  === Methods that execute code on the database
91
82
 
92
83
  Most other dataset methods commonly used will execute the dataset's SQL on the database:
93
84
 
94
- SELECT (All Records):: all, each, map, to_hash, to_hash_groups, select_map, select_order_map, select_hash, select_hash_groups
85
+ SELECT (All Records):: all, each, map, as_hash, to_hash_groups, select_map, select_order_map, select_hash, select_hash_groups
95
86
  SELECT (First Record):: first, last, [], single_record
96
87
  SELECT (Single Value):: get, single_value
97
- SELECT (Aggregates):: count, avg, max, min, sum, range, interval
88
+ SELECT (Aggregates):: count, avg, max, min, sum
98
89
  INSERT:: insert, <<, import, multi_insert
99
90
  UPDATE:: update
100
91
  DELETE:: delete
@@ -1,206 +1,201 @@
1
1
  = Dataset Filtering
2
2
 
3
- Sequel is very flexible when it comes to filtering records. You can specify your conditions as a custom string, as a string with parameters, as a hash of values to compare against, or as ruby code that Sequel translates into SQL expressions.
4
-
5
- == Filtering using a custom filter string
6
-
7
- If you wish to write your SQL by hand, you can just supply it to the dataset's #where method:
8
-
9
- items.where('x < 10').sql
10
- #=> "SELECT * FROM items WHERE x < 10"
11
-
12
- In order to prevent SQL injection, you can replace literal values with question marks and supply the values as additional arguments:
13
-
14
- items.where('category = ?', 'ruby').sql
15
- #=> "SELECT * FROM items WHERE category = 'ruby'"
16
-
17
- You can also use placeholders with :placeholder and a hash of placeholder values:
18
-
19
- items.where('category = :category', :category=>'ruby').sql
20
- #=> "SELECT * FROM items WHERE category = 'ruby'"
21
-
22
- === Specifying SQL functions
23
-
24
- Sequel also allows you to specify functions by using the Sequel.function method:
25
-
26
- items.literal(Sequel.function(:avg, :price)) #=> "avg(price)"
27
-
28
- If you are specifying a filter/selection/order, you can use a virtual row block:
29
-
30
- items.select{avg(price)}
31
-
32
- You can also use the {core_extensions extension}[rdoc-ref:doc/core_extensions.rdoc] and the +sql_function+ method:
33
-
34
- :avg.sql_function(:price)
3
+ Sequel is very flexible when it comes to filtering records. You can specify your conditions as a hash of values to compare against, or as ruby code that Sequel translates into SQL expressions, or as an SQL code fragment (with optional parameters), .
35
4
 
36
5
  == Filtering using a hash
37
6
 
38
7
  If you just need to compare records against values, you can supply a hash:
39
8
 
40
- items.where(:category => 'ruby').sql
41
- #=> "SELECT * FROM items WHERE (category = 'ruby')"
9
+ items.where(category: 'ruby').sql
10
+ # "SELECT * FROM items WHERE (category = 'ruby')"
42
11
 
43
12
  Sequel can check for null values:
44
13
 
45
- items.where(:category => nil).sql
46
- #=> "SELECT * FROM items WHERE (category IS NULL)"
14
+ items.where(category: nil).sql
15
+ # "SELECT * FROM items WHERE (category IS NULL)"
47
16
 
48
17
  Or compare two columns:
49
18
 
50
- items.where{{:x => some_table[:y]}}.sql
51
- #=> "SELECT * FROM items WHERE (x = some_table.y)"
19
+ items.where{{x: some_table[:y]}}.sql
20
+ # "SELECT * FROM items WHERE (x = some_table.y)"
52
21
 
53
22
  And also compare against multiple values:
54
23
 
55
- items.where(:category => ['ruby', 'perl']).sql
56
- #=> "SELECT * FROM items WHERE (category IN ('ruby', 'perl'))"
24
+ items.where(category: ['ruby', 'perl']).sql
25
+ # "SELECT * FROM items WHERE (category IN ('ruby', 'perl'))"
57
26
 
58
27
  Ranges (both inclusive and exclusive) can also be used:
59
28
 
60
- items.where(:price => 100..200).sql
61
- #=> "SELECT * FROM items WHERE (price >= 100 AND price <= 200)"
29
+ items.where(price: 100..200).sql
30
+ # "SELECT * FROM items WHERE (price >= 100 AND price <= 200)"
62
31
 
63
- items.where(:price => 100...200).sql
64
- #=> "SELECT * FROM items WHERE (price >= 100 AND price < 200)"
32
+ items.where(price: 100...200).sql
33
+ # "SELECT * FROM items WHERE (price >= 100 AND price < 200)"
65
34
 
66
35
  == Filtering using an array
67
36
 
68
37
  If you need to select multiple items from a dataset, you can supply an array:
69
38
 
70
- item_array = [1, 38, 47, 99]
71
- items.where(:id => item_array).sql
72
- #=> "SELECT * FROM items WHERE (id IN (1, 38, 47, 99))"
39
+ items.where(id: [1, 38, 47, 99]).sql
40
+ # "SELECT * FROM items WHERE (id IN (1, 38, 47, 99))"
73
41
 
74
42
  == Filtering using expressions
75
43
 
76
- You can pass a block to where, which is evaluated in a special context:
44
+ You can pass a block to where (referred to as a virtual row block), which is evaluated in a special context:
77
45
 
78
46
  items.where{price * 2 < 50}.sql
79
- #=> "SELECT * FROM items WHERE ((price * 2) < 50)
47
+ # "SELECT * FROM items WHERE ((price * 2) < 50)
80
48
 
81
49
  This works for the standard inequality and arithmetic operators:
82
50
 
83
51
  items.where{price + 100 < 200}.sql
84
- #=> "SELECT * FROM items WHERE ((price + 100) < 200)
52
+ # "SELECT * FROM items WHERE ((price + 100) < 200)
85
53
 
86
54
  items.where{price - 100 > 200}.sql
87
- #=> "SELECT * FROM items WHERE ((price - 100) > 200)
55
+ # "SELECT * FROM items WHERE ((price - 100) > 200)
88
56
 
89
57
  items.where{price * 100 <= 200}.sql
90
- #=> "SELECT * FROM items WHERE ((price * 100) <= 200)
58
+ # "SELECT * FROM items WHERE ((price * 100) <= 200)
91
59
 
92
60
  items.where{price / 100 >= 200}.sql
93
- #=> "SELECT * FROM items WHERE ((price / 100) >= 200)
61
+ # "SELECT * FROM items WHERE ((price / 100) >= 200)
94
62
 
95
63
  items.where{price ** 2 >= 200}.sql
96
- #=> "SELECT * FROM items WHERE (power(price, 2) >= 200)
64
+ # "SELECT * FROM items WHERE (power(price, 2) >= 200)
97
65
 
98
66
  You use the overloaded bitwise and (&) and or (|) operators to combine expressions:
99
67
 
100
68
  items.where{(price + 100 < 200) & (price * 100 <= 200)}.sql
101
- #=> "SELECT * FROM items WHERE (((price + 100) < 200) AND ((price * 100) <= 200))
69
+ # "SELECT * FROM items WHERE (((price + 100) < 200) AND ((price * 100) <= 200))
102
70
 
103
71
  items.where{(price - 100 > 200) | (price / 100 >= 200)}.sql
104
- #=> "SELECT * FROM items WHERE (((price - 100) > 200) OR ((price / 100) >= 200))
72
+ # "SELECT * FROM items WHERE (((price - 100) > 200) OR ((price / 100) >= 200))
105
73
 
106
74
  To filter by equality, you use the standard hash, which can be combined with other expressions using Sequel.& and Sequel.|:
107
75
 
108
- items.where{Sequel.&({:category => 'ruby'}, (price + 100 < 200))}.sql
109
- #=> "SELECT * FROM items WHERE ((category = 'ruby') AND ((price + 100) < 200))"
76
+ items.where{Sequel.&({category: 'ruby'}, (price + 100 < 200))}.sql
77
+ # "SELECT * FROM items WHERE ((category = 'ruby') AND ((price + 100) < 200))"
110
78
 
111
79
  You can also use the =~ operator:
112
80
 
113
81
  items.where{(category =~ 'ruby') & (price + 100 < 200)}.sql
114
- #=> "SELECT * FROM items WHERE ((category = 'ruby') AND ((price + 100) < 200))"
82
+ # "SELECT * FROM items WHERE ((category = 'ruby') AND ((price + 100) < 200))"
115
83
 
116
84
  This works with other hash values, such as arrays and ranges:
117
85
 
118
- items.where{Sequel.|({:category => ['ruby', 'other']}, (price - 100 > 200))}.sql
119
- #=> "SELECT * FROM items WHERE ((category IN ('ruby', 'other')) OR ((price - 100) <= 200))"
86
+ items.where{Sequel.|({category: ['ruby', 'other']}, (price - 100 > 200))}.sql
87
+ # "SELECT * FROM items WHERE ((category IN ('ruby', 'other')) OR ((price - 100) <= 200))"
120
88
 
121
89
  items.where{(price =~ (100..200)) & :active}.sql
122
- #=> "SELECT * FROM items WHERE ((price >= 100 AND price <= 200) AND active)"
90
+ # "SELECT * FROM items WHERE ((price >= 100 AND price <= 200) AND active)"
91
+
92
+ == Filtering using a custom filter string
93
+
94
+ If you wish to include an SQL fragment as part of a filter, you need to wrap it with +Sequel.lit+ to mark that it is literal SQL code, and pass it to the #where method:
95
+
96
+ items.where(Sequel.lit('x < 10')).sql
97
+ # "SELECT * FROM items WHERE x < 10"
98
+
99
+ In order to prevent SQL injection, you can replace literal values with question marks and supply the values as additional arguments to +Sequel.lit+:
100
+
101
+ items.where(Sequel.lit('category = ?', 'ruby')).sql
102
+ # "SELECT * FROM items WHERE category = 'ruby'"
103
+
104
+ You can also use placeholders with :placeholder and a hash of placeholder values:
105
+
106
+ items.where(Sequel.lit('category = :category', category: "ruby")).sql
107
+ # "SELECT * FROM items WHERE category = 'ruby'"
108
+
109
+ === Specifying SQL functions
110
+
111
+ Sequel also allows you to specify functions by using the Sequel.function method:
112
+
113
+ items.literal(Sequel.function(:avg, :price)) # "avg(price)"
114
+
115
+ If you are specifying a filter/selection/order, you can use a virtual row block:
116
+
117
+ items.select{avg(price)}
123
118
 
124
119
  === Negating conditions
125
120
 
126
121
  You can use the exclude method to exclude whole conditions:
127
122
 
128
- items.exclude(:category => 'ruby').sql
129
- #=> "SELECT * FROM items WHERE (category != 'ruby')"
123
+ items.exclude(category: 'ruby').sql
124
+ # "SELECT * FROM items WHERE (category != 'ruby')"
130
125
 
131
126
  items.exclude(:active).sql
132
- #=> "SELECT * FROM items WHERE NOT active"
127
+ # "SELECT * FROM items WHERE NOT active"
133
128
 
134
129
  items.exclude{price / 100 >= 200}.sql
135
- #=> "SELECT * FROM items WHERE ((price / 100) < 200)
130
+ # "SELECT * FROM items WHERE ((price / 100) < 200)
136
131
 
137
132
  To exclude only parts of conditions, you can use when in combination with Sequel.~ or the ~ method on Sequel expressions:
138
133
 
139
- items.where{Sequel.&(Sequel.~(:category => 'ruby'), (price + 100 < 200))}.sql
140
- #=> "SELECT * FROM items WHERE ((category != 'ruby') AND ((price + 100) < 200))"
134
+ items.where{Sequel.&(Sequel.~(category: 'ruby'), (price + 100 < 200))}.sql
135
+ # "SELECT * FROM items WHERE ((category != 'ruby') AND ((price + 100) < 200))"
141
136
 
142
137
  items.where{~(category =~ 'ruby') & (price + 100 < 200)}.sql
143
- #=> "SELECT * FROM items WHERE ((category != 'ruby') AND ((price + 100) < 200))"
138
+ # "SELECT * FROM items WHERE ((category != 'ruby') AND ((price + 100) < 200))"
144
139
 
145
- On Ruby 1.9+, you can also use the !~ method:
140
+ You can also use the !~ method:
146
141
 
147
142
  items.where{(category !~ 'ruby') & (price + 100 < 200)}.sql
148
- #=> "SELECT * FROM items WHERE ((category != 'ruby') AND ((price + 100) < 200))"
143
+ # "SELECT * FROM items WHERE ((category != 'ruby') AND ((price + 100) < 200))"
149
144
 
150
145
  === Comparing against column references
151
146
 
152
147
  You can also compare against other columns:
153
148
 
154
149
  items.where{credit > debit}.sql
155
- #=> "SELECT * FROM items WHERE (credit > debit)
150
+ # "SELECT * FROM items WHERE (credit > debit)
156
151
 
157
152
  Or against SQL functions:
158
153
 
159
154
  items.where{price - 100 < max(price)}.sql
160
- #=> "SELECT * FROM items WHERE ((price - 100) < max(price))"
155
+ # "SELECT * FROM items WHERE ((price - 100) < max(price))"
161
156
 
162
157
  == String search functions
163
158
 
164
159
  You can search SQL strings in a case sensitive manner using the Sequel.like method:
165
160
 
166
161
  items.where(Sequel.like(:name, 'Acme%')).sql
167
- #=> "SELECT * FROM items WHERE (name LIKE 'Acme%' ESCAPE '\')"
162
+ # "SELECT * FROM items WHERE (name LIKE 'Acme%' ESCAPE '\')"
168
163
 
169
164
  You can search SQL strings in a case insensitive manner using the Sequel.ilike method:
170
165
 
171
166
  items.where(Sequel.ilike(:name, 'Acme%')).sql
172
- #=> "SELECT * FROM items WHERE (name ILIKE 'Acme%' ESCAPE '\')"
167
+ # "SELECT * FROM items WHERE (name ILIKE 'Acme%' ESCAPE '\')"
173
168
 
174
- You can specify a Regexp as a like argument, but this will probably only work
169
+ You can specify a Regexp as a hash value (or like argument), but this will probably only work
175
170
  on PostgreSQL and MySQL:
176
171
 
177
- items.where(Sequel.like(:name, /Acme.*/)).sql
178
- #=> "SELECT * FROM items WHERE (name ~ 'Acme.*')"
172
+ items.where(name: /Acme.*/).sql
173
+ # "SELECT * FROM items WHERE (name ~ 'Acme.*')"
179
174
 
180
175
  Like can also take more than one argument:
181
176
 
182
177
  items.where(Sequel.like(:name, 'Acme%', /Beta.*/)).sql
183
- #=> "SELECT * FROM items WHERE ((name LIKE 'Acme%' ESCAPE '\') OR (name ~ 'Beta.*'))"
178
+ # "SELECT * FROM items WHERE ((name LIKE 'Acme%' ESCAPE '\') OR (name ~ 'Beta.*'))"
184
179
 
185
180
  == String concatenation
186
181
 
187
182
  You can concatenate SQL strings using Sequel.join:
188
183
 
189
184
  items.where(Sequel.join([:name, :comment]).like('Jo%nice%')).sql
190
- #=> "SELECT * FROM items WHERE ((name || comment) LIKE 'Jo%nice%' ESCAPE '\')"
185
+ # "SELECT * FROM items WHERE ((name || comment) LIKE 'Jo%nice%' ESCAPE '\')"
191
186
 
192
187
  Sequel.join also takes a join argument:
193
188
 
194
189
  items.where(Sequel.join([:name, :comment], ':').like('John:%nice%')).sql
195
- #=> "SELECT * FROM items WHERE ((name || ':' || comment) LIKE 'John:%nice%' ESCAPE '\')"
190
+ # "SELECT * FROM items WHERE ((name || ':' || comment) LIKE 'John:%nice%' ESCAPE '\')"
196
191
 
197
192
  == Filtering using sub-queries
198
193
 
199
- One of the best features of Sequel is the ability to use datasets as sub-queries. Sub-queries can be very useful for filtering records, and many times provide a simpler alternative to table joins. Sub-queries can be used in all forms of filters:
194
+ Datasets can be used as subqueries. Subqueries can be very useful for filtering records, and many times provide a simpler alternative to table joins. Subqueries can be used in all forms of filters:
200
195
 
201
196
  refs = consumer_refs.where(:logged_in).select(:consumer_id)
202
- consumers.where(:id => refs).sql
203
- #=> "SELECT * FROM consumers WHERE (id IN (SELECT consumer_id FROM consumer_refs WHERE logged_in))"
197
+ consumers.where(id: refs).sql
198
+ # "SELECT * FROM consumers WHERE (id IN (SELECT consumer_id FROM consumer_refs WHERE logged_in))"
204
199
 
205
200
  Note that if you are checking for the inclusion of a single column in a subselect, the subselect should only select a single column.
206
201
 
@@ -208,5 +203,5 @@ Note that if you are checking for the inclusion of a single column in a subselec
208
203
 
209
204
  By default, if you chain calls to +where+, the conditions get ANDed together. If you want to use an OR for a condition, you can use the +or+ method:
210
205
 
211
- items.where(:name=>'Food').or(:vendor=>1).sql
212
- #=> "SELECT * FROM items WHERE ((name = 'Food') OR (vendor = 1))"
206
+ items.where(name: 'Food').or(vendor: 1).sql
207
+ # "SELECT * FROM items WHERE ((name = 'Food') OR (vendor = 1))"
@@ -10,7 +10,7 @@ Global extensions are loaded via <tt>Sequel.extension</tt>:
10
10
 
11
11
  Sequel.extension :named_timezones
12
12
 
13
- What this does is require the relevent extension from <tt>sequel/extensions/named_timezones</tt> somewhere in the ruby path. Actually, that is all that does. Global extensions are just a simpler, consistent way to require code that modifies Sequel.
13
+ All this does is require the relevent extension from <tt>sequel/extensions/named_timezones</tt> somewhere in the ruby path. Global extensions are just a simpler, consistent way to require code that modifies Sequel.
14
14
 
15
15
  == Database Extensions
16
16
 
@@ -28,18 +28,11 @@ All future <tt>Sequel::Database</tt> instances created afterward will then autom
28
28
 
29
29
  == Dataset Extensions
30
30
 
31
- Dataset extensions should add or modify the behavior of a single <tt>Sequel::Dataset</tt> instance. They are loaded via <tt>Sequel::Dataset#extension</tt> or <tt>Sequel::Dataset#extension!</tt>. <tt>Sequel::Dataset#extension</tt> returns a modifies copy of the dataset that includes the extension (similar to how most dataset query methods work):
31
+ Dataset extensions should add or modify the behavior of a single <tt>Sequel::Dataset</tt> instance. They are loaded via <tt>Sequel::Dataset#extension</tt>. <tt>Sequel::Dataset#extension</tt> returns a modifies copy of the dataset that includes the extension (similar to how most dataset query methods work):
32
32
 
33
33
  ds = DB[:a].extension(:columns_introspection)
34
34
 
35
- <tt>Sequel::Dataset#extension!</tt> modifies a dataset to include the extension (similar to how dataset mutation methods work):
36
-
37
- ds = DB[:a]
38
- ds.extension!(:columns_introspection)
39
-
40
- It is recommended you only use <tt>Sequel::Dataset#extension!</tt> if you have good reasons to.
41
-
42
- The first thing loading a Dataset extension does is load the relevent extension globally. Similar to Database extensions, loading a Dataset extension globally should not affect state other than maybe adding a module. After loading the extension globally, it modifies the related <tt>Sequel::Dataset</tt> instance to modify its behavior.
35
+ The first thing loading a Dataset extension does is load the relevent extension globally. Similar to Database extensions, loading a Dataset extension globally should not affect state other than maybe adding a module. After loading the extension globally, it returned a modified copy of the <tt>Sequel::Dataset</tt> with the extension loaded into it.
43
36
 
44
37
  If you want to load an extension into all future datasets for a given <tt>Sequel::Database</tt> instance, you can also load it as a Database extension:
45
38
 
@@ -1,33 +1,42 @@
1
1
  = Sequel::Model Mass Assignment
2
2
 
3
- Most Model methods that take a hash of attribute keys and values, including <tt>Model.new</tt>, <tt>Model.create</tt>, <tt>Model#set</tt> and <tt>Model#update</tt> are subject to Sequel's mass assignment rules.
4
- When you pass a hash to these methods, each key has an <tt>=</tt> appended to it (the setter method), and if the setter method exists and access to it is not restricted, Sequel will call the setter method with the hash value.
3
+ Most Model methods that take a hash of attribute keys and values, including <tt>Model.new</tt>,
4
+ <tt>Model.create</tt>, <tt>Model#set</tt> and <tt>Model#update</tt> are subject to Sequel's mass assignment rules.
5
+
6
+ If you have an instance of a plain Sequel::Model class:
7
+
8
+ class Post < Sequel::Model
9
+ end
10
+ post = Post.new
11
+
12
+ and you call a mass assignment method with a hash:
13
+
14
+ post.set(title: 'T', body: 'B')
15
+
16
+ the mass assignment method will go through each key in the hash, append <tt>=</tt> to it to determine the
17
+ setter method, and if the setter method is defined and access to it is not restricted, Sequel will call the
18
+ setter method with the hash value. So if we assume that the posts table has subject and text columns, what
19
+ the above mass assignment call actually does is:
20
+
21
+ post.title=('T')
22
+ post.body=('B')
23
+
5
24
  By default, there are two types of setter methods that are restricted.
6
25
  The first is methods like <tt>typecast_on_assignment=</tt> and <tt>==</tt>, which don't affect columns.
7
26
  These methods cannot be enabled for mass assignment.
8
27
  The second is primary key setters.
9
- To enable use of primary key setters, you need to call +unrestrict_primary_key+ for that model:
10
28
 
11
- Post.unrestrict_primary_key
12
-
13
- Since mass assignment by default allows modification of all column values except for primary key columns, it can be a security risk in some cases.
14
- Sequel has multiple ways of securing mass assignment.
15
- The first way is using +set_allowed_columns+:
29
+ So if you do:
16
30
 
17
- Post.set_allowed_columns :title, :body, :category
31
+ post = Post.new(id: 1)
18
32
 
19
- This explicitly sets which methods are allowed (<tt>title=</tt>, <tt>body=</tt>, and <tt>category=</tt>), all other methods will not be allowed.
20
- This method is useful in simple applications where the same columns are allowed in all cases, but not appropriate when different columns are allowed in different scenarios (e.g. admin access vs. user access).
21
- To handle cases where different columns are allowed in different cases, you can use +set_only+ or +update_only+:
33
+ Sequel will raise a Sequel::MassAssignmentRestriction exception, since by default setting the primary key is not allowed.
22
34
 
23
- # user case
24
- post.set_only(params[:post], :title, :body)
25
- # admin case
26
- post.set_only(params[:post], :title, :body, :deleted)
35
+ To enable use of primary key setters, you need to call +unrestrict_primary_key+ for that model:
27
36
 
28
- In this case, only the <tt>title=</tt> and <tt>body=</tt> methods will be allowed in the mass assignment in the user case, and only <tt>title=</tt>, <tt>body=</tt>, and <tt>deleted=</tt> will be allowed for mass assignment in the admin case.
37
+ Post.unrestrict_primary_key
29
38
 
30
- By default, if an invalid setter method call is attempted, Sequel raises a <tt>Sequel::Error</tt> exception. You can have Sequel silently ignore invalid calls by doing:
39
+ If you want to change mass assignment so it ignores attempts to access restricted setter methods, you can do:
31
40
 
32
41
  # Global default
33
42
  Sequel::Model.strict_param_setting = false
@@ -36,20 +45,54 @@ By default, if an invalid setter method call is attempted, Sequel raises a <tt>S
36
45
  # Instance level
37
46
  post.strict_param_setting = false
38
47
 
39
- In addition to +set_only+ and +update_only+, Sequel also has +set_fields+ and +update_fields+ methods, and these may be a better mass assignment choice for most users.
40
- These methods take two arguments, the attributes hash as the first argument, and a single array of valid field names as the second argument:
48
+ Since mass assignment by default allows modification of all column values except for primary key columns, it can be a security risk in some cases.
49
+ If you are dealing with untrusted input, you are generally going to want to restrict what should be updated.
50
+
51
+ Sequel has <tt>Model#set_fields</tt> and <tt>Model#update_fields</tt> methods, which are designed to be used with untrused input.
52
+ These methods take two arguments, the untrusted hash as the first argument, and a trusted array of field names as the second argument:
41
53
 
42
- post.set_fields(params[:post], [:title, :body])
54
+ post.set_fields({title: 'T', body: 'B'}, [:title, :body])
43
55
 
44
- +set_fields+ and +update_fields+ differ in implementation from +set_only+ and +update_only+.
45
- With +set_only+ and +update_only+, the hash is iterated over and it checks each method call attempt to see if it is valid.
46
- With +set_fields+ and +update_fields+, the array is iterated over, and it just looks up the value in the hash and calls the appropriate setter method.
56
+ Instead of looking at every key in the untrusted hash, +set_fields+ will iterate over the trusted field names, looking each up in the hash, and
57
+ calling the setter method appropriately with the result. +set_fields+ basically translates the above method call to:
58
+
59
+ post.title=('T')
60
+ post.body=('B')
61
+
62
+ By using this method, you can be sure that the mass assignment method only sets the fields you expect it to set.
63
+
64
+ Note that if one of the fields does not exist in the hash:
65
+
66
+ post.set_fields({title: 'T'}, [:title, :body])
67
+
68
+ +set_fields+ will set the value to nil (the default hash value) by default, with behavior equivalent to:
69
+
70
+ post.title=('T')
71
+ post.body=(nil)
72
+
73
+ You can use the :missing option to +set_fields+ to change the behavior:
74
+
75
+ post.set_fields({title: 'T'}, [:title, :body], missing: :skip)
76
+ # post.title=('T') # only
77
+
78
+ post.set_fields({title: 'T'}, [:title, :body], missing: :raise)
79
+ # raises Sequel::Error
80
+
81
+ If you want to set a model level default for the +set_fields+ options, you can use the +default_set_fields_options+ class accessor:
82
+
83
+ # Global default
84
+ Sequel::Model.default_set_fields_options[:missing] = :skip
85
+ # Class level
86
+ Post.default_set_fields_options[:missing] = :skip
47
87
 
48
- +set_fields+ and +update_fields+ are designed for the case where you are expecting specific fields in the input, and want to ignore the other fields.
49
- They work great for things like HTML forms where the form fields are static.
50
- +set_only+ and +update_only+ are designed for cases where you are not sure what fields are going to be present in the input, but still want to make sure only certain setter methods can be called.
51
- They work great for flexible APIs.
88
+ Here's a table describing Sequel's default mass assignment methods:
52
89
 
53
- +set_fields+ and +update_fields+ take an optional argument hash, and currently handles the :missing option. With <tt>:missing=>:skip</tt>, +set_fields+ and +update_fields+ will just skip missing entries in the hash, allowing them to be used in flexible APIs. With <tt>:missing=>:raise</tt>, +set_fields+ and +update_fields+ will raise an error if one of the entries in the hash is missing, instead of just assigning the value to nil or whatever the hash's default value is. That allows stricter checks, similar to the :strict_param_checking setting for the default mass assignment methods. You can use the <tt>Model.default_set_fields_options=</tt> method to set the default options to use for +set_fields+ and +update_fields+ on a global or per-model basis.
90
+ Model.new(hash) :: Creates a new model instance, then calls Model#set(hash)
91
+ Model.create(hash) :: Calls Model.new(hash).save
92
+ Model#set(hash) :: Calls related setter method (unless access is restricted) for each key in the hash, then returns self
93
+ Model#update(hash) :: Calls set(hash).save_changes
94
+ Model#set_fields(hash, columns, options) :: For each column in columns, looks up related entry in hash, and calls the related setter method
95
+ Model#update_fields(hash, columns, options) :: Calls set_fields(hash, columns, options).save_changes
54
96
 
55
- In all of the mass assignment cases, methods starting with +set+ will set the attributes without saving the object, while methods starting with +update+ will set the attributes and then save the changes to the object.
97
+ For backwards compatibility, Sequel also ships with a whitelist_security and blacklist_security plugins that offer additional mass assignment
98
+ methods, but it is recommended to use +set_fields+ or +update_fields+ for untrusted input, and the other methods for trusted input.