viking-sequel 3.10.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.
- 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
|