where_row 0.1.0 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +22 -21
- data/lib/where_row/query_builder.rb +10 -7
- data/lib/where_row/version.rb +1 -1
- data/where_row.gemspec +3 -1
- metadata +17 -4
- data/Gemfile.lock +0 -66
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 563fa38bd6eacdc602cd365f11985ccfa9ea91d7c2f9720227a75a67e9b082d2
|
4
|
+
data.tar.gz: 6dcc2112211fb876d80b5c7451d8f6cf2ebf44b17f7afbc8491cfb92f9d4e70c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e1e3f1a9b1a33143aa7aef4cd68c5d3fbe8681261ded57398f938f4217d63e8089ff3b0dd7dba849da920add74cc184112c3809d6ae3d4bb679c9beac7cf1e3
|
7
|
+
data.tar.gz: 8f634e35ebdfb1e74d2762a93f63165b4c09a6d4d5679c2d38364dd02cbd6be398ba41f3095468135decb3d39e7684972419a6672655b9d546cab27d1748b448
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -6,47 +6,48 @@ Sometimes, the classic offset method to paginate results can be very inneficient
|
|
6
6
|
|
7
7
|
Consider the following example, as it appears on [Use The Index Luke](https://use-the-index-luke.com/sql/partial-results/fetch-next-page)
|
8
8
|
|
9
|
+
Suppose we want to have an infinite scrolling functionality for a collection of sales, ordered by the date the sale took place. Ordering just by sale_date will not suffice, since many sales can occur on the same date. Hence, we need to order by both the date and the id, to have a deterministic order. In SQL, this would look like this:
|
10
|
+
|
9
11
|
```SQL
|
10
12
|
CREATE INDEX sl_dtid ON sales (sale_date, sale_id)
|
11
13
|
|
12
14
|
SELECT *
|
13
15
|
FROM sales
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
WHERE (sale_date, sale_id) < (?, ?)
|
17
|
+
ORDER BY sale_date DESC, sale_id DESC
|
18
|
+
FETCH FIRST 10 ROWS ONLY
|
17
19
|
```
|
18
20
|
|
19
|
-
The Row Value syntax is
|
20
|
-
maybe there is partial support (for example, the index is not properly utilized).
|
21
|
+
The Row Value syntax is not supported in Rails directly. Furthermore, some databases still don't support this syntax as well, or maybe there is partial support (for example, the index is not properly utilized).
|
21
22
|
|
22
23
|
Thankfully, the same results can be achieved with plain-old logical expressions and comparisons. The equivalent query would look like this:
|
23
24
|
|
24
25
|
```SQL
|
25
|
-
|
26
|
+
SELECT *
|
26
27
|
FROM sales
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
28
|
+
WHERE sale_date <= ?
|
29
|
+
AND NOT (sale_date = ? AND sale_id >= ?)
|
30
|
+
ORDER BY sale_date DESC, sale_id DESC
|
31
|
+
FETCH FIRST 10 ROWS ONLY
|
31
32
|
```
|
32
33
|
|
33
|
-
This is something that can be directly expressed in Rails
|
34
|
+
This is something that can be directly expressed in Rails. One possible way is the following:
|
34
35
|
|
35
36
|
```ruby
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
37
|
+
Sales.
|
38
|
+
where(sale_date: (..date_offset)).
|
39
|
+
where.not(sale_date: date_offset, sale_id: (sale_id_offset..)).
|
40
|
+
order(sale_date: :desc, sale_id: :desc).
|
41
|
+
limit(10)
|
41
42
|
```
|
42
43
|
|
43
|
-
However, the intent of this query is not clear at all when reading through this piece of code. Furthermore, if for any reason we need more than two columns, this will blow up pretty quickly. This gem allows us to generate this query/relation with a more explicit syntax.
|
44
|
+
However, the intent of this query is not clear at all when reading through this piece of code. Furthermore, if for any reason we need more than two columns (maybe by the sale's client_id), this will blow up pretty quickly. This gem allows us to generate this query/relation with a more explicit syntax.
|
44
45
|
|
45
46
|
```ruby
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
47
|
+
Sales.
|
48
|
+
where_row(:sale_date, :sale_id).lt(date_offset, sale_id_offset).
|
49
|
+
order(sale_date: :desc, sale_id: :desc).
|
50
|
+
limit(10)
|
50
51
|
```
|
51
52
|
|
52
53
|
## Installation
|
@@ -84,19 +84,22 @@ module WhereRow
|
|
84
84
|
|
85
85
|
def build_comparison_predicate
|
86
86
|
last_idx = keys.size - 1
|
87
|
-
reversed_op = REVERSE_OP_MAP[operator]
|
88
|
-
last_pred = build_predicate_for_key(relation, last_idx, reversed_op)
|
89
87
|
|
90
|
-
|
88
|
+
if last_idx.zero?
|
89
|
+
return build_predicate(relation, keys[last_idx], values[last_idx], operator)
|
90
|
+
end
|
91
|
+
|
92
|
+
last_pred = build_predicate_for_key(relation, last_idx, operator)
|
91
93
|
|
92
|
-
first_keys_op = :lt if
|
93
|
-
first_keys_op = :gt if
|
94
|
-
first_keys_op ||=
|
94
|
+
first_keys_op = :lt if operator == :lteq
|
95
|
+
first_keys_op = :gt if operator == :gteq
|
96
|
+
first_keys_op ||= operator
|
95
97
|
|
96
98
|
(0...last_idx).
|
97
99
|
map { |i| build_predicate_for_key(relation, i, first_keys_op) }.
|
98
100
|
reduce(:and).
|
99
|
-
and(last_pred)
|
101
|
+
and(last_pred).
|
102
|
+
not
|
100
103
|
end
|
101
104
|
|
102
105
|
def build_predicate_for_key(relation, idx, op)
|
data/lib/where_row/version.rb
CHANGED
data/where_row.gemspec
CHANGED
@@ -11,7 +11,7 @@ Gem::Specification.new do |spec|
|
|
11
11
|
|
12
12
|
spec.summary = 'Write row value queries in active record'
|
13
13
|
spec.description = 'Write row value queries in active record'
|
14
|
-
spec.homepage = "https://github.com/
|
14
|
+
spec.homepage = "https://github.com/odydoum/where_row"
|
15
15
|
spec.license = "MIT"
|
16
16
|
spec.required_ruby_version = ">= 2.5.0"
|
17
17
|
|
@@ -30,4 +30,6 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_development_dependency "appraisal"
|
31
31
|
spec.add_development_dependency "sqlite3"
|
32
32
|
spec.add_development_dependency "yard"
|
33
|
+
spec.add_development_dependency "gem-release"
|
33
34
|
end
|
35
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: where_row
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Odysseas Doumas
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-06-
|
11
|
+
date: 2023-06-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -114,6 +114,20 @@ dependencies:
|
|
114
114
|
- - ">="
|
115
115
|
- !ruby/object:Gem::Version
|
116
116
|
version: '0'
|
117
|
+
- !ruby/object:Gem::Dependency
|
118
|
+
name: gem-release
|
119
|
+
requirement: !ruby/object:Gem::Requirement
|
120
|
+
requirements:
|
121
|
+
- - ">="
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
124
|
+
type: :development
|
125
|
+
prerelease: false
|
126
|
+
version_requirements: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ">="
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
117
131
|
description: Write row value queries in active record
|
118
132
|
email:
|
119
133
|
- odydoum@gmail.com
|
@@ -125,7 +139,6 @@ files:
|
|
125
139
|
- ".rspec"
|
126
140
|
- Appraisals
|
127
141
|
- Gemfile
|
128
|
-
- Gemfile.lock
|
129
142
|
- LICENSE.txt
|
130
143
|
- README.md
|
131
144
|
- Rakefile
|
@@ -137,7 +150,7 @@ files:
|
|
137
150
|
- lib/where_row/query_builder_fascade.rb
|
138
151
|
- lib/where_row/version.rb
|
139
152
|
- where_row.gemspec
|
140
|
-
homepage: https://github.com/
|
153
|
+
homepage: https://github.com/odydoum/where_row
|
141
154
|
licenses:
|
142
155
|
- MIT
|
143
156
|
metadata: {}
|
data/Gemfile.lock
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: .
|
3
|
-
specs:
|
4
|
-
where_row (0.1.0)
|
5
|
-
activerecord (>= 5.2, < 7.1)
|
6
|
-
|
7
|
-
GEM
|
8
|
-
remote: https://rubygems.org/
|
9
|
-
specs:
|
10
|
-
activemodel (6.1.7.3)
|
11
|
-
activesupport (= 6.1.7.3)
|
12
|
-
activerecord (6.1.7.3)
|
13
|
-
activemodel (= 6.1.7.3)
|
14
|
-
activesupport (= 6.1.7.3)
|
15
|
-
activesupport (6.1.7.3)
|
16
|
-
concurrent-ruby (~> 1.0, >= 1.0.2)
|
17
|
-
i18n (>= 1.6, < 2)
|
18
|
-
minitest (>= 5.1)
|
19
|
-
tzinfo (~> 2.0)
|
20
|
-
zeitwerk (~> 2.3)
|
21
|
-
appraisal (2.4.1)
|
22
|
-
bundler
|
23
|
-
rake
|
24
|
-
thor (>= 0.14.0)
|
25
|
-
concurrent-ruby (1.2.2)
|
26
|
-
diff-lcs (1.5.0)
|
27
|
-
i18n (1.14.0)
|
28
|
-
concurrent-ruby (~> 1.0)
|
29
|
-
mini_portile2 (2.8.2)
|
30
|
-
minitest (5.15.0)
|
31
|
-
rake (10.5.0)
|
32
|
-
rspec (3.12.0)
|
33
|
-
rspec-core (~> 3.12.0)
|
34
|
-
rspec-expectations (~> 3.12.0)
|
35
|
-
rspec-mocks (~> 3.12.0)
|
36
|
-
rspec-core (3.12.2)
|
37
|
-
rspec-support (~> 3.12.0)
|
38
|
-
rspec-expectations (3.12.3)
|
39
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
40
|
-
rspec-support (~> 3.12.0)
|
41
|
-
rspec-mocks (3.12.5)
|
42
|
-
diff-lcs (>= 1.2.0, < 2.0)
|
43
|
-
rspec-support (~> 3.12.0)
|
44
|
-
rspec-support (3.12.0)
|
45
|
-
sqlite3 (1.6.3)
|
46
|
-
mini_portile2 (~> 2.8.0)
|
47
|
-
thor (1.2.1)
|
48
|
-
tzinfo (2.0.6)
|
49
|
-
concurrent-ruby (~> 1.0)
|
50
|
-
yard (0.9.34)
|
51
|
-
zeitwerk (2.6.8)
|
52
|
-
|
53
|
-
PLATFORMS
|
54
|
-
ruby
|
55
|
-
|
56
|
-
DEPENDENCIES
|
57
|
-
appraisal
|
58
|
-
bundler (~> 1.17)
|
59
|
-
rake (~> 10.0)
|
60
|
-
rspec (~> 3.0)
|
61
|
-
sqlite3
|
62
|
-
where_row!
|
63
|
-
yard
|
64
|
-
|
65
|
-
BUNDLED WITH
|
66
|
-
1.17.3
|