sequel 3.47.0 → 3.48.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|