sequel 4.41.0 → 4.42.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG +98 -0
- data/README.rdoc +23 -10
- data/doc/active_record.rdoc +4 -4
- data/doc/advanced_associations.rdoc +2 -2
- data/doc/association_basics.rdoc +5 -2
- data/doc/cheat_sheet.rdoc +3 -3
- data/doc/core_extensions.rdoc +2 -2
- data/doc/dataset_basics.rdoc +4 -4
- data/doc/dataset_filtering.rdoc +1 -1
- data/doc/migration.rdoc +19 -1
- data/doc/prepared_statements.rdoc +2 -2
- data/doc/release_notes/4.42.0.txt +221 -0
- data/doc/testing.rdoc +3 -1
- data/lib/sequel/adapters/ado/access.rb +0 -1
- data/lib/sequel/adapters/ado/mssql.rb +0 -1
- data/lib/sequel/adapters/do/mysql.rb +0 -1
- data/lib/sequel/adapters/do/postgres.rb +0 -1
- data/lib/sequel/adapters/do/sqlite3.rb +0 -1
- data/lib/sequel/adapters/ibmdb.rb +21 -25
- data/lib/sequel/adapters/jdbc.rb +8 -16
- data/lib/sequel/adapters/jdbc/as400.rb +0 -1
- data/lib/sequel/adapters/jdbc/cubrid.rb +0 -1
- data/lib/sequel/adapters/jdbc/db2.rb +0 -1
- data/lib/sequel/adapters/jdbc/derby.rb +0 -1
- data/lib/sequel/adapters/jdbc/firebirdsql.rb +0 -1
- data/lib/sequel/adapters/jdbc/h2.rb +0 -1
- data/lib/sequel/adapters/jdbc/hsqldb.rb +0 -1
- data/lib/sequel/adapters/jdbc/informix-sqli.rb +0 -1
- data/lib/sequel/adapters/jdbc/jdbcprogress.rb +0 -1
- data/lib/sequel/adapters/jdbc/jtds.rb +0 -1
- data/lib/sequel/adapters/jdbc/mssql.rb +0 -1
- data/lib/sequel/adapters/jdbc/mysql.rb +0 -1
- data/lib/sequel/adapters/jdbc/oracle.rb +0 -1
- data/lib/sequel/adapters/jdbc/postgresql.rb +0 -13
- data/lib/sequel/adapters/jdbc/sqlanywhere.rb +0 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +0 -1
- data/lib/sequel/adapters/jdbc/sqlserver.rb +3 -4
- data/lib/sequel/adapters/mock.rb +54 -12
- data/lib/sequel/adapters/mysql.rb +1 -1
- data/lib/sequel/adapters/mysql2.rb +11 -17
- data/lib/sequel/adapters/odbc/mssql.rb +0 -1
- data/lib/sequel/adapters/oracle.rb +8 -20
- data/lib/sequel/adapters/postgres.rb +11 -29
- data/lib/sequel/adapters/shared/access.rb +5 -12
- data/lib/sequel/adapters/shared/cubrid.rb +4 -13
- data/lib/sequel/adapters/shared/db2.rb +4 -2
- data/lib/sequel/adapters/shared/firebird.rb +2 -4
- data/lib/sequel/adapters/shared/informix.rb +4 -2
- data/lib/sequel/adapters/shared/mssql.rb +3 -5
- data/lib/sequel/adapters/shared/mysql.rb +4 -14
- data/lib/sequel/adapters/shared/oracle.rb +1 -3
- data/lib/sequel/adapters/shared/postgres.rb +16 -38
- data/lib/sequel/adapters/shared/progress.rb +0 -2
- data/lib/sequel/adapters/shared/sqlanywhere.rb +0 -2
- data/lib/sequel/adapters/shared/sqlite.rb +20 -16
- data/lib/sequel/adapters/sqlite.rb +8 -20
- data/lib/sequel/adapters/swift/mysql.rb +0 -1
- data/lib/sequel/adapters/swift/postgres.rb +0 -1
- data/lib/sequel/adapters/swift/sqlite.rb +0 -1
- data/lib/sequel/adapters/tinytds.rb +4 -12
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +1 -1
- data/lib/sequel/adapters/utils/mysql_mysql2.rb +2 -2
- data/lib/sequel/adapters/utils/mysql_prepared_statements.rb +11 -34
- data/lib/sequel/adapters/utils/stored_procedures.rb +9 -22
- data/lib/sequel/adapters/utils/unmodified_identifiers.rb +26 -0
- data/lib/sequel/ast_transformer.rb +2 -2
- data/lib/sequel/database/dataset.rb +1 -1
- data/lib/sequel/database/dataset_defaults.rb +0 -66
- data/lib/sequel/database/features.rb +6 -0
- data/lib/sequel/database/misc.rb +31 -17
- data/lib/sequel/database/query.rb +7 -4
- data/lib/sequel/database/schema_methods.rb +1 -1
- data/lib/sequel/dataset.rb +8 -8
- data/lib/sequel/dataset/actions.rb +140 -46
- data/lib/sequel/dataset/features.rb +1 -5
- data/lib/sequel/dataset/graph.rb +7 -8
- data/lib/sequel/dataset/misc.rb +127 -56
- data/lib/sequel/dataset/mutation.rb +9 -20
- data/lib/sequel/dataset/placeholder_literalizer.rb +10 -1
- data/lib/sequel/dataset/prepared_statements.rb +102 -46
- data/lib/sequel/dataset/query.rb +155 -72
- data/lib/sequel/dataset/sql.rb +26 -9
- data/lib/sequel/extensions/columns_introspection.rb +3 -1
- data/lib/sequel/extensions/core_extensions.rb +5 -5
- data/lib/sequel/extensions/core_refinements.rb +5 -5
- data/lib/sequel/extensions/duplicate_columns_handler.rb +4 -2
- data/lib/sequel/extensions/freeze_datasets.rb +69 -0
- data/lib/sequel/extensions/identifier_mangling.rb +196 -0
- data/lib/sequel/extensions/looser_typecasting.rb +11 -7
- data/lib/sequel/extensions/migration.rb +1 -1
- data/lib/sequel/extensions/null_dataset.rb +5 -2
- data/lib/sequel/extensions/pagination.rb +42 -23
- data/lib/sequel/extensions/pg_enum.rb +3 -3
- data/lib/sequel/extensions/query.rb +3 -3
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +15 -8
- data/lib/sequel/model/associations.rb +25 -8
- data/lib/sequel/model/base.rb +88 -29
- data/lib/sequel/model/dataset_module.rb +37 -0
- data/lib/sequel/plugins/association_pks.rb +4 -4
- data/lib/sequel/plugins/class_table_inheritance.rb +2 -2
- data/lib/sequel/plugins/constraint_validations.rb +1 -2
- data/lib/sequel/plugins/csv_serializer.rb +2 -2
- data/lib/sequel/plugins/dataset_associations.rb +8 -8
- data/lib/sequel/plugins/eager_each.rb +2 -2
- data/lib/sequel/plugins/instance_filters.rb +1 -1
- data/lib/sequel/plugins/json_serializer.rb +2 -2
- data/lib/sequel/plugins/lazy_attributes.rb +1 -1
- data/lib/sequel/plugins/list.rb +4 -4
- data/lib/sequel/plugins/prepared_statements.rb +2 -4
- data/lib/sequel/plugins/prepared_statements_associations.rb +1 -3
- data/lib/sequel/plugins/prepared_statements_with_pk.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +13 -13
- data/lib/sequel/plugins/sharding.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +9 -4
- data/lib/sequel/plugins/tactical_eager_loading.rb +4 -4
- data/lib/sequel/plugins/validation_class_methods.rb +1 -1
- data/lib/sequel/plugins/validation_helpers.rb +1 -1
- data/lib/sequel/plugins/xml_serializer.rb +2 -2
- data/lib/sequel/sql.rb +69 -36
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/db2_spec.rb +10 -0
- data/spec/adapters/firebird_spec.rb +1 -1
- data/spec/adapters/mssql_spec.rb +4 -5
- data/spec/adapters/mysql_spec.rb +9 -9
- data/spec/adapters/postgres_spec.rb +67 -68
- data/spec/adapters/spec_helper.rb +6 -1
- data/spec/adapters/sqlite_spec.rb +29 -15
- data/spec/core/connection_pool_spec.rb +14 -14
- data/spec/core/database_spec.rb +38 -180
- data/spec/core/dataset_mutation_spec.rb +253 -0
- data/spec/core/dataset_spec.rb +394 -537
- data/spec/core/expression_filters_spec.rb +34 -32
- data/spec/core/mock_adapter_spec.rb +27 -35
- data/spec/core/placeholder_literalizer_spec.rb +2 -4
- data/spec/core/schema_generator_spec.rb +4 -4
- data/spec/core/schema_spec.rb +1 -2
- data/spec/core_extensions_spec.rb +22 -29
- data/spec/extensions/active_model_spec.rb +6 -6
- data/spec/extensions/association_dependencies_spec.rb +2 -2
- data/spec/extensions/blacklist_security_spec.rb +3 -3
- data/spec/extensions/boolean_readers_spec.rb +12 -12
- data/spec/extensions/caching_spec.rb +13 -10
- data/spec/extensions/class_table_inheritance_spec.rb +38 -43
- data/spec/extensions/column_conflicts_spec.rb +1 -3
- data/spec/extensions/columns_introspection_spec.rb +2 -3
- data/spec/extensions/composition_spec.rb +5 -3
- data/spec/extensions/constraint_validations_plugin_spec.rb +5 -5
- data/spec/extensions/constraint_validations_spec.rb +14 -8
- data/spec/extensions/core_refinements_spec.rb +22 -29
- data/spec/extensions/csv_serializer_spec.rb +7 -6
- data/spec/extensions/date_arithmetic_spec.rb +15 -15
- data/spec/extensions/defaults_setter_spec.rb +2 -2
- data/spec/extensions/delay_add_association_spec.rb +1 -1
- data/spec/extensions/dirty_spec.rb +19 -10
- data/spec/extensions/duplicate_columns_handler_spec.rb +12 -18
- data/spec/extensions/eager_each_spec.rb +12 -16
- data/spec/extensions/empty_array_consider_nulls_spec.rb +1 -1
- data/spec/extensions/eval_inspect_spec.rb +4 -3
- data/spec/extensions/force_encoding_spec.rb +12 -12
- data/spec/extensions/freeze_datasets_spec.rb +31 -0
- data/spec/extensions/graph_each_spec.rb +6 -18
- data/spec/extensions/hook_class_methods_spec.rb +7 -7
- data/spec/extensions/identifier_mangling_spec.rb +307 -0
- data/spec/extensions/instance_filters_spec.rb +5 -6
- data/spec/extensions/instance_hooks_spec.rb +12 -12
- data/spec/extensions/json_serializer_spec.rb +12 -15
- data/spec/extensions/lazy_attributes_spec.rb +4 -4
- data/spec/extensions/list_spec.rb +19 -21
- data/spec/extensions/many_through_many_spec.rb +108 -163
- data/spec/extensions/meta_def_spec.rb +7 -2
- data/spec/extensions/migration_spec.rb +10 -12
- data/spec/extensions/mssql_optimistic_locking_spec.rb +4 -3
- data/spec/extensions/named_timezones_spec.rb +4 -3
- data/spec/extensions/nested_attributes_spec.rb +2 -2
- data/spec/extensions/null_dataset_spec.rb +17 -12
- data/spec/extensions/optimistic_locking_spec.rb +4 -5
- data/spec/extensions/pagination_spec.rb +8 -10
- data/spec/extensions/pg_array_associations_spec.rb +28 -27
- data/spec/extensions/pg_array_ops_spec.rb +2 -1
- data/spec/extensions/pg_array_spec.rb +6 -2
- data/spec/extensions/pg_enum_spec.rb +5 -3
- data/spec/extensions/pg_hstore_ops_spec.rb +3 -1
- data/spec/extensions/pg_hstore_spec.rb +7 -6
- data/spec/extensions/pg_inet_ops_spec.rb +2 -1
- data/spec/extensions/pg_inet_spec.rb +2 -1
- data/spec/extensions/pg_interval_spec.rb +2 -1
- data/spec/extensions/pg_json_ops_spec.rb +2 -1
- data/spec/extensions/pg_json_spec.rb +6 -3
- data/spec/extensions/pg_loose_count_spec.rb +1 -0
- data/spec/extensions/pg_range_ops_spec.rb +3 -1
- data/spec/extensions/pg_range_spec.rb +9 -5
- data/spec/extensions/pg_row_ops_spec.rb +2 -1
- data/spec/extensions/pg_row_plugin_spec.rb +4 -6
- data/spec/extensions/pg_row_spec.rb +5 -3
- data/spec/extensions/pg_static_cache_updater_spec.rb +2 -1
- data/spec/extensions/pg_typecast_on_load_spec.rb +1 -1
- data/spec/extensions/prepared_statements_associations_spec.rb +1 -1
- data/spec/extensions/prepared_statements_spec.rb +12 -11
- data/spec/extensions/pretty_table_spec.rb +1 -1
- data/spec/extensions/query_spec.rb +8 -5
- data/spec/extensions/rcte_tree_spec.rb +39 -39
- data/spec/extensions/round_timestamps_spec.rb +2 -2
- data/spec/extensions/schema_dumper_spec.rb +3 -2
- data/spec/extensions/schema_spec.rb +2 -2
- data/spec/extensions/scissors_spec.rb +1 -2
- data/spec/extensions/sequel_3_dataset_methods_spec.rb +30 -17
- data/spec/extensions/serialization_modification_detection_spec.rb +2 -2
- data/spec/extensions/serialization_spec.rb +15 -13
- data/spec/extensions/set_overrides_spec.rb +14 -8
- data/spec/extensions/sharding_spec.rb +9 -18
- data/spec/extensions/shared_caching_spec.rb +3 -4
- data/spec/extensions/single_table_inheritance_spec.rb +11 -11
- data/spec/extensions/skip_create_refresh_spec.rb +2 -1
- data/spec/extensions/spec_helper.rb +1 -1
- data/spec/extensions/split_values_spec.rb +2 -2
- data/spec/extensions/sql_comments_spec.rb +6 -0
- data/spec/extensions/static_cache_spec.rb +7 -9
- data/spec/extensions/string_agg_spec.rb +30 -29
- data/spec/extensions/tactical_eager_loading_spec.rb +4 -5
- data/spec/extensions/thread_local_timezones_spec.rb +2 -2
- data/spec/extensions/timestamps_spec.rb +28 -3
- data/spec/extensions/to_dot_spec.rb +1 -2
- data/spec/extensions/tree_spec.rb +33 -29
- data/spec/extensions/typecast_on_load_spec.rb +1 -1
- data/spec/extensions/unlimited_update_spec.rb +1 -0
- data/spec/extensions/update_primary_key_spec.rb +11 -7
- data/spec/extensions/update_refresh_spec.rb +1 -1
- data/spec/extensions/uuid_spec.rb +0 -1
- data/spec/extensions/validate_associated_spec.rb +1 -1
- data/spec/extensions/validation_class_methods_spec.rb +10 -10
- data/spec/extensions/validation_helpers_spec.rb +10 -10
- data/spec/extensions/xml_serializer_spec.rb +7 -3
- data/spec/integration/associations_test.rb +31 -31
- data/spec/integration/dataset_test.rb +17 -19
- data/spec/integration/eager_loader_test.rb +24 -24
- data/spec/integration/model_test.rb +6 -6
- data/spec/integration/plugin_test.rb +43 -43
- data/spec/integration/prepared_statement_test.rb +6 -6
- data/spec/integration/schema_test.rb +63 -52
- data/spec/integration/spec_helper.rb +6 -1
- data/spec/integration/transaction_test.rb +13 -13
- data/spec/model/association_reflection_spec.rb +17 -17
- data/spec/model/associations_spec.rb +101 -96
- data/spec/model/base_spec.rb +175 -49
- data/spec/model/class_dataset_methods_spec.rb +5 -9
- data/spec/model/dataset_methods_spec.rb +5 -5
- data/spec/model/eager_loading_spec.rb +209 -235
- data/spec/model/hooks_spec.rb +15 -15
- data/spec/model/model_spec.rb +28 -21
- data/spec/model/plugins_spec.rb +4 -5
- data/spec/model/record_spec.rb +59 -57
- data/spec/model/spec_helper.rb +1 -1
- data/spec/model/validations_spec.rb +6 -6
- data/spec/spec_config.rb +1 -1
- 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
|
data/spec/core/dataset_spec.rb
CHANGED
|
@@ -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].
|
|
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].
|
|
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
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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
|
|
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 @
|
|
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 @
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1196
|
-
|
|
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
|
|
1242
|
-
@d.select
|
|
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
|
|
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
|
-
|
|
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)
|
|
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)
|
|
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)
|
|
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)
|
|
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.
|
|
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#
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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.
|
|
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)
|
|
1583
|
-
@dataset.order(Sequel.desc(:clumsy), :fool)
|
|
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.
|
|
1509
|
+
@dataset.unordered.reverse.sql.must_equal 'SELECT * FROM test'
|
|
1588
1510
|
end
|
|
1589
1511
|
|
|
1590
|
-
it "should have #
|
|
1591
|
-
@dataset.order(:name).
|
|
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.
|
|
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;
|
|
1702
|
-
m2 = Module.new{def
|
|
1703
|
-
d.with_extend(m1, m2).
|
|
1704
|
-
d.respond_to?(:
|
|
1705
|
-
ds = d.freeze.with_extend(m1, m2)
|
|
1706
|
-
ds.
|
|
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
|
-
|
|
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
|
|
1727
|
-
d.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
|
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
|
|
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 =
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
1953
|
-
|
|
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
|
-
|
|
1958
|
-
|
|
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
|
-
|
|
1963
|
-
|
|
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
|
-
|
|
1968
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
2165
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
2379
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
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
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
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
|
-
|
|
2511
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2528
|
-
|
|
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
|
-
|
|
2540
|
-
|
|
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)
|
|
2548
|
-
|
|
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
|
-
|
|
2553
|
-
|
|
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).
|
|
2564
|
-
|
|
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).
|
|
2569
|
-
|
|
2570
|
-
|
|
2571
|
-
|
|
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
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
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.
|
|
2583
|
-
|
|
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.
|
|
2588
|
-
|
|
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
|
-
|
|
2593
|
-
|
|
2594
|
-
|
|
2595
|
-
|
|
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.
|
|
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 ((
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
2755
|
-
|
|
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.
|
|
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!.
|
|
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.
|
|
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!.
|
|
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.
|
|
2859
|
-
|
|
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.
|
|
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
|
|
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
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
2920
|
-
@d.get(:n).
|
|
2921
|
-
@d.get([:n, :a]).
|
|
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.
|
|
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'], []).
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
3143
|
-
|
|
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([]).
|
|
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
|
|
3418
|
-
InspectDataset.new(Sequel.mock).from(:blah).inspect.must_equal '#<InspectDataset: "SELECT * FROM
|
|
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
|
|
3423
|
-
Class.new(InspectDataset).new(Sequel.mock).from(:blah).inspect.must_equal '#<InspectDataset: "SELECT * FROM
|
|
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
|
-
|
|
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.
|
|
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').
|
|
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').
|
|
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).
|
|
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
|
-
|
|
3685
|
-
|
|
3686
|
-
|
|
3687
|
-
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
-
|
|
3775
|
-
|
|
3776
|
-
|
|
3777
|
-
|
|
3778
|
-
|
|
3779
|
-
|
|
3780
|
-
|
|
3781
|
-
|
|
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.
|
|
3791
|
-
p.
|
|
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.
|
|
3813
|
-
ps.
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
4082
|
-
|
|
4083
|
-
|
|
4084
|
-
|
|
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
|
-
|
|
4092
|
-
|
|
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
|
-
|
|
4148
|
-
|
|
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.
|
|
4284
|
-
Sequel.application_timezone.
|
|
4285
|
-
Sequel.typecast_timezone.
|
|
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
|
-
|
|
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
|
-
|
|
4609
|
-
|
|
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
|
-
|
|
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
|
-
|
|
4635
|
-
|
|
4636
|
-
|
|
4637
|
-
|
|
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
|
|
4681
|
-
|
|
4682
|
-
|
|
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
|
-
|
|
4730
|
-
|
|
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
|
-
|
|
4736
|
-
|
|
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
|
-
|
|
4742
|
-
Sequel::Dataset.register_extension(:
|
|
4743
|
-
|
|
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.
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
5118
|
-
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
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).
|
|
5216
|
-
@ds.unqualified_column_for('a').
|
|
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')).
|
|
5221
|
-
@ds.unqualified_column_for(Sequel.as('a', 'b')).
|
|
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
|