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
data/lib/sequel/dataset/query.rb
CHANGED
|
@@ -18,7 +18,7 @@ module Sequel
|
|
|
18
18
|
|
|
19
19
|
# Which options don't affect the SQL generation. Used by simple_select_all?
|
|
20
20
|
# to determine if this is a simple SELECT * FROM table.
|
|
21
|
-
NON_SQL_OPTIONS = [:server, :graph, :eager, :eager_graph, :graph_aliases].freeze
|
|
21
|
+
NON_SQL_OPTIONS = [:server, :graph, :eager, :eager_graph, :graph_aliases, :row_proc, :quote_identifiers, :identifier_input_method, :identifier_output_method, :skip_symbol_cache, :model, :model_object, :association_reflection, :fetch, :numrows, :autoid].freeze
|
|
22
22
|
|
|
23
23
|
# These symbols have _join methods created (e.g. inner_join) that
|
|
24
24
|
# call join_table with the symbol, passing along the arguments and
|
|
@@ -69,19 +69,44 @@ module Sequel
|
|
|
69
69
|
where(*cond, &block)
|
|
70
70
|
end
|
|
71
71
|
|
|
72
|
-
#
|
|
73
|
-
#
|
|
74
|
-
#
|
|
75
|
-
#
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
72
|
+
# On Ruby 2.4+, use clone(:freeze=>false) to create clones, because
|
|
73
|
+
# we use true freezing in that case, and we need to modify the opts
|
|
74
|
+
# in the frozen copy.
|
|
75
|
+
#
|
|
76
|
+
# On Ruby <2.4, just use Object#clone directly, since we don't
|
|
77
|
+
# use true freezing as it isn't possible.
|
|
78
|
+
if TRUE_FREEZE
|
|
79
|
+
# Save original clone implementation, as some other methods need
|
|
80
|
+
# to call it internally.
|
|
81
|
+
alias _clone clone
|
|
82
|
+
private :_clone
|
|
83
|
+
|
|
84
|
+
# Returns a new clone of the dataset with the given options merged.
|
|
85
|
+
# If the options changed include options in COLUMN_CHANGE_OPTS, the cached
|
|
86
|
+
# columns are deleted. This method should generally not be called
|
|
87
|
+
# directly by user code.
|
|
88
|
+
def clone(opts = OPTS)
|
|
89
|
+
c = super(:freeze=>false)
|
|
90
|
+
c.opts.merge!(opts)
|
|
91
|
+
unless opts.each_key{|o| break if COLUMN_CHANGE_OPTS.include?(o)}
|
|
92
|
+
c.clear_columns_cache
|
|
93
|
+
end
|
|
94
|
+
c.freeze if frozen?
|
|
95
|
+
c
|
|
83
96
|
end
|
|
84
|
-
|
|
97
|
+
else
|
|
98
|
+
# :nocov:
|
|
99
|
+
# :nodoc:
|
|
100
|
+
def clone(opts = OPTS)
|
|
101
|
+
c = super()
|
|
102
|
+
c.opts.merge!(opts)
|
|
103
|
+
unless opts.each_key{|o| break if COLUMN_CHANGE_OPTS.include?(o)}
|
|
104
|
+
c.clear_columns_cache
|
|
105
|
+
end
|
|
106
|
+
c.freeze if frozen?
|
|
107
|
+
c
|
|
108
|
+
end
|
|
109
|
+
# :nocov:
|
|
85
110
|
end
|
|
86
111
|
|
|
87
112
|
# Returns a copy of the dataset with the SQL DISTINCT clause. The DISTINCT
|
|
@@ -97,7 +122,7 @@ module Sequel
|
|
|
97
122
|
def distinct(*args, &block)
|
|
98
123
|
virtual_row_columns(args, block)
|
|
99
124
|
raise(InvalidOperation, "DISTINCT ON not supported") if !args.empty? && !supports_distinct_on?
|
|
100
|
-
clone(:distinct => args)
|
|
125
|
+
clone(:distinct => args.freeze)
|
|
101
126
|
end
|
|
102
127
|
|
|
103
128
|
# Adds an EXCEPT clause using a second dataset object.
|
|
@@ -131,6 +156,22 @@ module Sequel
|
|
|
131
156
|
#
|
|
132
157
|
# DB[:items].exclude(:category => 'software', :id=>3)
|
|
133
158
|
# # SELECT * FROM items WHERE ((category != 'software') OR (id != 3))
|
|
159
|
+
#
|
|
160
|
+
# Also note that SQL uses 3-valued boolean logic (+true+, +false+, +NULL+), so
|
|
161
|
+
# the inverse of a true condition is a false condition, and will still
|
|
162
|
+
# not match rows that were NULL originally. If you take the earlier
|
|
163
|
+
# example:
|
|
164
|
+
#
|
|
165
|
+
# DB[:items].exclude(:category => 'software')
|
|
166
|
+
# # SELECT * FROM items WHERE (category != 'software')
|
|
167
|
+
#
|
|
168
|
+
# Note that this does not match rows where +category+ is +NULL+. This
|
|
169
|
+
# is because +NULL+ is an unknown value, and you do not know whether
|
|
170
|
+
# or not the +NULL+ category is +software+. You can explicitly
|
|
171
|
+
# specify how to handle +NULL+ values if you want:
|
|
172
|
+
#
|
|
173
|
+
# DB[:items].exclude(Sequel.~(:category=>nil) & {:category => 'software'})
|
|
174
|
+
# # SELECT * FROM items WHERE ((category IS NULL) OR (category != 'software'))
|
|
134
175
|
def exclude(*cond, &block)
|
|
135
176
|
_filter_or_exclude(true, :where, *cond, &block)
|
|
136
177
|
end
|
|
@@ -139,6 +180,9 @@ module Sequel
|
|
|
139
180
|
#
|
|
140
181
|
# DB[:items].select_group(:name).exclude_having{count(name) < 2}
|
|
141
182
|
# # SELECT name FROM items GROUP BY name HAVING (count(name) >= 2)
|
|
183
|
+
#
|
|
184
|
+
# See documentation for exclude for how inversion is handled in regards
|
|
185
|
+
# to SQL 3-valued boolean logic.
|
|
142
186
|
def exclude_having(*cond, &block)
|
|
143
187
|
_filter_or_exclude(true, :having, *cond, &block)
|
|
144
188
|
end
|
|
@@ -148,13 +192,25 @@ module Sequel
|
|
|
148
192
|
exclude(*cond, &block)
|
|
149
193
|
end
|
|
150
194
|
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
195
|
+
if TRUE_FREEZE
|
|
196
|
+
# Return a clone of the dataset loaded with the given dataset extensions.
|
|
197
|
+
# If no related extension file exists or the extension does not have
|
|
198
|
+
# specific support for Dataset objects, an Error will be raised.
|
|
199
|
+
def extension(*a)
|
|
200
|
+
c = _clone(:freeze=>false)
|
|
201
|
+
c.send(:_extension!, a)
|
|
202
|
+
c.freeze if frozen?
|
|
203
|
+
c
|
|
204
|
+
end
|
|
205
|
+
else
|
|
206
|
+
# :nocov:
|
|
207
|
+
# :nodoc:
|
|
208
|
+
def extension(*exts)
|
|
209
|
+
c = clone
|
|
210
|
+
c.send(:_extension!, exts)
|
|
211
|
+
c
|
|
212
|
+
end
|
|
213
|
+
# :nocov:
|
|
158
214
|
end
|
|
159
215
|
|
|
160
216
|
# Alias for where.
|
|
@@ -166,7 +222,7 @@ module Sequel
|
|
|
166
222
|
#
|
|
167
223
|
# DB[:table].for_update # SELECT * FROM table FOR UPDATE
|
|
168
224
|
def for_update
|
|
169
|
-
lock_style(:update)
|
|
225
|
+
cached_dataset(:_for_update_ds){lock_style(:update)}
|
|
170
226
|
end
|
|
171
227
|
|
|
172
228
|
# Returns a copy of the dataset with the source changed. If no
|
|
@@ -203,8 +259,8 @@ module Sequel
|
|
|
203
259
|
s
|
|
204
260
|
end
|
|
205
261
|
end
|
|
206
|
-
o = {:from=>source.empty? ? nil : source}
|
|
207
|
-
o[:with] = (opts[:with] || []) + ctes if ctes
|
|
262
|
+
o = {:from=>source.empty? ? nil : source.freeze}
|
|
263
|
+
o[:with] = ((opts[:with] || []) + ctes).freeze if ctes
|
|
208
264
|
o[:num_dataset_sources] = table_alias_num if table_alias_num > 0
|
|
209
265
|
clone(o)
|
|
210
266
|
end
|
|
@@ -288,7 +344,7 @@ module Sequel
|
|
|
288
344
|
# DB[:items].group{[a, sum(b)]} # SELECT * FROM items GROUP BY a, sum(b)
|
|
289
345
|
def group(*columns, &block)
|
|
290
346
|
virtual_row_columns(columns, block)
|
|
291
|
-
clone(:group => (columns.compact.empty? ? nil : columns))
|
|
347
|
+
clone(:group => (columns.compact.empty? ? nil : columns.freeze))
|
|
292
348
|
end
|
|
293
349
|
|
|
294
350
|
# Alias of group
|
|
@@ -318,7 +374,7 @@ module Sequel
|
|
|
318
374
|
# # SELECT substr(first_name, 1, 1) AS initial, count(*) AS count FROM items GROUP BY substr(first_name, 1, 1)
|
|
319
375
|
# # => [{:initial=>'a', :count=>1}, ...]
|
|
320
376
|
def group_and_count(*columns, &block)
|
|
321
|
-
select_group(*columns, &block).
|
|
377
|
+
select_group(*columns, &block).select_append(COUNT_OF_ALL_AS_COUNT)
|
|
322
378
|
end
|
|
323
379
|
|
|
324
380
|
# Returns a copy of the dataset with the given columns added to the list of
|
|
@@ -389,15 +445,20 @@ module Sequel
|
|
|
389
445
|
#
|
|
390
446
|
# DB[:items].where(:category => 'software', :id=>3).invert
|
|
391
447
|
# # SELECT * FROM items WHERE ((category != 'software') OR (id != 3))
|
|
448
|
+
#
|
|
449
|
+
# See documentation for exclude for how inversion is handled in regards
|
|
450
|
+
# to SQL 3-valued boolean logic.
|
|
392
451
|
def invert
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
where
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
452
|
+
cached_dataset(:_invert_ds) do
|
|
453
|
+
having, where = @opts.values_at(:having, :where)
|
|
454
|
+
if having.nil? && where.nil?
|
|
455
|
+
where(false)
|
|
456
|
+
else
|
|
457
|
+
o = {}
|
|
458
|
+
o[:having] = SQL::BooleanExpression.invert(having) if having
|
|
459
|
+
o[:where] = SQL::BooleanExpression.invert(where) if where
|
|
460
|
+
clone(o)
|
|
461
|
+
end
|
|
401
462
|
end
|
|
402
463
|
end
|
|
403
464
|
|
|
@@ -535,7 +596,7 @@ module Sequel
|
|
|
535
596
|
SQL::JoinOnClause.new(expr, type, table_expr)
|
|
536
597
|
end
|
|
537
598
|
|
|
538
|
-
opts = {:join => (@opts[:join] || []) + [join]}
|
|
599
|
+
opts = {:join => ((@opts[:join] || []) + [join]).freeze}
|
|
539
600
|
opts[:last_joined_table] = table_name unless options[:reset_implicit_qualifier] == false
|
|
540
601
|
opts[:num_dataset_sources] = table_alias_num if table_alias_num
|
|
541
602
|
clone(opts)
|
|
@@ -615,7 +676,7 @@ module Sequel
|
|
|
615
676
|
# ds.all # => [{2=>:id}]
|
|
616
677
|
# ds.naked.all # => [{:id=>2}]
|
|
617
678
|
def naked
|
|
618
|
-
with_row_proc(nil)
|
|
679
|
+
cached_dataset(:_naked_ds){with_row_proc(nil)}
|
|
619
680
|
end
|
|
620
681
|
|
|
621
682
|
# Returns a copy of the dataset with a specified order. Can be safely combined with limit.
|
|
@@ -661,12 +722,17 @@ module Sequel
|
|
|
661
722
|
# DB[:items].order(nil) # SELECT * FROM items
|
|
662
723
|
def order(*columns, &block)
|
|
663
724
|
virtual_row_columns(columns, block)
|
|
664
|
-
clone(:order => (columns.compact.empty?) ? nil : columns)
|
|
725
|
+
clone(:order => (columns.compact.empty?) ? nil : columns.freeze)
|
|
665
726
|
end
|
|
666
727
|
|
|
667
|
-
#
|
|
728
|
+
# Returns a copy of the dataset with the order columns added
|
|
729
|
+
# to the end of the existing order.
|
|
730
|
+
#
|
|
731
|
+
# DB[:items].order(:a).order(:b) # SELECT * FROM items ORDER BY b
|
|
732
|
+
# DB[:items].order(:a).order_append(:b) # SELECT * FROM items ORDER BY a, b
|
|
668
733
|
def order_append(*columns, &block)
|
|
669
|
-
|
|
734
|
+
columns = @opts[:order] + columns if @opts[:order]
|
|
735
|
+
order(*columns, &block)
|
|
670
736
|
end
|
|
671
737
|
|
|
672
738
|
# Alias of order
|
|
@@ -674,14 +740,9 @@ module Sequel
|
|
|
674
740
|
order(*columns, &block)
|
|
675
741
|
end
|
|
676
742
|
|
|
677
|
-
#
|
|
678
|
-
# to the end of the existing order.
|
|
679
|
-
#
|
|
680
|
-
# DB[:items].order(:a).order(:b) # SELECT * FROM items ORDER BY b
|
|
681
|
-
# DB[:items].order(:a).order_more(:b) # SELECT * FROM items ORDER BY a, b
|
|
743
|
+
# Alias of order_append.
|
|
682
744
|
def order_more(*columns, &block)
|
|
683
|
-
columns
|
|
684
|
-
order(*columns, &block)
|
|
745
|
+
order_append(*columns, &block)
|
|
685
746
|
end
|
|
686
747
|
|
|
687
748
|
# Returns a copy of the dataset with the order columns added
|
|
@@ -691,7 +752,7 @@ module Sequel
|
|
|
691
752
|
# DB[:items].order(:a).order_prepend(:b) # SELECT * FROM items ORDER BY b, a
|
|
692
753
|
def order_prepend(*columns, &block)
|
|
693
754
|
ds = order(*columns, &block)
|
|
694
|
-
@opts[:order] ? ds.
|
|
755
|
+
@opts[:order] ? ds.order_append(*@opts[:order]) : ds
|
|
695
756
|
end
|
|
696
757
|
|
|
697
758
|
# Qualify to the given table, or first source if no table is given.
|
|
@@ -708,7 +769,7 @@ module Sequel
|
|
|
708
769
|
(o.keys & QUALIFY_KEYS).each do |k|
|
|
709
770
|
h[k] = qualified_expression(o[k], table)
|
|
710
771
|
end
|
|
711
|
-
h[:select] = [SQL::ColumnAll.new(table)] if !o[:select] || o[:select].empty?
|
|
772
|
+
h[:select] = [SQL::ColumnAll.new(table)].freeze if !o[:select] || o[:select].empty?
|
|
712
773
|
clone(h)
|
|
713
774
|
end
|
|
714
775
|
|
|
@@ -722,7 +783,7 @@ module Sequel
|
|
|
722
783
|
# DB[:items].returning(:id, :name) # RETURNING id, name
|
|
723
784
|
def returning(*values)
|
|
724
785
|
raise Error, "RETURNING is not supported on #{db.database_type}" unless supports_returning?(:insert)
|
|
725
|
-
clone(:returning=>values)
|
|
786
|
+
clone(:returning=>values.freeze)
|
|
726
787
|
end
|
|
727
788
|
|
|
728
789
|
# Returns a copy of the dataset with the order reversed. If no order is
|
|
@@ -733,8 +794,12 @@ module Sequel
|
|
|
733
794
|
# DB[:items].order(:id).reverse # SELECT * FROM items ORDER BY id DESC
|
|
734
795
|
# DB[:items].order(:id).reverse(Sequel.desc(:name)) # SELECT * FROM items ORDER BY name ASC
|
|
735
796
|
def reverse(*order, &block)
|
|
736
|
-
|
|
737
|
-
|
|
797
|
+
if order.empty? && !block
|
|
798
|
+
cached_dataset(:_reverse_ds){order(*invert_order(@opts[:order]))}
|
|
799
|
+
else
|
|
800
|
+
virtual_row_columns(order, block)
|
|
801
|
+
order(*invert_order(order.empty? ? @opts[:order] : order.freeze))
|
|
802
|
+
end
|
|
738
803
|
end
|
|
739
804
|
|
|
740
805
|
# Alias of +reverse+
|
|
@@ -751,7 +816,7 @@ module Sequel
|
|
|
751
816
|
# DB[:items].select{[a, sum(b)]} # SELECT a, sum(b) FROM items
|
|
752
817
|
def select(*columns, &block)
|
|
753
818
|
virtual_row_columns(columns, block)
|
|
754
|
-
clone(:select => columns)
|
|
819
|
+
clone(:select => columns.freeze)
|
|
755
820
|
end
|
|
756
821
|
|
|
757
822
|
# Returns a copy of the dataset selecting the wildcard if no arguments
|
|
@@ -765,7 +830,7 @@ module Sequel
|
|
|
765
830
|
if tables.empty?
|
|
766
831
|
clone(:select => nil)
|
|
767
832
|
else
|
|
768
|
-
select(*tables.map{|t| i, a = split_alias(t); a || i}.map{|t| SQL::ColumnAll.new(t)})
|
|
833
|
+
select(*tables.map{|t| i, a = split_alias(t); a || i}.map!{|t| SQL::ColumnAll.new(t)}.freeze)
|
|
769
834
|
end
|
|
770
835
|
end
|
|
771
836
|
|
|
@@ -780,7 +845,7 @@ module Sequel
|
|
|
780
845
|
cur_sel = @opts[:select]
|
|
781
846
|
if !cur_sel || cur_sel.empty?
|
|
782
847
|
unless supports_select_all_and_column?
|
|
783
|
-
return select_all(*(Array(@opts[:from]) + Array(@opts[:join]))).
|
|
848
|
+
return select_all(*(Array(@opts[:from]) + Array(@opts[:join]))).select_append(*columns, &block)
|
|
784
849
|
end
|
|
785
850
|
cur_sel = [WILDCARD]
|
|
786
851
|
end
|
|
@@ -832,8 +897,10 @@ module Sequel
|
|
|
832
897
|
|
|
833
898
|
# Skip locked rows when returning results from this dataset.
|
|
834
899
|
def skip_locked
|
|
835
|
-
|
|
836
|
-
|
|
900
|
+
cached_dataset(:_skip_locked_ds) do
|
|
901
|
+
raise(Error, 'This dataset does not support skipping locked rows') unless supports_skip_locked?
|
|
902
|
+
clone(:skip_locked=>true)
|
|
903
|
+
end
|
|
837
904
|
end
|
|
838
905
|
|
|
839
906
|
# Unbind bound variables from this dataset's filter and return an array of two
|
|
@@ -857,7 +924,7 @@ module Sequel
|
|
|
857
924
|
# DB[:items].group(:a).having(:a=>1).where(:b).unfiltered
|
|
858
925
|
# # SELECT * FROM items GROUP BY a
|
|
859
926
|
def unfiltered
|
|
860
|
-
clone(:where => nil, :having => nil)
|
|
927
|
+
cached_dataset(:_unfiltered_ds){clone(:where => nil, :having => nil)}
|
|
861
928
|
end
|
|
862
929
|
|
|
863
930
|
# Returns a copy of the dataset with no grouping (GROUP or HAVING clause) applied.
|
|
@@ -865,7 +932,7 @@ module Sequel
|
|
|
865
932
|
# DB[:items].group(:a).having(:a=>1).where(:b).ungrouped
|
|
866
933
|
# # SELECT * FROM items WHERE b
|
|
867
934
|
def ungrouped
|
|
868
|
-
clone(:group => nil, :having => nil)
|
|
935
|
+
cached_dataset(:_ungrouped_ds){clone(:group => nil, :having => nil)}
|
|
869
936
|
end
|
|
870
937
|
|
|
871
938
|
# Adds a UNION clause using a second dataset object.
|
|
@@ -892,14 +959,14 @@ module Sequel
|
|
|
892
959
|
#
|
|
893
960
|
# DB[:items].limit(10, 20).unlimited # SELECT * FROM items
|
|
894
961
|
def unlimited
|
|
895
|
-
clone(:limit=>nil, :offset=>nil)
|
|
962
|
+
cached_dataset(:_unlimited_ds){clone(:limit=>nil, :offset=>nil)}
|
|
896
963
|
end
|
|
897
964
|
|
|
898
965
|
# Returns a copy of the dataset with no order.
|
|
899
966
|
#
|
|
900
967
|
# DB[:items].order(:a).unordered # SELECT * FROM items
|
|
901
968
|
def unordered
|
|
902
|
-
order
|
|
969
|
+
cached_dataset(:_unordered_ds){clone(:order=>nil)}
|
|
903
970
|
end
|
|
904
971
|
|
|
905
972
|
# Returns a copy of the dataset with the given WHERE conditions imposed upon it.
|
|
@@ -970,7 +1037,7 @@ module Sequel
|
|
|
970
1037
|
s, ds = hoist_cte(dataset)
|
|
971
1038
|
s.with(name, ds, opts)
|
|
972
1039
|
else
|
|
973
|
-
clone(:with=>(@opts[:with]||[]) + [Hash[opts].merge!(:name=>name, :dataset=>dataset)])
|
|
1040
|
+
clone(:with=>((@opts[:with]||[]) + [Hash[opts].merge!(:name=>name, :dataset=>dataset)]).freeze)
|
|
974
1041
|
end
|
|
975
1042
|
end
|
|
976
1043
|
|
|
@@ -999,15 +1066,33 @@ module Sequel
|
|
|
999
1066
|
s, ds = hoist_cte(recursive)
|
|
1000
1067
|
s.with_recursive(name, nonrecursive, ds, opts)
|
|
1001
1068
|
else
|
|
1002
|
-
clone(:with=>(@opts[:with]||[]) + [Hash[opts].merge!(:recursive=>true, :name=>name, :dataset=>nonrecursive.union(recursive, {:all=>opts[:union_all] != false, :from_self=>false}))])
|
|
1069
|
+
clone(:with=>((@opts[:with]||[]) + [Hash[opts].merge!(:recursive=>true, :name=>name, :dataset=>nonrecursive.union(recursive, {:all=>opts[:union_all] != false, :from_self=>false}))]).freeze)
|
|
1003
1070
|
end
|
|
1004
1071
|
end
|
|
1005
1072
|
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1073
|
+
if TRUE_FREEZE
|
|
1074
|
+
# Return a clone of the dataset extended with the given modules.
|
|
1075
|
+
# Note that like Object#extend, when multiple modules are provided
|
|
1076
|
+
# as arguments the cloned dataset is extended with the modules in reverse
|
|
1077
|
+
# order. If a block is provided, a module is created using the block and
|
|
1078
|
+
# the clone is extended with that module after any modules given as arguments.
|
|
1079
|
+
def with_extend(*mods, &block)
|
|
1080
|
+
c = _clone(:freeze=>false)
|
|
1081
|
+
c.extend(*mods) unless mods.empty?
|
|
1082
|
+
c.extend(Module.new(&block)) if block
|
|
1083
|
+
c.freeze if frozen?
|
|
1084
|
+
c
|
|
1085
|
+
end
|
|
1086
|
+
else
|
|
1087
|
+
# :nocov:
|
|
1088
|
+
# :nodoc:
|
|
1089
|
+
def with_extend(*mods, &block)
|
|
1090
|
+
c = clone
|
|
1091
|
+
c.extend(*mods) unless mods.empty?
|
|
1092
|
+
c.extend(Module.new(&block)) if block
|
|
1093
|
+
c
|
|
1094
|
+
end
|
|
1095
|
+
# :nocov:
|
|
1011
1096
|
end
|
|
1012
1097
|
|
|
1013
1098
|
# Returns a cloned dataset with the given row_proc.
|
|
@@ -1016,9 +1101,7 @@ module Sequel
|
|
|
1016
1101
|
# ds.all # => [{:id=>2}]
|
|
1017
1102
|
# ds.with_row_proc(proc(&:invert)).all # => [{2=>:id}]
|
|
1018
1103
|
def with_row_proc(callable)
|
|
1019
|
-
|
|
1020
|
-
c.instance_variable_set(:@row_proc, callable)
|
|
1021
|
-
c
|
|
1104
|
+
clone(:row_proc=>callable)
|
|
1022
1105
|
end
|
|
1023
1106
|
|
|
1024
1107
|
# Returns a copy of the dataset with the static SQL used. This is useful if you want
|
|
@@ -1050,7 +1133,7 @@ module Sequel
|
|
|
1050
1133
|
s, ds = hoist_cte(dataset)
|
|
1051
1134
|
return s.compound_clone(type, ds, opts)
|
|
1052
1135
|
end
|
|
1053
|
-
ds = compound_from_self.clone(:compounds=>Array(@opts[:compounds]).map(&:dup) + [[type, dataset.compound_from_self, opts[:all]]])
|
|
1136
|
+
ds = compound_from_self.clone(:compounds=>(Array(@opts[:compounds]).map(&:dup) + [[type, dataset.compound_from_self, opts[:all]].freeze]).freeze)
|
|
1054
1137
|
opts[:from_self] == false ? ds : ds.from_self(opts)
|
|
1055
1138
|
end
|
|
1056
1139
|
|
|
@@ -1152,7 +1235,7 @@ module Sequel
|
|
|
1152
1235
|
# clause from the given dataset added to it, and the second a clone of
|
|
1153
1236
|
# the given dataset with the WITH clause removed.
|
|
1154
1237
|
def hoist_cte(ds)
|
|
1155
|
-
[clone(:with => (opts[:with] || []) + ds.opts[:with]), ds.clone(:with => nil)]
|
|
1238
|
+
[clone(:with => ((opts[:with] || []) + ds.opts[:with]).freeze), ds.clone(:with => nil)]
|
|
1156
1239
|
end
|
|
1157
1240
|
|
|
1158
1241
|
# Whether CTEs need to be hoisted from the given ds into the current ds.
|
data/lib/sequel/dataset/sql.rb
CHANGED
|
@@ -198,11 +198,13 @@ module Sequel
|
|
|
198
198
|
# being an array of symbol/strings for the appropriate branch.
|
|
199
199
|
def self.def_sql_method(mod, type, clauses)
|
|
200
200
|
priv = type == :update || type == :insert
|
|
201
|
+
cacheable = type == :select || type == :delete
|
|
201
202
|
|
|
202
203
|
lines = []
|
|
203
204
|
lines << 'private' if priv
|
|
204
205
|
lines << "def #{'_' if priv}#{type}_sql"
|
|
205
206
|
lines << 'if sql = opts[:sql]; return static_sql(sql) end' unless priv
|
|
207
|
+
lines << "if sql = cache_get(:_#{type}_sql); return sql end" if cacheable
|
|
206
208
|
lines << 'check_modification_allowed!' if type == :delete
|
|
207
209
|
lines << 'sql = @opts[:append_sql] || sql_string_origin'
|
|
208
210
|
|
|
@@ -216,6 +218,7 @@ module Sequel
|
|
|
216
218
|
lines.concat(clause_methods(type, clauses).map{|x| "#{x}(sql)"})
|
|
217
219
|
end
|
|
218
220
|
|
|
221
|
+
lines << "cache_set(:_#{type}_sql, sql) if cache_sql?" if cacheable
|
|
219
222
|
lines << 'sql'
|
|
220
223
|
lines << 'end'
|
|
221
224
|
|
|
@@ -522,6 +525,11 @@ module Sequel
|
|
|
522
525
|
# Append literalization of delayed evaluation to SQL string,
|
|
523
526
|
# causing the delayed evaluation proc to be evaluated.
|
|
524
527
|
def delayed_evaluation_sql_append(sql, delay)
|
|
528
|
+
# Delayed evaluations are used specifically so the SQL
|
|
529
|
+
# can differ in subsequent calls, so we definitely don't
|
|
530
|
+
# want to cache the sql in this case.
|
|
531
|
+
disable_sql_caching!
|
|
532
|
+
|
|
525
533
|
if recorder = @opts[:placeholder_literalizer]
|
|
526
534
|
recorder.use(sql, lambda{delay.call(self)}, nil)
|
|
527
535
|
else
|
|
@@ -901,6 +909,12 @@ module Sequel
|
|
|
901
909
|
end
|
|
902
910
|
end
|
|
903
911
|
|
|
912
|
+
# Only allow caching the select SQL if the dataset is frozen and hasn't
|
|
913
|
+
# specifically been marked as not allowing SQL caching.
|
|
914
|
+
def cache_sql?
|
|
915
|
+
frozen? && !@opts[:no_cache_sql] && !cache_get(:_no_cache_sql)
|
|
916
|
+
end
|
|
917
|
+
|
|
904
918
|
# Raise an InvalidOperation exception if deletion is not allowed
|
|
905
919
|
# for this dataset
|
|
906
920
|
def check_modification_allowed!
|
|
@@ -993,6 +1007,11 @@ module Sequel
|
|
|
993
1007
|
end
|
|
994
1008
|
end
|
|
995
1009
|
|
|
1010
|
+
# Disable caching of SQL for the current dataset
|
|
1011
|
+
def disable_sql_caching!
|
|
1012
|
+
cache_set(:_no_cache_sql, true)
|
|
1013
|
+
end
|
|
1014
|
+
|
|
996
1015
|
# An SQL FROM clause to use in SELECT statements where the dataset has
|
|
997
1016
|
# no from tables.
|
|
998
1017
|
def empty_from_sql
|
|
@@ -1099,10 +1118,9 @@ module Sequel
|
|
|
1099
1118
|
end
|
|
1100
1119
|
end
|
|
1101
1120
|
|
|
1102
|
-
#
|
|
1103
|
-
# identifier_output_method.
|
|
1121
|
+
# Upcase identifiers by default when inputting them into the database.
|
|
1104
1122
|
def input_identifier(v)
|
|
1105
|
-
|
|
1123
|
+
v.to_s.upcase
|
|
1106
1124
|
end
|
|
1107
1125
|
|
|
1108
1126
|
def insert_into_sql(sql)
|
|
@@ -1250,6 +1268,10 @@ module Sequel
|
|
|
1250
1268
|
# calls +sql_literal+ if object responds to it, otherwise raises an error.
|
|
1251
1269
|
# If a database specific type is allowed, this should be overriden in a subclass.
|
|
1252
1270
|
def literal_other_append(sql, v)
|
|
1271
|
+
# We can't be sure if v will always literalize to the same SQL, so
|
|
1272
|
+
# don't cache SQL for a dataset that uses this.
|
|
1273
|
+
disable_sql_caching!
|
|
1274
|
+
|
|
1253
1275
|
if v.respond_to?(:sql_literal_append)
|
|
1254
1276
|
v.sql_literal_append(self, sql)
|
|
1255
1277
|
elsif v.respond_to?(:sql_literal)
|
|
@@ -1496,12 +1518,7 @@ module Sequel
|
|
|
1496
1518
|
|
|
1497
1519
|
# Whether the symbol cache should be skipped when literalizing the dataset
|
|
1498
1520
|
def skip_symbol_cache?
|
|
1499
|
-
@skip_symbol_cache
|
|
1500
|
-
end
|
|
1501
|
-
|
|
1502
|
-
# Set the dataset to skip the symbol cache
|
|
1503
|
-
def skip_symbol_cache!
|
|
1504
|
-
@skip_symbol_cache = true
|
|
1521
|
+
@opts[:skip_symbol_cache]
|
|
1505
1522
|
end
|
|
1506
1523
|
|
|
1507
1524
|
# Append literalization of array of sources/tables to SQL string, raising an Error if there
|