sequel 3.10.0 → 3.11.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 +68 -0
- data/COPYING +1 -1
- data/README.rdoc +87 -27
- data/bin/sequel +2 -4
- data/doc/association_basics.rdoc +1383 -0
- data/doc/dataset_basics.rdoc +106 -0
- data/doc/opening_databases.rdoc +45 -16
- data/doc/querying.rdoc +210 -0
- data/doc/release_notes/3.11.0.txt +254 -0
- data/doc/virtual_rows.rdoc +217 -31
- data/lib/sequel/adapters/ado.rb +28 -12
- data/lib/sequel/adapters/ado/mssql.rb +33 -1
- data/lib/sequel/adapters/amalgalite.rb +13 -8
- data/lib/sequel/adapters/db2.rb +1 -2
- data/lib/sequel/adapters/dbi.rb +7 -4
- data/lib/sequel/adapters/do.rb +14 -15
- data/lib/sequel/adapters/do/postgres.rb +4 -5
- data/lib/sequel/adapters/do/sqlite.rb +9 -0
- data/lib/sequel/adapters/firebird.rb +5 -10
- data/lib/sequel/adapters/informix.rb +2 -4
- data/lib/sequel/adapters/jdbc.rb +111 -49
- data/lib/sequel/adapters/jdbc/mssql.rb +1 -2
- data/lib/sequel/adapters/jdbc/mysql.rb +11 -0
- data/lib/sequel/adapters/jdbc/oracle.rb +4 -7
- data/lib/sequel/adapters/jdbc/postgresql.rb +8 -1
- data/lib/sequel/adapters/jdbc/sqlite.rb +12 -0
- data/lib/sequel/adapters/mysql.rb +14 -5
- data/lib/sequel/adapters/odbc.rb +2 -4
- data/lib/sequel/adapters/odbc/mssql.rb +2 -4
- data/lib/sequel/adapters/openbase.rb +1 -2
- data/lib/sequel/adapters/oracle.rb +4 -8
- data/lib/sequel/adapters/postgres.rb +4 -11
- data/lib/sequel/adapters/shared/mssql.rb +22 -9
- data/lib/sequel/adapters/shared/mysql.rb +33 -30
- data/lib/sequel/adapters/shared/oracle.rb +0 -5
- data/lib/sequel/adapters/shared/postgres.rb +13 -11
- data/lib/sequel/adapters/shared/sqlite.rb +56 -10
- data/lib/sequel/adapters/sqlite.rb +16 -9
- data/lib/sequel/connection_pool.rb +6 -1
- data/lib/sequel/connection_pool/single.rb +1 -0
- data/lib/sequel/core.rb +6 -1
- data/lib/sequel/database.rb +52 -23
- data/lib/sequel/database/schema_generator.rb +6 -0
- data/lib/sequel/database/schema_methods.rb +5 -5
- data/lib/sequel/database/schema_sql.rb +1 -1
- data/lib/sequel/dataset.rb +4 -190
- data/lib/sequel/dataset/actions.rb +323 -1
- data/lib/sequel/dataset/features.rb +18 -2
- data/lib/sequel/dataset/graph.rb +7 -0
- data/lib/sequel/dataset/misc.rb +119 -0
- data/lib/sequel/dataset/mutation.rb +64 -0
- data/lib/sequel/dataset/prepared_statements.rb +6 -0
- data/lib/sequel/dataset/query.rb +272 -6
- data/lib/sequel/dataset/sql.rb +186 -394
- data/lib/sequel/model.rb +4 -2
- data/lib/sequel/model/associations.rb +31 -14
- data/lib/sequel/model/base.rb +32 -13
- data/lib/sequel/model/exceptions.rb +8 -4
- data/lib/sequel/model/plugins.rb +3 -13
- data/lib/sequel/plugins/active_model.rb +26 -7
- data/lib/sequel/plugins/instance_filters.rb +98 -0
- data/lib/sequel/plugins/many_through_many.rb +1 -1
- data/lib/sequel/plugins/optimistic_locking.rb +25 -9
- data/lib/sequel/version.rb +1 -1
- data/spec/adapters/mssql_spec.rb +26 -0
- data/spec/adapters/mysql_spec.rb +33 -4
- data/spec/adapters/postgres_spec.rb +24 -1
- data/spec/adapters/spec_helper.rb +6 -0
- data/spec/adapters/sqlite_spec.rb +28 -0
- data/spec/core/connection_pool_spec.rb +17 -5
- data/spec/core/database_spec.rb +101 -1
- data/spec/core/dataset_spec.rb +42 -4
- data/spec/core/schema_spec.rb +13 -0
- data/spec/extensions/active_model_spec.rb +34 -11
- data/spec/extensions/caching_spec.rb +2 -0
- data/spec/extensions/instance_filters_spec.rb +55 -0
- data/spec/extensions/spec_helper.rb +2 -0
- data/spec/integration/dataset_test.rb +12 -1
- data/spec/integration/model_test.rb +12 -0
- data/spec/integration/plugin_test.rb +61 -1
- data/spec/integration/schema_test.rb +14 -3
- data/spec/model/base_spec.rb +27 -0
- data/spec/model/plugins_spec.rb +0 -22
- data/spec/model/record_spec.rb +32 -1
- data/spec/model/spec_helper.rb +2 -0
- metadata +14 -3
- data/lib/sequel/dataset/convenience.rb +0 -326
data/spec/model/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sequel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jeremy Evans
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2010-
|
12
|
+
date: 2010-05-03 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|
@@ -32,6 +32,9 @@ extra_rdoc_files:
|
|
32
32
|
- doc/schema.rdoc
|
33
33
|
- doc/sharding.rdoc
|
34
34
|
- doc/virtual_rows.rdoc
|
35
|
+
- doc/dataset_basics.rdoc
|
36
|
+
- doc/association_basics.rdoc
|
37
|
+
- doc/querying.rdoc
|
35
38
|
- doc/release_notes/1.0.txt
|
36
39
|
- doc/release_notes/1.1.txt
|
37
40
|
- doc/release_notes/1.3.txt
|
@@ -61,6 +64,7 @@ extra_rdoc_files:
|
|
61
64
|
- doc/release_notes/3.8.0.txt
|
62
65
|
- doc/release_notes/3.9.0.txt
|
63
66
|
- doc/release_notes/3.10.0.txt
|
67
|
+
- doc/release_notes/3.11.0.txt
|
64
68
|
files:
|
65
69
|
- COPYING
|
66
70
|
- CHANGELOG
|
@@ -102,9 +106,13 @@ files:
|
|
102
106
|
- doc/release_notes/3.8.0.txt
|
103
107
|
- doc/release_notes/3.9.0.txt
|
104
108
|
- doc/release_notes/3.10.0.txt
|
109
|
+
- doc/release_notes/3.11.0.txt
|
105
110
|
- doc/schema.rdoc
|
106
111
|
- doc/sharding.rdoc
|
107
112
|
- doc/virtual_rows.rdoc
|
113
|
+
- doc/dataset_basics.rdoc
|
114
|
+
- doc/association_basics.rdoc
|
115
|
+
- doc/querying.rdoc
|
108
116
|
- spec/adapters/firebird_spec.rb
|
109
117
|
- spec/adapters/informix_spec.rb
|
110
118
|
- spec/adapters/mssql_spec.rb
|
@@ -162,6 +170,7 @@ files:
|
|
162
170
|
- spec/extensions/validation_helpers_spec.rb
|
163
171
|
- spec/extensions/composition_spec.rb
|
164
172
|
- spec/extensions/rcte_tree_spec.rb
|
173
|
+
- spec/extensions/instance_filters_spec.rb
|
165
174
|
- spec/integration/associations_test.rb
|
166
175
|
- spec/integration/database_test.rb
|
167
176
|
- spec/integration/dataset_test.rb
|
@@ -236,12 +245,13 @@ files:
|
|
236
245
|
- lib/sequel/database/schema_sql.rb
|
237
246
|
- lib/sequel/dataset.rb
|
238
247
|
- lib/sequel/dataset/actions.rb
|
239
|
-
- lib/sequel/dataset/convenience.rb
|
240
248
|
- lib/sequel/dataset/features.rb
|
241
249
|
- lib/sequel/dataset/graph.rb
|
250
|
+
- lib/sequel/dataset/misc.rb
|
242
251
|
- lib/sequel/dataset/prepared_statements.rb
|
243
252
|
- lib/sequel/dataset/query.rb
|
244
253
|
- lib/sequel/dataset/sql.rb
|
254
|
+
- lib/sequel/dataset/mutation.rb
|
245
255
|
- lib/sequel/exceptions.rb
|
246
256
|
- lib/sequel/extensions/blank.rb
|
247
257
|
- lib/sequel/extensions/inflector.rb
|
@@ -290,6 +300,7 @@ files:
|
|
290
300
|
- lib/sequel/plugins/validation_helpers.rb
|
291
301
|
- lib/sequel/plugins/composition.rb
|
292
302
|
- lib/sequel/plugins/rcte_tree.rb
|
303
|
+
- lib/sequel/plugins/instance_filters.rb
|
293
304
|
- lib/sequel/sql.rb
|
294
305
|
- lib/sequel/timezones.rb
|
295
306
|
- lib/sequel/version.rb
|
@@ -1,326 +0,0 @@
|
|
1
|
-
module Sequel
|
2
|
-
class Dataset
|
3
|
-
COMMA_SEPARATOR = ', '.freeze
|
4
|
-
COUNT_OF_ALL_AS_COUNT = SQL::Function.new(:count, LiteralString.new('*'.freeze)).as(:count)
|
5
|
-
ARRAY_ACCESS_ERROR_MSG = 'You cannot call Dataset#[] with an integer or with no arguments.'.freeze
|
6
|
-
ARG_BLOCK_ERROR_MSG = 'Must use either an argument or a block, not both'.freeze
|
7
|
-
IMPORT_ERROR_MSG = 'Using Sequel::Dataset#import an empty column array is not allowed'.freeze
|
8
|
-
|
9
|
-
# Returns the first record matching the conditions. Examples:
|
10
|
-
#
|
11
|
-
# ds[:id=>1] => {:id=1}
|
12
|
-
def [](*conditions)
|
13
|
-
raise(Error, ARRAY_ACCESS_ERROR_MSG) if (conditions.length == 1 and conditions.first.is_a?(Integer)) or conditions.length == 0
|
14
|
-
first(*conditions)
|
15
|
-
end
|
16
|
-
|
17
|
-
# Update all records matching the conditions
|
18
|
-
# with the values specified. Examples:
|
19
|
-
#
|
20
|
-
# ds[:id=>1] = {:id=>2} # SQL: UPDATE ... SET id = 2 WHERE id = 1
|
21
|
-
def []=(conditions, values)
|
22
|
-
filter(conditions).update(values)
|
23
|
-
end
|
24
|
-
|
25
|
-
# Returns the average value for the given column.
|
26
|
-
def avg(column)
|
27
|
-
aggregate_dataset.get{avg(column)}
|
28
|
-
end
|
29
|
-
|
30
|
-
# Returns true if no records exist in the dataset, false otherwise
|
31
|
-
def empty?
|
32
|
-
get(1).nil?
|
33
|
-
end
|
34
|
-
|
35
|
-
# If a integer argument is
|
36
|
-
# given, it is interpreted as a limit, and then returns all
|
37
|
-
# matching records up to that limit. If no argument is passed,
|
38
|
-
# it returns the first matching record. If any other type of
|
39
|
-
# argument(s) is passed, it is given to filter and the
|
40
|
-
# first matching record is returned. If a block is given, it is used
|
41
|
-
# to filter the dataset before returning anything. Examples:
|
42
|
-
#
|
43
|
-
# ds.first => {:id=>7}
|
44
|
-
# ds.first(2) => [{:id=>6}, {:id=>4}]
|
45
|
-
# ds.order(:id).first(2) => [{:id=>1}, {:id=>2}]
|
46
|
-
# ds.first(:id=>2) => {:id=>2}
|
47
|
-
# ds.first("id = 3") => {:id=>3}
|
48
|
-
# ds.first("id = ?", 4) => {:id=>4}
|
49
|
-
# ds.first{|o| o.id > 2} => {:id=>5}
|
50
|
-
# ds.order(:id).first{|o| o.id > 2} => {:id=>3}
|
51
|
-
# ds.first{|o| o.id > 2} => {:id=>5}
|
52
|
-
# ds.first("id > ?", 4){|o| o.id < 6} => {:id=>5}
|
53
|
-
# ds.order(:id).first(2){|o| o.id < 2} => [{:id=>1}]
|
54
|
-
def first(*args, &block)
|
55
|
-
ds = block ? filter(&block) : self
|
56
|
-
|
57
|
-
if args.empty?
|
58
|
-
ds.single_record
|
59
|
-
else
|
60
|
-
args = (args.size == 1) ? args.first : args
|
61
|
-
if Integer === args
|
62
|
-
ds.limit(args).all
|
63
|
-
else
|
64
|
-
ds.filter(args).single_record
|
65
|
-
end
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
# Return the column value for the first matching record in the dataset.
|
70
|
-
# Raises an error if both an argument and block is given.
|
71
|
-
#
|
72
|
-
# ds.get(:id)
|
73
|
-
# ds.get{|o| o.sum(:id)}
|
74
|
-
def get(column=nil, &block)
|
75
|
-
if column
|
76
|
-
raise(Error, ARG_BLOCK_ERROR_MSG) if block
|
77
|
-
select(column).single_value
|
78
|
-
else
|
79
|
-
select(&block).single_value
|
80
|
-
end
|
81
|
-
end
|
82
|
-
|
83
|
-
# Returns a dataset grouped by the given column with count by group,
|
84
|
-
# order by the count of records. Column aliases may be supplied, and will
|
85
|
-
# be included in the select clause.
|
86
|
-
#
|
87
|
-
# Examples:
|
88
|
-
#
|
89
|
-
# ds.group_and_count(:name).all => [{:name=>'a', :count=>1}, ...]
|
90
|
-
# ds.group_and_count(:first_name, :last_name).all => [{:first_name=>'a', :last_name=>'b', :count=>1}, ...]
|
91
|
-
# ds.group_and_count(:first_name___name).all => [{:name=>'a', :count=>1}, ...]
|
92
|
-
def group_and_count(*columns)
|
93
|
-
group(*columns.map{|c| unaliased_identifier(c)}).select(*(columns + [COUNT_OF_ALL_AS_COUNT]))
|
94
|
-
end
|
95
|
-
|
96
|
-
# Inserts multiple records into the associated table. This method can be
|
97
|
-
# to efficiently insert a large amounts of records into a table. Inserts
|
98
|
-
# are automatically wrapped in a transaction.
|
99
|
-
#
|
100
|
-
# This method is called with a columns array and an array of value arrays:
|
101
|
-
#
|
102
|
-
# dataset.import([:x, :y], [[1, 2], [3, 4]])
|
103
|
-
#
|
104
|
-
# This method also accepts a dataset instead of an array of value arrays:
|
105
|
-
#
|
106
|
-
# dataset.import([:x, :y], other_dataset.select(:a___x, :b___y))
|
107
|
-
#
|
108
|
-
# The method also accepts a :slice or :commit_every option that specifies
|
109
|
-
# the number of records to insert per transaction. This is useful especially
|
110
|
-
# when inserting a large number of records, e.g.:
|
111
|
-
#
|
112
|
-
# # this will commit every 50 records
|
113
|
-
# dataset.import([:x, :y], [[1, 2], [3, 4], ...], :slice => 50)
|
114
|
-
def import(columns, values, opts={})
|
115
|
-
return @db.transaction{insert(columns, values)} if values.is_a?(Dataset)
|
116
|
-
|
117
|
-
return if values.empty?
|
118
|
-
raise(Error, IMPORT_ERROR_MSG) if columns.empty?
|
119
|
-
|
120
|
-
if slice_size = opts[:commit_every] || opts[:slice]
|
121
|
-
offset = 0
|
122
|
-
loop do
|
123
|
-
@db.transaction(opts){multi_insert_sql(columns, values[offset, slice_size]).each{|st| execute_dui(st)}}
|
124
|
-
offset += slice_size
|
125
|
-
break if offset >= values.length
|
126
|
-
end
|
127
|
-
else
|
128
|
-
statements = multi_insert_sql(columns, values)
|
129
|
-
@db.transaction{statements.each{|st| execute_dui(st)}}
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
# Returns the interval between minimum and maximum values for the given
|
134
|
-
# column.
|
135
|
-
def interval(column)
|
136
|
-
aggregate_dataset.get{max(column) - min(column)}
|
137
|
-
end
|
138
|
-
|
139
|
-
# Reverses the order and then runs first. Note that this
|
140
|
-
# will not necessarily give you the last record in the dataset,
|
141
|
-
# unless you have an unambiguous order. If there is not
|
142
|
-
# currently an order for this dataset, raises an Error.
|
143
|
-
def last(*args, &block)
|
144
|
-
raise(Error, 'No order specified') unless @opts[:order]
|
145
|
-
reverse.first(*args, &block)
|
146
|
-
end
|
147
|
-
|
148
|
-
# Maps column values for each record in the dataset (if a column name is
|
149
|
-
# given), or performs the stock mapping functionality of Enumerable.
|
150
|
-
# Raises an error if both an argument and block are given. Examples:
|
151
|
-
#
|
152
|
-
# ds.map(:id) => [1, 2, 3, ...]
|
153
|
-
# ds.map{|r| r[:id] * 2} => [2, 4, 6, ...]
|
154
|
-
def map(column=nil, &block)
|
155
|
-
if column
|
156
|
-
raise(Error, ARG_BLOCK_ERROR_MSG) if block
|
157
|
-
super(){|r| r[column]}
|
158
|
-
else
|
159
|
-
super(&block)
|
160
|
-
end
|
161
|
-
end
|
162
|
-
|
163
|
-
# Returns the maximum value for the given column.
|
164
|
-
def max(column)
|
165
|
-
aggregate_dataset.get{max(column)}
|
166
|
-
end
|
167
|
-
|
168
|
-
# Returns the minimum value for the given column.
|
169
|
-
def min(column)
|
170
|
-
aggregate_dataset.get{min(column)}
|
171
|
-
end
|
172
|
-
|
173
|
-
# This is a front end for import that allows you to submit an array of
|
174
|
-
# hashes instead of arrays of columns and values:
|
175
|
-
#
|
176
|
-
# dataset.multi_insert([{:x => 1}, {:x => 2}])
|
177
|
-
#
|
178
|
-
# Be aware that all hashes should have the same keys if you use this calling method,
|
179
|
-
# otherwise some columns could be missed or set to null instead of to default
|
180
|
-
# values.
|
181
|
-
#
|
182
|
-
# You can also use the :slice or :commit_every option that import accepts.
|
183
|
-
def multi_insert(hashes, opts={})
|
184
|
-
return if hashes.empty?
|
185
|
-
columns = hashes.first.keys
|
186
|
-
import(columns, hashes.map{|h| columns.map{|c| h[c]}}, opts)
|
187
|
-
end
|
188
|
-
|
189
|
-
# Returns a Range object made from the minimum and maximum values for the
|
190
|
-
# given column.
|
191
|
-
def range(column)
|
192
|
-
if r = aggregate_dataset.select{[min(column).as(v1), max(column).as(v2)]}.first
|
193
|
-
(r[:v1]..r[:v2])
|
194
|
-
end
|
195
|
-
end
|
196
|
-
|
197
|
-
# Returns a hash with key_column values as keys and value_column values as
|
198
|
-
# values. Similar to to_hash, but only selects the two columns.
|
199
|
-
def select_hash(key_column, value_column)
|
200
|
-
select(key_column, value_column).to_hash(hash_key_symbol(key_column), hash_key_symbol(value_column))
|
201
|
-
end
|
202
|
-
|
203
|
-
# Selects the column given (either as an argument or as a block), and
|
204
|
-
# returns an array of all values of that column in the dataset. If you
|
205
|
-
# give a block argument that returns an array with multiple entries,
|
206
|
-
# the contents of the resulting array are undefined.
|
207
|
-
def select_map(column=nil, &block)
|
208
|
-
ds = naked.ungraphed
|
209
|
-
ds = if column
|
210
|
-
raise(Error, ARG_BLOCK_ERROR_MSG) if block
|
211
|
-
ds.select(column)
|
212
|
-
else
|
213
|
-
ds.select(&block)
|
214
|
-
end
|
215
|
-
ds.map{|r| r.values.first}
|
216
|
-
end
|
217
|
-
|
218
|
-
# The same as select_map, but in addition orders the array by the column.
|
219
|
-
def select_order_map(column=nil, &block)
|
220
|
-
ds = naked.ungraphed
|
221
|
-
ds = if column
|
222
|
-
raise(Error, ARG_BLOCK_ERROR_MSG) if block
|
223
|
-
ds.select(column).order(unaliased_identifier(column))
|
224
|
-
else
|
225
|
-
ds.select(&block).order(&block)
|
226
|
-
end
|
227
|
-
ds.map{|r| r.values.first}
|
228
|
-
end
|
229
|
-
|
230
|
-
# Returns the first record in the dataset.
|
231
|
-
def single_record
|
232
|
-
clone(:limit=>1).each{|r| return r}
|
233
|
-
nil
|
234
|
-
end
|
235
|
-
|
236
|
-
# Returns the first value of the first record in the dataset.
|
237
|
-
# Returns nil if dataset is empty.
|
238
|
-
def single_value
|
239
|
-
if r = naked.ungraphed.single_record
|
240
|
-
r.values.first
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
# Returns the sum for the given column.
|
245
|
-
def sum(column)
|
246
|
-
aggregate_dataset.get{sum(column)}
|
247
|
-
end
|
248
|
-
|
249
|
-
# Returns a string in CSV format containing the dataset records. By
|
250
|
-
# default the CSV representation includes the column titles in the
|
251
|
-
# first line. You can turn that off by passing false as the
|
252
|
-
# include_column_titles argument.
|
253
|
-
#
|
254
|
-
# This does not use a CSV library or handle quoting of values in
|
255
|
-
# any way. If any values in any of the rows could include commas or line
|
256
|
-
# endings, you shouldn't use this.
|
257
|
-
def to_csv(include_column_titles = true)
|
258
|
-
n = naked
|
259
|
-
cols = n.columns
|
260
|
-
csv = ''
|
261
|
-
csv << "#{cols.join(COMMA_SEPARATOR)}\r\n" if include_column_titles
|
262
|
-
n.each{|r| csv << "#{cols.collect{|c| r[c]}.join(COMMA_SEPARATOR)}\r\n"}
|
263
|
-
csv
|
264
|
-
end
|
265
|
-
|
266
|
-
# Returns a hash with one column used as key and another used as value.
|
267
|
-
# If rows have duplicate values for the key column, the latter row(s)
|
268
|
-
# will overwrite the value of the previous row(s). If the value_column
|
269
|
-
# is not given or nil, uses the entire hash as the value.
|
270
|
-
def to_hash(key_column, value_column = nil)
|
271
|
-
inject({}) do |m, r|
|
272
|
-
m[r[key_column]] = value_column ? r[value_column] : r
|
273
|
-
m
|
274
|
-
end
|
275
|
-
end
|
276
|
-
|
277
|
-
# Creates a unique table alias that hasn't already been used in the dataset.
|
278
|
-
# table_alias can be any type of object accepted by alias_symbol.
|
279
|
-
# The symbol returned will be the implicit alias in the argument,
|
280
|
-
# possibly appended with "_N" if the implicit alias has already been
|
281
|
-
# used, where N is an integer starting at 0 and increasing until an
|
282
|
-
# unused one is found.
|
283
|
-
def unused_table_alias(table_alias)
|
284
|
-
table_alias = alias_symbol(table_alias)
|
285
|
-
used_aliases = []
|
286
|
-
used_aliases += opts[:from].map{|t| alias_symbol(t)} if opts[:from]
|
287
|
-
used_aliases += opts[:join].map{|j| j.table_alias ? alias_alias_symbol(j.table_alias) : alias_symbol(j.table)} if opts[:join]
|
288
|
-
if used_aliases.include?(table_alias)
|
289
|
-
i = 0
|
290
|
-
loop do
|
291
|
-
ta = :"#{table_alias}_#{i}"
|
292
|
-
return ta unless used_aliases.include?(ta)
|
293
|
-
i += 1
|
294
|
-
end
|
295
|
-
else
|
296
|
-
table_alias
|
297
|
-
end
|
298
|
-
end
|
299
|
-
|
300
|
-
private
|
301
|
-
|
302
|
-
# Return a plain symbol given a potentially qualified or aliased symbol,
|
303
|
-
# specifying the symbol that is likely to be used as the hash key
|
304
|
-
# for the column when records are returned.
|
305
|
-
def hash_key_symbol(s)
|
306
|
-
raise(Error, "#{s.inspect} is not a symbol") unless s.is_a?(Symbol)
|
307
|
-
_, c, a = split_symbol(s)
|
308
|
-
(a || c).to_sym
|
309
|
-
end
|
310
|
-
|
311
|
-
# Return the unaliased part of the identifier. Handles both
|
312
|
-
# implicit aliases in symbols, as well as SQL::AliasedExpression
|
313
|
-
# objects. Other objects are returned as is.
|
314
|
-
def unaliased_identifier(c)
|
315
|
-
case c
|
316
|
-
when Symbol
|
317
|
-
c_table, column, _ = split_symbol(c)
|
318
|
-
c_table ? column.to_sym.qualify(c_table) : column.to_sym
|
319
|
-
when SQL::AliasedExpression
|
320
|
-
c.expression
|
321
|
-
else
|
322
|
-
c
|
323
|
-
end
|
324
|
-
end
|
325
|
-
end
|
326
|
-
end
|