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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a233847b8c1a9de8c77e8c5e1d12f70ea7c8b9efa498208491a17ff09a6f217
4
- data.tar.gz: f87fbaf43703cd29b60b94a480ad903d00cad2b9b3bd9bfb4a77b7748f68aa81
3
+ metadata.gz: 0dc125a06b3fa732e1064483f13e5abbe2a7c64b4e6ac7f1b2d37337d8e233cb
4
+ data.tar.gz: 5c47a9a644b757463d5dd1961c1b86ed1de50cf247a286e8d1d0c3dd5daa99b8
5
5
  SHA512:
6
- metadata.gz: 21115e90f5f455eaf33d5c0596d6276957905fb14932583fcdfacdb1a44f7afeaee029458de903fa58c2801e7504643c6c6e4a530822409ff93da6954648a06e
7
- data.tar.gz: a38eba237379a4a0b55d027746a8796f9aa9904e60bb1ba6acd6fd46348fc84e0aef17fc6de482d5b32d6677c09b2ea53602b000bf6da9a60d5bd2dec0e72b3f
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
- Continue using ActiveRecord's query builder, but let Occams take over running them, eager loading, and raw SQL calls. None of the examples below are possible with ActiveRecord, but OccamsRecord makes them trivial. (More complete examples are shown later, but these should whet your appetite.)
17
-
18
- **Customize the SQL used to eager load associations**
19
-
20
- ```ruby
21
- OccamsRecord
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 forget one, an exception will be raised.
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
- # Installation
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 it to your `Gemfile`:
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
@@ -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
@@ -3,5 +3,5 @@
3
3
  #
4
4
  module OccamsRecord
5
5
  # @private
6
- VERSION = "1.6.2".freeze
6
+ VERSION = "1.7.1".freeze
7
7
  end
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.6.2
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-02-21 00:00:00.000000000 Z
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