occams-record 1.6.2 → 1.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +13 -87
- data/lib/occams-record/pluck.rb +15 -0
- data/lib/occams-record/query.rb +27 -0
- data/lib/occams-record/raw_query.rb +23 -0
- data/lib/occams-record/version.rb +1 -1
- data/lib/occams-record.rb +1 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0dc125a06b3fa732e1064483f13e5abbe2a7c64b4e6ac7f1b2d37337d8e233cb
|
4
|
+
data.tar.gz: 5c47a9a644b757463d5dd1961c1b86ed1de50cf247a286e8d1d0c3dd5daa99b8
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7fb55ec18a98e4d2bb4b3fab8d3f609a378bee578d1b405d56a43b1f035f40d53149fc8dabc321bbaf17b180eb9e3b1dda282cc2fd8675a3e10c8bc59a9f7a59
|
7
|
+
data.tar.gz: f9f28ad1537cc297a0b5b1fe8a5209d4f4dfa4529148a603f715da884fa9d9f8188836aca84c8e5dcc36f674bb6abe7211de57c014e90a4539d892da0192c28d
|
data/README.md
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
> Do not multiply entities beyond necessity. -- Occam's Razor
|
4
4
|
|
5
|
+
Full documentation is available at [rubydoc.info/gems/occams-record](http://www.rubydoc.info/gems/occams-record).
|
6
|
+
|
5
7
|
OccamsRecord is a high-efficiency, advanced query library for use alongside ActiveRecord. It is **not** an ORM or an ActiveRecord replacement. OccamsRecord can breathe fresh life into your ActiveRecord app by giving it two things:
|
6
8
|
|
7
9
|
### 1) Huge performance gains
|
@@ -9,109 +11,33 @@ OccamsRecord is a high-efficiency, advanced query library for use alongside Acti
|
|
9
11
|
* 3x-5x faster than ActiveRecord queries, *minimum*.
|
10
12
|
* Uses 1/3 the memory of ActiveRecord query results.
|
11
13
|
* Eliminates the N+1 query problem. (This often exceeds the baseline 3x-5x gain.)
|
12
|
-
* Support for cursors (Postgres only, new in v1.4.0)
|
13
14
|
|
14
15
|
### 2) Supercharged querying & eager loading
|
15
16
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
.query(User.active)
|
23
|
-
.eager_load(:orders) { |l|
|
24
|
-
l.scope { |q| q.where("created_at >= ?", date).order("created_at DESC") }
|
25
|
-
}
|
26
|
-
```
|
27
|
-
|
28
|
-
**Use `ORDER BY` with `find_each`/`find_in_batches`**
|
29
|
-
|
30
|
-
```ruby
|
31
|
-
OccamsRecord
|
32
|
-
.query(Order.order("created_at DESC"))
|
33
|
-
.find_each { |order|
|
34
|
-
...
|
35
|
-
}
|
36
|
-
```
|
37
|
-
|
38
|
-
**Use cursors**
|
39
|
-
|
40
|
-
```ruby
|
41
|
-
OccamsRecord
|
42
|
-
.query(Order.order("created_at DESC"))
|
43
|
-
.find_each_with_cursor { |order|
|
44
|
-
...
|
45
|
-
}
|
46
|
-
```
|
47
|
-
|
48
|
-
**Use `find_each`/`find_in_batches` with raw SQL**
|
49
|
-
|
50
|
-
```ruby
|
51
|
-
OccamsRecord
|
52
|
-
.sql("
|
53
|
-
SELECT * FROM orders
|
54
|
-
WHERE created_at >= %{date}
|
55
|
-
LIMIT %{batch_limit}
|
56
|
-
OFFSET %{batch_offset}",
|
57
|
-
{date: 10.years.ago}
|
58
|
-
)
|
59
|
-
.find_each { |order|
|
60
|
-
...
|
61
|
-
}
|
62
|
-
```
|
63
|
-
|
64
|
-
**Eager load associations when you're writing raw SQL**
|
65
|
-
|
66
|
-
```ruby
|
67
|
-
OccamsRecord
|
68
|
-
.sql("
|
69
|
-
SELECT * FROM users
|
70
|
-
LEFT OUTER JOIN ...
|
71
|
-
")
|
72
|
-
.model(User)
|
73
|
-
.eager_load(:orders)
|
74
|
-
```
|
75
|
-
|
76
|
-
**Eager load "ad hoc associations" using raw SQL**
|
77
|
-
|
78
|
-
Relationships are complicated, and sometimes they can't be expressed in ActiveRecord models. Define your relationship on the fly!
|
79
|
-
(Don't worry, there's a full explanation later on.)
|
80
|
-
|
81
|
-
```ruby
|
82
|
-
OccamsRecord
|
83
|
-
.query(User.all)
|
84
|
-
.eager_load_many(:orders, {:id => :user_id}, "
|
85
|
-
SELECT user_id, orders.*
|
86
|
-
FROM orders INNER JOIN ...
|
87
|
-
WHERE user_id IN (%{ids})
|
88
|
-
")
|
89
|
-
```
|
17
|
+
* Customize the SQL used to eager load associations (order them, apply filters, etc)
|
18
|
+
* Use cursors (Postgres only)
|
19
|
+
* Use `ORDER BY` with `find_each`/`find_in_batches`
|
20
|
+
* Use `find_each`/`find_in_batches` with raw SQL
|
21
|
+
* Eager load associations off of raw SQL queries
|
22
|
+
* Use `pluck` with raw SQL queries
|
90
23
|
|
24
|
+
### How does OccamsRecord do all this?
|
91
25
|
[Look over the speed and memory measurements yourself!](https://github.com/jhollinger/occams-record/wiki/Measurements) OccamsRecord achieves all of this by making some **very specific trade-offs:**
|
92
26
|
|
93
27
|
* OccamsRecord results are *read-only*.
|
94
28
|
* OccamsRecord results are *purely database rows* - they don't have any instance methods from your Rails models.
|
95
|
-
* You *must eager load* each assocation you intend to use. If you
|
29
|
+
* You *must eager load* each assocation you intend to use. If you try to use one you didn't eager load, an exception will be raised.
|
96
30
|
|
97
|
-
|
31
|
+
# Overview
|
98
32
|
|
99
|
-
|
33
|
+
Full documentation is available at [rubydoc.info/gems/occams-record](http://www.rubydoc.info/gems/occams-record). Code lives at at [github.com/jhollinger/occams-record](https://github.com/jhollinger/occams-record). Contributions welcome!
|
100
34
|
|
101
|
-
Simply add
|
35
|
+
Simply add `occams-record` to your `Gemfile`:
|
102
36
|
|
103
37
|
```ruby
|
104
38
|
gem 'occams-record'
|
105
39
|
```
|
106
40
|
|
107
|
-
---
|
108
|
-
|
109
|
-
# Overview
|
110
|
-
|
111
|
-
Full documentation is available at [rubydoc.info/gems/occams-record](http://www.rubydoc.info/gems/occams-record).
|
112
|
-
|
113
|
-
Code lives at at [github.com/jhollinger/occams-record](https://github.com/jhollinger/occams-record). Contributions welcome!
|
114
|
-
|
115
41
|
Build your queries like normal, using ActiveRecord's excellent query builder. Then pass them off to Occams Record.
|
116
42
|
|
117
43
|
```ruby
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module OccamsRecord
|
2
|
+
module Pluck
|
3
|
+
private
|
4
|
+
|
5
|
+
def pluck_results(results, cols)
|
6
|
+
if cols.size == 1
|
7
|
+
col = cols[0].to_s
|
8
|
+
results.map { |r| r[col] }
|
9
|
+
else
|
10
|
+
cols = cols.map(&:to_s)
|
11
|
+
results.map { |r| r.values_at(*cols) }
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/occams-record/query.rb
CHANGED
@@ -36,6 +36,7 @@ module OccamsRecord
|
|
36
36
|
attr_reader :scope
|
37
37
|
|
38
38
|
include OccamsRecord::Batches::CursorHelpers
|
39
|
+
include OccamsRecord::Pluck
|
39
40
|
include EagerLoaders::Builder
|
40
41
|
include Enumerable
|
41
42
|
include Measureable
|
@@ -95,6 +96,8 @@ module OccamsRecord
|
|
95
96
|
#
|
96
97
|
def run
|
97
98
|
sql = block_given? ? yield(scope).to_sql : scope.to_sql
|
99
|
+
return [] if sql.blank? # return early in case ActiveRecord::QueryMethods#none was used
|
100
|
+
|
98
101
|
@query_logger << "#{@eager_loaders.tracer}: #{sql}" if @query_logger
|
99
102
|
result = if measure?
|
100
103
|
record_start_time!
|
@@ -225,5 +228,29 @@ module OccamsRecord
|
|
225
228
|
use: @use, query_logger: @query_logger, eager_loaders: @eager_loaders,
|
226
229
|
)
|
227
230
|
end
|
231
|
+
|
232
|
+
#
|
233
|
+
# Returns the specified column(s) as an array of values.
|
234
|
+
#
|
235
|
+
# If more than one column is given, the result will be an array of arrays.
|
236
|
+
#
|
237
|
+
# @param cols [Array] one or more column names as Symbols or Strings. Also accepts SQL functions, e.g. "LENGTH(name)".
|
238
|
+
# @return [Array]
|
239
|
+
#
|
240
|
+
def pluck(*cols)
|
241
|
+
sql = (block_given? ? yield(scope).to_sql : scope).select(*cols).to_sql
|
242
|
+
return [] if sql.blank? # return early in case ActiveRecord::QueryMethods#none was used
|
243
|
+
|
244
|
+
@query_logger << "#{@eager_loaders.tracer}: #{sql}" if @query_logger
|
245
|
+
result = if measure?
|
246
|
+
record_start_time!
|
247
|
+
measure!(model.table_name, sql) {
|
248
|
+
model.connection.exec_query sql
|
249
|
+
}
|
250
|
+
else
|
251
|
+
model.connection.exec_query sql
|
252
|
+
end
|
253
|
+
pluck_results result, cols
|
254
|
+
end
|
228
255
|
end
|
229
256
|
end
|
@@ -62,6 +62,7 @@ module OccamsRecord
|
|
62
62
|
attr_reader :binds
|
63
63
|
|
64
64
|
include OccamsRecord::Batches::CursorHelpers
|
65
|
+
include OccamsRecord::Pluck
|
65
66
|
include EagerLoaders::Builder
|
66
67
|
include Enumerable
|
67
68
|
include Measureable
|
@@ -209,6 +210,28 @@ module OccamsRecord
|
|
209
210
|
)
|
210
211
|
end
|
211
212
|
|
213
|
+
#
|
214
|
+
# Returns the specified column(s) as an array of values.
|
215
|
+
#
|
216
|
+
# If more than one column is given, the result will be an array of arrays.
|
217
|
+
#
|
218
|
+
# @param cols [Array] one or more column names as Symbols or Strings. Also accepts SQL functions, e.g. "LENGTH(name)".
|
219
|
+
# @return [Array]
|
220
|
+
#
|
221
|
+
def pluck(*cols)
|
222
|
+
_escaped_sql = escaped_sql
|
223
|
+
@query_logger << _escaped_sql if @query_logger
|
224
|
+
result = if measure?
|
225
|
+
record_start_time!
|
226
|
+
measure!(table_name, _escaped_sql) {
|
227
|
+
conn.exec_query _escaped_sql
|
228
|
+
}
|
229
|
+
else
|
230
|
+
conn.exec_query _escaped_sql
|
231
|
+
end
|
232
|
+
pluck_results result, cols
|
233
|
+
end
|
234
|
+
|
212
235
|
private
|
213
236
|
|
214
237
|
# Returns the SQL as a String with all variables escaped
|
data/lib/occams-record.rb
CHANGED
@@ -5,6 +5,7 @@ require 'occams-record/measureable'
|
|
5
5
|
require 'occams-record/eager_loaders/eager_loaders'
|
6
6
|
require 'occams-record/results/results'
|
7
7
|
require 'occams-record/results/row'
|
8
|
+
require 'occams-record/pluck'
|
8
9
|
require 'occams-record/cursor'
|
9
10
|
require 'occams-record/errors'
|
10
11
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: occams-record
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jordan Hollinger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-05-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -74,6 +74,7 @@ files:
|
|
74
74
|
- lib/occams-record/errors.rb
|
75
75
|
- lib/occams-record/measureable.rb
|
76
76
|
- lib/occams-record/merge.rb
|
77
|
+
- lib/occams-record/pluck.rb
|
77
78
|
- lib/occams-record/query.rb
|
78
79
|
- lib/occams-record/raw_query.rb
|
79
80
|
- lib/occams-record/results/results.rb
|