sequel 4.41.0 → 4.42.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (256) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG +98 -0
  3. data/README.rdoc +23 -10
  4. data/doc/active_record.rdoc +4 -4
  5. data/doc/advanced_associations.rdoc +2 -2
  6. data/doc/association_basics.rdoc +5 -2
  7. data/doc/cheat_sheet.rdoc +3 -3
  8. data/doc/core_extensions.rdoc +2 -2
  9. data/doc/dataset_basics.rdoc +4 -4
  10. data/doc/dataset_filtering.rdoc +1 -1
  11. data/doc/migration.rdoc +19 -1
  12. data/doc/prepared_statements.rdoc +2 -2
  13. data/doc/release_notes/4.42.0.txt +221 -0
  14. data/doc/testing.rdoc +3 -1
  15. data/lib/sequel/adapters/ado/access.rb +0 -1
  16. data/lib/sequel/adapters/ado/mssql.rb +0 -1
  17. data/lib/sequel/adapters/do/mysql.rb +0 -1
  18. data/lib/sequel/adapters/do/postgres.rb +0 -1
  19. data/lib/sequel/adapters/do/sqlite3.rb +0 -1
  20. data/lib/sequel/adapters/ibmdb.rb +21 -25
  21. data/lib/sequel/adapters/jdbc.rb +8 -16
  22. data/lib/sequel/adapters/jdbc/as400.rb +0 -1
  23. data/lib/sequel/adapters/jdbc/cubrid.rb +0 -1
  24. data/lib/sequel/adapters/jdbc/db2.rb +0 -1
  25. data/lib/sequel/adapters/jdbc/derby.rb +0 -1
  26. data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -1
  27. data/lib/sequel/adapters/jdbc/h2.rb +0 -1
  28. data/lib/sequel/adapters/jdbc/hsqldb.rb +0 -1
  29. data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -1
  30. data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -1
  31. data/lib/sequel/adapters/jdbc/jtds.rb +0 -1
  32. data/lib/sequel/adapters/jdbc/mssql.rb +0 -1
  33. data/lib/sequel/adapters/jdbc/mysql.rb +0 -1
  34. data/lib/sequel/adapters/jdbc/oracle.rb +0 -1
  35. data/lib/sequel/adapters/jdbc/postgresql.rb +0 -13
  36. data/lib/sequel/adapters/jdbc/sqlanywhere.rb +0 -1
  37. data/lib/sequel/adapters/jdbc/sqlite.rb +0 -1
  38. data/lib/sequel/adapters/jdbc/sqlserver.rb +3 -4
  39. data/lib/sequel/adapters/mock.rb +54 -12
  40. data/lib/sequel/adapters/mysql.rb +1 -1
  41. data/lib/sequel/adapters/mysql2.rb +11 -17
  42. data/lib/sequel/adapters/odbc/mssql.rb +0 -1
  43. data/lib/sequel/adapters/oracle.rb +8 -20
  44. data/lib/sequel/adapters/postgres.rb +11 -29
  45. data/lib/sequel/adapters/shared/access.rb +5 -12
  46. data/lib/sequel/adapters/shared/cubrid.rb +4 -13
  47. data/lib/sequel/adapters/shared/db2.rb +4 -2
  48. data/lib/sequel/adapters/shared/firebird.rb +2 -4
  49. data/lib/sequel/adapters/shared/informix.rb +4 -2
  50. data/lib/sequel/adapters/shared/mssql.rb +3 -5
  51. data/lib/sequel/adapters/shared/mysql.rb +4 -14
  52. data/lib/sequel/adapters/shared/oracle.rb +1 -3
  53. data/lib/sequel/adapters/shared/postgres.rb +16 -38
  54. data/lib/sequel/adapters/shared/progress.rb +0 -2
  55. data/lib/sequel/adapters/shared/sqlanywhere.rb +0 -2
  56. data/lib/sequel/adapters/shared/sqlite.rb +20 -16
  57. data/lib/sequel/adapters/sqlite.rb +8 -20
  58. data/lib/sequel/adapters/swift/mysql.rb +0 -1
  59. data/lib/sequel/adapters/swift/postgres.rb +0 -1
  60. data/lib/sequel/adapters/swift/sqlite.rb +0 -1
  61. data/lib/sequel/adapters/tinytds.rb +4 -12
  62. data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +1 -1
  63. data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -2
  64. data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +11 -34
  65. data/lib/sequel/adapters/utils/stored_procedures.rb +9 -22
  66. data/lib/sequel/adapters/utils/unmodified_identifiers.rb +26 -0
  67. data/lib/sequel/ast_transformer.rb +2 -2
  68. data/lib/sequel/database/dataset.rb +1 -1
  69. data/lib/sequel/database/dataset_defaults.rb +0 -66
  70. data/lib/sequel/database/features.rb +6 -0
  71. data/lib/sequel/database/misc.rb +31 -17
  72. data/lib/sequel/database/query.rb +7 -4
  73. data/lib/sequel/database/schema_methods.rb +1 -1
  74. data/lib/sequel/dataset.rb +8 -8
  75. data/lib/sequel/dataset/actions.rb +140 -46
  76. data/lib/sequel/dataset/features.rb +1 -5
  77. data/lib/sequel/dataset/graph.rb +7 -8
  78. data/lib/sequel/dataset/misc.rb +127 -56
  79. data/lib/sequel/dataset/mutation.rb +9 -20
  80. data/lib/sequel/dataset/placeholder_literalizer.rb +10 -1
  81. data/lib/sequel/dataset/prepared_statements.rb +102 -46
  82. data/lib/sequel/dataset/query.rb +155 -72
  83. data/lib/sequel/dataset/sql.rb +26 -9
  84. data/lib/sequel/extensions/columns_introspection.rb +3 -1
  85. data/lib/sequel/extensions/core_extensions.rb +5 -5
  86. data/lib/sequel/extensions/core_refinements.rb +5 -5
  87. data/lib/sequel/extensions/duplicate_columns_handler.rb +4 -2
  88. data/lib/sequel/extensions/freeze_datasets.rb +69 -0
  89. data/lib/sequel/extensions/identifier_mangling.rb +196 -0
  90. data/lib/sequel/extensions/looser_typecasting.rb +11 -7
  91. data/lib/sequel/extensions/migration.rb +1 -1
  92. data/lib/sequel/extensions/null_dataset.rb +5 -2
  93. data/lib/sequel/extensions/pagination.rb +42 -23
  94. data/lib/sequel/extensions/pg_enum.rb +3 -3
  95. data/lib/sequel/extensions/query.rb +3 -3
  96. data/lib/sequel/extensions/sequel_3_dataset_methods.rb +15 -8
  97. data/lib/sequel/model/associations.rb +25 -8
  98. data/lib/sequel/model/base.rb +88 -29
  99. data/lib/sequel/model/dataset_module.rb +37 -0
  100. data/lib/sequel/plugins/association_pks.rb +4 -4
  101. data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
  102. data/lib/sequel/plugins/constraint_validations.rb +1 -2
  103. data/lib/sequel/plugins/csv_serializer.rb +2 -2
  104. data/lib/sequel/plugins/dataset_associations.rb +8 -8
  105. data/lib/sequel/plugins/eager_each.rb +2 -2
  106. data/lib/sequel/plugins/instance_filters.rb +1 -1
  107. data/lib/sequel/plugins/json_serializer.rb +2 -2
  108. data/lib/sequel/plugins/lazy_attributes.rb +1 -1
  109. data/lib/sequel/plugins/list.rb +4 -4
  110. data/lib/sequel/plugins/prepared_statements.rb +2 -4
  111. data/lib/sequel/plugins/prepared_statements_associations.rb +1 -3
  112. data/lib/sequel/plugins/prepared_statements_with_pk.rb +1 -1
  113. data/lib/sequel/plugins/rcte_tree.rb +13 -13
  114. data/lib/sequel/plugins/sharding.rb +1 -1
  115. data/lib/sequel/plugins/single_table_inheritance.rb +9 -4
  116. data/lib/sequel/plugins/tactical_eager_loading.rb +4 -4
  117. data/lib/sequel/plugins/validation_class_methods.rb +1 -1
  118. data/lib/sequel/plugins/validation_helpers.rb +1 -1
  119. data/lib/sequel/plugins/xml_serializer.rb +2 -2
  120. data/lib/sequel/sql.rb +69 -36
  121. data/lib/sequel/version.rb +1 -1
  122. data/spec/adapters/db2_spec.rb +10 -0
  123. data/spec/adapters/firebird_spec.rb +1 -1
  124. data/spec/adapters/mssql_spec.rb +4 -5
  125. data/spec/adapters/mysql_spec.rb +9 -9
  126. data/spec/adapters/postgres_spec.rb +67 -68
  127. data/spec/adapters/spec_helper.rb +6 -1
  128. data/spec/adapters/sqlite_spec.rb +29 -15
  129. data/spec/core/connection_pool_spec.rb +14 -14
  130. data/spec/core/database_spec.rb +38 -180
  131. data/spec/core/dataset_mutation_spec.rb +253 -0
  132. data/spec/core/dataset_spec.rb +394 -537
  133. data/spec/core/expression_filters_spec.rb +34 -32
  134. data/spec/core/mock_adapter_spec.rb +27 -35
  135. data/spec/core/placeholder_literalizer_spec.rb +2 -4
  136. data/spec/core/schema_generator_spec.rb +4 -4
  137. data/spec/core/schema_spec.rb +1 -2
  138. data/spec/core_extensions_spec.rb +22 -29
  139. data/spec/extensions/active_model_spec.rb +6 -6
  140. data/spec/extensions/association_dependencies_spec.rb +2 -2
  141. data/spec/extensions/blacklist_security_spec.rb +3 -3
  142. data/spec/extensions/boolean_readers_spec.rb +12 -12
  143. data/spec/extensions/caching_spec.rb +13 -10
  144. data/spec/extensions/class_table_inheritance_spec.rb +38 -43
  145. data/spec/extensions/column_conflicts_spec.rb +1 -3
  146. data/spec/extensions/columns_introspection_spec.rb +2 -3
  147. data/spec/extensions/composition_spec.rb +5 -3
  148. data/spec/extensions/constraint_validations_plugin_spec.rb +5 -5
  149. data/spec/extensions/constraint_validations_spec.rb +14 -8
  150. data/spec/extensions/core_refinements_spec.rb +22 -29
  151. data/spec/extensions/csv_serializer_spec.rb +7 -6
  152. data/spec/extensions/date_arithmetic_spec.rb +15 -15
  153. data/spec/extensions/defaults_setter_spec.rb +2 -2
  154. data/spec/extensions/delay_add_association_spec.rb +1 -1
  155. data/spec/extensions/dirty_spec.rb +19 -10
  156. data/spec/extensions/duplicate_columns_handler_spec.rb +12 -18
  157. data/spec/extensions/eager_each_spec.rb +12 -16
  158. data/spec/extensions/empty_array_consider_nulls_spec.rb +1 -1
  159. data/spec/extensions/eval_inspect_spec.rb +4 -3
  160. data/spec/extensions/force_encoding_spec.rb +12 -12
  161. data/spec/extensions/freeze_datasets_spec.rb +31 -0
  162. data/spec/extensions/graph_each_spec.rb +6 -18
  163. data/spec/extensions/hook_class_methods_spec.rb +7 -7
  164. data/spec/extensions/identifier_mangling_spec.rb +307 -0
  165. data/spec/extensions/instance_filters_spec.rb +5 -6
  166. data/spec/extensions/instance_hooks_spec.rb +12 -12
  167. data/spec/extensions/json_serializer_spec.rb +12 -15
  168. data/spec/extensions/lazy_attributes_spec.rb +4 -4
  169. data/spec/extensions/list_spec.rb +19 -21
  170. data/spec/extensions/many_through_many_spec.rb +108 -163
  171. data/spec/extensions/meta_def_spec.rb +7 -2
  172. data/spec/extensions/migration_spec.rb +10 -12
  173. data/spec/extensions/mssql_optimistic_locking_spec.rb +4 -3
  174. data/spec/extensions/named_timezones_spec.rb +4 -3
  175. data/spec/extensions/nested_attributes_spec.rb +2 -2
  176. data/spec/extensions/null_dataset_spec.rb +17 -12
  177. data/spec/extensions/optimistic_locking_spec.rb +4 -5
  178. data/spec/extensions/pagination_spec.rb +8 -10
  179. data/spec/extensions/pg_array_associations_spec.rb +28 -27
  180. data/spec/extensions/pg_array_ops_spec.rb +2 -1
  181. data/spec/extensions/pg_array_spec.rb +6 -2
  182. data/spec/extensions/pg_enum_spec.rb +5 -3
  183. data/spec/extensions/pg_hstore_ops_spec.rb +3 -1
  184. data/spec/extensions/pg_hstore_spec.rb +7 -6
  185. data/spec/extensions/pg_inet_ops_spec.rb +2 -1
  186. data/spec/extensions/pg_inet_spec.rb +2 -1
  187. data/spec/extensions/pg_interval_spec.rb +2 -1
  188. data/spec/extensions/pg_json_ops_spec.rb +2 -1
  189. data/spec/extensions/pg_json_spec.rb +6 -3
  190. data/spec/extensions/pg_loose_count_spec.rb +1 -0
  191. data/spec/extensions/pg_range_ops_spec.rb +3 -1
  192. data/spec/extensions/pg_range_spec.rb +9 -5
  193. data/spec/extensions/pg_row_ops_spec.rb +2 -1
  194. data/spec/extensions/pg_row_plugin_spec.rb +4 -6
  195. data/spec/extensions/pg_row_spec.rb +5 -3
  196. data/spec/extensions/pg_static_cache_updater_spec.rb +2 -1
  197. data/spec/extensions/pg_typecast_on_load_spec.rb +1 -1
  198. data/spec/extensions/prepared_statements_associations_spec.rb +1 -1
  199. data/spec/extensions/prepared_statements_spec.rb +12 -11
  200. data/spec/extensions/pretty_table_spec.rb +1 -1
  201. data/spec/extensions/query_spec.rb +8 -5
  202. data/spec/extensions/rcte_tree_spec.rb +39 -39
  203. data/spec/extensions/round_timestamps_spec.rb +2 -2
  204. data/spec/extensions/schema_dumper_spec.rb +3 -2
  205. data/spec/extensions/schema_spec.rb +2 -2
  206. data/spec/extensions/scissors_spec.rb +1 -2
  207. data/spec/extensions/sequel_3_dataset_methods_spec.rb +30 -17
  208. data/spec/extensions/serialization_modification_detection_spec.rb +2 -2
  209. data/spec/extensions/serialization_spec.rb +15 -13
  210. data/spec/extensions/set_overrides_spec.rb +14 -8
  211. data/spec/extensions/sharding_spec.rb +9 -18
  212. data/spec/extensions/shared_caching_spec.rb +3 -4
  213. data/spec/extensions/single_table_inheritance_spec.rb +11 -11
  214. data/spec/extensions/skip_create_refresh_spec.rb +2 -1
  215. data/spec/extensions/spec_helper.rb +1 -1
  216. data/spec/extensions/split_values_spec.rb +2 -2
  217. data/spec/extensions/sql_comments_spec.rb +6 -0
  218. data/spec/extensions/static_cache_spec.rb +7 -9
  219. data/spec/extensions/string_agg_spec.rb +30 -29
  220. data/spec/extensions/tactical_eager_loading_spec.rb +4 -5
  221. data/spec/extensions/thread_local_timezones_spec.rb +2 -2
  222. data/spec/extensions/timestamps_spec.rb +28 -3
  223. data/spec/extensions/to_dot_spec.rb +1 -2
  224. data/spec/extensions/tree_spec.rb +33 -29
  225. data/spec/extensions/typecast_on_load_spec.rb +1 -1
  226. data/spec/extensions/unlimited_update_spec.rb +1 -0
  227. data/spec/extensions/update_primary_key_spec.rb +11 -7
  228. data/spec/extensions/update_refresh_spec.rb +1 -1
  229. data/spec/extensions/uuid_spec.rb +0 -1
  230. data/spec/extensions/validate_associated_spec.rb +1 -1
  231. data/spec/extensions/validation_class_methods_spec.rb +10 -10
  232. data/spec/extensions/validation_helpers_spec.rb +10 -10
  233. data/spec/extensions/xml_serializer_spec.rb +7 -3
  234. data/spec/integration/associations_test.rb +31 -31
  235. data/spec/integration/dataset_test.rb +17 -19
  236. data/spec/integration/eager_loader_test.rb +24 -24
  237. data/spec/integration/model_test.rb +6 -6
  238. data/spec/integration/plugin_test.rb +43 -43
  239. data/spec/integration/prepared_statement_test.rb +6 -6
  240. data/spec/integration/schema_test.rb +63 -52
  241. data/spec/integration/spec_helper.rb +6 -1
  242. data/spec/integration/transaction_test.rb +13 -13
  243. data/spec/model/association_reflection_spec.rb +17 -17
  244. data/spec/model/associations_spec.rb +101 -96
  245. data/spec/model/base_spec.rb +175 -49
  246. data/spec/model/class_dataset_methods_spec.rb +5 -9
  247. data/spec/model/dataset_methods_spec.rb +5 -5
  248. data/spec/model/eager_loading_spec.rb +209 -235
  249. data/spec/model/hooks_spec.rb +15 -15
  250. data/spec/model/model_spec.rb +28 -21
  251. data/spec/model/plugins_spec.rb +4 -5
  252. data/spec/model/record_spec.rb +59 -57
  253. data/spec/model/spec_helper.rb +1 -1
  254. data/spec/model/validations_spec.rb +6 -6
  255. data/spec/spec_config.rb +1 -1
  256. metadata +10 -2
@@ -0,0 +1,253 @@
1
+ require File.join(File.dirname(File.expand_path(__FILE__)), "spec_helper")
2
+
3
+ # SEQUEL5: Remove
4
+ unless Sequel.mock.dataset.frozen?
5
+
6
+ describe "Dataset" do
7
+ before do
8
+ @d = Sequel.mock.dataset.from(:x)
9
+ end
10
+
11
+ it "should support self-changing select!" do
12
+ @d.select!(:y)
13
+ @d.sql.must_equal "SELECT y FROM x"
14
+ end
15
+
16
+ it "should support self-changing from!" do
17
+ @d.from!(:y)
18
+ @d.sql.must_equal "SELECT * FROM y"
19
+ end
20
+
21
+ it "should support self-changing order!" do
22
+ @d.order!(:y)
23
+ @d.sql.must_equal "SELECT * FROM x ORDER BY y"
24
+ end
25
+
26
+ it "should support self-changing filter!" do
27
+ @d.filter!(:y => 1)
28
+ @d.sql.must_equal "SELECT * FROM x WHERE (y = 1)"
29
+ end
30
+
31
+ it "should support self-changing filter! with block" do
32
+ @d.filter!{y < 2}
33
+ @d.sql.must_equal "SELECT * FROM x WHERE (y < 2)"
34
+ end
35
+
36
+ it "should raise for ! methods that don't return a dataset" do
37
+ proc {@d.opts!}.must_raise(NoMethodError)
38
+ end
39
+
40
+ it "should raise for missing methods" do
41
+ proc {@d.xuyz}.must_raise(NoMethodError)
42
+ proc {@d.xyz!}.must_raise(NoMethodError)
43
+ proc {@d.xyz?}.must_raise(NoMethodError)
44
+ end
45
+
46
+ it "should support chaining of bang methods" do
47
+ @d.order!(:y).filter!(:y => 1).sql.must_equal "SELECT * FROM x WHERE (y = 1) ORDER BY y"
48
+ end
49
+ end
50
+
51
+ describe "Frozen Datasets" do
52
+ before do
53
+ @ds = Sequel.mock[:test].freeze
54
+ end
55
+
56
+ it "should have dups not be frozen" do
57
+ @ds.dup.wont_be :frozen?
58
+ end
59
+
60
+ it "should raise an error when calling mutation methods" do
61
+ proc{@ds.select!(:a)}.must_raise RuntimeError
62
+ proc{@ds.row_proc = proc{}}.must_raise RuntimeError
63
+ proc{@ds.extension! :query}.must_raise RuntimeError
64
+ proc{@ds.naked!}.must_raise RuntimeError
65
+ proc{@ds.from_self!}.must_raise RuntimeError
66
+ end
67
+ end
68
+
69
+ describe "Dataset mutation methods" do
70
+ def m(&block)
71
+ ds = Sequel.mock[:t]
72
+ def ds.supports_cte?(*) true end
73
+ ds.instance_exec(&block)
74
+ ds.sql
75
+ end
76
+
77
+ it "should modify the dataset in place" do
78
+ dsc = Sequel.mock[:u]
79
+ dsc.send(:columns=, [:v])
80
+
81
+ m{and!(:a=>1).or!(:b=>2)}.must_equal "SELECT * FROM t WHERE ((a = 1) OR (b = 2))"
82
+ m{select!(:f).graph!(dsc, :b=>:c).set_graph_aliases!(:e=>[:m, :n]).add_graph_aliases!(:d=>[:g, :c])}.must_equal "SELECT m.n AS e, g.c AS d FROM t LEFT OUTER JOIN u ON (u.b = t.c)"
83
+ m{cross_join!(:a)}.must_equal "SELECT * FROM t CROSS JOIN a"
84
+ m{distinct!}.must_equal "SELECT DISTINCT * FROM t"
85
+ m{except!(dsc)}.must_equal "SELECT * FROM (SELECT * FROM t EXCEPT SELECT * FROM u) AS t1"
86
+ m{exclude!(:a=>1)}.must_equal "SELECT * FROM t WHERE (a != 1)"
87
+ m{exclude_having!(:a=>1)}.must_equal "SELECT * FROM t HAVING (a != 1)"
88
+ m{exclude_where!(:a=>1)}.must_equal "SELECT * FROM t WHERE (a != 1)"
89
+ m{filter!(:a=>1)}.must_equal "SELECT * FROM t WHERE (a = 1)"
90
+ m{for_update!}.must_equal "SELECT * FROM t FOR UPDATE"
91
+ m{from!(:p)}.must_equal "SELECT * FROM p"
92
+ m{full_join!(:a, [:b])}.must_equal "SELECT * FROM t FULL JOIN a USING (b)"
93
+ m{full_outer_join!(:a, [:b])}.must_equal "SELECT * FROM t FULL OUTER JOIN a USING (b)"
94
+ m{grep!(:a, 'b')}.must_equal "SELECT * FROM t WHERE ((a LIKE 'b' ESCAPE '\\'))"
95
+ m{group!(:a)}.must_equal "SELECT * FROM t GROUP BY a"
96
+ m{group_and_count!(:a)}.must_equal "SELECT a, count(*) AS count FROM t GROUP BY a"
97
+ m{group_by!(:a)}.must_equal "SELECT * FROM t GROUP BY a"
98
+ m{having!(:a)}.must_equal "SELECT * FROM t HAVING a"
99
+ m{inner_join!(:a, [:b])}.must_equal "SELECT * FROM t INNER JOIN a USING (b)"
100
+ m{intersect!(dsc)}.must_equal "SELECT * FROM (SELECT * FROM t INTERSECT SELECT * FROM u) AS t1"
101
+ m{where!(:a).invert!}.must_equal "SELECT * FROM t WHERE NOT a"
102
+ m{join!(:a, [:b])}.must_equal "SELECT * FROM t INNER JOIN a USING (b)"
103
+ m{join_table!(:inner, :a, [:b])}.must_equal "SELECT * FROM t INNER JOIN a USING (b)"
104
+ m{left_join!(:a, [:b])}.must_equal "SELECT * FROM t LEFT JOIN a USING (b)"
105
+ m{left_outer_join!(:a, [:b])}.must_equal "SELECT * FROM t LEFT OUTER JOIN a USING (b)"
106
+ m{limit!(1)}.must_equal "SELECT * FROM t LIMIT 1"
107
+ m{lock_style!(:update)}.must_equal "SELECT * FROM t FOR UPDATE"
108
+ m{natural_full_join!(:a)}.must_equal "SELECT * FROM t NATURAL FULL JOIN a"
109
+ m{natural_join!(:a)}.must_equal "SELECT * FROM t NATURAL JOIN a"
110
+ m{natural_left_join!(:a)}.must_equal "SELECT * FROM t NATURAL LEFT JOIN a"
111
+ m{natural_right_join!(:a)}.must_equal "SELECT * FROM t NATURAL RIGHT JOIN a"
112
+ m{offset!(1)}.must_equal "SELECT * FROM t OFFSET 1"
113
+ m{order!(:a).reverse_order!}.must_equal "SELECT * FROM t ORDER BY a DESC"
114
+ m{order_by!(:a).order_more!(:b).order_append!(:c).order_prepend!(:d).reverse!}.must_equal "SELECT * FROM t ORDER BY d DESC, a DESC, b DESC, c DESC"
115
+ m{qualify!}.must_equal "SELECT t.* FROM t"
116
+ m{right_join!(:a, [:b])}.must_equal "SELECT * FROM t RIGHT JOIN a USING (b)"
117
+ m{right_outer_join!(:a, [:b])}.must_equal "SELECT * FROM t RIGHT OUTER JOIN a USING (b)"
118
+ m{select!(:a)}.must_equal "SELECT a FROM t"
119
+ m{select_all!(:t).select_more!(:b).select_append!(:c)}.must_equal "SELECT t.*, b, c FROM t"
120
+ m{select_group!(:a)}.must_equal "SELECT a FROM t GROUP BY a"
121
+ m{where!(:a).unfiltered!}.must_equal "SELECT * FROM t"
122
+ m{group!(:a).ungrouped!}.must_equal "SELECT * FROM t"
123
+ m{limit!(1).unlimited!}.must_equal "SELECT * FROM t"
124
+ m{order!(:a).unordered!}.must_equal "SELECT * FROM t"
125
+ m{union!(dsc)}.must_equal "SELECT * FROM (SELECT * FROM t UNION SELECT * FROM u) AS t1"
126
+ m{with!(:a, dsc)}.must_equal "WITH a AS (SELECT * FROM u) SELECT * FROM t"
127
+ m{with_recursive!(:a, dsc, dsc)}.must_equal "WITH a AS (SELECT * FROM u UNION ALL SELECT * FROM u) SELECT * FROM t"
128
+ m{with_sql!('SELECT foo')}.must_equal "SELECT foo"
129
+
130
+ dsc.server!(:a)
131
+ dsc.opts[:server].must_equal :a
132
+ dsc.graph!(dsc, {:b=>:c}, :table_alias=>:foo).ungraphed!.opts[:graph].must_be_nil
133
+ end
134
+
135
+ it "should clear the cache" do
136
+ ds = Sequel.mock[:a]
137
+ ds.columns
138
+ ds.send(:cache_set, :columns, [:a])
139
+ ds.select!(:foo, :bar).send(:cache_get, :columns).must_be_nil
140
+ end
141
+ end
142
+
143
+ describe "Dataset#clone" do
144
+ before do
145
+ @dataset = Sequel.mock.dataset.from(:items)
146
+ end
147
+
148
+ it "should copy the dataset opts" do
149
+ clone = @dataset.clone
150
+ clone.opts.must_equal @dataset.opts
151
+ @dataset.filter!(:a => 'b')
152
+ clone.opts[:filter].must_be_nil
153
+ end
154
+ end
155
+
156
+ describe "Dataset extensions" do
157
+ before(:all) do
158
+ class << Sequel
159
+ alias _extension extension
160
+ remove_method :extension
161
+ def extension(*)
162
+ end
163
+ end
164
+ end
165
+ after(:all) do
166
+ class << Sequel
167
+ remove_method :extension
168
+ alias extension _extension
169
+ remove_method :_extension
170
+ end
171
+ end
172
+ before do
173
+ @ds = Sequel.mock.dataset
174
+ end
175
+
176
+ it "should have #extension! modify the receiver" do
177
+ Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
178
+ @ds.extension!(:foo)
179
+ @ds.a.must_equal 1
180
+ end
181
+
182
+ it "should have #extension! return the receiver" do
183
+ Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
184
+ @ds.extension!(:foo).must_be_same_as(@ds)
185
+ end
186
+ end
187
+
188
+ describe "Dataset#naked!" do
189
+ it "should remove any existing row_proc" do
190
+ d = Sequel.mock.dataset.with_row_proc(Proc.new{|r| r})
191
+ d.naked!.row_proc.must_be_nil
192
+ d.row_proc.must_be_nil
193
+ end
194
+ end
195
+
196
+ describe "Dataset#row_proc=" do
197
+ it "should set the row_proc" do
198
+ d = Sequel.mock.dataset.with_row_proc(Proc.new{|r| r})
199
+ d.row_proc.wont_be_nil
200
+ d.row_proc = nil
201
+ d.row_proc.must_be_nil
202
+ end
203
+ end
204
+
205
+ describe "Dataset#quote_identifiers=" do
206
+ it "should change quote identifiers setting" do
207
+ d = Sequel.mock.dataset.with_quote_identifiers(true)
208
+ d.literal(:a).must_equal '"a"'
209
+ d.quote_identifiers = false
210
+ d.literal(:a).must_equal 'a'
211
+ end
212
+ end
213
+
214
+ describe "Dataset#from_self!" do
215
+ it "should work" do
216
+ Sequel.mock.dataset.from(:test).select(:name).limit(1).from_self!.sql.must_equal 'SELECT * FROM (SELECT name FROM test LIMIT 1) AS t1'
217
+ end
218
+ end
219
+
220
+ describe "Sequel Mock Adapter" do
221
+ it "should be able to set the rows returned by each on a per dataset basis using _fetch" do
222
+ rs = []
223
+ db = Sequel.mock(:fetch=>{:a=>1})
224
+ ds = db[:t]
225
+ ds.each{|r| rs << r}
226
+ rs.must_equal [{:a=>1}]
227
+ ds._fetch = {:b=>2}
228
+ ds.each{|r| rs << r}
229
+ rs.must_equal [{:a=>1}, {:b=>2}]
230
+ end
231
+
232
+ it "should be able to set the number of rows modified by update and delete on a per dataset basis" do
233
+ db = Sequel.mock(:numrows=>2)
234
+ ds = db[:t]
235
+ ds.update(:a=>1).must_equal 2
236
+ ds.delete.must_equal 2
237
+ ds.numrows = 3
238
+ ds.update(:a=>1).must_equal 3
239
+ ds.delete.must_equal 3
240
+ end
241
+
242
+ it "should be able to set the autogenerated primary key returned by insert on a per dataset basis" do
243
+ db = Sequel.mock(:autoid=>1)
244
+ ds = db[:t]
245
+ ds.insert(:a=>1).must_equal 1
246
+ ds.autoid = 5
247
+ ds.insert(:a=>1).must_equal 5
248
+ ds.insert(:a=>1).must_equal 6
249
+ db[:t].insert(:a=>1).must_equal 2
250
+ end
251
+ end
252
+
253
+ end
@@ -18,7 +18,7 @@ describe "Dataset" do
18
18
  d1.wont_equal @dataset
19
19
  d1.db.must_be_same_as(@dataset.db)
20
20
  d1.opts[:from].must_equal [:test]
21
- @dataset.opts[:from].must_equal nil
21
+ @dataset.opts[:from].must_be_nil
22
22
 
23
23
  d2 = d1.clone(:order => [:name])
24
24
  d2.class.must_equal @dataset.class
@@ -27,7 +27,7 @@ describe "Dataset" do
27
27
  d2.db.must_be_same_as(@dataset.db)
28
28
  d2.opts[:from].must_equal [:test]
29
29
  d2.opts[:order].must_equal [:name]
30
- d1.opts[:order].must_equal nil
30
+ d1.opts[:order].must_be_nil
31
31
  end
32
32
 
33
33
  it "should include Enumerable" do
@@ -35,96 +35,11 @@ describe "Dataset" do
35
35
  end
36
36
 
37
37
  it "should yield rows to each" do
38
- ds = Sequel.mock[:t]
39
- ds._fetch = {:x=>1}
38
+ ds = Sequel.mock[:t].with_fetch(:x=>1)
40
39
  called = false
41
40
  ds.each{|a| called = true; a.must_equal(:x=>1)}
42
41
  called.must_equal true
43
42
  end
44
-
45
- it "should get quote_identifiers default from database" do
46
- db = Sequel::Database.new(:quote_identifiers=>true)
47
- db[:a].quote_identifiers?.must_equal true
48
- db = Sequel::Database.new(:quote_identifiers=>false)
49
- db[:a].quote_identifiers?.must_equal false
50
- end
51
-
52
- it "should get identifier_input_method default from database" do
53
- db = Sequel::Database.new(:identifier_input_method=>:upcase)
54
- db[:a].identifier_input_method.must_equal :upcase
55
- db = Sequel::Database.new(:identifier_input_method=>:downcase)
56
- db[:a].identifier_input_method.must_equal :downcase
57
- end
58
-
59
- it "should get identifier_output_method default from database" do
60
- db = Sequel::Database.new(:identifier_output_method=>:upcase)
61
- db[:a].identifier_output_method.must_equal :upcase
62
- db = Sequel::Database.new(:identifier_output_method=>:downcase)
63
- db[:a].identifier_output_method.must_equal :downcase
64
- end
65
-
66
- it "should have quote_identifiers= method which changes literalization of identifiers" do
67
- @dataset.quote_identifiers = true
68
- @dataset.literal(:a).must_equal '"a"'
69
- @dataset.quote_identifiers = false
70
- @dataset.literal(:a).must_equal 'a'
71
- end
72
-
73
- it "should have identifier_input_method= method which changes literalization of identifiers" do
74
- @dataset.identifier_input_method = :upcase
75
- @dataset.literal(:a).must_equal 'A'
76
- @dataset.identifier_input_method = :downcase
77
- @dataset.literal(:A).must_equal 'a'
78
- @dataset.identifier_input_method = :reverse
79
- @dataset.literal(:at_b).must_equal 'b_ta'
80
- end
81
-
82
- it "should have identifier_output_method= method which changes identifiers returned from the database" do
83
- @dataset.send(:output_identifier, "at_b_C").must_equal :at_b_C
84
- @dataset.identifier_output_method = :upcase
85
- @dataset.send(:output_identifier, "at_b_C").must_equal :AT_B_C
86
- @dataset.identifier_output_method = :downcase
87
- @dataset.send(:output_identifier, "at_b_C").must_equal :at_b_c
88
- @dataset.identifier_output_method = :reverse
89
- @dataset.send(:output_identifier, "at_b_C").must_equal :C_b_ta
90
- end
91
-
92
- it "should have with_quote_identifiers method which returns cloned dataset with changed literalization of identifiers" do
93
- @dataset.with_quote_identifiers(true).literal(:a).must_equal '"a"'
94
- @dataset.with_quote_identifiers(false).literal(:a).must_equal 'a'
95
- ds = @dataset.freeze.with_quote_identifiers(false)
96
- ds.literal(:a).must_equal 'a'
97
- ds.frozen?.must_equal true
98
- end
99
-
100
- it "should have with_identifier_input_method method which returns cloned dataset with changed literalization of identifiers" do
101
- @dataset.with_identifier_input_method(:upcase).literal(:a).must_equal 'A'
102
- @dataset.with_identifier_input_method(:downcase).literal(:A).must_equal 'a'
103
- @dataset.with_identifier_input_method(:reverse).literal(:at_b).must_equal 'b_ta'
104
- ds = @dataset.freeze.with_identifier_input_method(:reverse)
105
- ds.frozen?.must_equal true
106
- ds.literal(:at_b).must_equal 'b_ta'
107
- end
108
-
109
- it "should have with_identifier_output_method method which returns cloned dataset with changed identifiers returned from the database" do
110
- @dataset.send(:output_identifier, "at_b_C").must_equal :at_b_C
111
- @dataset.with_identifier_output_method(:upcase).send(:output_identifier, "at_b_C").must_equal :AT_B_C
112
- @dataset.with_identifier_output_method(:downcase).send(:output_identifier, "at_b_C").must_equal :at_b_c
113
- @dataset.with_identifier_output_method(:reverse).send(:output_identifier, "at_b_C").must_equal :C_b_ta
114
- ds = @dataset.freeze.with_identifier_output_method(:reverse)
115
- ds.send(:output_identifier, "at_b_C").must_equal :C_b_ta
116
- ds.frozen?.must_equal true
117
- end
118
-
119
- it "should have output_identifier handle empty identifiers" do
120
- @dataset.send(:output_identifier, "").must_equal :untitled
121
- @dataset.identifier_output_method = :upcase
122
- @dataset.send(:output_identifier, "").must_equal :UNTITLED
123
- @dataset.identifier_output_method = :downcase
124
- @dataset.send(:output_identifier, "").must_equal :untitled
125
- @dataset.identifier_output_method = :reverse
126
- @dataset.send(:output_identifier, "").must_equal :deltitnu
127
- end
128
43
  end
129
44
 
130
45
  describe "Dataset#clone" do
@@ -133,23 +48,16 @@ describe "Dataset#clone" do
133
48
  end
134
49
 
135
50
  it "should create an exact copy of the dataset" do
136
- @dataset.row_proc = Proc.new{|r| r}
51
+ @dataset = @dataset.with_row_proc(Proc.new{|r| r})
137
52
  clone = @dataset.clone
138
53
 
139
54
  clone.object_id.wont_equal @dataset.object_id
140
55
  clone.class.must_equal @dataset.class
141
56
  clone.db.must_equal @dataset.db
142
57
  clone.opts.must_equal @dataset.opts
143
- clone.row_proc.must_equal @dataset.row_proc
144
58
  end
145
59
 
146
60
  it "should copy the dataset opts" do
147
- clone = @dataset.clone
148
-
149
- clone.opts.must_equal @dataset.opts
150
- @dataset.filter!(:a => 'b')
151
- clone.opts[:filter].must_equal nil
152
-
153
61
  clone = @dataset.clone(:from => [:other])
154
62
  @dataset.opts[:from].must_equal [:items]
155
63
  clone.opts[:from].must_equal [:other]
@@ -169,8 +77,7 @@ describe "Dataset#clone" do
169
77
  m = Module.new do
170
78
  def __xyz__; "xyz"; end
171
79
  end
172
- @dataset.extend(m)
173
- @dataset.clone({}).must_respond_to(:__xyz__)
80
+ @dataset.with_extend(m).clone({}).must_respond_to(:__xyz__)
174
81
  end
175
82
  end
176
83
 
@@ -242,8 +149,7 @@ describe "A simple dataset" do
242
149
  end
243
150
 
244
151
  it "should format a truncate statement with multiple tables if supported" do
245
- meta_def(@dataset, :check_truncation_allowed!){}
246
- @dataset.from(:test, :test2).truncate_sql.must_equal 'TRUNCATE TABLE test, test2'
152
+ @dataset.with_extend{def check_truncation_allowed!; end}.from(:test, :test2).truncate_sql.must_equal 'TRUNCATE TABLE test, test2'
247
153
  end
248
154
 
249
155
  it "should format an insert statement with default values" do
@@ -251,9 +157,10 @@ describe "A simple dataset" do
251
157
  end
252
158
 
253
159
  it "should use a single column with a default value when the dataset doesn't support using insert statement with default values" do
254
- meta_def(@dataset, :insert_supports_empty_values?){false}
255
- meta_def(@dataset, :columns){[:a, :b]}
256
- @dataset.insert_sql.must_equal 'INSERT INTO test (b) VALUES (DEFAULT)'
160
+ @dataset.with_extend do
161
+ def insert_supports_empty_values?; false end
162
+ def columns; [:a, :b] end
163
+ end.insert_sql.must_equal 'INSERT INTO test (b) VALUES (DEFAULT)'
257
164
  end
258
165
 
259
166
  it "should format an insert statement with hash" do
@@ -521,7 +428,7 @@ describe "Dataset#where" do
521
428
  end
522
429
 
523
430
  it "should handle IN/NOT IN queries with multiple columns and an array where the database doesn't support it" do
524
- meta_def(@dataset, :supports_multiple_column_in?){false}
431
+ @dataset = @dataset.with_extend{def supports_multiple_column_in?; false end}
525
432
  @dataset.filter([:id1, :id2] => [[1, 2], [3,4]]).sql.must_equal "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
526
433
  @dataset.exclude([:id1, :id2] => [[1, 2], [3,4]]).sql.must_equal "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
527
434
  @dataset.filter([:id1, :id2] => Sequel.value_list([[1, 2], [3,4]])).sql.must_equal "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
@@ -529,7 +436,7 @@ describe "Dataset#where" do
529
436
  end
530
437
 
531
438
  it "should handle IN/NOT IN queries with multiple columns and a dataset where the database doesn't support it" do
532
- meta_def(@dataset, :supports_multiple_column_in?){false}
439
+ @dataset = @dataset.with_extend{def supports_multiple_column_in?; false end}
533
440
  db = Sequel.mock(:fetch=>[{:id1=>1, :id2=>2}, {:id1=>3, :id2=>4}])
534
441
  d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
535
442
  @dataset.filter([:id1, :id2] => d1).sql.must_equal "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
@@ -539,7 +446,7 @@ describe "Dataset#where" do
539
446
  end
540
447
 
541
448
  it "should handle IN/NOT IN queries with multiple columns and an empty dataset where the database doesn't support it" do
542
- meta_def(@dataset, :supports_multiple_column_in?){false}
449
+ @dataset = @dataset.with_extend{def supports_multiple_column_in?; false end}
543
450
  db = Sequel.mock
544
451
  d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
545
452
  @dataset.filter([:id1, :id2] => d1).sql.must_equal "SELECT * FROM test WHERE (1 = 0)"
@@ -549,10 +456,9 @@ describe "Dataset#where" do
549
456
  end
550
457
 
551
458
  it "should handle IN/NOT IN queries for datasets with row_procs" do
552
- meta_def(@dataset, :supports_multiple_column_in?){false}
459
+ @dataset = @dataset.with_extend{def supports_multiple_column_in?; false end}
553
460
  db = Sequel.mock(:fetch=>[{:id1=>1, :id2=>2}, {:id1=>3, :id2=>4}])
554
- d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2)
555
- d1.row_proc = proc{|h| Object.new}
461
+ d1 = db[:test].select(:id1, :id2).filter(:region=>'Asia').columns(:id1, :id2).with_row_proc(proc{|h| Object.new})
556
462
  @dataset.filter([:id1, :id2] => d1).sql.must_equal "SELECT * FROM test WHERE (((id1 = 1) AND (id2 = 2)) OR ((id1 = 3) AND (id2 = 4)))"
557
463
  db.sqls.must_equal ["SELECT id1, id2 FROM test WHERE (region = 'Asia')"]
558
464
  @dataset.exclude([:id1, :id2] => d1).sql.must_equal "SELECT * FROM test WHERE (((id1 != 1) OR (id2 != 2)) AND ((id1 != 3) OR (id2 != 4)))"
@@ -585,7 +491,7 @@ describe "Dataset#where" do
585
491
  end
586
492
 
587
493
  it "should use boolean expression if dataset does not support where true/false" do
588
- def @dataset.supports_where_true?() false end
494
+ @dataset = @dataset.with_extend{def supports_where_true?() false end}
589
495
  @dataset.filter(true).sql.must_equal "SELECT * FROM test WHERE (1 = 1)"
590
496
  @dataset.filter(Sequel::SQLTRUE).sql.must_equal "SELECT * FROM test WHERE (1 = 1)"
591
497
  @dataset.filter(false).sql.must_equal "SELECT * FROM test WHERE (1 = 0)"
@@ -771,7 +677,9 @@ describe "Dataset#invert" do
771
677
  end
772
678
 
773
679
  it "should return a dataset that selects no rows if dataset is not filtered" do
774
- @d.invert.sql.must_equal "SELECT * FROM test WHERE 'f'"
680
+ 3.times do
681
+ @d.invert.sql.must_equal "SELECT * FROM test WHERE 'f'"
682
+ end
775
683
  end
776
684
 
777
685
  it "should invert current filter if dataset is filtered" do
@@ -877,25 +785,25 @@ describe "Dataset#group_by" do
877
785
  end
878
786
 
879
787
  it "should support a #group_rollup method if the database supports it" do
880
- meta_def(@dataset, :supports_group_rollup?){true}
788
+ @dataset = @dataset.with_extend{def supports_group_rollup?; true end}
881
789
  @dataset.group(:type_id).group_rollup.select_sql.must_equal "SELECT * FROM test GROUP BY ROLLUP(type_id)"
882
790
  @dataset.group(:type_id, :b).group_rollup.select_sql.must_equal "SELECT * FROM test GROUP BY ROLLUP(type_id, b)"
883
- meta_def(@dataset, :uses_with_rollup?){true}
791
+ @dataset = @dataset.with_extend{def uses_with_rollup?; true end}
884
792
  @dataset.group(:type_id).group_rollup.select_sql.must_equal "SELECT * FROM test GROUP BY type_id WITH ROLLUP"
885
793
  @dataset.group(:type_id, :b).group_rollup.select_sql.must_equal "SELECT * FROM test GROUP BY type_id, b WITH ROLLUP"
886
794
  end
887
795
 
888
796
  it "should support a #group_cube method if the database supports it" do
889
- meta_def(@dataset, :supports_group_cube?){true}
797
+ @dataset = @dataset.with_extend{def supports_group_cube?; true end}
890
798
  @dataset.group(:type_id).group_cube.select_sql.must_equal "SELECT * FROM test GROUP BY CUBE(type_id)"
891
799
  @dataset.group(:type_id, :b).group_cube.select_sql.must_equal "SELECT * FROM test GROUP BY CUBE(type_id, b)"
892
- meta_def(@dataset, :uses_with_rollup?){true}
800
+ @dataset = @dataset.with_extend{def uses_with_rollup?; true end}
893
801
  @dataset.group(:type_id).group_cube.select_sql.must_equal "SELECT * FROM test GROUP BY type_id WITH CUBE"
894
802
  @dataset.group(:type_id, :b).group_cube.select_sql.must_equal "SELECT * FROM test GROUP BY type_id, b WITH CUBE"
895
803
  end
896
804
 
897
805
  it "should support a #grouping_sets method if the database supports it" do
898
- meta_def(@dataset, :supports_grouping_sets?){true}
806
+ @dataset = @dataset.with_extend{def supports_grouping_sets?; true end}
899
807
  @dataset.group(:type_id).grouping_sets.select_sql.must_equal "SELECT * FROM test GROUP BY GROUPING SETS((type_id))"
900
808
  @dataset.group([:type_id, :b], :type_id, []).grouping_sets.select_sql.must_equal "SELECT * FROM test GROUP BY GROUPING SETS((type_id, b), (type_id), ())"
901
809
  end
@@ -936,7 +844,7 @@ end
936
844
 
937
845
  describe "Dataset#literal" do
938
846
  before do
939
- @ds = Sequel::Database.new.dataset
847
+ @ds = Sequel.mock.dataset
940
848
  end
941
849
 
942
850
  it "should convert qualified symbol notation into dot notation" do
@@ -972,7 +880,7 @@ end
972
880
 
973
881
  describe "Dataset#literal" do
974
882
  before do
975
- @dataset = Sequel::Database.new.from(:test)
883
+ @dataset = Sequel.mock[:test]
976
884
  end
977
885
 
978
886
  it "should escape strings properly" do
@@ -1019,10 +927,7 @@ describe "Dataset#literal" do
1019
927
  "not called #{ds.blah}"
1020
928
  end
1021
929
  end
1022
- def @dataset.blah
1023
- "ds"
1024
- end
1025
- @dataset.literal(@a.new).must_equal "called ds"
930
+ @dataset.with_extend{def blah; "ds" end}.literal(@a.new).must_equal "called ds"
1026
931
  end
1027
932
 
1028
933
  it "should call sql_literal with dataset on type if not natively supported and the object responds to it" do
@@ -1031,10 +936,7 @@ describe "Dataset#literal" do
1031
936
  "called #{ds.blah}"
1032
937
  end
1033
938
  end
1034
- def @dataset.blah
1035
- "ds"
1036
- end
1037
- @dataset.literal(@a.new).must_equal "called ds"
939
+ @dataset.with_extend{def blah; "ds" end}.literal(@a.new).must_equal "called ds"
1038
940
  end
1039
941
 
1040
942
  it "should literalize datasets as subqueries" do
@@ -1049,7 +951,7 @@ describe "Dataset#literal" do
1049
951
  end
1050
952
 
1051
953
  it "should literalize times properly for databases supporting millisecond precision" do
1052
- meta_def(@dataset, :timestamp_precision){3}
954
+ @dataset = @dataset.with_extend{def timestamp_precision; 3 end}
1053
955
  @dataset.literal(Sequel::SQLTime.create(1, 2, 3, 500000)).must_equal "'01:02:03.500'"
1054
956
  @dataset.literal(Time.local(2010, 1, 2, 3, 4, 5, 500000)).must_equal "'2010-01-02 03:04:05.500'"
1055
957
  @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, Rational(55, 10))).must_equal "'2010-01-02 03:04:05.500'"
@@ -1069,18 +971,18 @@ describe "Dataset#literal" do
1069
971
  end
1070
972
 
1071
973
  it "should literalize Time, DateTime, Date properly if SQL standard format is required" do
1072
- meta_def(@dataset, :requires_sql_standard_datetimes?){true}
974
+ @dataset = @dataset.with_extend{def requires_sql_standard_datetimes?; true end}
1073
975
  @dataset.literal(Time.local(2010, 1, 2, 3, 4, 5, 500000)).must_equal "TIMESTAMP '2010-01-02 03:04:05.500000'"
1074
976
  @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, Rational(55, 10))).must_equal "TIMESTAMP '2010-01-02 03:04:05.500000'"
1075
977
  @dataset.literal(Date.new(2010, 1, 2)).must_equal "DATE '2010-01-02'"
1076
978
  end
1077
979
 
1078
980
  it "should literalize Time and DateTime properly if the database support timezones in timestamps" do
1079
- meta_def(@dataset, :supports_timestamp_timezones?){true}
981
+ @dataset = @dataset.with_extend{def supports_timestamp_timezones?; true end}
1080
982
  @dataset.literal(Time.utc(2010, 1, 2, 3, 4, 5, 500000)).must_equal "'2010-01-02 03:04:05.500000+0000'"
1081
983
  @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, Rational(55, 10))).must_equal "'2010-01-02 03:04:05.500000+0000'"
1082
984
 
1083
- meta_def(@dataset, :supports_timestamp_usecs?){false}
985
+ @dataset = @dataset.with_extend{def supports_timestamp_usecs?; false end}
1084
986
  @dataset.literal(Time.utc(2010, 1, 2, 3, 4, 5)).must_equal "'2010-01-02 03:04:05+0000'"
1085
987
  @dataset.literal(DateTime.new(2010, 1, 2, 3, 4, 5)).must_equal "'2010-01-02 03:04:05+0000'"
1086
988
  end
@@ -1171,7 +1073,7 @@ describe "Dataset#from" do
1171
1073
  end
1172
1074
 
1173
1075
  it "should automatically use a default from table if no from table is present" do
1174
- def @dataset.empty_from_sql; ' FROM DEFFROM'; end
1076
+ @dataset = @dataset.with_extend{def empty_from_sql; ' FROM DEFFROM'; end}
1175
1077
  @dataset.select_sql.must_equal "SELECT * FROM DEFFROM"
1176
1078
  end
1177
1079
 
@@ -1192,8 +1094,10 @@ describe "Dataset#from" do
1192
1094
  end
1193
1095
 
1194
1096
  it "should hoist WITH clauses from subqueries if the dataset doesn't support CTEs in subselects" do
1195
- meta_def(@dataset, :supports_cte?){true}
1196
- meta_def(@dataset, :supports_cte_in_subselect?){false}
1097
+ @dataset = @dataset.with_extend do
1098
+ def supports_cte?; true end
1099
+ def supports_cte_in_subselect?; false end
1100
+ end
1197
1101
  @dataset.from(@dataset.from(:a).with(:a, @dataset.from(:b))).sql.must_equal 'WITH a AS (SELECT * FROM b) SELECT * FROM (SELECT * FROM a) AS t1'
1198
1102
  @dataset.from(@dataset.from(:a).with(:a, @dataset.from(:b)), @dataset.from(:c).with(:c, @dataset.from(:d))).sql.must_equal 'WITH a AS (SELECT * FROM b), c AS (SELECT * FROM d) SELECT * FROM (SELECT * FROM a) AS t1, (SELECT * FROM c) AS t2'
1199
1103
  end
@@ -1238,8 +1142,8 @@ describe "Dataset#select" do
1238
1142
  end
1239
1143
 
1240
1144
  it "should override the previous select option" do
1241
- @d.select!(:a, :b, :c).select.sql.must_equal 'SELECT * FROM test'
1242
- @d.select!(:price).select(:name).sql.must_equal 'SELECT name FROM test'
1145
+ @d.select(:a, :b, :c).select.sql.must_equal 'SELECT * FROM test'
1146
+ @d.select(:price).select(:name).sql.must_equal 'SELECT name FROM test'
1243
1147
  end
1244
1148
 
1245
1149
  it "should accept arbitrary objects and literalize them correctly" do
@@ -1294,7 +1198,7 @@ describe "Dataset#select_all" do
1294
1198
  end
1295
1199
 
1296
1200
  it "should override the previous select option" do
1297
- @d.select!(:a, :b, :c).select_all.sql.must_equal 'SELECT * FROM test'
1201
+ @d.select(:a, :b, :c).select_all.sql.must_equal 'SELECT * FROM test'
1298
1202
  end
1299
1203
 
1300
1204
  it "should select all columns in a table if given an argument" do
@@ -1376,7 +1280,7 @@ describe "Dataset#select_append" do
1376
1280
  end
1377
1281
 
1378
1282
  it "should select from all from and join tables if SELECT *, column not supported" do
1379
- meta_def(@d, :supports_select_all_and_column?){false}
1283
+ @d = @d.with_extend{def supports_select_all_and_column?; false end}
1380
1284
  @d.select_append(:b).sql.must_equal 'SELECT test.*, b FROM test'
1381
1285
  @d.from(:test, :c).select_append(:b).sql.must_equal 'SELECT test.*, c.*, b FROM test, c'
1382
1286
  @d.cross_join(:c).select_append(:b).sql.must_equal 'SELECT test.*, c.*, b FROM test CROSS JOIN c'
@@ -1434,25 +1338,37 @@ end
1434
1338
 
1435
1339
  describe "Dataset#unfiltered" do
1436
1340
  it "should remove filtering from the dataset" do
1437
- Sequel.mock.dataset.from(:test).filter(:score=>1).unfiltered.sql.must_equal 'SELECT * FROM test'
1341
+ ds = Sequel.mock.dataset.from(:test).filter(:score=>1)
1342
+ 3.times do
1343
+ ds.unfiltered.sql.must_equal 'SELECT * FROM test'
1344
+ end
1438
1345
  end
1439
1346
  end
1440
1347
 
1441
1348
  describe "Dataset#unlimited" do
1442
1349
  it "should remove limit and offset from the dataset" do
1443
- Sequel.mock.dataset.from(:test).limit(1, 2).unlimited.sql.must_equal 'SELECT * FROM test'
1350
+ ds = Sequel.mock.dataset.from(:test).limit(1, 2)
1351
+ 3.times do
1352
+ ds.unlimited.sql.must_equal 'SELECT * FROM test'
1353
+ end
1444
1354
  end
1445
1355
  end
1446
1356
 
1447
1357
  describe "Dataset#ungrouped" do
1448
1358
  it "should remove group and having clauses from the dataset" do
1449
- Sequel.mock.dataset.from(:test).group(:a).having(:b).ungrouped.sql.must_equal 'SELECT * FROM test'
1359
+ ds = Sequel.mock.dataset.from(:test).group(:a).having(:b)
1360
+ 3.times do
1361
+ ds.ungrouped.sql.must_equal 'SELECT * FROM test'
1362
+ end
1450
1363
  end
1451
1364
  end
1452
1365
 
1453
1366
  describe "Dataset#unordered" do
1454
1367
  it "should remove ordering from the dataset" do
1455
- Sequel.mock.dataset.from(:test).order(:name).unordered.sql.must_equal 'SELECT * FROM test'
1368
+ ds = Sequel.mock.dataset.from(:test).order(:name)
1369
+ 3.times do
1370
+ ds.unordered.sql.must_equal 'SELECT * FROM test'
1371
+ end
1456
1372
  end
1457
1373
  end
1458
1374
 
@@ -1474,7 +1390,9 @@ describe "Dataset#with_sql" do
1474
1390
  end
1475
1391
 
1476
1392
  it "should keep row_proc" do
1477
- @dataset.with_sql('SELECT 1 FROM test').row_proc.must_equal @dataset.row_proc
1393
+ @dataset.with_sql('SELECT 1 FROM test').row_proc.must_be_nil
1394
+ p = lambda{}
1395
+ @dataset.with_row_proc(p).with_sql('SELECT 1 FROM test').row_proc.must_equal p
1478
1396
  end
1479
1397
 
1480
1398
  it "should work with method symbols and arguments" do
@@ -1553,42 +1471,46 @@ describe "Dataset#order_prepend" do
1553
1471
  end
1554
1472
  end
1555
1473
 
1556
- describe "Dataset#reverse_order" do
1474
+ describe "Dataset#reverse" do
1557
1475
  before do
1558
1476
  @dataset = Sequel.mock.dataset.from(:test)
1559
1477
  end
1560
1478
 
1561
1479
  it "should use DESC as default order" do
1562
- @dataset.reverse_order(:name).sql.must_equal 'SELECT * FROM test ORDER BY name DESC'
1480
+ @dataset.reverse(:name).sql.must_equal 'SELECT * FROM test ORDER BY name DESC'
1563
1481
  end
1564
1482
 
1565
1483
  it "should invert the order given" do
1566
- @dataset.reverse_order(Sequel.desc(:name)).sql.must_equal 'SELECT * FROM test ORDER BY name ASC'
1484
+ @dataset.reverse(Sequel.desc(:name)).sql.must_equal 'SELECT * FROM test ORDER BY name ASC'
1567
1485
  end
1568
1486
 
1569
1487
  it "should invert the order for ASC expressions" do
1570
- @dataset.reverse_order(Sequel.asc(:name)).sql.must_equal 'SELECT * FROM test ORDER BY name DESC'
1488
+ @dataset.reverse(Sequel.asc(:name)).sql.must_equal 'SELECT * FROM test ORDER BY name DESC'
1571
1489
  end
1572
1490
 
1573
1491
  it "should accept multiple arguments" do
1574
- @dataset.reverse_order(:name, Sequel.desc(:price)).sql.must_equal 'SELECT * FROM test ORDER BY name DESC, price ASC'
1492
+ @dataset.reverse(:name, Sequel.desc(:price)).sql.must_equal 'SELECT * FROM test ORDER BY name DESC, price ASC'
1575
1493
  end
1576
1494
 
1577
1495
  it "should handles NULLS ordering correctly when reversing" do
1578
- @dataset.reverse_order(Sequel.asc(:name, :nulls=>:first), Sequel.desc(:price, :nulls=>:last)).sql.must_equal 'SELECT * FROM test ORDER BY name DESC NULLS LAST, price ASC NULLS FIRST'
1496
+ @dataset.reverse(Sequel.asc(:name, :nulls=>:first), Sequel.desc(:price, :nulls=>:last)).sql.must_equal 'SELECT * FROM test ORDER BY name DESC NULLS LAST, price ASC NULLS FIRST'
1579
1497
  end
1580
1498
 
1581
1499
  it "should reverse a previous ordering if no arguments are given" do
1582
- @dataset.order(:name).reverse_order.sql.must_equal 'SELECT * FROM test ORDER BY name DESC'
1583
- @dataset.order(Sequel.desc(:clumsy), :fool).reverse_order.sql.must_equal 'SELECT * FROM test ORDER BY clumsy ASC, fool DESC'
1500
+ ds1 = @dataset.order(:name)
1501
+ ds2 = @dataset.order(Sequel.desc(:clumsy), :fool)
1502
+ 3.times do
1503
+ ds1.reverse.sql.must_equal 'SELECT * FROM test ORDER BY name DESC'
1504
+ ds2.reverse.sql.must_equal 'SELECT * FROM test ORDER BY clumsy ASC, fool DESC'
1505
+ end
1584
1506
  end
1585
1507
 
1586
1508
  it "should return an unordered dataset for a dataset with no order" do
1587
- @dataset.unordered.reverse_order.sql.must_equal 'SELECT * FROM test'
1509
+ @dataset.unordered.reverse.sql.must_equal 'SELECT * FROM test'
1588
1510
  end
1589
1511
 
1590
- it "should have #reverse alias" do
1591
- @dataset.order(:name).reverse.sql.must_equal 'SELECT * FROM test ORDER BY name DESC'
1512
+ it "should have #reverse_order alias" do
1513
+ @dataset.order(:name).reverse_order.sql.must_equal 'SELECT * FROM test ORDER BY name DESC'
1592
1514
  end
1593
1515
 
1594
1516
  it "should accept a block" do
@@ -1638,8 +1560,7 @@ describe "Dataset#limit" do
1638
1560
  end
1639
1561
 
1640
1562
  it "should work with fixed sql datasets" do
1641
- @dataset.opts[:sql] = 'select * from cccc'
1642
- @dataset.limit(6, 10).sql.must_equal 'SELECT * FROM (select * from cccc) AS t1 LIMIT 6 OFFSET 10'
1563
+ @dataset.with_sql('select * from cccc').limit(6, 10).sql.must_equal 'SELECT * FROM (select * from cccc) AS t1 LIMIT 6 OFFSET 10'
1643
1564
  end
1644
1565
 
1645
1566
  it "should raise an error if an invalid limit or offset is used" do
@@ -1698,14 +1619,18 @@ end
1698
1619
  describe "Dataset#with_extend" do
1699
1620
  it "should returned clone dataset extended with given modules" do
1700
1621
  d = Sequel.mock.dataset
1701
- m1 = Module.new{def a; 1; end}
1702
- m2 = Module.new{def b; a+2; end}
1703
- d.with_extend(m1, m2).b.must_equal 3
1704
- d.respond_to?(:b).must_equal false
1705
- ds = d.freeze.with_extend(m1, m2)
1706
- ds.b.must_equal 3
1622
+ m1 = Module.new{def a; 2**super end}
1623
+ m2 = Module.new{def a; 3 end}
1624
+ d.with_extend(m1, m2){def a; 4**super end}.a.must_equal 65536
1625
+ d.respond_to?(:a).must_equal false
1626
+ ds = d.freeze.with_extend(m1, m2){def a; 4**super end}
1627
+ ds.a.must_equal 65536
1707
1628
  ds.frozen?.must_equal true
1708
1629
  end
1630
+
1631
+ it "should work with just a block" do
1632
+ Sequel.mock.dataset.with_extend{def a; 1 end}.a.must_equal 1
1633
+ end
1709
1634
  end
1710
1635
 
1711
1636
  describe "Dataset#with_row_proc" do
@@ -1713,7 +1638,7 @@ describe "Dataset#with_row_proc" do
1713
1638
  d = Sequel.mock.dataset
1714
1639
  l = lambda{|r| r}
1715
1640
  d.with_row_proc(l).row_proc.must_equal l
1716
- assert_equal nil, d.row_proc
1641
+ d.row_proc.must_be_nil
1717
1642
  ds = d.freeze.with_row_proc(l)
1718
1643
  ds.frozen?.must_equal true
1719
1644
  ds.row_proc.must_equal l
@@ -1722,19 +1647,9 @@ end
1722
1647
 
1723
1648
  describe "Dataset#naked" do
1724
1649
  it "should returned clone dataset without row_proc" do
1725
- d = Sequel.mock.dataset
1726
- d.row_proc = Proc.new{|r| r}
1727
- d.naked.row_proc.must_equal nil
1728
- refute_equal nil, d.row_proc
1729
- end
1730
- end
1731
-
1732
- describe "Dataset#naked!" do
1733
- it "should remove any existing row_proc" do
1734
- d = Sequel.mock.dataset
1735
- d.row_proc = Proc.new{|r| r}
1736
- d.naked!.row_proc.must_equal nil
1737
- d.row_proc.must_equal nil
1650
+ d = Sequel.mock.dataset.with_row_proc(Proc.new{|r| r})
1651
+ d.naked.row_proc.must_be_nil
1652
+ d.row_proc.wont_be_nil
1738
1653
  end
1739
1654
  end
1740
1655
 
@@ -1780,13 +1695,13 @@ describe "Dataset#map" do
1780
1695
  end
1781
1696
 
1782
1697
  it "should not call the row_proc if an argument is given" do
1783
- @d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
1698
+ @d = @d.with_row_proc(proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h})
1784
1699
  @d.map(:a).must_equal [1, 3, 5]
1785
1700
  @d.map([:a, :b]).must_equal [[1, 2], [3, 4], [5, 6]]
1786
1701
  end
1787
1702
 
1788
1703
  it "should call the row_proc if no argument is given" do
1789
- @d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
1704
+ @d = @d.with_row_proc(proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h})
1790
1705
  @d.map{|n| n[:a] + n[:b]}.must_equal [6, 14, 22]
1791
1706
  end
1792
1707
 
@@ -1822,7 +1737,7 @@ describe "Dataset#to_hash" do
1822
1737
  end
1823
1738
 
1824
1739
  it "should not call the row_proc if two arguments are given" do
1825
- @d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
1740
+ @d = @d.with_row_proc(proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h})
1826
1741
  @d.to_hash(:a, :b).must_equal(1 => 2, 3 => 4, 5 => 6)
1827
1742
  @d.to_hash(:b, :a).must_equal(2 => 1, 4 => 3, 6 => 5)
1828
1743
  @d.to_hash([:a, :b], :b).must_equal([1, 2] => 2, [3, 4] => 4, [5, 6] => 6)
@@ -1831,21 +1746,21 @@ describe "Dataset#to_hash" do
1831
1746
  end
1832
1747
 
1833
1748
  it "should call the row_proc if only a single argument is given" do
1834
- @d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
1749
+ @d = @d.with_row_proc(proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h})
1835
1750
  @d.to_hash(:a).must_equal(2 => {:a => 2, :b => 4}, 6 => {:a => 6, :b => 8}, 10 => {:a => 10, :b => 12})
1836
1751
  @d.to_hash(:b).must_equal(4 => {:a => 2, :b => 4}, 8 => {:a => 6, :b => 8}, 12 => {:a => 10, :b => 12})
1837
1752
  @d.to_hash([:a, :b]).must_equal([2, 4] => {:a => 2, :b => 4}, [6, 8] => {:a => 6, :b => 8}, [10, 12] => {:a => 10, :b => 12})
1838
1753
  end
1839
1754
 
1840
1755
  it "should handle a single composite key when using a row_proc" do
1841
- c = @d.row_proc = Class.new do
1756
+ c = Class.new do
1842
1757
  def self.call(h); new(h); end
1843
1758
  def initialize(h); @h = h; end
1844
1759
  def [](k) @h[k]; end
1845
1760
  def h; @h; end
1846
1761
  def ==(o) @h == o.h; end
1847
1762
  end
1848
- @d.to_hash([:a, :b]).must_equal([1, 2] => c.call(:a => 1, :b => 2), [3, 4] => c.call(:a => 3, :b => 4), [5, 6] => c.call(:a => 5, :b => 6))
1763
+ @d.with_row_proc(c).to_hash([:a, :b]).must_equal([1, 2] => c.call(:a => 1, :b => 2), [3, 4] => c.call(:a => 3, :b => 4), [5, 6] => c.call(:a => 5, :b => 6))
1849
1764
  end
1850
1765
  end
1851
1766
 
@@ -1877,13 +1792,12 @@ describe "Dataset#to_hash_groups" do
1877
1792
 
1878
1793
  it "should accept an :all option to use all into which entries can be merged" do
1879
1794
  called = false
1880
- meta_def(@d, :post_load){|_| called = true}
1881
- @d.to_hash_groups(:a, :b, :all=>true)
1795
+ @d.with_extend{define_method(:post_load){|_| called = true}}.to_hash_groups(:a, :b, :all=>true)
1882
1796
  called.must_equal true
1883
1797
  end
1884
1798
 
1885
1799
  it "should not call the row_proc if two arguments are given" do
1886
- @d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
1800
+ @d = @d.with_row_proc(proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h})
1887
1801
  @d.to_hash_groups(:a, :b).must_equal(1 => [2, 6], 3 => [4], 7 => [4])
1888
1802
  @d.to_hash_groups(:b, :a).must_equal(2 => [1], 4=>[3, 7], 6=>[1])
1889
1803
  @d.to_hash_groups([:a, :b], :b).must_equal([1, 2] => [2], [3, 4] => [4], [1, 6] => [6], [7, 4]=>[4])
@@ -1892,21 +1806,21 @@ describe "Dataset#to_hash_groups" do
1892
1806
  end
1893
1807
 
1894
1808
  it "should call the row_proc if only a single argument is given" do
1895
- @d.row_proc = proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h}
1809
+ @d = @d.with_row_proc(proc{|r| h = {}; r.keys.each{|k| h[k] = r[k] * 2}; h})
1896
1810
  @d.to_hash_groups(:a).must_equal(2 => [{:a => 2, :b => 4}, {:a => 2, :b => 12}], 6 => [{:a => 6, :b => 8}], 14 => [{:a => 14, :b => 8}])
1897
1811
  @d.to_hash_groups(:b).must_equal(4 => [{:a => 2, :b => 4}], 8 => [{:a => 6, :b => 8}, {:a => 14, :b => 8}], 12 => [{:a => 2, :b => 12}])
1898
1812
  @d.to_hash_groups([:a, :b]).must_equal([2, 4] => [{:a => 2, :b => 4}], [6, 8] => [{:a => 6, :b => 8}], [2, 12] => [{:a => 2, :b => 12}], [14, 8] => [{:a => 14, :b => 8}])
1899
1813
  end
1900
1814
 
1901
1815
  it "should handle a single composite key when using a row_proc" do
1902
- c = @d.row_proc = Class.new do
1816
+ c = Class.new do
1903
1817
  def self.call(h); new(h); end
1904
1818
  def initialize(h); @h = h; end
1905
1819
  def [](k) @h[k]; end
1906
1820
  def h; @h; end
1907
1821
  def ==(o) @h == o.h; end
1908
1822
  end
1909
- @d.to_hash_groups([:a, :b]).must_equal([1, 2] => [c.call(:a => 1, :b => 2)], [3, 4] => [c.call(:a => 3, :b => 4)], [1, 6] => [c.call(:a => 1, :b => 6)], [7, 4] => [c.call(:a => 7, :b => 4)])
1823
+ @d.with_row_proc(c).to_hash_groups([:a, :b]).must_equal([1, 2] => [c.call(:a => 1, :b => 2)], [3, 4] => [c.call(:a => 3, :b => 4)], [1, 6] => [c.call(:a => 1, :b => 6)], [7, 4] => [c.call(:a => 7, :b => 4)])
1910
1824
  end
1911
1825
  end
1912
1826
 
@@ -1926,13 +1840,13 @@ describe "Dataset#distinct" do
1926
1840
  end
1927
1841
 
1928
1842
  it "should use DISTINCT ON if columns are given and DISTINCT ON is supported" do
1929
- meta_def(@dataset, :supports_distinct_on?){true}
1843
+ @dataset = @dataset.with_extend{def supports_distinct_on?; true end}
1930
1844
  @dataset.distinct(:a, :b).sql.must_equal 'SELECT DISTINCT ON (a, b) name FROM test'
1931
1845
  @dataset.distinct(Sequel.cast(:stamp, :integer), :node_id=>nil).sql.must_equal 'SELECT DISTINCT ON (CAST(stamp AS integer), (node_id IS NULL)) name FROM test'
1932
1846
  end
1933
1847
 
1934
1848
  it "should use DISTINCT ON if columns are given in a virtual row block and DISTINCT ON is supported" do
1935
- meta_def(@dataset, :supports_distinct_on?){true}
1849
+ @dataset = @dataset.with_extend{def supports_distinct_on?; true end}
1936
1850
  @dataset.distinct{func(:id)}.sql.must_equal 'SELECT DISTINCT ON (func(id)) name FROM test'
1937
1851
  end
1938
1852
 
@@ -1945,27 +1859,35 @@ end
1945
1859
  describe "Dataset#count" do
1946
1860
  before do
1947
1861
  @db = Sequel.mock(:fetch=>{:count=>1})
1948
- @dataset = @db.from(:test).columns(:count)
1862
+ @dataset = @db.from(:test).columns(:count).freeze
1949
1863
  end
1950
1864
 
1951
1865
  it "should format SQL properly" do
1952
- @dataset.count.must_equal 1
1953
- @db.sqls.must_equal ['SELECT count(*) AS count FROM test LIMIT 1']
1866
+ 5.times do
1867
+ @dataset.count.must_equal 1
1868
+ @db.sqls.must_equal ['SELECT count(*) AS count FROM test LIMIT 1']
1869
+ end
1954
1870
  end
1955
1871
 
1956
1872
  it "should accept an argument" do
1957
- @dataset.count(:foo).must_equal 1
1958
- @db.sqls.must_equal ['SELECT count(foo) AS count FROM test LIMIT 1']
1873
+ 5.times do
1874
+ @dataset.count(:foo).must_equal 1
1875
+ @db.sqls.must_equal ['SELECT count(foo) AS count FROM test LIMIT 1']
1876
+ end
1959
1877
  end
1960
1878
 
1961
1879
  it "should work with a nil argument" do
1962
- @dataset.count(nil).must_equal 1
1963
- @db.sqls.must_equal ['SELECT count(NULL) AS count FROM test LIMIT 1']
1880
+ 5.times do
1881
+ @dataset.count(nil).must_equal 1
1882
+ @db.sqls.must_equal ['SELECT count(NULL) AS count FROM test LIMIT 1']
1883
+ end
1964
1884
  end
1965
1885
 
1966
1886
  it "should accept a virtual row block" do
1967
- @dataset.count{foo(bar)}.must_equal 1
1968
- @db.sqls.must_equal ['SELECT count(foo(bar)) AS count FROM test LIMIT 1']
1887
+ 5.times do
1888
+ @dataset.count{foo(bar)}.must_equal 1
1889
+ @db.sqls.must_equal ['SELECT count(foo(bar)) AS count FROM test LIMIT 1']
1890
+ end
1969
1891
  end
1970
1892
 
1971
1893
  it "should raise an Error if given an argument and a block" do
@@ -1978,8 +1900,7 @@ describe "Dataset#count" do
1978
1900
  end
1979
1901
 
1980
1902
  it "should count properly for datasets with fixed sql" do
1981
- @dataset.opts[:sql] = "select abc from xyz"
1982
- @dataset.count.must_equal 1
1903
+ @dataset.with_sql("select abc from xyz").count.must_equal 1
1983
1904
  @db.sqls.must_equal ["SELECT count(*) AS count FROM (select abc from xyz) AS t1 LIMIT 1"]
1984
1905
  end
1985
1906
 
@@ -2003,9 +1924,7 @@ describe "Dataset#count" do
2003
1924
  end
2004
1925
 
2005
1926
  it "should work on a graphed_dataset" do
2006
- def @dataset.columns
2007
- [:a]
2008
- end
1927
+ ds = @dataset.with_extend{ def columns; [:a] end}
2009
1928
  @dataset.graph(@dataset, [:a], :table_alias=>:test2).count.must_equal 1
2010
1929
  @db.sqls.must_equal ['SELECT count(*) AS count FROM test LEFT OUTER JOIN test AS test2 USING (a) LIMIT 1']
2011
1930
  end
@@ -2161,16 +2080,13 @@ describe "Dataset#from_self" do
2161
2080
 
2162
2081
  it "should hoist WITH clauses in current dataset if dataset doesn't support WITH in subselect" do
2163
2082
  ds = Sequel.mock.dataset
2164
- meta_def(ds, :supports_cte?){true}
2165
- meta_def(ds, :supports_cte_in_subselect?){false}
2083
+ ds = ds.with_extend do
2084
+ def supports_cte?; true end
2085
+ def supports_cte_in_subselect?; false end
2086
+ end
2166
2087
  ds.from(:a).with(:a, ds.from(:b)).from_self.sql.must_equal 'WITH a AS (SELECT * FROM b) SELECT * FROM (SELECT * FROM a) AS t1'
2167
2088
  ds.from(:a, :c).with(:a, ds.from(:b)).with(:c, ds.from(:d)).from_self.sql.must_equal 'WITH a AS (SELECT * FROM b), c AS (SELECT * FROM d) SELECT * FROM (SELECT * FROM a, c) AS t1'
2168
2089
  end
2169
-
2170
- it "should have working mutation method" do
2171
- @ds.from_self!
2172
- @ds.sql.must_equal 'SELECT * FROM (SELECT name FROM test LIMIT 1) AS t1'
2173
- end
2174
2090
  end
2175
2091
 
2176
2092
  describe "Dataset#join_table" do
@@ -2295,7 +2211,7 @@ describe "Dataset#join_table" do
2295
2211
  end
2296
2212
 
2297
2213
  it "should default :qualify option to default_join_table_qualification" do
2298
- def @d.default_join_table_qualification; false; end
2214
+ @d = @d.with_extend{def default_join_table_qualification; false end}
2299
2215
  @d.from('stats').join(:players, :id => :player_id).sql.must_equal 'SELECT * FROM "stats" INNER JOIN "players" ON ("id" = "player_id")'
2300
2216
  end
2301
2217
 
@@ -2325,7 +2241,7 @@ describe "Dataset#join_table" do
2325
2241
  it "should support joining datasets" do
2326
2242
  ds = Sequel.mock.dataset.from(:categories)
2327
2243
  @d.join_table(:left_outer, ds, :item_id => :id).sql.must_equal 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories) AS "t1" ON ("t1"."item_id" = "items"."id")'
2328
- ds.filter!(:active => true)
2244
+ ds = ds.where(:active => true)
2329
2245
  @d.join_table(:left_outer, ds, :item_id => :id).sql.must_equal 'SELECT * FROM "items" LEFT OUTER JOIN (SELECT * FROM categories WHERE (active IS TRUE)) AS "t1" ON ("t1"."item_id" = "items"."id")'
2330
2246
  @d.from_self.join_table(:left_outer, ds, :item_id => :id).sql.must_equal 'SELECT * FROM (SELECT * FROM "items") AS "t1" LEFT OUTER JOIN (SELECT * FROM categories WHERE (active IS TRUE)) AS "t2" ON ("t2"."item_id" = "t1"."id")'
2331
2247
  end
@@ -2370,16 +2286,17 @@ describe "Dataset#join_table" do
2370
2286
  end
2371
2287
 
2372
2288
  it "should emulate JOIN USING (poorly) if the dataset doesn't support it" do
2373
- meta_def(@d, :supports_join_using?){false}
2289
+ @d = @d.with_extend{def supports_join_using?; false end}
2374
2290
  @d.join(:categories, [:id]).sql.must_equal 'SELECT * FROM "items" INNER JOIN "categories" ON ("categories"."id" = "items"."id")'
2375
2291
  end
2376
2292
 
2377
2293
  it "should hoist WITH clauses from subqueries if the dataset doesn't support CTEs in subselects" do
2378
- meta_def(@d, :supports_cte?){true}
2379
- meta_def(@d, :supports_cte_in_subselect?){false}
2294
+ @d = @d.with_extend do
2295
+ def supports_cte?; true end
2296
+ def supports_cte_in_subselect?; false end
2297
+ end
2380
2298
  ds = Sequel.mock.dataset.from(:categories)
2381
- meta_def(ds, :supports_cte?){true}
2382
- @d.join(ds.with(:a, Sequel.mock.dataset.from(:b)), [:id]).sql.must_equal 'WITH "a" AS (SELECT * FROM b) SELECT * FROM "items" INNER JOIN (SELECT * FROM categories) AS "t1" USING ("id")'
2299
+ @d.join(ds.with_extend{def supports_cte?; true end}.with(:a, Sequel.mock.dataset.from(:b)), [:id]).sql.must_equal 'WITH "a" AS (SELECT * FROM b) SELECT * FROM "items" INNER JOIN (SELECT * FROM categories) AS "t1" USING ("id")'
2383
2300
  end
2384
2301
 
2385
2302
  it "should raise an error if using an array of symbols with a block" do
@@ -2461,61 +2378,79 @@ end
2461
2378
 
2462
2379
  describe "Dataset aggregate methods" do
2463
2380
  before do
2464
- @d = Sequel.mock(:fetch=>proc{|s| {1=>s}})[:test]
2381
+ @d = Sequel.mock(:fetch=>proc{|s| {1=>s}})[:test].freeze
2465
2382
  end
2466
2383
 
2467
2384
  it "should include min" do
2468
- @d.min(:a).must_equal 'SELECT min(a) AS min FROM test LIMIT 1'
2385
+ 5.times do
2386
+ @d.min(:a).must_equal 'SELECT min(a) AS min FROM test LIMIT 1'
2387
+ end
2469
2388
  end
2470
2389
 
2471
2390
  it "should include max" do
2472
- @d.max(:b).must_equal 'SELECT max(b) AS max FROM test LIMIT 1'
2391
+ 5.times do
2392
+ @d.max(:b).must_equal 'SELECT max(b) AS max FROM test LIMIT 1'
2393
+ end
2473
2394
  end
2474
2395
 
2475
2396
  it "should include sum" do
2476
- @d.sum(:c).must_equal 'SELECT sum(c) AS sum FROM test LIMIT 1'
2397
+ 5.times do
2398
+ @d.sum(:c).must_equal 'SELECT sum(c) AS sum FROM test LIMIT 1'
2399
+ end
2477
2400
  end
2478
2401
 
2479
2402
  it "should include avg" do
2480
- @d.avg(:d).must_equal 'SELECT avg(d) AS avg FROM test LIMIT 1'
2403
+ 5.times do
2404
+ @d.avg(:d).must_equal 'SELECT avg(d) AS avg FROM test LIMIT 1'
2405
+ end
2481
2406
  end
2482
2407
 
2483
2408
  it "should accept qualified columns" do
2484
- @d.avg(:test__bc).must_equal 'SELECT avg(test.bc) AS avg FROM test LIMIT 1'
2409
+ 5.times do
2410
+ @d.avg(:test__bc).must_equal 'SELECT avg(test.bc) AS avg FROM test LIMIT 1'
2411
+ end
2485
2412
  end
2486
2413
 
2487
2414
  it "should use a subselect for the same conditions as count" do
2488
2415
  d = @d.order(:a).limit(5)
2489
- d.avg(:a).must_equal 'SELECT avg(a) AS avg FROM (SELECT * FROM test ORDER BY a LIMIT 5) AS t1 LIMIT 1'
2490
- d.sum(:a).must_equal 'SELECT sum(a) AS sum FROM (SELECT * FROM test ORDER BY a LIMIT 5) AS t1 LIMIT 1'
2491
- d.min(:a).must_equal 'SELECT min(a) AS min FROM (SELECT * FROM test ORDER BY a LIMIT 5) AS t1 LIMIT 1'
2492
- d.max(:a).must_equal 'SELECT max(a) AS max FROM (SELECT * FROM test ORDER BY a LIMIT 5) AS t1 LIMIT 1'
2416
+ 5.times do
2417
+ d.avg(:a).must_equal 'SELECT avg(a) AS avg FROM (SELECT * FROM test ORDER BY a LIMIT 5) AS t1 LIMIT 1'
2418
+ d.sum(:a).must_equal 'SELECT sum(a) AS sum FROM (SELECT * FROM test ORDER BY a LIMIT 5) AS t1 LIMIT 1'
2419
+ d.min(:a).must_equal 'SELECT min(a) AS min FROM (SELECT * FROM test ORDER BY a LIMIT 5) AS t1 LIMIT 1'
2420
+ d.max(:a).must_equal 'SELECT max(a) AS max FROM (SELECT * FROM test ORDER BY a LIMIT 5) AS t1 LIMIT 1'
2421
+ end
2493
2422
  end
2494
2423
 
2495
2424
  it "should accept virtual row blocks" do
2496
- @d.avg{a(b)}.must_equal 'SELECT avg(a(b)) AS avg FROM test LIMIT 1'
2497
- @d.sum{a(b)}.must_equal 'SELECT sum(a(b)) AS sum FROM test LIMIT 1'
2498
- @d.min{a(b)}.must_equal 'SELECT min(a(b)) AS min FROM test LIMIT 1'
2499
- @d.max{a(b)}.must_equal 'SELECT max(a(b)) AS max FROM test LIMIT 1'
2425
+ 5.times do
2426
+ @d.avg{a(b)}.must_equal 'SELECT avg(a(b)) AS avg FROM test LIMIT 1'
2427
+ @d.sum{a(b)}.must_equal 'SELECT sum(a(b)) AS sum FROM test LIMIT 1'
2428
+ @d.min{a(b)}.must_equal 'SELECT min(a(b)) AS min FROM test LIMIT 1'
2429
+ @d.max{a(b)}.must_equal 'SELECT max(a(b)) AS max FROM test LIMIT 1'
2430
+ end
2500
2431
  end
2501
2432
  end
2502
2433
 
2503
2434
  describe "Dataset#range" do
2504
2435
  before do
2505
2436
  @db = Sequel.mock(:fetch=>{:v1 => 1, :v2 => 10})
2506
- @ds = @db[:test]
2437
+ @ds = @db[:test].freeze
2507
2438
  end
2508
2439
 
2509
2440
  it "should generate a correct SQL statement" do
2510
- @ds.range(:stamp)
2511
- @db.sqls.must_equal ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test LIMIT 1"]
2441
+ 5.times do
2442
+ @ds.range(:stamp)
2443
+ @db.sqls.must_equal ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test LIMIT 1"]
2444
+ end
2512
2445
 
2513
2446
  @ds.filter(Sequel.expr(:price) > 100).range(:stamp)
2514
2447
  @db.sqls.must_equal ["SELECT min(stamp) AS v1, max(stamp) AS v2 FROM test WHERE (price > 100) LIMIT 1"]
2515
2448
  end
2516
2449
 
2517
2450
  it "should return a range object" do
2518
- @ds.range(:tryme).must_equal(1..10)
2451
+ 5.times do
2452
+ @ds.range(:tryme).must_equal(1..10)
2453
+ end
2519
2454
  end
2520
2455
 
2521
2456
  it "should use a subselect for the same conditions as count" do
@@ -2524,33 +2459,42 @@ describe "Dataset#range" do
2524
2459
  end
2525
2460
 
2526
2461
  it "should accept virtual row blocks" do
2527
- @ds.range{a(b)}
2528
- @db.sqls.must_equal ["SELECT min(a(b)) AS v1, max(a(b)) AS v2 FROM test LIMIT 1"]
2462
+ 5.times do
2463
+ @ds.range{a(b)}
2464
+ @db.sqls.must_equal ["SELECT min(a(b)) AS v1, max(a(b)) AS v2 FROM test LIMIT 1"]
2465
+ end
2529
2466
  end
2530
2467
  end
2531
2468
 
2532
2469
  describe "Dataset#interval" do
2533
2470
  before do
2534
2471
  @db = Sequel.mock(:fetch=>{:v => 1234})
2535
- @ds = @db[:test]
2472
+ @ds = @db[:test].freeze
2536
2473
  end
2537
2474
 
2538
2475
  it "should generate the correct SQL statement" do
2539
- @ds.interval(:stamp)
2540
- @db.sqls.must_equal ["SELECT (max(stamp) - min(stamp)) AS interval FROM test LIMIT 1"]
2476
+ 5.times do
2477
+ @ds.interval(:stamp)
2478
+ @db.sqls.must_equal ["SELECT (max(stamp) - min(stamp)) AS interval FROM test LIMIT 1"]
2479
+ end
2541
2480
 
2542
2481
  @ds.filter(Sequel.expr(:price) > 100).interval(:stamp)
2543
2482
  @db.sqls.must_equal ["SELECT (max(stamp) - min(stamp)) AS interval FROM test WHERE (price > 100) LIMIT 1"]
2544
2483
  end
2545
2484
 
2546
2485
  it "should use a subselect for the same conditions as count" do
2547
- @ds.order(:stamp).limit(5).interval(:stamp).must_equal 1234
2548
- @db.sqls.must_equal ['SELECT (max(stamp) - min(stamp)) AS interval FROM (SELECT * FROM test ORDER BY stamp LIMIT 5) AS t1 LIMIT 1']
2486
+ ds = @ds.order(:stamp).limit(5)
2487
+ 5.times do
2488
+ ds.interval(:stamp).must_equal 1234
2489
+ @db.sqls.must_equal ['SELECT (max(stamp) - min(stamp)) AS interval FROM (SELECT * FROM test ORDER BY stamp LIMIT 5) AS t1 LIMIT 1']
2490
+ end
2549
2491
  end
2550
2492
 
2551
2493
  it "should accept virtual row blocks" do
2552
- @ds.interval{a(b)}
2553
- @db.sqls.must_equal ["SELECT (max(a(b)) - min(a(b))) AS interval FROM test LIMIT 1"]
2494
+ 5.times do
2495
+ @ds.interval{a(b)}
2496
+ @db.sqls.must_equal ["SELECT (max(a(b)) - min(a(b))) AS interval FROM test LIMIT 1"]
2497
+ end
2554
2498
  end
2555
2499
  end
2556
2500
 
@@ -2560,43 +2504,59 @@ describe "Dataset #first and #last" do
2560
2504
  end
2561
2505
 
2562
2506
  it "should return a single record if no argument is given" do
2563
- @d.order(:a).first.must_equal(:s=>'SELECT * FROM test ORDER BY a LIMIT 1')
2564
- @d.order(:a).last.must_equal(:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1')
2507
+ ds = @d.order(:a).freeze
2508
+ 3.times do
2509
+ ds.first.must_equal(:s=>'SELECT * FROM test ORDER BY a LIMIT 1')
2510
+ ds.last.must_equal(:s=>'SELECT * FROM test ORDER BY a DESC LIMIT 1')
2511
+ end
2565
2512
  end
2566
2513
 
2567
2514
  it "should return the first/last matching record if argument is not an Integer" do
2568
- @d.order(:a).first(:z => 26).must_equal(:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1')
2569
- @d.order(:a).first('z = ?', 15).must_equal(:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1')
2570
- @d.order(:a).last(:z => 26).must_equal(:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a DESC LIMIT 1')
2571
- @d.order(:a).last('z = ?', 15).must_equal(:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a DESC LIMIT 1')
2515
+ ds = @d.order(:a).freeze
2516
+ 5.times do
2517
+ ds.first(:z => 26).must_equal(:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a LIMIT 1')
2518
+ ds.first('z = ?', 15).must_equal(:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a LIMIT 1')
2519
+ ds.last(:z => 26).must_equal(:s=>'SELECT * FROM test WHERE (z = 26) ORDER BY a DESC LIMIT 1')
2520
+ ds.last('z = ?', 15).must_equal(:s=>'SELECT * FROM test WHERE (z = 15) ORDER BY a DESC LIMIT 1')
2521
+ end
2572
2522
  end
2573
2523
 
2574
2524
  it "should set the limit and return an array of records if the given number is > 1" do
2575
- i = rand(10) + 10
2576
- r = @d.order(:a).first(i).must_equal [{:s=>"SELECT * FROM test ORDER BY a LIMIT #{i}"}]
2577
- i = rand(10) + 10
2578
- r = @d.order(:a).last(i).must_equal [{:s=>"SELECT * FROM test ORDER BY a DESC LIMIT #{i}"}]
2525
+ ds = @d.order(:a).freeze
2526
+ 5.times do
2527
+ i = rand(10) + 10
2528
+ ds.first(i).must_equal [{:s=>"SELECT * FROM test ORDER BY a LIMIT #{i}"}]
2529
+ ds.last(i).must_equal [{:s=>"SELECT * FROM test ORDER BY a DESC LIMIT #{i}"}]
2530
+ end
2579
2531
  end
2580
2532
 
2581
2533
  it "should return the first matching record if a block is given without an argument" do
2582
- @d.first{z > 26}.must_equal(:s=>'SELECT * FROM test WHERE (z > 26) LIMIT 1')
2583
- @d.order(:name).last{z > 26}.must_equal(:s=>'SELECT * FROM test WHERE (z > 26) ORDER BY name DESC LIMIT 1')
2534
+ ds = @d.order(:name).freeze
2535
+ 5.times do
2536
+ @d.first{z > 26}.must_equal(:s=>'SELECT * FROM test WHERE (z > 26) LIMIT 1')
2537
+ ds.last{z > 26}.must_equal(:s=>'SELECT * FROM test WHERE (z > 26) ORDER BY name DESC LIMIT 1')
2538
+ end
2584
2539
  end
2585
2540
 
2586
2541
  it "should combine block and standard argument filters if argument is not an Integer" do
2587
- @d.first(:y=>25){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((z > 26) AND (y = 25)) LIMIT 1')
2588
- @d.order(:name).last('y = ?', 16){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((z > 26) AND (y = 16)) ORDER BY name DESC LIMIT 1')
2542
+ ds = @d.order(:name).freeze
2543
+ 5.times do
2544
+ @d.first(:y=>25){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 25) AND (z > 26)) LIMIT 1')
2545
+ ds.last('y = ?', 16){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 16) AND (z > 26)) ORDER BY name DESC LIMIT 1')
2546
+ end
2589
2547
  end
2590
2548
 
2591
2549
  it "should filter and return an array of records if an Integer argument is provided and a block is given" do
2592
- i = rand(10) + 10
2593
- r = @d.order(:a).first(i){z > 26}.must_equal [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a LIMIT #{i}"}]
2594
- i = rand(10) + 10
2595
- r = @d.order(:a).last(i){z > 26}.must_equal [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a DESC LIMIT #{i}"}]
2550
+ ds = @d.order(:a).freeze
2551
+ 5.times do
2552
+ i = rand(10) + 10
2553
+ ds.first(i){z > 26}.must_equal [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a LIMIT #{i}"}]
2554
+ ds.last(i){z > 26}.must_equal [{:s=>"SELECT * FROM test WHERE (z > 26) ORDER BY a DESC LIMIT #{i}"}]
2555
+ end
2596
2556
  end
2597
2557
 
2598
2558
  it "should return nil if no records match" do
2599
- Sequel.mock[:t].first.must_equal nil
2559
+ Sequel.mock[:t].first.must_be_nil
2600
2560
  end
2601
2561
 
2602
2562
  it "#last should raise if no order is given" do
@@ -2639,7 +2599,7 @@ describe "Dataset #first!" do
2639
2599
  end
2640
2600
 
2641
2601
  it "should combine block and standard argument filters if argument is not an Integer" do
2642
- @d.first!(:y=>25){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((z > 26) AND (y = 25)) LIMIT 1')
2602
+ @d.first!(:y=>25){z > 26}.must_equal(:s=>'SELECT * FROM test WHERE ((y = 25) AND (z > 26)) LIMIT 1')
2643
2603
  end
2644
2604
 
2645
2605
  it "should filter and return an array of records if an Integer argument is provided and a block is given" do
@@ -2701,7 +2661,7 @@ describe "Dataset compound operations" do
2701
2661
  end
2702
2662
 
2703
2663
  it "should raise an InvalidOperation if INTERSECT or EXCEPT is used and they are not supported" do
2704
- meta_def(@a, :supports_intersect_except?){false}
2664
+ @a = @a.with_extend{def supports_intersect_except?; false end}
2705
2665
  proc{@a.intersect(@b)}.must_raise(Sequel::InvalidOperation)
2706
2666
  proc{@a.intersect(@b,:all=> true)}.must_raise(Sequel::InvalidOperation)
2707
2667
  proc{@a.except(@b)}.must_raise(Sequel::InvalidOperation)
@@ -2709,7 +2669,7 @@ describe "Dataset compound operations" do
2709
2669
  end
2710
2670
 
2711
2671
  it "should raise an InvalidOperation if INTERSECT ALL or EXCEPT ALL is used and they are not supported" do
2712
- meta_def(@a, :supports_intersect_except_all?){false}
2672
+ @a = @a.with_extend{def supports_intersect_except_all?; false end}
2713
2673
  @a.intersect(@b)
2714
2674
  proc{@a.intersect(@b, :all=>true)}.must_raise(Sequel::InvalidOperation)
2715
2675
  @a.except(@b)
@@ -2751,8 +2711,10 @@ describe "Dataset compound operations" do
2751
2711
 
2752
2712
  it "should hoist WITH clauses in given dataset if dataset doesn't support WITH in subselect" do
2753
2713
  ds = Sequel.mock.dataset
2754
- meta_def(ds, :supports_cte?){true}
2755
- meta_def(ds, :supports_cte_in_subselect?){false}
2714
+ ds = ds.with_extend do
2715
+ def supports_cte?; true end
2716
+ def supports_cte_in_subselect?; false end
2717
+ end
2756
2718
  ds.from(:a).union(ds.from(:c).with(:c, ds.from(:d)), :from_self=>false).sql.must_equal 'WITH c AS (SELECT * FROM d) SELECT * FROM a UNION SELECT * FROM c'
2757
2719
  ds.from(:a).except(ds.from(:c).with(:c, ds.from(:d))).sql.must_equal 'WITH c AS (SELECT * FROM d) SELECT * FROM (SELECT * FROM a EXCEPT SELECT * FROM c) AS t1'
2758
2720
  ds.from(:a).with(:a, ds.from(:b)).intersect(ds.from(:c).with(:c, ds.from(:d)), :from_self=>false).sql.must_equal 'WITH a AS (SELECT * FROM b), c AS (SELECT * FROM d) SELECT * FROM a INTERSECT SELECT * FROM c'
@@ -2786,7 +2748,7 @@ describe "Dataset#single_record" do
2786
2748
  end
2787
2749
 
2788
2750
  it "should return nil if no record is present" do
2789
- @db[:test].single_record.must_equal nil
2751
+ @db[:test].single_record.must_be_nil
2790
2752
  @db.sqls.must_equal ['SELECT * FROM test LIMIT 1']
2791
2753
  end
2792
2754
  end
@@ -2803,7 +2765,7 @@ describe "Dataset#single_record!" do
2803
2765
  end
2804
2766
 
2805
2767
  it "should return nil if no record is present" do
2806
- @db[:test].single_record!.must_equal nil
2768
+ @db[:test].single_record!.must_be_nil
2807
2769
  @db.sqls.must_equal ['SELECT * FROM test']
2808
2770
  end
2809
2771
  end
@@ -2820,7 +2782,7 @@ describe "Dataset#single_value" do
2820
2782
  end
2821
2783
 
2822
2784
  it "should return nil if no records" do
2823
- @db[:test].single_value.must_equal nil
2785
+ @db[:test].single_value.must_be_nil
2824
2786
  @db.sqls.must_equal ['SELECT * FROM test LIMIT 1']
2825
2787
  end
2826
2788
 
@@ -2844,7 +2806,7 @@ describe "Dataset#single_value!" do
2844
2806
  end
2845
2807
 
2846
2808
  it "should return nil if no records" do
2847
- @db[:test].single_value!.must_equal nil
2809
+ @db[:test].single_value!.must_be_nil
2848
2810
  @db.sqls.must_equal ['SELECT * FROM test']
2849
2811
  end
2850
2812
  end
@@ -2855,8 +2817,11 @@ describe "Dataset#get" do
2855
2817
  end
2856
2818
 
2857
2819
  it "should select the specified column and fetch its value" do
2858
- @d.get(:name).must_equal "SELECT name FROM test LIMIT 1"
2859
- @d.get(:abc).must_equal "SELECT abc FROM test LIMIT 1"
2820
+ @d.freeze
2821
+ 5.times do
2822
+ @d.get(:name).must_equal "SELECT name FROM test LIMIT 1"
2823
+ @d.get(:abc).must_equal "SELECT abc FROM test LIMIT 1"
2824
+ end
2860
2825
  end
2861
2826
 
2862
2827
  it "should work with filters" do
@@ -2864,7 +2829,17 @@ describe "Dataset#get" do
2864
2829
  end
2865
2830
 
2866
2831
  it "should work with aliased fields" do
2867
- @d.get(Sequel.expr(:x__b).as(:name)).must_equal "SELECT x.b AS name FROM test LIMIT 1"
2832
+ @d.freeze
2833
+ 5.times do
2834
+ @d.get(Sequel.expr(:x__b).as(:name)).must_equal "SELECT x.b AS name FROM test LIMIT 1"
2835
+ end
2836
+ end
2837
+
2838
+ it "should work with plain strings" do
2839
+ @d.freeze
2840
+ 5.times do
2841
+ @d.get('a').must_equal "SELECT 'a' AS v FROM test LIMIT 1"
2842
+ end
2868
2843
  end
2869
2844
 
2870
2845
  it "should accept a block that yields a virtual row" do
@@ -2882,7 +2857,7 @@ describe "Dataset#get" do
2882
2857
  end
2883
2858
 
2884
2859
  it "should support an array of expressions to get an array of results" do
2885
- @d._fetch = {:name=>1, :abc=>2}
2860
+ @d = @d.with_fetch(:name=>1, :abc=>2)
2886
2861
  @d.get([:name, :abc]).must_equal [1, 2]
2887
2862
  @d.db.sqls.must_equal ['SELECT name, abc FROM test LIMIT 1']
2888
2863
  end
@@ -2892,33 +2867,32 @@ describe "Dataset#get" do
2892
2867
  end
2893
2868
 
2894
2869
  it "should handle an array with aliases" do
2895
- @d._fetch = {:name=>1, :abc=>2}
2870
+ @d = @d.with_fetch(:name=>1, :abc=>2)
2896
2871
  @d.get([:n___name, Sequel.as(:a, :abc)]).must_equal [1, 2]
2897
2872
  @d.db.sqls.must_equal ['SELECT n AS name, a AS abc FROM test LIMIT 1']
2898
2873
  end
2899
2874
 
2900
2875
  it "should raise an Error if an alias cannot be determined" do
2901
- @d._fetch = {:name=>1, :abc=>2}
2902
- proc{@d.get([Sequel.+(:a, 1), :a])}.must_raise(Sequel::Error)
2876
+ proc{@d.with_fetch(:name=>1, :abc=>2).get([Sequel.+(:a, 1), :a])}.must_raise(Sequel::Error)
2903
2877
  end
2904
2878
 
2905
2879
  it "should support an array of expressions in a virtual row" do
2906
- @d._fetch = {:name=>1, :abc=>2}
2880
+ @d = @d.with_fetch(:name=>1, :abc=>2)
2907
2881
  @d.get{[name, n__abc]}.must_equal [1, 2]
2908
2882
  @d.db.sqls.must_equal ['SELECT name, n.abc FROM test LIMIT 1']
2909
2883
  end
2910
2884
 
2911
2885
  it "should work with static SQL" do
2912
2886
  @d.with_sql('SELECT foo').get(:name).must_equal "SELECT foo"
2913
- @d._fetch = {:name=>1, :abc=>2}
2887
+ @d = @d.with_fetch(:name=>1, :abc=>2)
2914
2888
  @d.with_sql('SELECT foo').get{[name, n__abc]}.must_equal [1, 2]
2915
2889
  @d.db.sqls.must_equal ['SELECT foo'] * 2
2916
2890
  end
2917
2891
 
2918
2892
  it "should handle cases where no rows are returned" do
2919
- @d._fetch = []
2920
- @d.get(:n).must_equal nil
2921
- @d.get([:n, :a]).must_equal nil
2893
+ @d = @d.with_fetch([])
2894
+ @d.get(:n).must_be_nil
2895
+ @d.get([:n, :a]).must_be_nil
2922
2896
  @d.db.sqls.must_equal ['SELECT n FROM test LIMIT 1', 'SELECT n, a FROM test LIMIT 1']
2923
2897
  end
2924
2898
  end
@@ -2926,8 +2900,7 @@ end
2926
2900
  describe "Dataset#set_row_proc" do
2927
2901
  before do
2928
2902
  @db = Sequel.mock(:fetch=>[{:a=>1}, {:a=>2}])
2929
- @dataset = @db[:items]
2930
- @dataset.row_proc = proc{|h| h[:der] = h[:a] + 2; h}
2903
+ @dataset = @db[:items].with_row_proc(proc{|h| h[:der] = h[:a] + 2; h})
2931
2904
  end
2932
2905
 
2933
2906
  it "should cause dataset to pass all rows through the filter" do
@@ -3013,7 +2986,7 @@ describe "Dataset#columns" do
3013
2986
 
3014
2987
  it "should ignore any filters, orders, or DISTINCT clauses" do
3015
2988
  @dataset.db.columns = [:a]
3016
- @dataset.filter!(:b=>100).order!(:b).distinct!
2989
+ @dataset = @dataset.where(:b=>100).order(:b).distinct
3017
2990
  @dataset.columns.must_equal [:a]
3018
2991
  @dataset.db.sqls.must_equal ['SELECT * FROM items LIMIT 1']
3019
2992
  end
@@ -3036,7 +3009,7 @@ describe "Dataset#import" do
3036
3009
  end
3037
3010
 
3038
3011
  it "should return nil without a query if no values" do
3039
- @ds.import(['x', 'y'], []).must_equal nil
3012
+ @ds.import(['x', 'y'], []).must_be_nil
3040
3013
  @db.sqls.must_equal []
3041
3014
  end
3042
3015
 
@@ -3066,7 +3039,7 @@ describe "Dataset#import" do
3066
3039
  end
3067
3040
 
3068
3041
  it "should slice based on the default_import_slice option" do
3069
- def @ds.default_import_slice; 2 end
3042
+ @ds = @ds.with_extend{def default_import_slice; 2 end}
3070
3043
  @ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]])
3071
3044
  @db.sqls.must_equal ['BEGIN',
3072
3045
  "INSERT INTO items (x, y) VALUES (1, 2)",
@@ -3107,7 +3080,7 @@ describe "Dataset#import" do
3107
3080
  end
3108
3081
 
3109
3082
  it "should use correct sql for :values strategy" do
3110
- def @ds.multi_insert_sql_strategy; :values end
3083
+ @ds = @ds.with_extend{def multi_insert_sql_strategy; :values end}
3111
3084
  @ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]])
3112
3085
  @db.sqls.must_equal ['BEGIN',
3113
3086
  "INSERT INTO items (x, y) VALUES (1, 2), (3, 4), (5, 6)",
@@ -3123,7 +3096,7 @@ describe "Dataset#import" do
3123
3096
  end
3124
3097
 
3125
3098
  it "should use correct sql for :union strategy" do
3126
- def @ds.multi_insert_sql_strategy; :union end
3099
+ @ds = @ds.with_extend{def multi_insert_sql_strategy; :union end}
3127
3100
  @ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]])
3128
3101
  @db.sqls.must_equal ['BEGIN',
3129
3102
  "INSERT INTO items (x, y) SELECT 1, 2 UNION ALL SELECT 3, 4 UNION ALL SELECT 5, 6",
@@ -3139,8 +3112,10 @@ describe "Dataset#import" do
3139
3112
  end
3140
3113
 
3141
3114
  it "should use correct sql for :union strategy when FROM is required" do
3142
- def @ds.empty_from_sql; ' FROM foo' end
3143
- def @ds.multi_insert_sql_strategy; :union end
3115
+ @ds = @ds.with_extend do
3116
+ def empty_from_sql; ' FROM foo' end
3117
+ def multi_insert_sql_strategy; :union end
3118
+ end
3144
3119
  @ds.import([:x, :y], [[1, 2], [3, 4], [5, 6]])
3145
3120
  @db.sqls.must_equal ['BEGIN',
3146
3121
  "INSERT INTO items (x, y) SELECT 1, 2 FROM foo UNION ALL SELECT 3, 4 FROM foo UNION ALL SELECT 5, 6 FROM foo",
@@ -3164,7 +3139,7 @@ describe "Dataset#multi_insert" do
3164
3139
  end
3165
3140
 
3166
3141
  it "should return nil without a query if no values" do
3167
- @ds.multi_insert([]).must_equal nil
3142
+ @ds.multi_insert([]).must_be_nil
3168
3143
  @db.sqls.must_equal []
3169
3144
  end
3170
3145
 
@@ -3269,51 +3244,6 @@ describe "Dataset#multi_insert" do
3269
3244
  end
3270
3245
  end
3271
3246
 
3272
- describe "Dataset" do
3273
- before do
3274
- @d = Sequel.mock.dataset.from(:x)
3275
- end
3276
-
3277
- it "should support self-changing select!" do
3278
- @d.select!(:y)
3279
- @d.sql.must_equal "SELECT y FROM x"
3280
- end
3281
-
3282
- it "should support self-changing from!" do
3283
- @d.from!(:y)
3284
- @d.sql.must_equal "SELECT * FROM y"
3285
- end
3286
-
3287
- it "should support self-changing order!" do
3288
- @d.order!(:y)
3289
- @d.sql.must_equal "SELECT * FROM x ORDER BY y"
3290
- end
3291
-
3292
- it "should support self-changing filter!" do
3293
- @d.filter!(:y => 1)
3294
- @d.sql.must_equal "SELECT * FROM x WHERE (y = 1)"
3295
- end
3296
-
3297
- it "should support self-changing filter! with block" do
3298
- @d.filter!{y < 2}
3299
- @d.sql.must_equal "SELECT * FROM x WHERE (y < 2)"
3300
- end
3301
-
3302
- it "should raise for ! methods that don't return a dataset" do
3303
- proc {@d.opts!}.must_raise(NoMethodError)
3304
- end
3305
-
3306
- it "should raise for missing methods" do
3307
- proc {@d.xuyz}.must_raise(NoMethodError)
3308
- proc {@d.xyz!}.must_raise(NoMethodError)
3309
- proc {@d.xyz?}.must_raise(NoMethodError)
3310
- end
3311
-
3312
- it "should support chaining of bang methods" do
3313
- @d.order!(:y).filter!(:y => 1).sql.must_equal "SELECT * FROM x WHERE (y = 1) ORDER BY y"
3314
- end
3315
- end
3316
-
3317
3247
  describe "Dataset#update_sql" do
3318
3248
  before do
3319
3249
  @ds = Sequel.mock.dataset.from(:items)
@@ -3414,13 +3344,13 @@ describe "Dataset#inspect" do
3414
3344
  end
3415
3345
 
3416
3346
  it "should include the class name and the corresponding SQL statement" do
3417
- Sequel::Dataset.new(Sequel.mock).from(:blah).inspect.must_equal '#<Sequel::Dataset: "SELECT * FROM blah">'
3418
- InspectDataset.new(Sequel.mock).from(:blah).inspect.must_equal '#<InspectDataset: "SELECT * FROM blah">'
3347
+ Sequel::Dataset.new(Sequel.mock).from(:blah).inspect.must_equal '#<Sequel::Dataset: "SELECT * FROM \\"BLAH\\"">'
3348
+ InspectDataset.new(Sequel.mock).from(:blah).inspect.must_equal '#<InspectDataset: "SELECT * FROM \\"BLAH\\"">'
3419
3349
  end
3420
3350
 
3421
3351
  it "should skip anonymous classes" do
3422
- Class.new(Class.new(Sequel::Dataset)).new(Sequel.mock).from(:blah).inspect.must_equal '#<Sequel::Dataset: "SELECT * FROM blah">'
3423
- Class.new(InspectDataset).new(Sequel.mock).from(:blah).inspect.must_equal '#<InspectDataset: "SELECT * FROM blah">'
3352
+ Class.new(Class.new(Sequel::Dataset)).new(Sequel.mock).from(:blah).inspect.must_equal '#<Sequel::Dataset: "SELECT * FROM \\"BLAH\\"">'
3353
+ Class.new(InspectDataset).new(Sequel.mock).from(:blah).inspect.must_equal '#<InspectDataset: "SELECT * FROM \\"BLAH\\"">'
3424
3354
  end
3425
3355
  end
3426
3356
 
@@ -3497,7 +3427,7 @@ describe "Dataset#grep" do
3497
3427
  end
3498
3428
 
3499
3429
  it "should support regexps if the database supports it" do
3500
- def @ds.supports_regexp?; true end
3430
+ @ds = @ds.with_extend{def supports_regexp?; true end}
3501
3431
  @ds.grep(:title, /ruby/).sql.must_equal "SELECT * FROM posts WHERE ((title ~ 'ruby'))"
3502
3432
  @ds.grep(:title, [/^ruby/, 'ruby']).sql.must_equal "SELECT * FROM posts WHERE ((title ~ '^ruby') OR (title LIKE 'ruby' ESCAPE '\\'))"
3503
3433
  end
@@ -3529,7 +3459,7 @@ describe "Dataset default #fetch_rows, #insert, #update, #delete, #truncate, #ex
3529
3459
  end
3530
3460
 
3531
3461
  it "#truncate should execute truncate SQL" do
3532
- @ds.truncate.must_equal nil
3462
+ @ds.truncate.must_be_nil
3533
3463
  @db.sqls.must_equal ["TRUNCATE TABLE items"]
3534
3464
  end
3535
3465
 
@@ -3596,7 +3526,7 @@ describe "Dataset#with_sql_*" do
3596
3526
 
3597
3527
  it "#with_sql_first should return nil if no rows returned" do
3598
3528
  @db.fetch = []
3599
- @ds.with_sql_first('SELECT * FROM foo').must_equal nil
3529
+ @ds.with_sql_first('SELECT * FROM foo').must_be_nil
3600
3530
  @db.sqls.must_equal ["SELECT * FROM foo -- read_only"]
3601
3531
  end
3602
3532
 
@@ -3607,7 +3537,7 @@ describe "Dataset#with_sql_*" do
3607
3537
 
3608
3538
  it "#with_sql_single_value should return nil if no rows returned" do
3609
3539
  @db.fetch = []
3610
- @ds.with_sql_single_value('SELECT * FROM foo').must_equal nil
3540
+ @ds.with_sql_single_value('SELECT * FROM foo').must_be_nil
3611
3541
  @db.sqls.must_equal ["SELECT * FROM foo -- read_only"]
3612
3542
  end
3613
3543
  end
@@ -3615,12 +3545,11 @@ end
3615
3545
  describe "Dataset prepared statements and bound variables " do
3616
3546
  before do
3617
3547
  @db = Sequel.mock
3618
- @ds = @db[:items]
3619
- meta_def(@ds, :insert_select_sql){|*v| "#{insert_sql(*v)} RETURNING *" }
3548
+ @ds = @db[:items].with_extend{def insert_select_sql(*v) "#{insert_sql(*v)} RETURNING *" end}
3620
3549
  end
3621
3550
 
3622
3551
  it "#call should take a type and bind hash and interpolate it" do
3623
- @ds.filter(:num=>:$n).call(:each, :n=>1)
3552
+ @ds.filter(:num=>:$n).bind({:n=>1}.freeze).call(:each)
3624
3553
  @ds.filter(:num=>:$n).call(:select, :n=>1)
3625
3554
  @ds.filter(:num=>:$n).call([:map, :a], :n=>1)
3626
3555
  @ds.filter(:num=>:$n).call([:to_hash, :a, :b], :n=>1)
@@ -3629,6 +3558,7 @@ describe "Dataset prepared statements and bound variables " do
3629
3558
  @ds.filter(:num=>:$n).call(:delete, :n=>1)
3630
3559
  @ds.filter(:num=>:$n).call(:update, {:n=>1, :n2=>2}, :num=>:$n2)
3631
3560
  @ds.call(:insert, {:n=>1}, :num=>:$n)
3561
+ @ds.call(:insert_pk, {:n=>1}, :num=>:$n)
3632
3562
  @ds.call(:insert_select, {:n=>1}, :num=>:$n)
3633
3563
  @db.sqls.must_equal [
3634
3564
  'SELECT * FROM items WHERE (num = 1)',
@@ -3640,6 +3570,7 @@ describe "Dataset prepared statements and bound variables " do
3640
3570
  'DELETE FROM items WHERE (num = 1)',
3641
3571
  'UPDATE items SET num = 2 WHERE (num = 1)',
3642
3572
  'INSERT INTO items (num) VALUES (1)',
3573
+ 'INSERT INTO items (num) VALUES (1)',
3643
3574
  'INSERT INTO items (num) VALUES (1) RETURNING *']
3644
3575
  end
3645
3576
 
@@ -3681,10 +3612,12 @@ describe "Dataset prepared statements and bound variables " do
3681
3612
  end
3682
3613
 
3683
3614
  it "#call and #prepare should handle returning" do
3684
- meta_def(@ds, :supports_returning?){|_| true}
3685
- meta_def(@ds, :insert_sql){|*v| "#{super(*v)} RETURNING *" }
3686
- meta_def(@ds, :update_sql){|*v| "#{super(*v)} RETURNING *" }
3687
- meta_def(@ds, :delete_sql){"#{super()} RETURNING *" }
3615
+ @ds = @ds.with_extend do
3616
+ def supports_returning?(_) true end
3617
+ def insert_sql(*v) "#{super(*v)} RETURNING *" end
3618
+ def update_sql(*v) "#{super(*v)} RETURNING *" end
3619
+ def delete_sql; "#{super()} RETURNING *" end
3620
+ end
3688
3621
  @ds = @ds.returning
3689
3622
  @ds.call(:insert, {:n=>1}, :num=>:$n)
3690
3623
  @ds.filter(:num=>:$n).call(:update, {:n=>1, :n2=>2}, :num=>:$n2)
@@ -3705,8 +3638,7 @@ describe "Dataset prepared statements and bound variables " do
3705
3638
  end
3706
3639
 
3707
3640
  it "PreparedStatement#prepare should not raise an error if preparing prepared statements is allowed" do
3708
- ps = @ds.prepare(:select, :select_n)
3709
- def ps.allow_preparing_prepared_statements?; true end
3641
+ ps = @ds.prepare(:select, :select_n).with_extend{def allow_preparing_prepared_statements?; true end}
3710
3642
  ps.prepare(:select, :select_n2).call
3711
3643
  @db.sqls.must_equal ["SELECT * FROM items"]
3712
3644
  end
@@ -3728,7 +3660,7 @@ describe "Dataset prepared statements and bound variables " do
3728
3660
 
3729
3661
  it "should handle columns on prepared statements correctly" do
3730
3662
  @db.columns = [:num]
3731
- meta_def(@ds, :select_where_sql){|sql| super(sql); sql << " OR #{columns.first} = 1" if opts[:where]}
3663
+ @ds = @ds.with_extend{def select_where_sql(sql) super(sql); sql << " OR #{columns.first} = 1" if opts[:where] end}
3732
3664
  @ds.filter(:num=>:$n).prepare(:select, :sn).sql.must_equal 'SELECT * FROM items WHERE (num = $n) OR num = 1'
3733
3665
  @db.sqls.must_equal ['SELECT * FROM items LIMIT 1']
3734
3666
  end
@@ -3759,26 +3691,32 @@ describe "Dataset prepared statements and bound variables " do
3759
3691
  end
3760
3692
 
3761
3693
  it "should handle usage with Dataset.prepared_statements_module" do
3762
- @ds.extend(Sequel::Dataset.send(:prepared_statements_module, :prepare_bind, [Sequel::Dataset::ArgumentMapper, Sequel::Dataset::PreparedStatementMethods]){def foo; :bar; end})
3694
+ @ds = @ds.with_extend(Sequel::Dataset.send(:prepared_statements_module, :prepare_bind, [Sequel::Dataset::ArgumentMapper, Sequel::Dataset::PreparedStatementMethods]){def foo; :bar; end})
3763
3695
  @ds.foo.must_equal :bar
3764
- @ds.prepared_statement_name = 'foo'
3696
+ @ds = @ds.clone(:prepared_statement_name => 'foo')
3765
3697
  @ds.call(:a=>1)
3766
3698
  @db.sqls.must_equal ["foo"]
3767
3699
  end
3700
+
3701
+ it "should support log_sql option" do
3702
+ @ds.prepare(:select, :foo).log_sql.must_be_nil
3703
+ @ds.clone(:log_sql=>true).prepare(:select, :foo).log_sql.must_equal true
3704
+ end
3768
3705
  end
3769
3706
 
3770
3707
  describe Sequel::Dataset::UnnumberedArgumentMapper do
3771
3708
  before do
3772
3709
  @db = Sequel.mock
3773
- @ds = @db[:items].filter(:num=>:$n)
3774
- def @ds.execute(sql, opts={}, &block)
3775
- super(sql, opts.merge({:arguments=>bind_arguments}), &block)
3776
- end
3777
- def @ds.execute_dui(sql, opts={}, &block)
3778
- super(sql, opts.merge({:arguments=>bind_arguments}), &block)
3779
- end
3780
- def @ds.execute_insert(sql, opts={}, &block)
3781
- super(sql, opts.merge({:arguments=>bind_arguments}), &block)
3710
+ @ds = @db[:items].filter(:num=>:$n).with_extend do
3711
+ def execute(sql, opts={}, &block)
3712
+ super(sql, opts.merge({:arguments=>bind_arguments}), &block)
3713
+ end
3714
+ def execute_dui(sql, opts={}, &block)
3715
+ super(sql, opts.merge({:arguments=>bind_arguments}), &block)
3716
+ end
3717
+ def execute_insert(sql, opts={}, &block)
3718
+ super(sql, opts.merge({:arguments=>bind_arguments}), &block)
3719
+ end
3782
3720
  end
3783
3721
  @ps = []
3784
3722
  @ps << @ds.prepare(:select, :s)
@@ -3787,9 +3725,8 @@ describe Sequel::Dataset::UnnumberedArgumentMapper do
3787
3725
  @ps << @ds.prepare(:delete, :d)
3788
3726
  @ps << @ds.prepare(:insert, :i, :num=>:$n)
3789
3727
  @ps << @ds.prepare(:update, :u, :num=>:$n)
3790
- @ps.each do |p|
3791
- p.extend(Sequel::Dataset::ArgumentMapper) # Work around for old rbx
3792
- p.extend(Sequel::Dataset::UnnumberedArgumentMapper)
3728
+ @ps.map! do |p|
3729
+ p.with_extend(Sequel::Dataset::UnnumberedArgumentMapper)
3793
3730
  end
3794
3731
  end
3795
3732
 
@@ -3809,9 +3746,9 @@ describe Sequel::Dataset::UnnumberedArgumentMapper do
3809
3746
 
3810
3747
  it "should handle unrecognized statement types as :all" do
3811
3748
  ps = @ds.prepare(:select_all, :s)
3812
- ps.extend(Sequel::Dataset::ArgumentMapper) # Work around for old rbx
3813
- ps.extend(Sequel::Dataset::UnnumberedArgumentMapper)
3814
- ps.prepared_sql
3749
+ ps = ps.with_extend(Sequel::Dataset::UnnumberedArgumentMapper)
3750
+ sql = ps.prepared_sql
3751
+ ps.prepared_sql.must_be_same_as(sql)
3815
3752
  ps.call(:n=>1)
3816
3753
  @db.sqls.must_equal ["SELECT * FROM items WHERE (num = ?) -- args: [1]"]
3817
3754
  end
@@ -3845,7 +3782,7 @@ end
3845
3782
 
3846
3783
  describe "Sequel::Dataset#qualify" do
3847
3784
  before do
3848
- @ds = Sequel::Database.new[:t]
3785
+ @ds = Sequel.mock[:t]
3849
3786
  end
3850
3787
 
3851
3788
  it "should qualify to the table if one is given" do
@@ -3926,7 +3863,7 @@ describe "Sequel::Dataset#qualify" do
3926
3863
  end
3927
3864
 
3928
3865
  it "should handle SQL::Functions with windows" do
3929
- meta_def(@ds, :supports_window_functions?){true}
3866
+ @ds = @ds.with_extend{def supports_window_functions?; true end}
3930
3867
  @ds.select{sum(:a).over(:partition=>:b, :order=>:c)}.qualify.sql.must_equal 'SELECT sum(t.a) OVER (PARTITION BY t.b ORDER BY t.c) FROM t'
3931
3868
  end
3932
3869
 
@@ -3958,7 +3895,7 @@ end
3958
3895
 
3959
3896
  describe "Sequel::Dataset#unbind" do
3960
3897
  before do
3961
- @ds = Sequel::Database.new[:t]
3898
+ @ds = Sequel.mock[:t]
3962
3899
  @u = proc{|ds| ds, bv = ds.unbind; [ds.sql, bv]}
3963
3900
  end
3964
3901
 
@@ -4037,9 +3974,8 @@ end
4037
3974
 
4038
3975
  describe "Sequel::Dataset #with and #with_recursive" do
4039
3976
  before do
4040
- @db = Sequel::Database.new
4041
- @ds = @db[:t]
4042
- def @ds.supports_cte?(*) true end
3977
+ @db = Sequel.mock
3978
+ @ds = @db[:t].with_extend{def supports_cte?(*) true end}
4043
3979
  end
4044
3980
 
4045
3981
  it "#with should take a name and dataset and use a WITH clause" do
@@ -4072,24 +4008,27 @@ describe "Sequel::Dataset #with and #with_recursive" do
4072
4008
  end
4073
4009
 
4074
4010
  it "#with and #with_recursive should raise an error unless the dataset supports CTEs" do
4075
- meta_def(@ds, :supports_cte?){false}
4011
+ @ds = @ds.with_extend{def supports_cte?; false end}
4076
4012
  proc{@ds.with(:t, @db[:x], :args=>[:b])}.must_raise(Sequel::Error)
4077
4013
  proc{@ds.with_recursive(:t, @db[:x], @db[:t], :args=>[:b, :c])}.must_raise(Sequel::Error)
4078
4014
  end
4079
4015
 
4080
4016
  it "#with should work on insert, update, and delete statements if they support it" do
4081
- sc = class << @ds; self; end
4082
- Sequel::Dataset.def_sql_method(sc, :delete, %w'with delete from where')
4083
- Sequel::Dataset.def_sql_method(sc, :insert, %w'with insert into columns values')
4084
- Sequel::Dataset.def_sql_method(sc, :update, %w'with update table set where')
4017
+ @ds = @ds.with_extend do
4018
+ Sequel::Dataset.def_sql_method(self, :delete, %w'with delete from where')
4019
+ Sequel::Dataset.def_sql_method(self, :insert, %w'with insert into columns values')
4020
+ Sequel::Dataset.def_sql_method(self, :update, %w'with update table set where')
4021
+ end
4085
4022
  @ds.with(:t, @db[:x]).insert_sql(1).must_equal 'WITH t AS (SELECT * FROM x) INSERT INTO t VALUES (1)'
4086
4023
  @ds.with(:t, @db[:x]).update_sql(:foo=>1).must_equal 'WITH t AS (SELECT * FROM x) UPDATE t SET foo = 1'
4087
4024
  @ds.with(:t, @db[:x]).delete_sql.must_equal 'WITH t AS (SELECT * FROM x) DELETE FROM t'
4088
4025
  end
4089
4026
 
4090
4027
  it "should hoist WITH clauses in given dataset(s) if dataset doesn't support WITH in subselect" do
4091
- meta_def(@ds, :supports_cte?){true}
4092
- meta_def(@ds, :supports_cte_in_subselect?){false}
4028
+ @ds = @ds.with_extend do
4029
+ def supports_cte?; true end
4030
+ def supports_cte_in_subselect?; false end
4031
+ end
4093
4032
  @ds.with(:t, @ds.from(:s).with(:s, @ds.from(:r))).sql.must_equal 'WITH s AS (SELECT * FROM r), t AS (SELECT * FROM s) SELECT * FROM t'
4094
4033
  @ds.with_recursive(:t, @ds.from(:s).with(:s, @ds.from(:r)), @ds.from(:q).with(:q, @ds.from(:p))).sql.must_equal 'WITH s AS (SELECT * FROM r), q AS (SELECT * FROM p), t AS (SELECT * FROM s UNION ALL SELECT * FROM q) SELECT * FROM t'
4095
4034
  end
@@ -4143,9 +4082,10 @@ end
4143
4082
  describe "Sequel timezone support" do
4144
4083
  before do
4145
4084
  @db = Sequel::Database.new
4146
- @dataset = @db.dataset
4147
- meta_def(@dataset, :supports_timestamp_timezones?){true}
4148
- meta_def(@dataset, :supports_timestamp_usecs?){false}
4085
+ @dataset = @db.dataset.with_extend do
4086
+ def supports_timestamp_timezones?; true end
4087
+ def supports_timestamp_usecs?; false end
4088
+ end
4149
4089
  @utc_time = Time.utc(2010, 1, 2, 3, 4, 5)
4150
4090
  @local_time = Time.local(2010, 1, 2, 3, 4, 5)
4151
4091
  @offset = sprintf("%+03i%02i", *(@local_time.utc_offset/60).divmod(60))
@@ -4280,9 +4220,9 @@ describe "Sequel timezone support" do
4280
4220
  end
4281
4221
 
4282
4222
  it "should have Sequel.default_timezone= should set all other timezones" do
4283
- Sequel.database_timezone.must_equal nil
4284
- Sequel.application_timezone.must_equal nil
4285
- Sequel.typecast_timezone.must_equal nil
4223
+ Sequel.database_timezone.must_be_nil
4224
+ Sequel.application_timezone.must_be_nil
4225
+ Sequel.typecast_timezone.must_be_nil
4286
4226
  Sequel.default_timezone = :utc
4287
4227
  Sequel.database_timezone.must_equal :utc
4288
4228
  Sequel.application_timezone.must_equal :utc
@@ -4562,8 +4502,7 @@ end
4562
4502
 
4563
4503
  describe "Modifying joined datasets" do
4564
4504
  before do
4565
- @ds = Sequel.mock.from(:b, :c).join(:d, [:id]).where(:id => 2)
4566
- meta_def(@ds, :supports_modifying_joins?){true}
4505
+ @ds = Sequel.mock.from(:b, :c).join(:d, [:id]).where(:id => 2).with_extend{def supports_modifying_joins?; true end}
4567
4506
  end
4568
4507
 
4569
4508
  it "should allow deleting from joined datasets" do
@@ -4583,7 +4522,9 @@ describe "Dataset#lock_style and for_update" do
4583
4522
  end
4584
4523
 
4585
4524
  it "#for_update should use FOR UPDATE" do
4586
- @ds.for_update.sql.must_equal "SELECT * FROM t FOR UPDATE"
4525
+ 3.times do
4526
+ @ds.for_update.sql.must_equal "SELECT * FROM t FOR UPDATE"
4527
+ end
4587
4528
  end
4588
4529
 
4589
4530
  it "#lock_style should accept symbols" do
@@ -4605,10 +4546,14 @@ describe "Dataset#skip_locked" do
4605
4546
  end
4606
4547
 
4607
4548
  it "should skipped locked rows if supported" do
4608
- def @ds.supports_skip_locked?; true end
4609
- def @ds.select_lock_sql(sql) super; sql << " SKIP LOCKED" if @opts[:skip_locked] end
4549
+ @ds = @ds.with_extend do
4550
+ def supports_skip_locked?; true end
4551
+ def select_lock_sql(sql) super; sql << " SKIP LOCKED" if @opts[:skip_locked] end
4552
+ end
4610
4553
  @ds.sql.must_equal "SELECT * FROM t FOR UPDATE"
4611
- @ds.skip_locked.sql.must_equal "SELECT * FROM t FOR UPDATE SKIP LOCKED"
4554
+ 3.times do
4555
+ @ds.skip_locked.sql.must_equal "SELECT * FROM t FOR UPDATE SKIP LOCKED"
4556
+ end
4612
4557
  end
4613
4558
  end
4614
4559
 
@@ -4631,10 +4576,11 @@ describe "Dataset#returning" do
4631
4576
  @db.extend_datasets{def supports_returning?(type) true end}
4632
4577
  @ds = @db[:t].returning(:foo)
4633
4578
  @pr = proc do
4634
- sc = class << @ds; self; end
4635
- Sequel::Dataset.def_sql_method(sc, :delete, %w'delete from where returning')
4636
- Sequel::Dataset.def_sql_method(sc, :insert, %w'insert into columns values returning')
4637
- Sequel::Dataset.def_sql_method(sc, :update, %w'update table set where returning')
4579
+ @ds = @ds.with_extend do
4580
+ Sequel::Dataset.def_sql_method(self, :delete, %w'delete from where returning')
4581
+ Sequel::Dataset.def_sql_method(self, :insert, %w'insert into columns values returning')
4582
+ Sequel::Dataset.def_sql_method(self, :update, %w'update table set where returning')
4583
+ end
4638
4584
  end
4639
4585
  end
4640
4586
 
@@ -4677,9 +4623,10 @@ end
4677
4623
 
4678
4624
  describe "Dataset emulating bitwise operator support" do
4679
4625
  before do
4680
- @ds = Sequel::Database.new.dataset.with_quote_identifiers(true)
4681
- def @ds.complex_expression_sql_append(sql, op, args)
4682
- complex_expression_arg_pairs_append(sql, args){|a, b| Sequel.function(:bitand, a, b)}
4626
+ @ds = Sequel.mock.dataset.with_quote_identifiers(true).with_extend do
4627
+ def complex_expression_sql_append(sql, op, args)
4628
+ complex_expression_arg_pairs_append(sql, args){|a, b| Sequel.function(:bitand, a, b)}
4629
+ end
4683
4630
  end
4684
4631
  end
4685
4632
 
@@ -4717,7 +4664,7 @@ describe "Dataset extensions" do
4717
4664
  end
4718
4665
  end
4719
4666
  before do
4720
- @ds = Sequel.mock.dataset
4667
+ @ds = Sequel.mock(:identifier_mangling=>false).dataset
4721
4668
  end
4722
4669
 
4723
4670
  it "should be able to register an extension with a module Database#extension extend the module" do
@@ -4726,24 +4673,19 @@ describe "Dataset extensions" do
4726
4673
  end
4727
4674
 
4728
4675
  it "should be able to register an extension with a block and Database#extension call the block" do
4729
- @ds = @ds.with_quote_identifiers(false)
4730
- Sequel::Dataset.register_extension(:foo){|db| db.quote_identifiers = true}
4731
- @ds.extension(:foo).quote_identifiers?.must_equal true
4676
+ Sequel::Dataset.register_extension(:foo){|ds| ds.extend(Module.new{def a; 1; end})}
4677
+ @ds.extension(:foo).a.must_equal 1
4732
4678
  end
4733
4679
 
4734
4680
  it "should be able to register an extension with a callable and Database#extension call the callable" do
4735
- @ds = @ds.with_quote_identifiers(false)
4736
- Sequel::Dataset.register_extension(:foo, proc{|db| db.quote_identifiers = true})
4737
- @ds.extension(:foo).quote_identifiers?.must_equal true
4681
+ Sequel::Dataset.register_extension(:foo, proc{|ds| ds.extend(Module.new{def a; 1; end})})
4682
+ @ds.extension(:foo).a.must_equal 1
4738
4683
  end
4739
4684
 
4740
4685
  it "should be able to load multiple extensions in the same call" do
4741
- @ds = @ds.with_quote_identifiers(false).with_identifier_input_method(:downcase)
4742
- Sequel::Dataset.register_extension(:foo, proc{|ds| ds.quote_identifiers = true})
4743
- Sequel::Dataset.register_extension(:bar, proc{|ds| ds.identifier_input_method = nil})
4744
- ds = @ds.extension(:foo, :bar)
4745
- ds.quote_identifiers?.must_equal true
4746
- ds.identifier_input_method.must_equal nil
4686
+ Sequel::Dataset.register_extension(:foo, proc{|ds| ds.send(:cache_set, :_columns, ds.columns + [:a])})
4687
+ Sequel::Dataset.register_extension(:bar, proc{|ds| ds.send(:cache_set, :_columns, ds.columns + [:b])})
4688
+ @ds.extension(:foo, :bar).columns.must_equal [:a, :b]
4747
4689
  end
4748
4690
 
4749
4691
  it "should have #extension not modify the receiver" do
@@ -4753,7 +4695,7 @@ describe "Dataset extensions" do
4753
4695
  end
4754
4696
 
4755
4697
  it "should have #extension not return a cloned dataset" do
4756
- @ds.extend(Module.new{def b; 2; end})
4698
+ @ds = @ds.with_extend(Module.new{def b; 2; end})
4757
4699
  Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
4758
4700
  v = @ds.extension(:foo)
4759
4701
  v.must_equal(@ds)
@@ -4761,20 +4703,9 @@ describe "Dataset extensions" do
4761
4703
  v.b.must_equal 2
4762
4704
  end
4763
4705
 
4764
- it "should have #extension! modify the receiver" do
4765
- Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
4766
- @ds.extension!(:foo)
4767
- @ds.a.must_equal 1
4768
- end
4769
-
4770
- it "should have #extension! return the receiver" do
4771
- Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
4772
- @ds.extension!(:foo).must_be_same_as(@ds)
4773
- end
4774
-
4775
4706
  it "should register a Database extension for modifying all datasets when registering with a module" do
4776
4707
  Sequel::Dataset.register_extension(:foo, Module.new{def a; 1; end})
4777
- Sequel.mock.extension(:foo).dataset.a.must_equal 1
4708
+ Sequel.mock(:identifier_mangling=>false).extension(:foo).dataset.a.must_equal 1
4778
4709
  end
4779
4710
 
4780
4711
  it "should raise an Error if registering with both a module and a block" do
@@ -4852,9 +4783,8 @@ end
4852
4783
 
4853
4784
  describe "Dataset#paged_each" do
4854
4785
  before do
4855
- @ds = Sequel.mock[:test].order(:x)
4856
4786
  @db = (0...10).map{|i| {:x=>i}}
4857
- @ds._fetch = @db
4787
+ @ds = Sequel.mock[:test].order(:x).with_fetch(@db)
4858
4788
  @rows = []
4859
4789
  @proc = lambda{|row| @rows << row}
4860
4790
  end
@@ -4870,7 +4800,7 @@ describe "Dataset#paged_each" do
4870
4800
  end
4871
4801
 
4872
4802
  it "should respect the row_proc" do
4873
- @ds.row_proc = lambda{|row| {:x=>row[:x]*2}}
4803
+ @ds = @ds.with_row_proc(lambda{|row| {:x=>row[:x]*2}})
4874
4804
  @ds.paged_each(&@proc)
4875
4805
  @rows.must_equal @db.map{|row| {:x=>row[:x]*2}}
4876
4806
  end
@@ -4888,7 +4818,7 @@ describe "Dataset#paged_each" do
4888
4818
  end
4889
4819
 
4890
4820
  it "should accept a :rows_per_fetch option to change the number of rows per fetch" do
4891
- @ds._fetch = @db.each_slice(3).to_a
4821
+ @ds = @ds.with_fetch(@db.each_slice(3).to_a)
4892
4822
  @ds.paged_each(:rows_per_fetch=>3, &@proc)
4893
4823
  @rows.must_equal @db
4894
4824
  @ds.db.sqls[1...-1].must_equal ['SELECT * FROM test ORDER BY x LIMIT 3 OFFSET 0',
@@ -4898,7 +4828,7 @@ describe "Dataset#paged_each" do
4898
4828
  end
4899
4829
 
4900
4830
  it "should handle cases where the last query returns nothing" do
4901
- @ds._fetch = @db.each_slice(5).to_a
4831
+ @ds = @ds.with_fetch(@db.each_slice(5).to_a)
4902
4832
  @ds.paged_each(:rows_per_fetch=>5, &@proc)
4903
4833
  @rows.must_equal @db
4904
4834
  @ds.db.sqls[1...-1].must_equal ['SELECT * FROM test ORDER BY x LIMIT 5 OFFSET 0',
@@ -4908,7 +4838,7 @@ describe "Dataset#paged_each" do
4908
4838
 
4909
4839
  it "should respect an existing server option to use" do
4910
4840
  @ds = Sequel.mock(:servers=>{:foo=>{}})[:test].order(:x)
4911
- @ds._fetch = @db
4841
+ @ds = @ds.with_fetch(@db)
4912
4842
  @ds.server(:foo).paged_each(&@proc)
4913
4843
  @rows.must_equal @db
4914
4844
  @ds.db.sqls.must_equal ["BEGIN -- foo", "SELECT * FROM test ORDER BY x LIMIT 1000 OFFSET 0 -- foo", "COMMIT -- foo"]
@@ -4919,28 +4849,28 @@ describe "Dataset#paged_each" do
4919
4849
  end
4920
4850
 
4921
4851
  it "should handle an existing limit and/or offset" do
4922
- @ds._fetch = @db.each_slice(3).to_a
4852
+ @ds = @ds.with_fetch(@db.each_slice(3).to_a)
4923
4853
  @ds.limit(5).paged_each(:rows_per_fetch=>3, &@proc)
4924
4854
  @ds.db.sqls[1...-1].must_equal ["SELECT * FROM test ORDER BY x LIMIT 3 OFFSET 0", "SELECT * FROM test ORDER BY x LIMIT 2 OFFSET 3"]
4925
4855
 
4926
- @ds._fetch = @db.each_slice(3).to_a
4856
+ @ds = @ds.with_fetch(@db.each_slice(3).to_a)
4927
4857
  @ds.limit(5, 2).paged_each(:rows_per_fetch=>3, &@proc)
4928
4858
  @ds.db.sqls[1...-1].must_equal ["SELECT * FROM test ORDER BY x LIMIT 3 OFFSET 2", "SELECT * FROM test ORDER BY x LIMIT 2 OFFSET 5"]
4929
4859
 
4930
- @ds._fetch = @db.each_slice(3).to_a
4860
+ @ds = @ds.with_fetch(@db.each_slice(3).to_a)
4931
4861
  @ds.limit(nil, 2).paged_each(:rows_per_fetch=>3, &@proc)
4932
4862
  @ds.db.sqls[1...-1].must_equal ["SELECT * FROM test ORDER BY x LIMIT 3 OFFSET 2", "SELECT * FROM test ORDER BY x LIMIT 3 OFFSET 5", "SELECT * FROM test ORDER BY x LIMIT 3 OFFSET 8", "SELECT * FROM test ORDER BY x LIMIT 3 OFFSET 11"]
4933
4863
  end
4934
4864
 
4935
4865
  it "should support :strategy=>:filter" do
4936
- @ds._fetch = @db.each_slice(5).to_a
4866
+ @ds = @ds.with_fetch(@db.each_slice(5).to_a)
4937
4867
  @ds.paged_each(:rows_per_fetch=>5, :strategy=>:filter, &@proc)
4938
4868
  @ds.db.sqls[1...-1].must_equal ["SELECT * FROM test ORDER BY x LIMIT 5", "SELECT * FROM test WHERE (x > 4) ORDER BY x LIMIT 5", "SELECT * FROM test WHERE (x > 9) ORDER BY x LIMIT 5"]
4939
4869
  @rows.must_equal @db
4940
4870
 
4941
4871
  @rows = []
4942
4872
  db = @db.map{|h| h[:y] = h[:x] % 5; h[:z] = h[:x] % 9; h}.sort_by{|h| [h[:z], -h[:y], h[:x]]}
4943
- @ds._fetch = db.each_slice(5).to_a
4873
+ @ds = @ds.with_fetch(db.each_slice(5).to_a)
4944
4874
  @ds.order(Sequel.identifier(:z), Sequel.desc(Sequel.qualify(:test, :y)), Sequel.asc(:x)).paged_each(:rows_per_fetch=>5, :strategy=>:filter, &@proc)
4945
4875
  @ds.db.sqls[1...-1].must_equal ["SELECT * FROM test ORDER BY z, test.y DESC, x ASC LIMIT 5",
4946
4876
  "SELECT * FROM test WHERE ((z > 3) OR ((z = 3) AND (test.y < 3)) OR ((z = 3) AND (test.y = 3) AND (x > 3))) ORDER BY z, test.y DESC, x ASC LIMIT 5",
@@ -4950,7 +4880,7 @@ describe "Dataset#paged_each" do
4950
4880
 
4951
4881
  it "should support :strategy=>:filter with :filter_values option" do
4952
4882
  db = @db.map{|h| h[:y] = h[:x] % 5; h[:z] = h[:x] % 9; h}.sort_by{|h| [h[:z], -h[:y], h[:x]]}
4953
- @ds._fetch = db.each_slice(5).to_a
4883
+ @ds = @ds.with_fetch(db.each_slice(5).to_a)
4954
4884
  @ds.order(Sequel.identifier(:z), Sequel.desc(Sequel.qualify(:test, :y) * 2), Sequel.asc(:x)).paged_each(:rows_per_fetch=>5, :strategy=>:filter, :filter_values=>proc{|row, expr| [row[expr[0].value], row[expr[1].args.first.column] * expr[1].args.last, row[expr[2]]]}, &@proc)
4955
4885
  @ds.db.sqls[1...-1].must_equal ["SELECT * FROM test ORDER BY z, (test.y * 2) DESC, x ASC LIMIT 5",
4956
4886
  "SELECT * FROM test WHERE ((z > 3) OR ((z = 3) AND ((test.y * 2) < 6)) OR ((z = 3) AND ((test.y * 2) = 6) AND (x > 3))) ORDER BY z, (test.y * 2) DESC, x ASC LIMIT 5",
@@ -5024,102 +4954,21 @@ describe "Frozen Datasets" do
5024
4954
  @ds.must_equal @ds.db[:test]
5025
4955
  end
5026
4956
 
5027
- it "should have dups not be frozen" do
5028
- @ds.dup.wont_be :frozen?
5029
- end
5030
-
5031
- it "should raise an error when calling mutation methods" do
5032
- proc{@ds.select!(:a)}.must_raise RuntimeError
5033
- proc{@ds.identifier_input_method = :a}.must_raise RuntimeError
5034
- proc{@ds.identifier_output_method = :a}.must_raise RuntimeError
5035
- proc{@ds.quote_identifiers = false}.must_raise RuntimeError
5036
- proc{@ds.row_proc = proc{}}.must_raise RuntimeError
5037
- proc{@ds.extension! :query}.must_raise RuntimeError
5038
- proc{@ds.naked!}.must_raise RuntimeError
5039
- proc{@ds.from_self!}.must_raise RuntimeError
5040
- end
5041
-
5042
4957
  it "should not raise an error when calling query methods" do
5043
4958
  @ds.select(:a).sql.must_equal 'SELECT a FROM test'
5044
4959
  end
5045
4960
  end
5046
4961
 
5047
- describe "Dataset mutation methods" do
5048
- def m(&block)
5049
- ds = Sequel.mock[:t]
5050
- def ds.supports_cte?(*) true end
5051
- ds.instance_exec(&block)
5052
- ds.sql
5053
- end
5054
-
5055
- it "should modify the dataset in place" do
5056
- dsc = Sequel.mock[:u]
5057
- dsc.instance_variable_set(:@columns, [:v])
5058
-
5059
- m{and!(:a=>1).or!(:b=>2)}.must_equal "SELECT * FROM t WHERE ((a = 1) OR (b = 2))"
5060
- m{select!(:f).graph!(dsc, :b=>:c).set_graph_aliases!(:e=>[:m, :n]).add_graph_aliases!(:d=>[:g, :c])}.must_equal "SELECT m.n AS e, g.c AS d FROM t LEFT OUTER JOIN u ON (u.b = t.c)"
5061
- m{cross_join!(:a)}.must_equal "SELECT * FROM t CROSS JOIN a"
5062
- m{distinct!}.must_equal "SELECT DISTINCT * FROM t"
5063
- m{except!(dsc)}.must_equal "SELECT * FROM (SELECT * FROM t EXCEPT SELECT * FROM u) AS t1"
5064
- m{exclude!(:a=>1)}.must_equal "SELECT * FROM t WHERE (a != 1)"
5065
- m{exclude_having!(:a=>1)}.must_equal "SELECT * FROM t HAVING (a != 1)"
5066
- m{exclude_where!(:a=>1)}.must_equal "SELECT * FROM t WHERE (a != 1)"
5067
- m{filter!(:a=>1)}.must_equal "SELECT * FROM t WHERE (a = 1)"
5068
- m{for_update!}.must_equal "SELECT * FROM t FOR UPDATE"
5069
- m{from!(:p)}.must_equal "SELECT * FROM p"
5070
- m{full_join!(:a, [:b])}.must_equal "SELECT * FROM t FULL JOIN a USING (b)"
5071
- m{full_outer_join!(:a, [:b])}.must_equal "SELECT * FROM t FULL OUTER JOIN a USING (b)"
5072
- m{grep!(:a, 'b')}.must_equal "SELECT * FROM t WHERE ((a LIKE 'b' ESCAPE '\\'))"
5073
- m{group!(:a)}.must_equal "SELECT * FROM t GROUP BY a"
5074
- m{group_and_count!(:a)}.must_equal "SELECT a, count(*) AS count FROM t GROUP BY a"
5075
- m{group_by!(:a)}.must_equal "SELECT * FROM t GROUP BY a"
5076
- m{having!(:a)}.must_equal "SELECT * FROM t HAVING a"
5077
- m{inner_join!(:a, [:b])}.must_equal "SELECT * FROM t INNER JOIN a USING (b)"
5078
- m{intersect!(dsc)}.must_equal "SELECT * FROM (SELECT * FROM t INTERSECT SELECT * FROM u) AS t1"
5079
- m{where!(:a).invert!}.must_equal "SELECT * FROM t WHERE NOT a"
5080
- m{join!(:a, [:b])}.must_equal "SELECT * FROM t INNER JOIN a USING (b)"
5081
- m{join_table!(:inner, :a, [:b])}.must_equal "SELECT * FROM t INNER JOIN a USING (b)"
5082
- m{left_join!(:a, [:b])}.must_equal "SELECT * FROM t LEFT JOIN a USING (b)"
5083
- m{left_outer_join!(:a, [:b])}.must_equal "SELECT * FROM t LEFT OUTER JOIN a USING (b)"
5084
- m{limit!(1)}.must_equal "SELECT * FROM t LIMIT 1"
5085
- m{lock_style!(:update)}.must_equal "SELECT * FROM t FOR UPDATE"
5086
- m{natural_full_join!(:a)}.must_equal "SELECT * FROM t NATURAL FULL JOIN a"
5087
- m{natural_join!(:a)}.must_equal "SELECT * FROM t NATURAL JOIN a"
5088
- m{natural_left_join!(:a)}.must_equal "SELECT * FROM t NATURAL LEFT JOIN a"
5089
- m{natural_right_join!(:a)}.must_equal "SELECT * FROM t NATURAL RIGHT JOIN a"
5090
- m{offset!(1)}.must_equal "SELECT * FROM t OFFSET 1"
5091
- m{order!(:a).reverse_order!}.must_equal "SELECT * FROM t ORDER BY a DESC"
5092
- m{order_by!(:a).order_more!(:b).order_append!(:c).order_prepend!(:d).reverse!}.must_equal "SELECT * FROM t ORDER BY d DESC, a DESC, b DESC, c DESC"
5093
- m{qualify!}.must_equal "SELECT t.* FROM t"
5094
- m{right_join!(:a, [:b])}.must_equal "SELECT * FROM t RIGHT JOIN a USING (b)"
5095
- m{right_outer_join!(:a, [:b])}.must_equal "SELECT * FROM t RIGHT OUTER JOIN a USING (b)"
5096
- m{select!(:a)}.must_equal "SELECT a FROM t"
5097
- m{select_all!(:t).select_more!(:b).select_append!(:c)}.must_equal "SELECT t.*, b, c FROM t"
5098
- m{select_group!(:a)}.must_equal "SELECT a FROM t GROUP BY a"
5099
- m{where!(:a).unfiltered!}.must_equal "SELECT * FROM t"
5100
- m{group!(:a).ungrouped!}.must_equal "SELECT * FROM t"
5101
- m{limit!(1).unlimited!}.must_equal "SELECT * FROM t"
5102
- m{order!(:a).unordered!}.must_equal "SELECT * FROM t"
5103
- m{union!(dsc)}.must_equal "SELECT * FROM (SELECT * FROM t UNION SELECT * FROM u) AS t1"
5104
- m{with!(:a, dsc)}.must_equal "WITH a AS (SELECT * FROM u) SELECT * FROM t"
5105
- m{with_recursive!(:a, dsc, dsc)}.must_equal "WITH a AS (SELECT * FROM u UNION ALL SELECT * FROM u) SELECT * FROM t"
5106
- m{with_sql!('SELECT foo')}.must_equal "SELECT foo"
5107
-
5108
- dsc.server!(:a)
5109
- dsc.opts[:server].must_equal :a
5110
- dsc.graph!(dsc, {:b=>:c}, :table_alias=>:foo).ungraphed!.opts[:graph].must_equal nil
5111
- end
5112
- end
5113
-
5114
4962
  describe "Dataset emulated complex expression operators" do
5115
4963
  before do
5116
- @ds = Sequel.mock[:test]
5117
- def @ds.complex_expression_sql_append(sql, op, args)
5118
- case op
5119
- when :&, :|, :^, :%, :<<, :>>, :'B~'
5120
- complex_expression_emulate_append(sql, op, args)
5121
- else
5122
- super
4964
+ @ds = Sequel.mock[:test].with_extend do
4965
+ def complex_expression_sql_append(sql, op, args)
4966
+ case op
4967
+ when :&, :|, :^, :%, :<<, :>>, :'B~'
4968
+ complex_expression_emulate_append(sql, op, args)
4969
+ else
4970
+ super
4971
+ end
5123
4972
  end
5124
4973
  end
5125
4974
  @n = Sequel.expr(:x).sql_number
@@ -5212,12 +5061,20 @@ describe "#unqualified_column_for" do
5212
5061
  end
5213
5062
 
5214
5063
  it "should return nil for other objects" do
5215
- @ds.unqualified_column_for(Object.new).must_equal nil
5216
- @ds.unqualified_column_for('a').must_equal nil
5064
+ @ds.unqualified_column_for(Object.new).must_be_nil
5065
+ @ds.unqualified_column_for('a').must_be_nil
5217
5066
  end
5218
5067
 
5219
5068
  it "should return nil for other objects inside SQL::AliasedExpressions" do
5220
- @ds.unqualified_column_for(Sequel.as(Object.new, 'a')).must_equal nil
5221
- @ds.unqualified_column_for(Sequel.as('a', 'b')).must_equal nil
5069
+ @ds.unqualified_column_for(Sequel.as(Object.new, 'a')).must_be_nil
5070
+ @ds.unqualified_column_for(Sequel.as('a', 'b')).must_be_nil
5071
+ end
5072
+ end
5073
+
5074
+ describe "Dataset#output_identifier" do
5075
+ it "should handle empty identifiers and uppercase identifiers" do
5076
+ meth = Sequel::Database.new(:identifier_mangling=>false).dataset.method(:output_identifier)
5077
+ meth.call('').must_equal :untitled
5078
+ meth.call('A').must_equal :a
5222
5079
  end
5223
5080
  end