sequel-select-order-clauses 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +22 -0
- data/Gemfile +10 -0
- data/LICENSE.txt +22 -0
- data/README.md +1 -0
- data/Rakefile +3 -0
- data/lib/sequel-select-order-clauses.rb +3 -0
- data/lib/sequel/extensions/select_order_clauses.rb +237 -0
- data/lib/sequel/extensions/select_order_clauses/version.rb +7 -0
- data/sequel-select-order-clauses.gemspec +26 -0
- data/spec/select_order_clauses_spec.rb +227 -0
- data/spec/spec_helper.rb +19 -0
- data/tasks/specs.rb +10 -0
- metadata +114 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 4596afa94f19b82c39ae79479131ff6c60643740
|
4
|
+
data.tar.gz: 1eb6f016f4d7ea86d33891dc3cb85b1e508b0f16
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0dd46ee1b0e93733b06ba789868d0c0990433bf75cf530e8ea2afb6a33566194d3f62607549ba88827abe0aa9fbafae05561b92b7e72fc9b7b94f356e1fb0ed4
|
7
|
+
data.tar.gz: cb3caecd7a4132fb3fd74339b0d8c91d8894960a0b8dd6e5d82080c1385e65e534665a208d7ef69fd4ee6d8dbd35340b72b10806b443c4f3ad0f2f5229bed654
|
data/.gitignore
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
*.gem
|
2
|
+
*.rbc
|
3
|
+
.bundle
|
4
|
+
.config
|
5
|
+
.yardoc
|
6
|
+
Gemfile.lock
|
7
|
+
InstalledFiles
|
8
|
+
_yardoc
|
9
|
+
coverage
|
10
|
+
doc/
|
11
|
+
lib/bundler/man
|
12
|
+
pkg
|
13
|
+
rdoc
|
14
|
+
spec/reports
|
15
|
+
test/tmp
|
16
|
+
test/version_tmp
|
17
|
+
tmp
|
18
|
+
*.bundle
|
19
|
+
*.so
|
20
|
+
*.o
|
21
|
+
*.a
|
22
|
+
mkmf.log
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2016 Chris Hanks
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
# Sequel::SelectOrderClauses
|
data/Rakefile
ADDED
@@ -0,0 +1,237 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'sequel'
|
4
|
+
require 'sequel/extensions/select_order_clauses/version'
|
5
|
+
|
6
|
+
module Sequel
|
7
|
+
module SelectOrderClauses
|
8
|
+
def append_order_as_selection
|
9
|
+
return self unless order = @opts[:order]
|
10
|
+
return self if @opts[:order_info]
|
11
|
+
|
12
|
+
# Note that since we're iterating over the order to return a modified
|
13
|
+
# version of this dataset, we can't modify the order in this method and
|
14
|
+
# remain sensible.
|
15
|
+
ds = self
|
16
|
+
|
17
|
+
selections = extract_selections(ds).map { |s| normalize_selection(s) }
|
18
|
+
|
19
|
+
order_info =
|
20
|
+
order.map.with_index do |o, index|
|
21
|
+
exp = normalize_expression(unwrap_order_expression(o))
|
22
|
+
dir = extract_direction(o)
|
23
|
+
|
24
|
+
# Try to figure out which of the select expressions is going to
|
25
|
+
# correspond to this order expression. This heuristic may not be
|
26
|
+
# perfect, but do our best and raise an error if we find more than one
|
27
|
+
# selection.
|
28
|
+
expression_selects =
|
29
|
+
selections.select do |s|
|
30
|
+
selection_satisfies_expression?(s, exp)
|
31
|
+
end
|
32
|
+
|
33
|
+
name =
|
34
|
+
case expression_selects.length
|
35
|
+
when 0 then nil
|
36
|
+
when 1
|
37
|
+
expression_select = expression_selects.first
|
38
|
+
|
39
|
+
# Once we have the SELECT expression that matches our ORDER BY
|
40
|
+
# expression, we just extract its name so that we'll be able to
|
41
|
+
# figure out how we sorted records later on. The exception is if
|
42
|
+
# the matching SELECT expression is "table".* - in that case
|
43
|
+
# we'll need to get the name from the ORDER BY expression.
|
44
|
+
target_expression =
|
45
|
+
if expression_select.is_a?(Sequel::SQL::ColumnAll)
|
46
|
+
exp
|
47
|
+
else
|
48
|
+
expression_select
|
49
|
+
end
|
50
|
+
|
51
|
+
extract_expression_name(target_expression)
|
52
|
+
else
|
53
|
+
raise "Found more than one selection in #{inspect} that matched the expression #{exp.inspect}: #{expression_selects.inspect}"
|
54
|
+
end
|
55
|
+
|
56
|
+
# After all that, we still might not have been able to get a name.
|
57
|
+
# In that case, just append the ORDER BY expression to the SELECT
|
58
|
+
# clause with a special alias that we'll use later.
|
59
|
+
unless name
|
60
|
+
name = "order_#{index}".to_sym
|
61
|
+
ds = ds.select_append(Sequel.as(exp, name))
|
62
|
+
end
|
63
|
+
|
64
|
+
{name: name, direction: dir}
|
65
|
+
end
|
66
|
+
|
67
|
+
ds.clone(order_info: order_info)
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
# Our inputs should have already been simplified and normalized to the
|
73
|
+
# extent possible, now the nitty-gritty of defining whatever equality
|
74
|
+
# logic we really need to for them.
|
75
|
+
|
76
|
+
# The question at hand: can we safely assume that this expression in the
|
77
|
+
# SELECT clause will always represent this expression in the ORDER BY?
|
78
|
+
def selection_satisfies_expression?(s, e)
|
79
|
+
case s
|
80
|
+
when Sequel::SQL::AliasedExpression
|
81
|
+
# Order expressions can be simple references to aliases, which is a
|
82
|
+
# pretty simple and useful case to check for. In other words:
|
83
|
+
# `SELECT function() AS my_value FROM table ORDER BY my_value`
|
84
|
+
if e.is_a?(Symbol) && s.aliaz == e
|
85
|
+
true
|
86
|
+
else
|
87
|
+
# Otherwise, see whether the expression being aliased does what we
|
88
|
+
# want. For example:
|
89
|
+
# `SELECT function() AS my_value FROM table ORDER BY function()`
|
90
|
+
selection_satisfies_expression?(normalize_selection(s.expression), e)
|
91
|
+
end
|
92
|
+
when Sequel::SQL::QualifiedIdentifier
|
93
|
+
# SELECT "table"."column"
|
94
|
+
case e
|
95
|
+
when Symbol
|
96
|
+
# SELECT "table"."column" FROM "table" ORDER BY "column"
|
97
|
+
s.column == e
|
98
|
+
when Sequel::SQL::QualifiedIdentifier
|
99
|
+
# SELECT "table"."column" FROM "table" ORDER BY "table"."column"
|
100
|
+
s == e
|
101
|
+
end
|
102
|
+
when Sequel::SQL::ColumnAll
|
103
|
+
# SELECT "table".*
|
104
|
+
case e
|
105
|
+
when Sequel::SQL::QualifiedIdentifier
|
106
|
+
# Satisfies any column anchored on that table...
|
107
|
+
s.table == e.table
|
108
|
+
when Symbol
|
109
|
+
# ...or a plain column reference that we can verify lives on this
|
110
|
+
# model. Note that m.columns.include?(e) would leave out
|
111
|
+
# lazy-loaded columns.
|
112
|
+
respond_to?(:model) &&
|
113
|
+
(m = model) &&
|
114
|
+
m.table_name == s.table &&
|
115
|
+
m.db_schema.has_key?(e)
|
116
|
+
end
|
117
|
+
else
|
118
|
+
# These values could be anything - functions, mathematical operations,
|
119
|
+
# literal SQL strings, etc. Just try for simple equality.
|
120
|
+
s == e
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
# In addition to the common normalization logic in normalize_expression(),
|
125
|
+
# which can be applied to expressions in either the SELECT or ORDER BY
|
126
|
+
# clauses, this method encapsulates an assumption that is safe to make
|
127
|
+
# about expressions in SELECT but not in ORDER BY, that a simple
|
128
|
+
# identifier (a symbol) on a single-source dataset must refer to a column
|
129
|
+
# in the table. In an ORDER BY clause it could also refer to an alias in
|
130
|
+
# the SELECT clause.
|
131
|
+
def normalize_selection(s)
|
132
|
+
s = normalize_expression(s)
|
133
|
+
|
134
|
+
case s
|
135
|
+
when Symbol
|
136
|
+
if joined_dataset?
|
137
|
+
s # Can't make any assumptions about the source table.
|
138
|
+
else
|
139
|
+
Sequel.qualify(first_source, s)
|
140
|
+
end
|
141
|
+
else
|
142
|
+
s
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
# Move more esoteric Sequel types to the baseline of symbols representing
|
147
|
+
# identifiers and QualifiedIdentifiers representing table-column pairs, so
|
148
|
+
# that it's easier for us to do comparisons without needing to define
|
149
|
+
# equality logic between every combination of classes in the Sequel AST.
|
150
|
+
def normalize_expression(expression)
|
151
|
+
case expression
|
152
|
+
when Symbol
|
153
|
+
# Take care of symbol notations like :table__column___alias.
|
154
|
+
table, column, aliaz =
|
155
|
+
Sequel.split_symbol(expression).map { |part| part&.to_sym }
|
156
|
+
|
157
|
+
exp = table ? Sequel.qualify(table, column) : column
|
158
|
+
exp = Sequel.as(exp, aliaz) if aliaz
|
159
|
+
exp
|
160
|
+
when Sequel::SQL::Identifier
|
161
|
+
# Identifier objects have their uses, but not here, where a symbol is
|
162
|
+
# just fine.
|
163
|
+
expression.value.to_sym
|
164
|
+
when Sequel::SQL::QualifiedIdentifier
|
165
|
+
t = expression.table
|
166
|
+
c = expression.column
|
167
|
+
|
168
|
+
if t.is_a?(Symbol) && c.is_a?(Symbol)
|
169
|
+
expression
|
170
|
+
else
|
171
|
+
Sequel::SQL::QualifiedIdentifier.new(
|
172
|
+
normalize_expression(t),
|
173
|
+
normalize_expression(c),
|
174
|
+
)
|
175
|
+
end
|
176
|
+
else
|
177
|
+
# Other arbitrary expressions can just be passed through.
|
178
|
+
expression
|
179
|
+
end
|
180
|
+
end
|
181
|
+
|
182
|
+
def extract_selections(ds)
|
183
|
+
if selections = ds.opts[:select]
|
184
|
+
return selections
|
185
|
+
end
|
186
|
+
|
187
|
+
if (froms = ds.opts[:from]) && froms.length == 1
|
188
|
+
from = unwrap_alias(froms.first)
|
189
|
+
if from.is_a?(Sequel::Dataset)
|
190
|
+
extract_selections(from)
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
def extract_expression_name(expression)
|
196
|
+
case expression
|
197
|
+
when Symbol
|
198
|
+
expression
|
199
|
+
when Sequel::SQL::AliasedExpression
|
200
|
+
expression.aliaz
|
201
|
+
when Sequel::SQL::Identifier
|
202
|
+
extract_expression_name(expression.value)
|
203
|
+
when Sequel::SQL::QualifiedIdentifier
|
204
|
+
extract_expression_name(expression.column)
|
205
|
+
end
|
206
|
+
end
|
207
|
+
|
208
|
+
def unwrap_order_expression(order)
|
209
|
+
case order
|
210
|
+
when Sequel::SQL::OrderedExpression
|
211
|
+
order.expression
|
212
|
+
else
|
213
|
+
order
|
214
|
+
end
|
215
|
+
end
|
216
|
+
|
217
|
+
def unwrap_alias(expression)
|
218
|
+
case expression
|
219
|
+
when Sequel::SQL::AliasedExpression
|
220
|
+
expression.expression
|
221
|
+
else
|
222
|
+
expression
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def extract_direction(order)
|
227
|
+
case order
|
228
|
+
when Sequel::SQL::OrderedExpression
|
229
|
+
order.descending ? :desc : :asc
|
230
|
+
else
|
231
|
+
:asc
|
232
|
+
end
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
Dataset.register_extension(:select_order_clauses, SelectOrderClauses)
|
237
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'sequel/extensions/select_order_clauses/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'sequel-select-order-clauses'
|
8
|
+
spec.version = Sequel::SelectOrderClauses::VERSION
|
9
|
+
spec.authors = ["Chris Hanks"]
|
10
|
+
spec.email = ['christopher.m.hanks@gmail.com']
|
11
|
+
spec.summary = %q{Select the order clauses in a dataset}
|
12
|
+
spec.description = %q{Simple support for selecting the order clauses in a dataset}
|
13
|
+
spec.homepage = 'https://github.com/chanks/sequel-select-order-clauses'
|
14
|
+
spec.license = 'MIT'
|
15
|
+
|
16
|
+
spec.files = `git ls-files -z`.split("\x0")
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'bundler', '~> 1.6'
|
22
|
+
spec.add_development_dependency 'rake'
|
23
|
+
spec.add_development_dependency 'sqlite3'
|
24
|
+
|
25
|
+
spec.add_dependency 'sequel', '~> 4.0'
|
26
|
+
end
|
@@ -0,0 +1,227 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class SelectOrderClausesSpec < Minitest::Spec
|
4
|
+
it "should have a version" do
|
5
|
+
assert Sequel::SelectOrderClauses::VERSION.is_a?(String)
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "append_order_as_selection" do
|
9
|
+
def assert_order_append(ds:, selects_to_append:, order_names:)
|
10
|
+
initial = ds
|
11
|
+
final = ds.append_order_as_selection
|
12
|
+
|
13
|
+
assert_equal (initial.opts[:select] || []) + selects_to_append, final.opts[:select] || []
|
14
|
+
|
15
|
+
order_info = final.opts.fetch(:order_info)
|
16
|
+
|
17
|
+
assert_equal order_names, order_info.map { |h| h.fetch(:name) }
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should do nothing to queries without order_by clauses" do
|
21
|
+
assert_equal User.dataset, User.dataset.append_order_as_selection
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "for simple symbol columns" do
|
25
|
+
it "when they are missing" do
|
26
|
+
assert_order_append \
|
27
|
+
ds: User.dataset.select(:id).order_by(:description),
|
28
|
+
selects_to_append: [Sequel.as(:description, :order_0)],
|
29
|
+
order_names: [:order_0]
|
30
|
+
|
31
|
+
assert_order_append \
|
32
|
+
ds: User.dataset.select(:id).order_by(:fake_column),
|
33
|
+
selects_to_append: [Sequel.as(:fake_column, :order_0)],
|
34
|
+
order_names: [:order_0]
|
35
|
+
end
|
36
|
+
|
37
|
+
it "when they are present" do
|
38
|
+
assert_order_append \
|
39
|
+
ds: User.dataset.select(:id).order_by(:id),
|
40
|
+
selects_to_append: [],
|
41
|
+
order_names: [:id]
|
42
|
+
|
43
|
+
assert_order_append \
|
44
|
+
ds: User.dataset.select(:created_at).order_by(:created_at),
|
45
|
+
selects_to_append: [],
|
46
|
+
order_names: [:created_at]
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
describe "when the dataset has been made via #from_self" do
|
51
|
+
it "when they are present" do
|
52
|
+
assert_order_append \
|
53
|
+
ds: User.dataset.select(:id).from_self.order_by(:id),
|
54
|
+
selects_to_append: [],
|
55
|
+
order_names: [:id]
|
56
|
+
|
57
|
+
assert_order_append \
|
58
|
+
ds: User.dataset.select(:users__created_at).from_self.order_by(:created_at),
|
59
|
+
selects_to_append: [],
|
60
|
+
order_names: [:created_at]
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "for qualified columns" do
|
65
|
+
it "when they are missing" do
|
66
|
+
assert_order_append \
|
67
|
+
ds: User.dataset.select(:id).order_by(Sequel.qualify(:other_table, :fake_column)),
|
68
|
+
selects_to_append: [Sequel.qualify(:other_table, :fake_column).as(:order_0)],
|
69
|
+
order_names: [:order_0]
|
70
|
+
|
71
|
+
assert_order_append \
|
72
|
+
ds: User.dataset.select(:id).order_by(:other_table__fake_column),
|
73
|
+
selects_to_append: [Sequel.qualify(:other_table, :fake_column).as(:order_0)],
|
74
|
+
order_names: [:order_0]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "when they are present" do
|
78
|
+
assert_order_append \
|
79
|
+
ds: User.dataset.select(Sequel.qualify(:users, :id)).order_by(:id),
|
80
|
+
selects_to_append: [],
|
81
|
+
order_names: [:id]
|
82
|
+
|
83
|
+
assert_order_append \
|
84
|
+
ds: User.dataset.select(Sequel.qualify(:users, Sequel::SQL::Identifier.new(:id))).order_by(:id),
|
85
|
+
selects_to_append: [],
|
86
|
+
order_names: [:id]
|
87
|
+
|
88
|
+
assert_order_append \
|
89
|
+
ds: User.dataset.select(:id).order_by(Sequel.qualify(:users, :id)),
|
90
|
+
selects_to_append: [],
|
91
|
+
order_names: [:id]
|
92
|
+
|
93
|
+
assert_order_append \
|
94
|
+
ds: User.dataset.select(:created_at).order_by(:users__created_at),
|
95
|
+
selects_to_append: [],
|
96
|
+
order_names: [:created_at]
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
describe "for columns with aliases" do
|
101
|
+
it "should recognize that ORDER BY can take either the column name or its alias" do
|
102
|
+
assert_order_append \
|
103
|
+
ds: User.dataset.select(Sequel.as(:description, :des)).order_by(:des),
|
104
|
+
selects_to_append: [],
|
105
|
+
order_names: [:des]
|
106
|
+
|
107
|
+
assert_order_append \
|
108
|
+
ds: User.dataset.select(Sequel.as(:description, :des)).order_by(:description),
|
109
|
+
selects_to_append: [],
|
110
|
+
order_names: [:des]
|
111
|
+
end
|
112
|
+
|
113
|
+
it "that are also qualified" do
|
114
|
+
assert_order_append \
|
115
|
+
ds: User.dataset.select(Sequel.qualify(:users, :description).as(:des)).order_by(:description),
|
116
|
+
selects_to_append: [],
|
117
|
+
order_names: [:des]
|
118
|
+
|
119
|
+
assert_order_append \
|
120
|
+
ds: User.dataset.select(Sequel.qualify(:users, :description).as(:des)).order_by(:des),
|
121
|
+
selects_to_append: [],
|
122
|
+
order_names: [:des]
|
123
|
+
|
124
|
+
assert_order_append \
|
125
|
+
ds: User.dataset.select(Sequel.as(:description, :des)).order_by(Sequel.qualify(:users, :description)),
|
126
|
+
selects_to_append: [],
|
127
|
+
order_names: [:des]
|
128
|
+
|
129
|
+
assert_order_append \
|
130
|
+
ds: User.dataset.select(:created_at___c_at).order_by(:users__created_at),
|
131
|
+
selects_to_append: [],
|
132
|
+
order_names: [:c_at]
|
133
|
+
|
134
|
+
assert_order_append \
|
135
|
+
ds: User.dataset.select(Sequel.qualify(:users, :description).as(:des)).order_by(:description),
|
136
|
+
selects_to_append: [],
|
137
|
+
order_names: [:des]
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
describe "when ordering by arbitrary expressions" do
|
142
|
+
it "when they are missing" do
|
143
|
+
assert_order_append \
|
144
|
+
ds: User.dataset.select(:id).order_by{function(:column1, 2)},
|
145
|
+
selects_to_append: [Sequel.virtual_row{function(:column1, 2)}.as(:order_0)],
|
146
|
+
order_names: [:order_0]
|
147
|
+
|
148
|
+
assert_order_append \
|
149
|
+
ds: User.dataset.select(:id).order_by{column - 2},
|
150
|
+
selects_to_append: [Sequel.virtual_row{column - 2}.as(:order_0)],
|
151
|
+
order_names: [:order_0]
|
152
|
+
|
153
|
+
assert_order_append \
|
154
|
+
ds: User.dataset.select(:id).order_by(Sequel.lit('function(column1, 2)')),
|
155
|
+
selects_to_append: [Sequel.lit('function(column1, 2)').as(:order_0)],
|
156
|
+
order_names: [:order_0]
|
157
|
+
end
|
158
|
+
|
159
|
+
it "when they are present" do
|
160
|
+
assert_order_append \
|
161
|
+
ds: User.dataset.select{function(:column1, 2).as(:my_column)}.order_by{function(:column1, 2)},
|
162
|
+
selects_to_append: [],
|
163
|
+
order_names: [:my_column]
|
164
|
+
end
|
165
|
+
|
166
|
+
it "when they are present but don't have a name we can safely predict" do
|
167
|
+
assert_order_append \
|
168
|
+
ds: User.dataset.select{function(:column1, 2)}.order_by{function(:column1, 2)},
|
169
|
+
selects_to_append: [Sequel.virtual_row{function(:column1, 2)}.as(:order_0)],
|
170
|
+
order_names: [:order_0]
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
174
|
+
describe "when a selection includes a ColumnAll" do
|
175
|
+
describe "and is not connected to a model" do
|
176
|
+
it "when ordering by a column qualified to that table" do
|
177
|
+
assert_order_append \
|
178
|
+
ds: DB[:users].select_all(:users).order_by(Sequel.qualify(:users, :id)),
|
179
|
+
selects_to_append: [],
|
180
|
+
order_names: [:id]
|
181
|
+
end
|
182
|
+
|
183
|
+
it "when ordering by a column qualified to a different table" do
|
184
|
+
assert_order_append \
|
185
|
+
ds: DB[:users].select_all(:users).order_by(Sequel.qualify(:users_2, :id)),
|
186
|
+
selects_to_append: [Sequel.qualify(:users_2, :id).as(:order_0)],
|
187
|
+
order_names: [:order_0]
|
188
|
+
end
|
189
|
+
|
190
|
+
it "when ordering by an unqualified column" do
|
191
|
+
assert_order_append \
|
192
|
+
ds: DB[:users].select_all(:users).order_by(:id),
|
193
|
+
selects_to_append: [Sequel.as(:id, :order_0)],
|
194
|
+
order_names: [:order_0]
|
195
|
+
end
|
196
|
+
|
197
|
+
it "when ordering by an arbitrary expression" do
|
198
|
+
assert_order_append \
|
199
|
+
ds: DB[:users].select_all(:users).order_by{function(:column, 2)},
|
200
|
+
selects_to_append: [Sequel.virtual_row{function(:column, 2)}.as(:order_0)],
|
201
|
+
order_names: [:order_0]
|
202
|
+
end
|
203
|
+
end
|
204
|
+
|
205
|
+
describe "and is connected to a model so we can look up columns" do
|
206
|
+
it "when ordering by an unqualified column that is present in the table" do
|
207
|
+
assert_order_append \
|
208
|
+
ds: User.dataset.select_all(:users).order_by(:id),
|
209
|
+
selects_to_append: [],
|
210
|
+
order_names: [:id]
|
211
|
+
|
212
|
+
assert_order_append \
|
213
|
+
ds: User.dataset.select_all(:users).order_by(:description),
|
214
|
+
selects_to_append: [],
|
215
|
+
order_names: [:description]
|
216
|
+
end
|
217
|
+
|
218
|
+
it "when ordering by an unqualified column that is not present in the table" do
|
219
|
+
assert_order_append \
|
220
|
+
ds: User.dataset.select_all(:users).order_by(:fake_column),
|
221
|
+
selects_to_append: [Sequel.as(:fake_column, :order_0)],
|
222
|
+
order_names: [:order_0]
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'sequel'
|
2
|
+
|
3
|
+
$: << File.join(File.dirname(__FILE__), '..', 'lib')
|
4
|
+
|
5
|
+
Sequel::Database.extension :select_order_clauses
|
6
|
+
|
7
|
+
DB = Sequel.sqlite
|
8
|
+
|
9
|
+
DB.create_table :users do
|
10
|
+
primary_key :id
|
11
|
+
Time :created_at
|
12
|
+
String :description
|
13
|
+
end
|
14
|
+
|
15
|
+
class User < Sequel::Model; end
|
16
|
+
|
17
|
+
require 'pry'
|
18
|
+
require 'minitest/autorun'
|
19
|
+
require 'minitest/rg'
|
data/tasks/specs.rb
ADDED
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: sequel-select-order-clauses
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Hanks
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-10-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.6'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.6'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: sqlite3
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sequel
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.0'
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.0'
|
69
|
+
description: Simple support for selecting the order clauses in a dataset
|
70
|
+
email:
|
71
|
+
- christopher.m.hanks@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- Gemfile
|
78
|
+
- LICENSE.txt
|
79
|
+
- README.md
|
80
|
+
- Rakefile
|
81
|
+
- lib/sequel-select-order-clauses.rb
|
82
|
+
- lib/sequel/extensions/select_order_clauses.rb
|
83
|
+
- lib/sequel/extensions/select_order_clauses/version.rb
|
84
|
+
- sequel-select-order-clauses.gemspec
|
85
|
+
- spec/select_order_clauses_spec.rb
|
86
|
+
- spec/spec_helper.rb
|
87
|
+
- tasks/specs.rb
|
88
|
+
homepage: https://github.com/chanks/sequel-select-order-clauses
|
89
|
+
licenses:
|
90
|
+
- MIT
|
91
|
+
metadata: {}
|
92
|
+
post_install_message:
|
93
|
+
rdoc_options: []
|
94
|
+
require_paths:
|
95
|
+
- lib
|
96
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
97
|
+
requirements:
|
98
|
+
- - ">="
|
99
|
+
- !ruby/object:Gem::Version
|
100
|
+
version: '0'
|
101
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
102
|
+
requirements:
|
103
|
+
- - ">="
|
104
|
+
- !ruby/object:Gem::Version
|
105
|
+
version: '0'
|
106
|
+
requirements: []
|
107
|
+
rubyforge_project:
|
108
|
+
rubygems_version: 2.5.1
|
109
|
+
signing_key:
|
110
|
+
specification_version: 4
|
111
|
+
summary: Select the order clauses in a dataset
|
112
|
+
test_files:
|
113
|
+
- spec/select_order_clauses_spec.rb
|
114
|
+
- spec/spec_helper.rb
|