viking-sequel 3.10.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG +3134 -0
- data/COPYING +19 -0
- data/README.rdoc +723 -0
- data/Rakefile +193 -0
- data/bin/sequel +196 -0
- data/doc/advanced_associations.rdoc +644 -0
- data/doc/cheat_sheet.rdoc +218 -0
- data/doc/dataset_basics.rdoc +106 -0
- data/doc/dataset_filtering.rdoc +158 -0
- data/doc/opening_databases.rdoc +296 -0
- data/doc/prepared_statements.rdoc +104 -0
- data/doc/reflection.rdoc +84 -0
- data/doc/release_notes/1.0.txt +38 -0
- data/doc/release_notes/1.1.txt +143 -0
- data/doc/release_notes/1.3.txt +101 -0
- data/doc/release_notes/1.4.0.txt +53 -0
- data/doc/release_notes/1.5.0.txt +155 -0
- data/doc/release_notes/2.0.0.txt +298 -0
- data/doc/release_notes/2.1.0.txt +271 -0
- data/doc/release_notes/2.10.0.txt +328 -0
- data/doc/release_notes/2.11.0.txt +215 -0
- data/doc/release_notes/2.12.0.txt +534 -0
- data/doc/release_notes/2.2.0.txt +253 -0
- data/doc/release_notes/2.3.0.txt +88 -0
- data/doc/release_notes/2.4.0.txt +106 -0
- data/doc/release_notes/2.5.0.txt +137 -0
- data/doc/release_notes/2.6.0.txt +157 -0
- data/doc/release_notes/2.7.0.txt +166 -0
- data/doc/release_notes/2.8.0.txt +171 -0
- data/doc/release_notes/2.9.0.txt +97 -0
- data/doc/release_notes/3.0.0.txt +221 -0
- data/doc/release_notes/3.1.0.txt +406 -0
- data/doc/release_notes/3.10.0.txt +286 -0
- data/doc/release_notes/3.2.0.txt +268 -0
- data/doc/release_notes/3.3.0.txt +192 -0
- data/doc/release_notes/3.4.0.txt +325 -0
- data/doc/release_notes/3.5.0.txt +510 -0
- data/doc/release_notes/3.6.0.txt +366 -0
- data/doc/release_notes/3.7.0.txt +179 -0
- data/doc/release_notes/3.8.0.txt +151 -0
- data/doc/release_notes/3.9.0.txt +233 -0
- data/doc/schema.rdoc +36 -0
- data/doc/sharding.rdoc +113 -0
- data/doc/virtual_rows.rdoc +205 -0
- data/lib/sequel.rb +1 -0
- data/lib/sequel/adapters/ado.rb +90 -0
- data/lib/sequel/adapters/ado/mssql.rb +30 -0
- data/lib/sequel/adapters/amalgalite.rb +176 -0
- data/lib/sequel/adapters/db2.rb +139 -0
- data/lib/sequel/adapters/dbi.rb +113 -0
- data/lib/sequel/adapters/do.rb +188 -0
- data/lib/sequel/adapters/do/mysql.rb +49 -0
- data/lib/sequel/adapters/do/postgres.rb +91 -0
- data/lib/sequel/adapters/do/sqlite.rb +40 -0
- data/lib/sequel/adapters/firebird.rb +283 -0
- data/lib/sequel/adapters/informix.rb +77 -0
- data/lib/sequel/adapters/jdbc.rb +587 -0
- data/lib/sequel/adapters/jdbc/as400.rb +58 -0
- data/lib/sequel/adapters/jdbc/h2.rb +133 -0
- data/lib/sequel/adapters/jdbc/mssql.rb +57 -0
- data/lib/sequel/adapters/jdbc/mysql.rb +78 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +50 -0
- data/lib/sequel/adapters/jdbc/postgresql.rb +108 -0
- data/lib/sequel/adapters/jdbc/sqlite.rb +55 -0
- data/lib/sequel/adapters/mysql.rb +421 -0
- data/lib/sequel/adapters/odbc.rb +143 -0
- data/lib/sequel/adapters/odbc/mssql.rb +42 -0
- data/lib/sequel/adapters/openbase.rb +64 -0
- data/lib/sequel/adapters/oracle.rb +131 -0
- data/lib/sequel/adapters/postgres.rb +504 -0
- data/lib/sequel/adapters/shared/mssql.rb +490 -0
- data/lib/sequel/adapters/shared/mysql.rb +498 -0
- data/lib/sequel/adapters/shared/oracle.rb +195 -0
- data/lib/sequel/adapters/shared/postgres.rb +830 -0
- data/lib/sequel/adapters/shared/progress.rb +44 -0
- data/lib/sequel/adapters/shared/sqlite.rb +389 -0
- data/lib/sequel/adapters/sqlite.rb +224 -0
- data/lib/sequel/adapters/utils/stored_procedures.rb +84 -0
- data/lib/sequel/connection_pool.rb +99 -0
- data/lib/sequel/connection_pool/sharded_single.rb +84 -0
- data/lib/sequel/connection_pool/sharded_threaded.rb +211 -0
- data/lib/sequel/connection_pool/single.rb +29 -0
- data/lib/sequel/connection_pool/threaded.rb +150 -0
- data/lib/sequel/core.rb +293 -0
- data/lib/sequel/core_sql.rb +241 -0
- data/lib/sequel/database.rb +1079 -0
- data/lib/sequel/database/schema_generator.rb +327 -0
- data/lib/sequel/database/schema_methods.rb +203 -0
- data/lib/sequel/database/schema_sql.rb +320 -0
- data/lib/sequel/dataset.rb +32 -0
- data/lib/sequel/dataset/actions.rb +441 -0
- data/lib/sequel/dataset/features.rb +86 -0
- data/lib/sequel/dataset/graph.rb +254 -0
- data/lib/sequel/dataset/misc.rb +119 -0
- data/lib/sequel/dataset/mutation.rb +64 -0
- data/lib/sequel/dataset/prepared_statements.rb +227 -0
- data/lib/sequel/dataset/query.rb +709 -0
- data/lib/sequel/dataset/sql.rb +996 -0
- data/lib/sequel/exceptions.rb +51 -0
- data/lib/sequel/extensions/blank.rb +43 -0
- data/lib/sequel/extensions/inflector.rb +242 -0
- data/lib/sequel/extensions/looser_typecasting.rb +21 -0
- data/lib/sequel/extensions/migration.rb +239 -0
- data/lib/sequel/extensions/named_timezones.rb +61 -0
- data/lib/sequel/extensions/pagination.rb +100 -0
- data/lib/sequel/extensions/pretty_table.rb +82 -0
- data/lib/sequel/extensions/query.rb +52 -0
- data/lib/sequel/extensions/schema_dumper.rb +271 -0
- data/lib/sequel/extensions/sql_expr.rb +122 -0
- data/lib/sequel/extensions/string_date_time.rb +46 -0
- data/lib/sequel/extensions/thread_local_timezones.rb +48 -0
- data/lib/sequel/metaprogramming.rb +9 -0
- data/lib/sequel/model.rb +120 -0
- data/lib/sequel/model/associations.rb +1514 -0
- data/lib/sequel/model/base.rb +1069 -0
- data/lib/sequel/model/default_inflections.rb +45 -0
- data/lib/sequel/model/errors.rb +39 -0
- data/lib/sequel/model/exceptions.rb +21 -0
- data/lib/sequel/model/inflections.rb +162 -0
- data/lib/sequel/model/plugins.rb +70 -0
- data/lib/sequel/plugins/active_model.rb +59 -0
- data/lib/sequel/plugins/association_dependencies.rb +103 -0
- data/lib/sequel/plugins/association_proxies.rb +41 -0
- data/lib/sequel/plugins/boolean_readers.rb +53 -0
- data/lib/sequel/plugins/caching.rb +141 -0
- data/lib/sequel/plugins/class_table_inheritance.rb +214 -0
- data/lib/sequel/plugins/composition.rb +138 -0
- data/lib/sequel/plugins/force_encoding.rb +72 -0
- data/lib/sequel/plugins/hook_class_methods.rb +126 -0
- data/lib/sequel/plugins/identity_map.rb +116 -0
- data/lib/sequel/plugins/instance_filters.rb +98 -0
- data/lib/sequel/plugins/instance_hooks.rb +57 -0
- data/lib/sequel/plugins/lazy_attributes.rb +77 -0
- data/lib/sequel/plugins/many_through_many.rb +208 -0
- data/lib/sequel/plugins/nested_attributes.rb +206 -0
- data/lib/sequel/plugins/optimistic_locking.rb +81 -0
- data/lib/sequel/plugins/rcte_tree.rb +281 -0
- data/lib/sequel/plugins/schema.rb +66 -0
- data/lib/sequel/plugins/serialization.rb +166 -0
- data/lib/sequel/plugins/single_table_inheritance.rb +74 -0
- data/lib/sequel/plugins/subclasses.rb +45 -0
- data/lib/sequel/plugins/tactical_eager_loading.rb +61 -0
- data/lib/sequel/plugins/timestamps.rb +87 -0
- data/lib/sequel/plugins/touch.rb +118 -0
- data/lib/sequel/plugins/typecast_on_load.rb +72 -0
- data/lib/sequel/plugins/validation_class_methods.rb +405 -0
- data/lib/sequel/plugins/validation_helpers.rb +223 -0
- data/lib/sequel/sql.rb +1020 -0
- data/lib/sequel/timezones.rb +161 -0
- data/lib/sequel/version.rb +12 -0
- data/lib/sequel_core.rb +1 -0
- data/lib/sequel_model.rb +1 -0
- data/spec/adapters/firebird_spec.rb +407 -0
- data/spec/adapters/informix_spec.rb +97 -0
- data/spec/adapters/mssql_spec.rb +403 -0
- data/spec/adapters/mysql_spec.rb +1019 -0
- data/spec/adapters/oracle_spec.rb +286 -0
- data/spec/adapters/postgres_spec.rb +969 -0
- data/spec/adapters/spec_helper.rb +51 -0
- data/spec/adapters/sqlite_spec.rb +432 -0
- data/spec/core/connection_pool_spec.rb +808 -0
- data/spec/core/core_sql_spec.rb +417 -0
- data/spec/core/database_spec.rb +1662 -0
- data/spec/core/dataset_spec.rb +3827 -0
- data/spec/core/expression_filters_spec.rb +595 -0
- data/spec/core/object_graph_spec.rb +296 -0
- data/spec/core/schema_generator_spec.rb +159 -0
- data/spec/core/schema_spec.rb +830 -0
- data/spec/core/spec_helper.rb +56 -0
- data/spec/core/version_spec.rb +7 -0
- data/spec/extensions/active_model_spec.rb +76 -0
- data/spec/extensions/association_dependencies_spec.rb +127 -0
- data/spec/extensions/association_proxies_spec.rb +50 -0
- data/spec/extensions/blank_spec.rb +67 -0
- data/spec/extensions/boolean_readers_spec.rb +92 -0
- data/spec/extensions/caching_spec.rb +250 -0
- data/spec/extensions/class_table_inheritance_spec.rb +252 -0
- data/spec/extensions/composition_spec.rb +194 -0
- data/spec/extensions/force_encoding_spec.rb +117 -0
- data/spec/extensions/hook_class_methods_spec.rb +470 -0
- data/spec/extensions/identity_map_spec.rb +202 -0
- data/spec/extensions/inflector_spec.rb +181 -0
- data/spec/extensions/instance_filters_spec.rb +55 -0
- data/spec/extensions/instance_hooks_spec.rb +133 -0
- data/spec/extensions/lazy_attributes_spec.rb +153 -0
- data/spec/extensions/looser_typecasting_spec.rb +39 -0
- data/spec/extensions/many_through_many_spec.rb +884 -0
- data/spec/extensions/migration_spec.rb +332 -0
- data/spec/extensions/named_timezones_spec.rb +72 -0
- data/spec/extensions/nested_attributes_spec.rb +396 -0
- data/spec/extensions/optimistic_locking_spec.rb +100 -0
- data/spec/extensions/pagination_spec.rb +99 -0
- data/spec/extensions/pretty_table_spec.rb +91 -0
- data/spec/extensions/query_spec.rb +85 -0
- data/spec/extensions/rcte_tree_spec.rb +205 -0
- data/spec/extensions/schema_dumper_spec.rb +357 -0
- data/spec/extensions/schema_spec.rb +127 -0
- data/spec/extensions/serialization_spec.rb +209 -0
- data/spec/extensions/single_table_inheritance_spec.rb +96 -0
- data/spec/extensions/spec_helper.rb +91 -0
- data/spec/extensions/sql_expr_spec.rb +89 -0
- data/spec/extensions/string_date_time_spec.rb +93 -0
- data/spec/extensions/subclasses_spec.rb +52 -0
- data/spec/extensions/tactical_eager_loading_spec.rb +65 -0
- data/spec/extensions/thread_local_timezones_spec.rb +45 -0
- data/spec/extensions/timestamps_spec.rb +150 -0
- data/spec/extensions/touch_spec.rb +155 -0
- data/spec/extensions/typecast_on_load_spec.rb +69 -0
- data/spec/extensions/validation_class_methods_spec.rb +984 -0
- data/spec/extensions/validation_helpers_spec.rb +438 -0
- data/spec/integration/associations_test.rb +281 -0
- data/spec/integration/database_test.rb +26 -0
- data/spec/integration/dataset_test.rb +963 -0
- data/spec/integration/eager_loader_test.rb +734 -0
- data/spec/integration/model_test.rb +130 -0
- data/spec/integration/plugin_test.rb +814 -0
- data/spec/integration/prepared_statement_test.rb +213 -0
- data/spec/integration/schema_test.rb +361 -0
- data/spec/integration/spec_helper.rb +73 -0
- data/spec/integration/timezone_test.rb +55 -0
- data/spec/integration/transaction_test.rb +122 -0
- data/spec/integration/type_test.rb +96 -0
- data/spec/model/association_reflection_spec.rb +175 -0
- data/spec/model/associations_spec.rb +2633 -0
- data/spec/model/base_spec.rb +418 -0
- data/spec/model/dataset_methods_spec.rb +78 -0
- data/spec/model/eager_loading_spec.rb +1391 -0
- data/spec/model/hooks_spec.rb +240 -0
- data/spec/model/inflector_spec.rb +26 -0
- data/spec/model/model_spec.rb +593 -0
- data/spec/model/plugins_spec.rb +236 -0
- data/spec/model/record_spec.rb +1500 -0
- data/spec/model/spec_helper.rb +97 -0
- data/spec/model/validations_spec.rb +153 -0
- data/spec/rcov.opts +6 -0
- data/spec/spec_config.rb.example +10 -0
- metadata +346 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
module Sequel
|
2
|
+
class Dataset
|
3
|
+
# ---------------------
|
4
|
+
# :section: Methods that describe what the dataset supports
|
5
|
+
# These methods all return booleans, with most describing whether or not the
|
6
|
+
# dataset supports a feature.
|
7
|
+
# ---------------------
|
8
|
+
|
9
|
+
# Method used to check if WITH is supported
|
10
|
+
WITH_SUPPORTED=:select_with_sql
|
11
|
+
|
12
|
+
# Whether this dataset quotes identifiers.
|
13
|
+
def quote_identifiers?
|
14
|
+
@quote_identifiers
|
15
|
+
end
|
16
|
+
|
17
|
+
# Whether this dataset will provide accurate number of rows matched for
|
18
|
+
# delete and update statements. Accurate in this case is the number of
|
19
|
+
# rows matched by the dataset's filter.
|
20
|
+
def provides_accurate_rows_matched?
|
21
|
+
true
|
22
|
+
end
|
23
|
+
|
24
|
+
# Whether the dataset requires SQL standard datetimes (false by default,
|
25
|
+
# as most allow strings with ISO 8601 format.
|
26
|
+
def requires_sql_standard_datetimes?
|
27
|
+
false
|
28
|
+
end
|
29
|
+
|
30
|
+
# Whether the dataset supports common table expressions (the WITH clause).
|
31
|
+
def supports_cte?
|
32
|
+
select_clause_methods.include?(WITH_SUPPORTED)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Whether the dataset supports the DISTINCT ON clause, false by default.
|
36
|
+
def supports_distinct_on?
|
37
|
+
false
|
38
|
+
end
|
39
|
+
|
40
|
+
# Whether the dataset supports the INTERSECT and EXCEPT compound operations, true by default.
|
41
|
+
def supports_intersect_except?
|
42
|
+
true
|
43
|
+
end
|
44
|
+
|
45
|
+
# Whether the dataset supports the INTERSECT ALL and EXCEPT ALL compound operations, true by default.
|
46
|
+
def supports_intersect_except_all?
|
47
|
+
true
|
48
|
+
end
|
49
|
+
|
50
|
+
# Whether the dataset supports the IS TRUE syntax.
|
51
|
+
def supports_is_true?
|
52
|
+
true
|
53
|
+
end
|
54
|
+
|
55
|
+
# Whether the dataset supports the JOIN table USING (column1, ...) syntax.
|
56
|
+
def supports_join_using?
|
57
|
+
true
|
58
|
+
end
|
59
|
+
|
60
|
+
# Whether modifying joined datasets is supported.
|
61
|
+
def supports_modifying_joins?
|
62
|
+
false
|
63
|
+
end
|
64
|
+
|
65
|
+
# Whether the IN/NOT IN operators support multiple columns when an
|
66
|
+
# array of values is given.
|
67
|
+
def supports_multiple_column_in?
|
68
|
+
true
|
69
|
+
end
|
70
|
+
|
71
|
+
# Whether the dataset supports timezones in literal timestamps
|
72
|
+
def supports_timestamp_timezones?
|
73
|
+
false
|
74
|
+
end
|
75
|
+
|
76
|
+
# Whether the dataset supports fractional seconds in literal timestamps
|
77
|
+
def supports_timestamp_usecs?
|
78
|
+
true
|
79
|
+
end
|
80
|
+
|
81
|
+
# Whether the dataset supports window functions.
|
82
|
+
def supports_window_functions?
|
83
|
+
false
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,254 @@
|
|
1
|
+
module Sequel
|
2
|
+
class Dataset
|
3
|
+
# ---------------------
|
4
|
+
# :section: Methods related to dataset graphing
|
5
|
+
# Dataset graphing changes the dataset to yield hashes where keys are table
|
6
|
+
# name symbols and columns are hashes representing the values related to
|
7
|
+
# that table. All of these methods return modified copies of the receiver.
|
8
|
+
# ---------------------
|
9
|
+
|
10
|
+
# Adds the given graph aliases to the list of graph aliases to use,
|
11
|
+
# unlike #set_graph_aliases, which replaces the list. See
|
12
|
+
# #set_graph_aliases.
|
13
|
+
def add_graph_aliases(graph_aliases)
|
14
|
+
ds = select_more(*graph_alias_columns(graph_aliases))
|
15
|
+
ds.opts[:graph_aliases] = (ds.opts[:graph_aliases] || (ds.opts[:graph][:column_aliases] rescue {}) || {}).merge(graph_aliases)
|
16
|
+
ds
|
17
|
+
end
|
18
|
+
|
19
|
+
# Allows you to join multiple datasets/tables and have the result set
|
20
|
+
# split into component tables.
|
21
|
+
#
|
22
|
+
# This differs from the usual usage of join, which returns the result set
|
23
|
+
# as a single hash. For example:
|
24
|
+
#
|
25
|
+
# # CREATE TABLE artists (id INTEGER, name TEXT);
|
26
|
+
# # CREATE TABLE albums (id INTEGER, name TEXT, artist_id INTEGER);
|
27
|
+
# DB[:artists].left_outer_join(:albums, :artist_id=>:id).first
|
28
|
+
# => {:id=>albums.id, :name=>albums.name, :artist_id=>albums.artist_id}
|
29
|
+
# DB[:artists].graph(:albums, :artist_id=>:id).first
|
30
|
+
# => {:artists=>{:id=>artists.id, :name=>artists.name}, :albums=>{:id=>albums.id, :name=>albums.name, :artist_id=>albums.artist_id}}
|
31
|
+
#
|
32
|
+
# Using a join such as left_outer_join, the attribute names that are shared between
|
33
|
+
# the tables are combined in the single return hash. You can get around that by
|
34
|
+
# using .select with correct aliases for all of the columns, but it is simpler to
|
35
|
+
# use graph and have the result set split for you. In addition, graph respects
|
36
|
+
# any row_proc of the current dataset and the datasets you use with graph.
|
37
|
+
#
|
38
|
+
# If you are graphing a table and all columns for that table are nil, this
|
39
|
+
# indicates that no matching rows existed in the table, so graph will return nil
|
40
|
+
# instead of a hash with all nil values:
|
41
|
+
#
|
42
|
+
# # If the artist doesn't have any albums
|
43
|
+
# DB[:artists].graph(:albums, :artist_id=>:id).first
|
44
|
+
# => {:artists=>{:id=>artists.id, :name=>artists.name}, :albums=>nil}
|
45
|
+
#
|
46
|
+
# Arguments:
|
47
|
+
# * dataset - Can be a symbol (specifying a table), another dataset,
|
48
|
+
# or an object that responds to .dataset and return a symbol or a dataset
|
49
|
+
# * join_conditions - Any condition(s) allowed by join_table.
|
50
|
+
# * options - A hash of graph options. The following options are currently used:
|
51
|
+
# * :from_self_alias - The alias to use when the receiver is not a graphed
|
52
|
+
# dataset but it contains multiple FROM tables or a JOIN. In this case,
|
53
|
+
# the receiver is wrapped in a from_self before graphing, and this option
|
54
|
+
# determines the alias to use.
|
55
|
+
# * :implicit_qualifier - The qualifier of implicit conditions, see #join_table.
|
56
|
+
# * :join_type - The type of join to use (passed to join_table). Defaults to
|
57
|
+
# :left_outer.
|
58
|
+
# * :select - An array of columns to select. When not used, selects
|
59
|
+
# all columns in the given dataset. When set to false, selects no
|
60
|
+
# columns and is like simply joining the tables, though graph keeps
|
61
|
+
# some metadata about join that makes it important to use graph instead
|
62
|
+
# of join.
|
63
|
+
# * :table_alias - The alias to use for the table. If not specified, doesn't
|
64
|
+
# alias the table. You will get an error if the the alias (or table) name is
|
65
|
+
# used more than once.
|
66
|
+
# * block - A block that is passed to join_table.
|
67
|
+
def graph(dataset, join_conditions = nil, options = {}, &block)
|
68
|
+
# Allow the use of a model, dataset, or symbol as the first argument
|
69
|
+
# Find the table name/dataset based on the argument
|
70
|
+
dataset = dataset.dataset if dataset.respond_to?(:dataset)
|
71
|
+
table_alias = options[:table_alias]
|
72
|
+
case dataset
|
73
|
+
when Symbol
|
74
|
+
table = dataset
|
75
|
+
dataset = @db[dataset]
|
76
|
+
table_alias ||= table
|
77
|
+
when ::Sequel::Dataset
|
78
|
+
if dataset.simple_select_all?
|
79
|
+
table = dataset.opts[:from].first
|
80
|
+
table_alias ||= table
|
81
|
+
else
|
82
|
+
table = dataset
|
83
|
+
table_alias ||= dataset_alias((@opts[:num_dataset_sources] || 0)+1)
|
84
|
+
end
|
85
|
+
else
|
86
|
+
raise Error, "The dataset argument should be a symbol, dataset, or model"
|
87
|
+
end
|
88
|
+
|
89
|
+
# Raise Sequel::Error with explanation that the table alias has been used
|
90
|
+
raise_alias_error = lambda do
|
91
|
+
raise(Error, "this #{options[:table_alias] ? 'alias' : 'table'} has already been been used, please specify " \
|
92
|
+
"#{options[:table_alias] ? 'a different alias' : 'an alias via the :table_alias option'}")
|
93
|
+
end
|
94
|
+
|
95
|
+
# Only allow table aliases that haven't been used
|
96
|
+
raise_alias_error.call if @opts[:graph] && @opts[:graph][:table_aliases] && @opts[:graph][:table_aliases].include?(table_alias)
|
97
|
+
|
98
|
+
# Use a from_self if this is already a joined table
|
99
|
+
ds = (!@opts[:graph] && (@opts[:from].length > 1 || @opts[:join])) ? from_self(:alias=>options[:from_self_alias] || first_source) : self
|
100
|
+
|
101
|
+
# Join the table early in order to avoid cloning the dataset twice
|
102
|
+
ds = ds.join_table(options[:join_type] || :left_outer, table, join_conditions, :table_alias=>table_alias, :implicit_qualifier=>options[:implicit_qualifier], &block)
|
103
|
+
opts = ds.opts
|
104
|
+
|
105
|
+
# Whether to include the table in the result set
|
106
|
+
add_table = options[:select] == false ? false : true
|
107
|
+
# Whether to add the columns to the list of column aliases
|
108
|
+
add_columns = !ds.opts.include?(:graph_aliases)
|
109
|
+
|
110
|
+
# Setup the initial graph data structure if it doesn't exist
|
111
|
+
unless graph = opts[:graph]
|
112
|
+
master = alias_symbol(ds.first_source_alias)
|
113
|
+
raise_alias_error.call if master == table_alias
|
114
|
+
# Master hash storing all .graph related information
|
115
|
+
graph = opts[:graph] = {}
|
116
|
+
# Associates column aliases back to tables and columns
|
117
|
+
column_aliases = graph[:column_aliases] = {}
|
118
|
+
# Associates table alias (the master is never aliased)
|
119
|
+
table_aliases = graph[:table_aliases] = {master=>self}
|
120
|
+
# Keep track of the alias numbers used
|
121
|
+
ca_num = graph[:column_alias_num] = Hash.new(0)
|
122
|
+
# All columns in the master table are never
|
123
|
+
# aliased, but are not included if set_graph_aliases
|
124
|
+
# has been used.
|
125
|
+
if add_columns
|
126
|
+
select = opts[:select] = []
|
127
|
+
columns.each do |column|
|
128
|
+
column_aliases[column] = [master, column]
|
129
|
+
select.push(SQL::QualifiedIdentifier.new(master, column))
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
# Add the table alias to the list of aliases
|
135
|
+
# Even if it isn't been used in the result set,
|
136
|
+
# we add a key for it with a nil value so we can check if it
|
137
|
+
# is used more than once
|
138
|
+
table_aliases = graph[:table_aliases]
|
139
|
+
table_aliases[table_alias] = add_table ? dataset : nil
|
140
|
+
|
141
|
+
# Add the columns to the selection unless we are ignoring them
|
142
|
+
if add_table && add_columns
|
143
|
+
select = opts[:select]
|
144
|
+
column_aliases = graph[:column_aliases]
|
145
|
+
ca_num = graph[:column_alias_num]
|
146
|
+
# Which columns to add to the result set
|
147
|
+
cols = options[:select] || dataset.columns
|
148
|
+
# If the column hasn't been used yet, don't alias it.
|
149
|
+
# If it has been used, try table_column.
|
150
|
+
# If that has been used, try table_column_N
|
151
|
+
# using the next value of N that we know hasn't been
|
152
|
+
# used
|
153
|
+
cols.each do |column|
|
154
|
+
col_alias, identifier = if column_aliases[column]
|
155
|
+
column_alias = :"#{table_alias}_#{column}"
|
156
|
+
if column_aliases[column_alias]
|
157
|
+
column_alias_num = ca_num[column_alias]
|
158
|
+
column_alias = :"#{column_alias}_#{column_alias_num}"
|
159
|
+
ca_num[column_alias] += 1
|
160
|
+
end
|
161
|
+
[column_alias, SQL::QualifiedIdentifier.new(table_alias, column).as(column_alias)]
|
162
|
+
else
|
163
|
+
[column, SQL::QualifiedIdentifier.new(table_alias, column)]
|
164
|
+
end
|
165
|
+
column_aliases[col_alias] = [table_alias, column]
|
166
|
+
select.push(identifier)
|
167
|
+
end
|
168
|
+
end
|
169
|
+
ds
|
170
|
+
end
|
171
|
+
|
172
|
+
# This allows you to manually specify the graph aliases to use
|
173
|
+
# when using graph. You can use it to only select certain
|
174
|
+
# columns, and have those columns mapped to specific aliases
|
175
|
+
# in the result set. This is the equivalent of .select for a
|
176
|
+
# graphed dataset, and must be used instead of .select whenever
|
177
|
+
# graphing is used. Example:
|
178
|
+
#
|
179
|
+
# DB[:artists].graph(:albums, :artist_id=>:id).set_graph_aliases(:artist_name=>[:artists, :name], :album_name=>[:albums, :name], :forty_two=>[:albums, :fourtwo, 42]).first
|
180
|
+
# => {:artists=>{:name=>artists.name}, :albums=>{:name=>albums.name, :fourtwo=>42}}
|
181
|
+
#
|
182
|
+
# Arguments:
|
183
|
+
# * graph_aliases - Should be a hash with keys being symbols of
|
184
|
+
# column aliases, and values being arrays with two or three elements.
|
185
|
+
# The first element of the array should be the table alias symbol,
|
186
|
+
# and the second should be the actual column name symbol. If the array
|
187
|
+
# has a third element, it is used as the value returned, instead of
|
188
|
+
# table_alias.column_name.
|
189
|
+
def set_graph_aliases(graph_aliases)
|
190
|
+
ds = select(*graph_alias_columns(graph_aliases))
|
191
|
+
ds.opts[:graph_aliases] = graph_aliases
|
192
|
+
ds
|
193
|
+
end
|
194
|
+
|
195
|
+
# Remove the splitting of results into subhashes. Also removes
|
196
|
+
# metadata related to graphing, so you should not call graph
|
197
|
+
# any tables to this dataset after calling this method.
|
198
|
+
def ungraphed
|
199
|
+
clone(:graph=>nil)
|
200
|
+
end
|
201
|
+
|
202
|
+
private
|
203
|
+
|
204
|
+
# Transform the hash of graph aliases to an array of columns
|
205
|
+
def graph_alias_columns(graph_aliases)
|
206
|
+
graph_aliases.collect do |col_alias, tc|
|
207
|
+
identifier = tc[2] || SQL::QualifiedIdentifier.new(tc[0], tc[1])
|
208
|
+
identifier = SQL::AliasedExpression.new(identifier, col_alias) if tc[2] or tc[1] != col_alias
|
209
|
+
identifier
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Fetch the rows, split them into component table parts,
|
214
|
+
# tranform and run the row_proc on each part (if applicable),
|
215
|
+
# and yield a hash of the parts.
|
216
|
+
def graph_each
|
217
|
+
# Reject tables with nil datasets, as they are excluded from
|
218
|
+
# the result set
|
219
|
+
datasets = @opts[:graph][:table_aliases].to_a.reject{|ta,ds| ds.nil?}
|
220
|
+
# Get just the list of table aliases into a local variable, for speed
|
221
|
+
table_aliases = datasets.collect{|ta,ds| ta}
|
222
|
+
# Get an array of arrays, one for each dataset, with
|
223
|
+
# the necessary information about each dataset, for speed
|
224
|
+
datasets = datasets.collect{|ta, ds| [ta, ds, ds.row_proc]}
|
225
|
+
# Use the manually set graph aliases, if any, otherwise
|
226
|
+
# use the ones automatically created by .graph
|
227
|
+
column_aliases = @opts[:graph_aliases] || @opts[:graph][:column_aliases]
|
228
|
+
fetch_rows(select_sql) do |r|
|
229
|
+
graph = {}
|
230
|
+
# Create the sub hashes, one per table
|
231
|
+
table_aliases.each{|ta| graph[ta]={}}
|
232
|
+
# Split the result set based on the column aliases
|
233
|
+
# If there are columns in the result set that are
|
234
|
+
# not in column_aliases, they are ignored
|
235
|
+
column_aliases.each do |col_alias, tc|
|
236
|
+
ta, column = tc
|
237
|
+
graph[ta][column] = r[col_alias]
|
238
|
+
end
|
239
|
+
# For each dataset run the row_proc if applicable
|
240
|
+
datasets.each do |ta,ds,rp|
|
241
|
+
g = graph[ta]
|
242
|
+
graph[ta] = if g.values.any?{|x| !x.nil?}
|
243
|
+
rp ? rp.call(g) : g
|
244
|
+
else
|
245
|
+
nil
|
246
|
+
end
|
247
|
+
end
|
248
|
+
|
249
|
+
yield graph
|
250
|
+
end
|
251
|
+
self
|
252
|
+
end
|
253
|
+
end
|
254
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Sequel
|
2
|
+
class Dataset
|
3
|
+
# ---------------------
|
4
|
+
# :section: Miscellaneous methods
|
5
|
+
# These methods don't fit cleanly into another section.
|
6
|
+
# ---------------------
|
7
|
+
|
8
|
+
NOTIMPL_MSG = "This method must be overridden in Sequel adapters".freeze
|
9
|
+
ARRAY_ACCESS_ERROR_MSG = 'You cannot call Dataset#[] with an integer or with no arguments.'.freeze
|
10
|
+
ARG_BLOCK_ERROR_MSG = 'Must use either an argument or a block, not both'.freeze
|
11
|
+
IMPORT_ERROR_MSG = 'Using Sequel::Dataset#import an empty column array is not allowed'.freeze
|
12
|
+
|
13
|
+
# The database that corresponds to this dataset
|
14
|
+
attr_accessor :db
|
15
|
+
|
16
|
+
# The hash of options for this dataset, keys are symbols.
|
17
|
+
attr_accessor :opts
|
18
|
+
|
19
|
+
# Constructs a new Dataset instance with an associated database and
|
20
|
+
# options. Datasets are usually constructed by invoking the Database#[] method:
|
21
|
+
#
|
22
|
+
# DB[:posts]
|
23
|
+
#
|
24
|
+
# Sequel::Dataset is an abstract class that is not useful by itself. Each
|
25
|
+
# database adaptor should provide a subclass of Sequel::Dataset, and have
|
26
|
+
# the Database#dataset method return an instance of that class.
|
27
|
+
def initialize(db, opts = nil)
|
28
|
+
@db = db
|
29
|
+
@quote_identifiers = db.quote_identifiers? if db.respond_to?(:quote_identifiers?)
|
30
|
+
@identifier_input_method = db.identifier_input_method if db.respond_to?(:identifier_input_method)
|
31
|
+
@identifier_output_method = db.identifier_output_method if db.respond_to?(:identifier_output_method)
|
32
|
+
@opts = opts || {}
|
33
|
+
@row_proc = nil
|
34
|
+
end
|
35
|
+
|
36
|
+
# Return the dataset as an aliased expression with the given alias. You can
|
37
|
+
# use this as a FROM or JOIN dataset, or as a column if this dataset
|
38
|
+
# returns a single row and column.
|
39
|
+
def as(aliaz)
|
40
|
+
::Sequel::SQL::AliasedExpression.new(self, aliaz)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Yield a dataset for each server in the connection pool that is tied to that server.
|
44
|
+
# Intended for use in sharded environments where all servers need to be modified
|
45
|
+
# with the same data:
|
46
|
+
#
|
47
|
+
# DB[:configs].where(:key=>'setting').each_server{|ds| ds.update(:value=>'new_value')}
|
48
|
+
def each_server
|
49
|
+
db.servers.each{|s| yield server(s)}
|
50
|
+
end
|
51
|
+
|
52
|
+
# The first source (primary table) for this dataset. If the dataset doesn't
|
53
|
+
# have a table, raises an error. If the table is aliased, returns the aliased name.
|
54
|
+
def first_source_alias
|
55
|
+
source = @opts[:from]
|
56
|
+
if source.nil? || source.empty?
|
57
|
+
raise Error, 'No source specified for query'
|
58
|
+
end
|
59
|
+
case s = source.first
|
60
|
+
when SQL::AliasedExpression
|
61
|
+
s.aliaz
|
62
|
+
when Symbol
|
63
|
+
sch, table, aliaz = split_symbol(s)
|
64
|
+
aliaz ? aliaz.to_sym : s
|
65
|
+
else
|
66
|
+
s
|
67
|
+
end
|
68
|
+
end
|
69
|
+
alias first_source first_source_alias
|
70
|
+
|
71
|
+
# The first source (primary table) for this dataset. If the dataset doesn't
|
72
|
+
# have a table, raises an error. If the table is aliased, returns the original
|
73
|
+
# table, not the alias
|
74
|
+
def first_source_table
|
75
|
+
source = @opts[:from]
|
76
|
+
if source.nil? || source.empty?
|
77
|
+
raise Error, 'No source specified for query'
|
78
|
+
end
|
79
|
+
case s = source.first
|
80
|
+
when SQL::AliasedExpression
|
81
|
+
s.expression
|
82
|
+
when Symbol
|
83
|
+
sch, table, aliaz = split_symbol(s)
|
84
|
+
aliaz ? (sch ? SQL::QualifiedIdentifier.new(sch, table) : table.to_sym) : s
|
85
|
+
else
|
86
|
+
s
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
# Returns a string representation of the dataset including the class name
|
91
|
+
# and the corresponding SQL select statement.
|
92
|
+
def inspect
|
93
|
+
"#<#{self.class}: #{sql.inspect}>"
|
94
|
+
end
|
95
|
+
|
96
|
+
# Creates a unique table alias that hasn't already been used in the dataset.
|
97
|
+
# table_alias can be any type of object accepted by alias_symbol.
|
98
|
+
# The symbol returned will be the implicit alias in the argument,
|
99
|
+
# possibly appended with "_N" if the implicit alias has already been
|
100
|
+
# used, where N is an integer starting at 0 and increasing until an
|
101
|
+
# unused one is found.
|
102
|
+
def unused_table_alias(table_alias)
|
103
|
+
table_alias = alias_symbol(table_alias)
|
104
|
+
used_aliases = []
|
105
|
+
used_aliases += opts[:from].map{|t| alias_symbol(t)} if opts[:from]
|
106
|
+
used_aliases += opts[:join].map{|j| j.table_alias ? alias_alias_symbol(j.table_alias) : alias_symbol(j.table)} if opts[:join]
|
107
|
+
if used_aliases.include?(table_alias)
|
108
|
+
i = 0
|
109
|
+
loop do
|
110
|
+
ta = :"#{table_alias}_#{i}"
|
111
|
+
return ta unless used_aliases.include?(ta)
|
112
|
+
i += 1
|
113
|
+
end
|
114
|
+
else
|
115
|
+
table_alias
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|