sequel 3.47.0 → 3.48.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 +230 -0
- data/README.rdoc +31 -40
- data/Rakefile +1 -14
- data/doc/active_record.rdoc +29 -29
- data/doc/association_basics.rdoc +4 -13
- data/doc/cheat_sheet.rdoc +8 -6
- data/doc/code_order.rdoc +89 -0
- data/doc/core_extensions.rdoc +3 -3
- data/doc/dataset_basics.rdoc +7 -8
- data/doc/dataset_filtering.rdoc +7 -2
- data/doc/mass_assignment.rdoc +2 -3
- data/doc/migration.rdoc +8 -8
- data/doc/model_hooks.rdoc +11 -7
- data/doc/object_model.rdoc +2 -2
- data/doc/opening_databases.rdoc +5 -14
- data/doc/prepared_statements.rdoc +5 -9
- data/doc/querying.rdoc +23 -28
- data/doc/reflection.rdoc +11 -0
- data/doc/release_notes/3.48.0.txt +477 -0
- data/doc/schema_modification.rdoc +12 -5
- data/doc/security.rdoc +2 -2
- data/doc/sharding.rdoc +1 -2
- data/doc/sql.rdoc +10 -13
- data/doc/testing.rdoc +8 -4
- data/doc/transactions.rdoc +2 -2
- data/doc/validations.rdoc +40 -17
- data/doc/virtual_rows.rdoc +2 -2
- data/lib/sequel/adapters/ado.rb +25 -20
- data/lib/sequel/adapters/ado/access.rb +1 -0
- data/lib/sequel/adapters/ado/mssql.rb +1 -0
- data/lib/sequel/adapters/db2.rb +9 -7
- data/lib/sequel/adapters/dbi.rb +16 -16
- data/lib/sequel/adapters/do.rb +17 -18
- data/lib/sequel/adapters/do/mysql.rb +1 -0
- data/lib/sequel/adapters/do/postgres.rb +2 -0
- data/lib/sequel/adapters/do/sqlite.rb +1 -0
- data/lib/sequel/adapters/firebird.rb +5 -7
- data/lib/sequel/adapters/ibmdb.rb +23 -20
- data/lib/sequel/adapters/informix.rb +8 -2
- data/lib/sequel/adapters/jdbc.rb +39 -35
- data/lib/sequel/adapters/jdbc/as400.rb +1 -0
- data/lib/sequel/adapters/jdbc/cubrid.rb +1 -0
- data/lib/sequel/adapters/jdbc/db2.rb +1 -0
- data/lib/sequel/adapters/jdbc/derby.rb +1 -0
- data/lib/sequel/adapters/jdbc/firebird.rb +1 -0
- data/lib/sequel/adapters/jdbc/h2.rb +1 -0
- data/lib/sequel/adapters/jdbc/hsqldb.rb +1 -0
- data/lib/sequel/adapters/jdbc/informix.rb +1 -0
- data/lib/sequel/adapters/jdbc/jtds.rb +1 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +1 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +1 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +1 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +2 -0
- data/lib/sequel/adapters/jdbc/progress.rb +1 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +1 -0
- data/lib/sequel/adapters/jdbc/sqlserver.rb +1 -0
- data/lib/sequel/adapters/mock.rb +30 -31
- data/lib/sequel/adapters/mysql.rb +6 -7
- data/lib/sequel/adapters/mysql2.rb +5 -6
- data/lib/sequel/adapters/odbc.rb +22 -20
- data/lib/sequel/adapters/odbc/mssql.rb +1 -0
- data/lib/sequel/adapters/openbase.rb +4 -1
- data/lib/sequel/adapters/oracle.rb +10 -8
- data/lib/sequel/adapters/postgres.rb +12 -10
- data/lib/sequel/adapters/shared/access.rb +6 -0
- data/lib/sequel/adapters/shared/cubrid.rb +2 -0
- data/lib/sequel/adapters/shared/db2.rb +2 -0
- data/lib/sequel/adapters/shared/firebird.rb +2 -0
- data/lib/sequel/adapters/shared/informix.rb +2 -0
- data/lib/sequel/adapters/shared/mssql.rb +14 -8
- data/lib/sequel/adapters/shared/mysql.rb +6 -0
- data/lib/sequel/adapters/shared/oracle.rb +2 -0
- data/lib/sequel/adapters/shared/postgres.rb +14 -4
- data/lib/sequel/adapters/shared/progress.rb +1 -0
- data/lib/sequel/adapters/shared/sqlite.rb +4 -3
- data/lib/sequel/adapters/sqlite.rb +6 -7
- data/lib/sequel/adapters/swift.rb +20 -21
- data/lib/sequel/adapters/swift/mysql.rb +1 -0
- data/lib/sequel/adapters/swift/postgres.rb +2 -0
- data/lib/sequel/adapters/swift/sqlite.rb +1 -0
- data/lib/sequel/adapters/tinytds.rb +5 -6
- data/lib/sequel/adapters/utils/emulate_offset_with_reverse_and_count.rb +68 -0
- data/lib/sequel/connection_pool.rb +1 -1
- data/lib/sequel/core.rb +57 -50
- data/lib/sequel/database/connecting.rb +9 -10
- data/lib/sequel/database/dataset.rb +11 -6
- data/lib/sequel/database/dataset_defaults.rb +61 -69
- data/lib/sequel/database/features.rb +21 -0
- data/lib/sequel/database/misc.rb +23 -3
- data/lib/sequel/database/query.rb +13 -7
- data/lib/sequel/database/schema_methods.rb +6 -6
- data/lib/sequel/database/transactions.rb +1 -0
- data/lib/sequel/dataset/actions.rb +51 -38
- data/lib/sequel/dataset/features.rb +1 -0
- data/lib/sequel/dataset/graph.rb +9 -33
- data/lib/sequel/dataset/misc.rb +30 -5
- data/lib/sequel/dataset/mutation.rb +2 -3
- data/lib/sequel/dataset/prepared_statements.rb +1 -1
- data/lib/sequel/dataset/query.rb +91 -27
- data/lib/sequel/dataset/sql.rb +40 -6
- data/lib/sequel/deprecated.rb +74 -0
- data/lib/sequel/deprecated_core_extensions.rb +135 -0
- data/lib/sequel/extensions/columns_introspection.rb +1 -5
- data/lib/sequel/extensions/core_extensions.rb +10 -3
- data/lib/sequel/extensions/date_arithmetic.rb +1 -0
- data/lib/sequel/extensions/empty_array_ignore_nulls.rb +33 -0
- data/lib/sequel/extensions/filter_having.rb +58 -0
- data/lib/sequel/extensions/graph_each.rb +63 -0
- data/lib/sequel/extensions/hash_aliases.rb +44 -0
- data/lib/sequel/extensions/looser_typecasting.rb +14 -3
- data/lib/sequel/extensions/migration.rb +2 -3
- data/lib/sequel/extensions/named_timezones.rb +14 -1
- data/lib/sequel/extensions/null_dataset.rb +7 -1
- data/lib/sequel/extensions/pagination.rb +15 -5
- data/lib/sequel/extensions/pg_auto_parameterize.rb +1 -0
- data/lib/sequel/extensions/pg_hstore_ops.rb +48 -14
- data/lib/sequel/extensions/pg_json.rb +7 -7
- data/lib/sequel/extensions/pg_range_ops.rb +8 -2
- data/lib/sequel/extensions/pg_statement_cache.rb +1 -0
- data/lib/sequel/extensions/pretty_table.rb +13 -4
- data/lib/sequel/extensions/query.rb +21 -4
- data/lib/sequel/extensions/ruby18_symbol_extensions.rb +22 -0
- data/lib/sequel/extensions/schema_caching.rb +10 -7
- data/lib/sequel/extensions/schema_dumper.rb +35 -48
- data/lib/sequel/extensions/select_remove.rb +13 -4
- data/lib/sequel/extensions/sequel_3_dataset_methods.rb +117 -0
- data/lib/sequel/extensions/set_overrides.rb +43 -0
- data/lib/sequel/extensions/to_dot.rb +6 -0
- data/lib/sequel/model.rb +12 -6
- data/lib/sequel/model/associations.rb +80 -38
- data/lib/sequel/model/base.rb +137 -52
- data/lib/sequel/model/errors.rb +7 -2
- data/lib/sequel/plugins/active_model.rb +13 -0
- data/lib/sequel/plugins/after_initialize.rb +43 -0
- data/lib/sequel/plugins/association_proxies.rb +63 -7
- data/lib/sequel/plugins/auto_validations.rb +56 -16
- data/lib/sequel/plugins/blacklist_security.rb +63 -0
- data/lib/sequel/plugins/class_table_inheritance.rb +9 -0
- data/lib/sequel/plugins/constraint_validations.rb +50 -8
- data/lib/sequel/plugins/dataset_associations.rb +2 -0
- data/lib/sequel/plugins/hook_class_methods.rb +7 -1
- data/lib/sequel/plugins/identity_map.rb +4 -0
- data/lib/sequel/plugins/json_serializer.rb +32 -13
- data/lib/sequel/plugins/optimistic_locking.rb +1 -1
- data/lib/sequel/plugins/rcte_tree.rb +4 -4
- data/lib/sequel/plugins/scissors.rb +33 -0
- data/lib/sequel/plugins/serialization.rb +1 -1
- data/lib/sequel/plugins/single_table_inheritance.rb +6 -0
- data/lib/sequel/plugins/tree.rb +5 -1
- data/lib/sequel/plugins/validation_class_methods.rb +2 -1
- data/lib/sequel/plugins/validation_helpers.rb +15 -11
- data/lib/sequel/plugins/xml_serializer.rb +12 -3
- data/lib/sequel/sql.rb +12 -2
- data/lib/sequel/timezones.rb +1 -1
- data/lib/sequel/version.rb +1 -1
- data/lib/sequel_core.rb +1 -0
- data/lib/sequel_model.rb +1 -0
- data/spec/adapters/mssql_spec.rb +24 -57
- data/spec/adapters/postgres_spec.rb +27 -55
- data/spec/adapters/spec_helper.rb +1 -1
- data/spec/adapters/sqlite_spec.rb +1 -1
- data/spec/bin_spec.rb +251 -0
- data/spec/core/database_spec.rb +46 -32
- data/spec/core/dataset_spec.rb +233 -181
- data/spec/core/deprecated_spec.rb +78 -0
- data/spec/core/expression_filters_spec.rb +3 -4
- data/spec/core/mock_adapter_spec.rb +9 -9
- data/spec/core/object_graph_spec.rb +9 -19
- data/spec/core/schema_spec.rb +3 -1
- data/spec/core/spec_helper.rb +19 -0
- data/spec/core_extensions_spec.rb +80 -30
- data/spec/extensions/after_initialize_spec.rb +24 -0
- data/spec/extensions/association_proxies_spec.rb +37 -1
- data/spec/extensions/auto_validations_spec.rb +20 -4
- data/spec/extensions/blacklist_security_spec.rb +87 -0
- data/spec/extensions/boolean_readers_spec.rb +2 -1
- data/spec/extensions/class_table_inheritance_spec.rb +7 -0
- data/spec/extensions/columns_introspection_spec.rb +3 -3
- data/spec/extensions/constraint_validations_plugin_spec.rb +83 -5
- data/spec/extensions/core_refinements_spec.rb +7 -7
- data/spec/extensions/dataset_associations_spec.rb +2 -2
- data/spec/extensions/date_arithmetic_spec.rb +1 -1
- data/spec/extensions/defaults_setter_spec.rb +2 -1
- data/spec/extensions/empty_array_ignore_nulls_spec.rb +24 -0
- data/spec/extensions/filter_having_spec.rb +40 -0
- data/spec/extensions/graph_each_spec.rb +109 -0
- data/spec/extensions/hash_aliases_spec.rb +16 -0
- data/spec/extensions/hook_class_methods_spec.rb +2 -2
- data/spec/extensions/identity_map_spec.rb +3 -3
- data/spec/extensions/json_serializer_spec.rb +19 -19
- data/spec/extensions/lazy_attributes_spec.rb +1 -0
- data/spec/extensions/list_spec.rb +13 -13
- data/spec/extensions/looser_typecasting_spec.rb +10 -3
- data/spec/extensions/many_through_many_spec.rb +1 -1
- data/spec/extensions/migration_spec.rb +7 -7
- data/spec/extensions/named_timezones_spec.rb +6 -0
- data/spec/extensions/nested_attributes_spec.rb +2 -2
- data/spec/extensions/null_dataset_spec.rb +1 -1
- data/spec/extensions/pagination_spec.rb +2 -2
- data/spec/extensions/pg_hstore_ops_spec.rb +75 -0
- data/spec/extensions/pg_range_ops_spec.rb +4 -2
- data/spec/extensions/pg_row_plugin_spec.rb +1 -1
- data/spec/extensions/pretty_table_spec.rb +1 -1
- data/spec/extensions/query_literals_spec.rb +1 -1
- data/spec/extensions/query_spec.rb +3 -3
- data/spec/extensions/schema_caching_spec.rb +3 -3
- data/spec/extensions/schema_dumper_spec.rb +27 -2
- data/spec/extensions/schema_spec.rb +2 -2
- data/spec/extensions/scissors_spec.rb +26 -0
- data/spec/extensions/select_remove_spec.rb +1 -1
- data/spec/extensions/sequel_3_dataset_methods_spec.rb +102 -0
- data/spec/extensions/set_overrides_spec.rb +45 -0
- data/spec/extensions/single_table_inheritance_spec.rb +10 -0
- data/spec/extensions/spec_helper.rb +24 -1
- data/spec/extensions/static_cache_spec.rb +1 -1
- data/spec/extensions/string_stripper_spec.rb +2 -1
- data/spec/extensions/to_dot_spec.rb +1 -1
- data/spec/extensions/typecast_on_load_spec.rb +3 -2
- data/spec/extensions/update_primary_key_spec.rb +2 -2
- data/spec/extensions/validation_class_methods_spec.rb +19 -19
- data/spec/extensions/validation_helpers_spec.rb +30 -21
- data/spec/extensions/xml_serializer_spec.rb +5 -5
- data/spec/integration/associations_test.rb +10 -30
- data/spec/integration/dataset_test.rb +20 -24
- data/spec/integration/eager_loader_test.rb +5 -5
- data/spec/integration/model_test.rb +3 -3
- data/spec/integration/plugin_test.rb +7 -39
- data/spec/integration/schema_test.rb +4 -38
- data/spec/integration/spec_helper.rb +2 -1
- data/spec/model/association_reflection_spec.rb +70 -5
- data/spec/model/associations_spec.rb +11 -11
- data/spec/model/base_spec.rb +25 -8
- data/spec/model/class_dataset_methods_spec.rb +143 -0
- data/spec/model/dataset_methods_spec.rb +1 -1
- data/spec/model/eager_loading_spec.rb +25 -25
- data/spec/model/hooks_spec.rb +1 -1
- data/spec/model/model_spec.rb +22 -7
- data/spec/model/plugins_spec.rb +1 -6
- data/spec/model/record_spec.rb +37 -29
- data/spec/model/spec_helper.rb +23 -1
- data/spec/model/validations_spec.rb +15 -17
- metadata +32 -3
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# The graph_each extension adds Dataset#graph_each and
|
|
2
|
+
# makes Dataset#each call #graph_each if the dataset has been graphed.
|
|
3
|
+
# Dataset#graph_each splits result hashes into subhashes per table:
|
|
4
|
+
#
|
|
5
|
+
# DB[:a].graph(:b, :id=>:b_id).all
|
|
6
|
+
# # => {:a=>{:id=>1, :b_id=>2}, :b=>{:id=>2}}
|
|
7
|
+
#
|
|
8
|
+
# You can load this extension into specific datasets:
|
|
9
|
+
#
|
|
10
|
+
# ds = DB[:table]
|
|
11
|
+
# ds.extension(:graph_each)
|
|
12
|
+
#
|
|
13
|
+
# Or you can load it into all of a database's datasets, which
|
|
14
|
+
# is probably the desired behavior if you are using this extension:
|
|
15
|
+
#
|
|
16
|
+
# DB.extension(:graph_each)
|
|
17
|
+
|
|
18
|
+
module Sequel
|
|
19
|
+
module GraphEach
|
|
20
|
+
# Fetch the rows, split them into component table parts,
|
|
21
|
+
# tranform and run the row_proc on each part (if applicable),
|
|
22
|
+
# and yield a hash of the parts.
|
|
23
|
+
def graph_each
|
|
24
|
+
# Reject tables with nil datasets, as they are excluded from
|
|
25
|
+
# the result set
|
|
26
|
+
datasets = @opts[:graph][:table_aliases].to_a.reject{|ta,ds| ds.nil?}
|
|
27
|
+
# Get just the list of table aliases into a local variable, for speed
|
|
28
|
+
table_aliases = datasets.collect{|ta,ds| ta}
|
|
29
|
+
# Get an array of arrays, one for each dataset, with
|
|
30
|
+
# the necessary information about each dataset, for speed
|
|
31
|
+
datasets = datasets.collect{|ta, ds| [ta, ds, ds.row_proc]}
|
|
32
|
+
# Use the manually set graph aliases, if any, otherwise
|
|
33
|
+
# use the ones automatically created by .graph
|
|
34
|
+
column_aliases = @opts[:graph_aliases] || @opts[:graph][:column_aliases]
|
|
35
|
+
fetch_rows(select_sql) do |r|
|
|
36
|
+
graph = {}
|
|
37
|
+
# Create the sub hashes, one per table
|
|
38
|
+
table_aliases.each{|ta| graph[ta]={}}
|
|
39
|
+
# Split the result set based on the column aliases
|
|
40
|
+
# If there are columns in the result set that are
|
|
41
|
+
# not in column_aliases, they are ignored
|
|
42
|
+
column_aliases.each do |col_alias, tc|
|
|
43
|
+
ta, column = tc
|
|
44
|
+
graph[ta][column] = r[col_alias]
|
|
45
|
+
end
|
|
46
|
+
# For each dataset run the row_proc if applicable
|
|
47
|
+
datasets.each do |ta,ds,rp|
|
|
48
|
+
g = graph[ta]
|
|
49
|
+
graph[ta] = if g.values.any?{|x| !x.nil?}
|
|
50
|
+
rp ? rp.call(g) : g
|
|
51
|
+
else
|
|
52
|
+
nil
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
yield graph
|
|
57
|
+
end
|
|
58
|
+
self
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
Dataset.register_extension(:graph_each, GraphEach)
|
|
63
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# The hash_aliases extension allows Dataset#select and Dataset#from
|
|
2
|
+
# to treat a hash argument as an alias specification, with keys
|
|
3
|
+
# being the expressions and values being the aliases,
|
|
4
|
+
# which was the historical behavior before Sequel 4.
|
|
5
|
+
# It is only recommended to use this for backwards compatibility.
|
|
6
|
+
#
|
|
7
|
+
# You can load this extension into specific datasets:
|
|
8
|
+
#
|
|
9
|
+
# ds = DB[:table]
|
|
10
|
+
# ds.extension(:hash_aliases)
|
|
11
|
+
#
|
|
12
|
+
# Or you can load it into all of a database's datasets, which
|
|
13
|
+
# is probably the desired behavior if you are using this extension:
|
|
14
|
+
#
|
|
15
|
+
# DB.extension(:hash_aliases)
|
|
16
|
+
|
|
17
|
+
module Sequel
|
|
18
|
+
module HashAliases
|
|
19
|
+
def from(*source)
|
|
20
|
+
super(*convert_hash_aliases(source))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def select(*columns, &block)
|
|
24
|
+
virtual_row_columns(columns, block)
|
|
25
|
+
super(*convert_hash_aliases(columns), &nil)
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
private
|
|
29
|
+
|
|
30
|
+
def convert_hash_aliases(columns)
|
|
31
|
+
m = []
|
|
32
|
+
columns.each do |i|
|
|
33
|
+
if i.is_a?(Hash)
|
|
34
|
+
m.concat(i.map{|k, v| SQL::AliasedExpression.new(k,v)})
|
|
35
|
+
else
|
|
36
|
+
m << i
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
m
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
Dataset.register_extension(:hash_aliases, HashAliases)
|
|
44
|
+
end
|
|
@@ -1,6 +1,12 @@
|
|
|
1
|
-
# The LooserTypecasting extension
|
|
2
|
-
#
|
|
3
|
-
#
|
|
1
|
+
# The LooserTypecasting extension loosens the default database typecasting
|
|
2
|
+
# for the following types:
|
|
3
|
+
#
|
|
4
|
+
# :float :: use to_f instead of Float()
|
|
5
|
+
# :integer :: use to_i instead of Integer()
|
|
6
|
+
# :decimal :: don't check string conversion with Float()
|
|
7
|
+
# :string :: silently allow hash and array conversion to string
|
|
8
|
+
#
|
|
9
|
+
# To load the extension into the database:
|
|
4
10
|
#
|
|
5
11
|
# DB.extension :looser_typecasting
|
|
6
12
|
|
|
@@ -16,6 +22,11 @@ module Sequel
|
|
|
16
22
|
value.to_i
|
|
17
23
|
end
|
|
18
24
|
|
|
25
|
+
# Typecast the value to an Integer using to_i instead of Kernel.Integer
|
|
26
|
+
def typecast_value_string(value)
|
|
27
|
+
value.to_s
|
|
28
|
+
end
|
|
29
|
+
|
|
19
30
|
# Typecast the value to a BigDecimal, without checking if strings
|
|
20
31
|
# have a valid format.
|
|
21
32
|
def typecast_value_decimal(value)
|
|
@@ -583,9 +583,8 @@ module Sequel
|
|
|
583
583
|
def schema_dataset
|
|
584
584
|
c = column
|
|
585
585
|
ds = db.from(table)
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
elsif !ds.columns.include?(c)
|
|
586
|
+
db.create_table?(table){Integer c, :default=>0, :null=>false}
|
|
587
|
+
unless ds.columns.include?(c)
|
|
589
588
|
db.alter_table(table){add_column c, Integer, :default=>0, :null=>false}
|
|
590
589
|
end
|
|
591
590
|
ds.insert(c=>0) if ds.empty?
|
|
@@ -26,6 +26,12 @@
|
|
|
26
26
|
# York time. When data is retrieved from the database, it is
|
|
27
27
|
# converted to Los Angeles time.
|
|
28
28
|
#
|
|
29
|
+
# If you are using database specific timezones, you may want to load
|
|
30
|
+
# this extension into the database in order to support similar API:
|
|
31
|
+
#
|
|
32
|
+
# DB.extension :named_timezones
|
|
33
|
+
# DB.timezone = 'America/New_York'
|
|
34
|
+
#
|
|
29
35
|
# Note that typecasting from the database timezone to the application
|
|
30
36
|
# timezone when fetching rows is dependent on the database adapter,
|
|
31
37
|
# and only works on adapters where Sequel itself does the conversion.
|
|
@@ -37,6 +43,12 @@ module Sequel
|
|
|
37
43
|
self.datetime_class = DateTime
|
|
38
44
|
|
|
39
45
|
module NamedTimezones
|
|
46
|
+
module DatabaseMethods
|
|
47
|
+
def timezone=(tz)
|
|
48
|
+
super(Sequel.send(:convert_timezone_setter_arg, tz))
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
40
52
|
# Handles TZInfo::AmbiguousTime exceptions automatically by providing a
|
|
41
53
|
# proc called with both the datetime value being converted as well as
|
|
42
54
|
# the array of TZInfo::TimezonePeriod results. Example:
|
|
@@ -47,7 +59,7 @@ module Sequel
|
|
|
47
59
|
private
|
|
48
60
|
|
|
49
61
|
# Assume the given DateTime has a correct time but a wrong timezone. It is
|
|
50
|
-
# currently in UTC timezone, but it should be converted to the
|
|
62
|
+
# currently in UTC timezone, but it should be converted to the input_timezone.
|
|
51
63
|
# Keep the time the same but convert the timezone to the input_timezone.
|
|
52
64
|
# Expects the input_timezone to be a TZInfo::Timezone instance.
|
|
53
65
|
def convert_input_datetime_other(v, input_timezone)
|
|
@@ -82,4 +94,5 @@ module Sequel
|
|
|
82
94
|
end
|
|
83
95
|
|
|
84
96
|
extend NamedTimezones
|
|
97
|
+
Database.register_extension(:named_timezones, NamedTimezones::DatabaseMethods)
|
|
85
98
|
end
|
|
@@ -29,11 +29,14 @@
|
|
|
29
29
|
|
|
30
30
|
module Sequel
|
|
31
31
|
class Dataset
|
|
32
|
+
module Nullifiable
|
|
33
|
+
end
|
|
34
|
+
|
|
32
35
|
module NullDataset
|
|
33
36
|
# Create a new dataset from the dataset (which won't
|
|
34
37
|
# be nulled) to get the columns if they aren't already cached.
|
|
35
38
|
def columns
|
|
36
|
-
@columns ||= db.dataset(@opts).columns
|
|
39
|
+
@columns ||= db.dataset.clone(@opts).columns
|
|
37
40
|
end
|
|
38
41
|
|
|
39
42
|
# Return 0 without sending a database query.
|
|
@@ -90,7 +93,10 @@ module Sequel
|
|
|
90
93
|
|
|
91
94
|
# Nullify the current dataset
|
|
92
95
|
def nullify!
|
|
96
|
+
Sequel::Deprecation.deprecate('Loading the null_dataset extension globally', "Please use Database/Dataset#extension to load the extension into this dataset") unless is_a?(Nullifiable)
|
|
93
97
|
extend NullDataset
|
|
94
98
|
end
|
|
95
99
|
end
|
|
100
|
+
|
|
101
|
+
Dataset.register_extension(:null_dataset, Dataset::Nullifiable)
|
|
96
102
|
end
|
|
@@ -2,19 +2,29 @@
|
|
|
2
2
|
# which return paginated (limited and offset) datasets with some helpful methods
|
|
3
3
|
# that make creating a paginated display easier.
|
|
4
4
|
#
|
|
5
|
-
#
|
|
5
|
+
# This extension uses Object#extend at runtime, which can hurt performance.
|
|
6
6
|
#
|
|
7
|
-
#
|
|
7
|
+
# You can load this extension into specific datasets:
|
|
8
8
|
#
|
|
9
|
-
#
|
|
9
|
+
# ds = DB[:table]
|
|
10
|
+
# ds.extension(:pagination)
|
|
11
|
+
#
|
|
12
|
+
# Or you can load it into all of a database's datasets, which
|
|
13
|
+
# is probably the desired behavior if you are using this extension:
|
|
14
|
+
#
|
|
15
|
+
# DB.extension(:pagination)
|
|
10
16
|
|
|
11
17
|
module Sequel
|
|
18
|
+
module DatasetPagination
|
|
19
|
+
end
|
|
20
|
+
|
|
12
21
|
class Dataset
|
|
13
22
|
# Returns a paginated dataset. The returned dataset is limited to
|
|
14
23
|
# the page size at the correct offset, and extended with the Pagination
|
|
15
24
|
# module. If a record count is not provided, does a count of total
|
|
16
25
|
# number of records for this dataset.
|
|
17
26
|
def paginate(page_no, page_size, record_count=nil)
|
|
27
|
+
Sequel::Deprecation.deprecate('Loading the pagination extension globally', "Please use Database/Dataset#extension to load the extension into this dataset") unless is_a?(DatasetPagination)
|
|
18
28
|
raise(Error, "You cannot paginate a dataset that already has a limit") if @opts[:limit]
|
|
19
29
|
paginated = limit(page_size, (page_no - 1) * page_size)
|
|
20
30
|
paginated.extend(Pagination)
|
|
@@ -24,6 +34,7 @@ module Sequel
|
|
|
24
34
|
# Yields a paginated dataset for each page and returns the receiver. Does
|
|
25
35
|
# a count to find the total number of records for this dataset.
|
|
26
36
|
def each_page(page_size)
|
|
37
|
+
Sequel::Deprecation.deprecate('Loading the pagination extension globally', "Please use Database/Dataset#extension to load the extension into this dataset") unless is_a?(DatasetPagination)
|
|
27
38
|
raise(Error, "You cannot paginate a dataset that already has a limit") if @opts[:limit]
|
|
28
39
|
record_count = count
|
|
29
40
|
total_pages = (record_count / page_size.to_f).ceil
|
|
@@ -104,6 +115,5 @@ module Sequel
|
|
|
104
115
|
end
|
|
105
116
|
end
|
|
106
117
|
|
|
107
|
-
|
|
108
|
-
Dataset.register_extension(:pagination){}
|
|
118
|
+
Dataset.register_extension(:pagination, DatasetPagination)
|
|
109
119
|
end
|
|
@@ -91,6 +91,7 @@ module Sequel
|
|
|
91
91
|
module DatabaseMethods
|
|
92
92
|
# Extend the database's datasets with the necessary code.
|
|
93
93
|
def self.extended(db)
|
|
94
|
+
Sequel::Deprecation.deprecate('The pg_auto_parameterize extension', 'Please stop loading it') unless defined?(SEQUEL_EXTENSIONS_NO_DEPRECATION_WARNING)
|
|
94
95
|
db.extend_datasets(DatasetMethods)
|
|
95
96
|
end
|
|
96
97
|
|
|
@@ -82,8 +82,10 @@ module Sequel
|
|
|
82
82
|
#
|
|
83
83
|
# hstore_op - 'a' # (hstore - 'a')
|
|
84
84
|
def -(other)
|
|
85
|
-
if other.is_a?(String) && !other.is_a?(Sequel::LiteralString)
|
|
86
|
-
|
|
85
|
+
other = if other.is_a?(String) && !other.is_a?(Sequel::LiteralString)
|
|
86
|
+
Sequel.cast_string(other)
|
|
87
|
+
else
|
|
88
|
+
wrap_input_array(wrap_input_hash(other))
|
|
87
89
|
end
|
|
88
90
|
HStoreOp.new(super)
|
|
89
91
|
end
|
|
@@ -92,35 +94,40 @@ module Sequel
|
|
|
92
94
|
#
|
|
93
95
|
# hstore_op['a'] # (hstore -> 'a')
|
|
94
96
|
def [](key)
|
|
95
|
-
|
|
97
|
+
v = Sequel::SQL::PlaceholderLiteralString.new(LOOKUP, [value, wrap_input_array(key)])
|
|
98
|
+
if key.is_a?(Array) || (defined?(Sequel::Postgres::PGArray) && key.is_a?(Sequel::Postgres::PGArray)) || (defined?(Sequel::Postgres::ArrayOp) && key.is_a?(Sequel::Postgres::ArrayOp))
|
|
99
|
+
wrap_output_array(v)
|
|
100
|
+
else
|
|
101
|
+
Sequel::SQL::StringExpression.new(:NOOP, v)
|
|
102
|
+
end
|
|
96
103
|
end
|
|
97
104
|
|
|
98
105
|
# Check if the receiver contains all of the keys in the given array:
|
|
99
106
|
#
|
|
100
107
|
# hstore_op.contain_all(:a) # (hstore ?& a)
|
|
101
108
|
def contain_all(other)
|
|
102
|
-
bool_op(CONTAIN_ALL, other)
|
|
109
|
+
bool_op(CONTAIN_ALL, wrap_input_array(other))
|
|
103
110
|
end
|
|
104
111
|
|
|
105
112
|
# Check if the receiver contains any of the keys in the given array:
|
|
106
113
|
#
|
|
107
114
|
# hstore_op.contain_any(:a) # (hstore ?| a)
|
|
108
115
|
def contain_any(other)
|
|
109
|
-
bool_op(CONTAIN_ANY, other)
|
|
116
|
+
bool_op(CONTAIN_ANY, wrap_input_array(other))
|
|
110
117
|
end
|
|
111
118
|
|
|
112
119
|
# Check if the receiver contains all entries in the other hstore:
|
|
113
120
|
#
|
|
114
121
|
# hstore_op.contains(:h) # (hstore @> h)
|
|
115
122
|
def contains(other)
|
|
116
|
-
bool_op(CONTAINS, other)
|
|
123
|
+
bool_op(CONTAINS, wrap_input_hash(other))
|
|
117
124
|
end
|
|
118
125
|
|
|
119
126
|
# Check if the other hstore contains all entries in the receiver:
|
|
120
127
|
#
|
|
121
128
|
# hstore_op.contained_by(:h) # (hstore <@ h)
|
|
122
129
|
def contained_by(other)
|
|
123
|
-
bool_op(CONTAINED_BY, other)
|
|
130
|
+
bool_op(CONTAINED_BY, wrap_input_hash(other))
|
|
124
131
|
end
|
|
125
132
|
|
|
126
133
|
# Check if the receiver contains a non-NULL value for the given key:
|
|
@@ -134,7 +141,7 @@ module Sequel
|
|
|
134
141
|
#
|
|
135
142
|
# hstore_op.delete('a') # delete(hstore, 'a')
|
|
136
143
|
def delete(key)
|
|
137
|
-
HStoreOp.new(function(:delete, key))
|
|
144
|
+
HStoreOp.new(function(:delete, wrap_input_array(wrap_input_hash(key))))
|
|
138
145
|
end
|
|
139
146
|
|
|
140
147
|
# Transform the receiver into a set of keys and values:
|
|
@@ -164,7 +171,7 @@ module Sequel
|
|
|
164
171
|
#
|
|
165
172
|
# hstore_op.keys # akeys(hstore)
|
|
166
173
|
def keys
|
|
167
|
-
function(:akeys)
|
|
174
|
+
wrap_output_array(function(:akeys))
|
|
168
175
|
end
|
|
169
176
|
alias akeys keys
|
|
170
177
|
|
|
@@ -172,7 +179,7 @@ module Sequel
|
|
|
172
179
|
#
|
|
173
180
|
# hstore_op.merge(:a) # (hstore || a)
|
|
174
181
|
def merge(other)
|
|
175
|
-
HStoreOp.new(Sequel::SQL::PlaceholderLiteralString.new(CONCAT, [self, other]))
|
|
182
|
+
HStoreOp.new(Sequel::SQL::PlaceholderLiteralString.new(CONCAT, [self, wrap_input_hash(other)]))
|
|
176
183
|
end
|
|
177
184
|
alias concat merge
|
|
178
185
|
|
|
@@ -201,7 +208,7 @@ module Sequel
|
|
|
201
208
|
#
|
|
202
209
|
# hstore_op.slice(:a) # slice(hstore, a)
|
|
203
210
|
def slice(keys)
|
|
204
|
-
HStoreOp.new(function(:slice, keys))
|
|
211
|
+
HStoreOp.new(function(:slice, wrap_input_array(keys)))
|
|
205
212
|
end
|
|
206
213
|
|
|
207
214
|
# Return the values as a PostgreSQL set:
|
|
@@ -216,7 +223,7 @@ module Sequel
|
|
|
216
223
|
#
|
|
217
224
|
# hstore_op.to_array # hstore_to_array(hstore)
|
|
218
225
|
def to_array
|
|
219
|
-
function(:hstore_to_array)
|
|
226
|
+
wrap_output_array(function(:hstore_to_array))
|
|
220
227
|
end
|
|
221
228
|
|
|
222
229
|
# Return a nested array of the receiver, with arrays of
|
|
@@ -224,14 +231,14 @@ module Sequel
|
|
|
224
231
|
#
|
|
225
232
|
# hstore_op.to_matrix # hstore_to_matrix(hstore)
|
|
226
233
|
def to_matrix
|
|
227
|
-
function(:hstore_to_matrix)
|
|
234
|
+
wrap_output_array(function(:hstore_to_matrix))
|
|
228
235
|
end
|
|
229
236
|
|
|
230
237
|
# Return the values as a PostgreSQL array:
|
|
231
238
|
#
|
|
232
239
|
# hstore_op.values # avals(hstore)
|
|
233
240
|
def values
|
|
234
|
-
function(:avals)
|
|
241
|
+
wrap_output_array(function(:avals))
|
|
235
242
|
end
|
|
236
243
|
alias avals values
|
|
237
244
|
|
|
@@ -248,6 +255,33 @@ module Sequel
|
|
|
248
255
|
def function(name, *args)
|
|
249
256
|
SQL::Function.new(name, self, *args)
|
|
250
257
|
end
|
|
258
|
+
|
|
259
|
+
# Wrap argument in a PGArray if it is an array
|
|
260
|
+
def wrap_input_array(obj)
|
|
261
|
+
if obj.is_a?(Array) && Sequel.respond_to?(:pg_array)
|
|
262
|
+
Sequel.pg_array(obj)
|
|
263
|
+
else
|
|
264
|
+
obj
|
|
265
|
+
end
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
# Wrap argument in an Hstore if it is a hash
|
|
269
|
+
def wrap_input_hash(obj)
|
|
270
|
+
if obj.is_a?(Hash) && Sequel.respond_to?(:hstore)
|
|
271
|
+
Sequel.hstore(obj)
|
|
272
|
+
else
|
|
273
|
+
obj
|
|
274
|
+
end
|
|
275
|
+
end
|
|
276
|
+
|
|
277
|
+
# Wrap argument in a PGArrayOp if supported
|
|
278
|
+
def wrap_output_array(obj)
|
|
279
|
+
if Sequel.respond_to?(:pg_array_op)
|
|
280
|
+
Sequel.pg_array_op(obj)
|
|
281
|
+
else
|
|
282
|
+
obj
|
|
283
|
+
end
|
|
284
|
+
end
|
|
251
285
|
end
|
|
252
286
|
|
|
253
287
|
module HStoreOpMethods
|
|
@@ -66,11 +66,11 @@ module Sequel
|
|
|
66
66
|
class JSONArray < DelegateClass(Array)
|
|
67
67
|
include Sequel::SQL::AliasMethods
|
|
68
68
|
|
|
69
|
-
# Convert the array to a string
|
|
69
|
+
# Convert the array to a json string, append a
|
|
70
70
|
# literalized version of the string to the sql, and explicitly
|
|
71
71
|
# cast the string to json.
|
|
72
72
|
def sql_literal_append(ds, sql)
|
|
73
|
-
ds.literal_append(sql,
|
|
73
|
+
ds.literal_append(sql, Sequel.object_to_json(self))
|
|
74
74
|
sql << CAST_JSON
|
|
75
75
|
end
|
|
76
76
|
end
|
|
@@ -79,11 +79,11 @@ module Sequel
|
|
|
79
79
|
class JSONHash < DelegateClass(Hash)
|
|
80
80
|
include Sequel::SQL::AliasMethods
|
|
81
81
|
|
|
82
|
-
# Convert the
|
|
82
|
+
# Convert the hash to a json string, append a
|
|
83
83
|
# literalized version of the string to the sql, and explicitly
|
|
84
84
|
# cast the string to json.
|
|
85
85
|
def sql_literal_append(ds, sql)
|
|
86
|
-
ds.literal_append(sql,
|
|
86
|
+
ds.literal_append(sql, Sequel.object_to_json(self))
|
|
87
87
|
sql << CAST_JSON
|
|
88
88
|
end
|
|
89
89
|
|
|
@@ -106,7 +106,7 @@ module Sequel
|
|
|
106
106
|
def self.parse_json(s)
|
|
107
107
|
begin
|
|
108
108
|
value = Sequel.parse_json(s)
|
|
109
|
-
rescue
|
|
109
|
+
rescue Sequel.json_parser_error_class => e
|
|
110
110
|
raise Sequel.convert_exception_class(e, Sequel::InvalidValue)
|
|
111
111
|
end
|
|
112
112
|
|
|
@@ -124,7 +124,7 @@ module Sequel
|
|
|
124
124
|
def bound_variable_arg(arg, conn)
|
|
125
125
|
case arg
|
|
126
126
|
when JSONArray, JSONHash
|
|
127
|
-
arg
|
|
127
|
+
Sequel.object_to_json(arg)
|
|
128
128
|
else
|
|
129
129
|
super
|
|
130
130
|
end
|
|
@@ -136,7 +136,7 @@ module Sequel
|
|
|
136
136
|
def bound_variable_array(a)
|
|
137
137
|
case a
|
|
138
138
|
when JSONHash, JSONArray
|
|
139
|
-
"\"#{a.
|
|
139
|
+
"\"#{Sequel.object_to_json(a).gsub('"', '\\"')}\""
|
|
140
140
|
else
|
|
141
141
|
super
|
|
142
142
|
end
|