occams-record 0.1.0 → 0.2.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.
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9637536cde1b2f57e976fa87ab6dfc2bdb34dee0
|
4
|
+
data.tar.gz: b639ad58c3b7b328a7e37a858b5693832604e620
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c84146477d0ba45f0f5a36386e06ade453339b45473a8bebba2f4b4da2eda876e6cfe62dc86c4a1f539838ff765c3753436f10853bc97df2a800f605c064daba
|
7
|
+
data.tar.gz: f941ae734b28a694921090d664e3a263c168aba74461d3106c3a04aeeaba3889157db5629c89f3f57187150e6622b3bb66977371999525c89188022da1db2a5b
|
data/README.md
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Occam's Record
|
1
|
+
# Occam's Record [](https://travis-ci.org/jhollinger/occams-record)
|
2
2
|
|
3
3
|
> Do not multiply entities beyond necessity. -- Occam's Razor
|
4
4
|
|
@@ -11,7 +11,7 @@ For those stuck with ActiveRecord, OccamsRecord seeks to solve these issues by m
|
|
11
11
|
|
12
12
|
**What does this buy you?**
|
13
13
|
|
14
|
-
* OccamsRecord results are **one-
|
14
|
+
* OccamsRecord results are **one-third the size** of ActiveRecord results.
|
15
15
|
* OccamsRecord queries run **three times faster** than ActiveRecord queries, or more.
|
16
16
|
* When you're eager loading associations you may specify which columns to `SELECT`. (This can be a significant performance boost to both your database and Rails app, on top of the above numbers.)
|
17
17
|
|
@@ -25,107 +25,125 @@ For those stuck with ActiveRecord, OccamsRecord seeks to solve these issues by m
|
|
25
25
|
|
26
26
|
Glad you asked. [Look over the results yourself.](https://github.com/jhollinger/occams-record/wiki/Measurements)
|
27
27
|
|
28
|
-
##
|
28
|
+
## Usage
|
29
|
+
|
30
|
+
**Add to your Gemfile**
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
gem 'occams-record'
|
34
|
+
```
|
29
35
|
|
30
36
|
**Simple example**
|
31
37
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
38
|
+
```ruby
|
39
|
+
widgets = OccamsRecord.
|
40
|
+
query(Widget.order("name")).
|
41
|
+
eager_load(:category).
|
42
|
+
run
|
36
43
|
|
37
|
-
|
38
|
-
|
44
|
+
widgets[0].id
|
45
|
+
=> 1000
|
39
46
|
|
40
|
-
|
41
|
-
|
47
|
+
widgets[0].name
|
48
|
+
=> "Widget 1000"
|
42
49
|
|
43
|
-
|
44
|
-
|
50
|
+
widgets[0].category.name
|
51
|
+
=> "Category 1"
|
52
|
+
```
|
45
53
|
|
46
54
|
**More complicated example**
|
47
55
|
|
48
56
|
Notice that we're eager loading splines, but *only the fields that we need*. If that's a wide table, your DBA will thank you.
|
49
57
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
58
|
+
```ruby
|
59
|
+
widgets = OccamsRecord.
|
60
|
+
query(Widget.order("name")).
|
61
|
+
eager_load(:category).
|
62
|
+
eager_load(:splines, -> { select("widget_id, description") }).
|
63
|
+
run
|
55
64
|
|
56
|
-
|
57
|
-
|
65
|
+
widgets[0].splines.map { |s| s.description }
|
66
|
+
=> ["Spline 1", "Spline 2", "Spline 3"]
|
58
67
|
|
59
|
-
|
60
|
-
|
68
|
+
widgets[1].splines.map { |s| s.description }
|
69
|
+
=> ["Spline 4", "Spline 5"]
|
70
|
+
```
|
61
71
|
|
62
72
|
**An insane example, but only half as insane as the one that prompted the creation of this library**
|
63
73
|
|
64
74
|
In addition to custom eager loading queries, we're also adding nested eager loading (and customizing those queries!).
|
65
75
|
|
66
|
-
|
67
|
-
|
68
|
-
|
76
|
+
```ruby
|
77
|
+
widgets = OccamsRecord.
|
78
|
+
query(Widget.order("name")).
|
79
|
+
eager_load(:category).
|
69
80
|
|
70
|
-
|
71
|
-
|
81
|
+
# load order_items, but only the fields needed to identify which orders go with which widgets
|
82
|
+
eager_load(:order_items, -> { select("widget_id, order_id") }) {
|
72
83
|
|
73
|
-
|
74
|
-
|
84
|
+
# load the orders
|
85
|
+
eager_load(:orders) {
|
75
86
|
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
87
|
+
# load the customers who made the orders, but only their names
|
88
|
+
eager_load(:customer, -> { select("id, name") })
|
89
|
+
}
|
90
|
+
}.
|
91
|
+
run
|
92
|
+
```
|
81
93
|
|
82
94
|
## Injecting instance methods
|
83
95
|
|
84
96
|
By default your results will only have getters for selected columns and eager-loaded associations. If you must, you *can* inject extra methods into your results by putting those methods into a Module. NOTE this is discouraged, as you should try to maintain a clear separation between your persistence layer and your domain.
|
85
97
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
98
|
+
```ruby
|
99
|
+
module MyWidgetMethods
|
100
|
+
def to_s
|
101
|
+
name
|
102
|
+
end
|
90
103
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
104
|
+
def expensive?
|
105
|
+
price_per_unit > 100
|
106
|
+
end
|
107
|
+
end
|
95
108
|
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
109
|
+
module MyOrderMethods
|
110
|
+
def description
|
111
|
+
"#{order_number} - #{date}"
|
112
|
+
end
|
113
|
+
end
|
101
114
|
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
115
|
+
widgets = OccamsRecord.
|
116
|
+
query(Widget.order("name"), use: MyWidgetMethods).
|
117
|
+
eager_load(:orders, use: MyOrderMethods).
|
118
|
+
run
|
106
119
|
|
107
|
-
|
108
|
-
|
120
|
+
widgets[0].to_s
|
121
|
+
=> "Widget A"
|
109
122
|
|
110
|
-
|
111
|
-
|
123
|
+
widgets[0].price_per_unit
|
124
|
+
=> 57.23
|
112
125
|
|
113
|
-
|
114
|
-
|
126
|
+
widgets[0].expensive?
|
127
|
+
=> false
|
115
128
|
|
116
|
-
|
117
|
-
|
129
|
+
widgets[0].orders[0].description
|
130
|
+
=> "O839SJZ98B 1/8/2017"
|
131
|
+
```
|
118
132
|
|
119
133
|
## Testing
|
120
134
|
|
121
135
|
To run the tests, simply run:
|
122
136
|
|
123
|
-
|
124
|
-
|
137
|
+
```bash
|
138
|
+
bundle install
|
139
|
+
bundle exec rake test
|
140
|
+
```
|
125
141
|
|
126
142
|
By default, bundler will install the latest (supported) version of ActiveRecord. To specify a version to test against, run:
|
127
143
|
|
128
|
-
|
129
|
-
|
144
|
+
```bash
|
145
|
+
AR=4.2 bundle update activerecord
|
146
|
+
bundle exec rake test
|
147
|
+
```
|
130
148
|
|
131
149
|
Look inside `Gemfile` to see all testable versions.
|
@@ -6,7 +6,7 @@ module OccamsRecord
|
|
6
6
|
class Base
|
7
7
|
# @return [String] association name
|
8
8
|
attr_reader :name
|
9
|
-
# @return [Module] optional Module to include in the result class
|
9
|
+
# @return [Array<Module>] optional Module to include in the result class (single or array)
|
10
10
|
attr_reader :use
|
11
11
|
# @return [Proc] optional Proc for eager loading things on this association
|
12
12
|
attr_reader :eval_block
|
@@ -14,7 +14,7 @@ module OccamsRecord
|
|
14
14
|
#
|
15
15
|
# @param ref [ActiveRecord::Association] the ActiveRecord association
|
16
16
|
# @param scope [Proc] a scope to apply to the query (optional)
|
17
|
-
# @param use [Module] optional Module to include in the result class
|
17
|
+
# @param use [Array(Module)] optional Module to include in the result class (single or array)
|
18
18
|
# @param eval_block [Proc] a block where you may perform eager loading on *this* association (optional)
|
19
19
|
#
|
20
20
|
def initialize(ref, scope = nil, use = nil, &eval_block)
|
@@ -4,7 +4,7 @@ module OccamsRecord
|
|
4
4
|
class PolymorphicBelongsTo
|
5
5
|
# @return [String] association name
|
6
6
|
attr_reader :name
|
7
|
-
# @return [Module] optional Module to include in the result class
|
7
|
+
# @return [Array<Module>] optional Module to include in the result class (single or array)
|
8
8
|
attr_reader :use
|
9
9
|
# @return [Proc] optional Proc for eager loading things on this association
|
10
10
|
attr_reader :eval_block
|
@@ -12,7 +12,7 @@ module OccamsRecord
|
|
12
12
|
#
|
13
13
|
# @param ref [ActiveRecord::Association] the ActiveRecord association
|
14
14
|
# @param scope [Proc] a scope to apply to the query (optional)
|
15
|
-
# @param use [Module] optional Module to include in the result class
|
15
|
+
# @param use [Array<Module>] optional Module to include in the result class (single or array)
|
16
16
|
# @param eval_block [Proc] a block where you may perform eager loading on *this* association (optional)
|
17
17
|
#
|
18
18
|
def initialize(ref, scope = nil, use = nil, &eval_block)
|
data/lib/occams-record/query.rb
CHANGED
@@ -44,7 +44,7 @@ module OccamsRecord
|
|
44
44
|
# Initialize a new query.
|
45
45
|
#
|
46
46
|
# @param scope [ActiveRecord::Relation]
|
47
|
-
# @param use [Module] optional Module to include in the result class
|
47
|
+
# @param use [Array<Module>] optional Module to include in the result class (single or array)
|
48
48
|
# @param query_logger [Array] (optional) an array into which all queries will be inserted for logging/debug purposes
|
49
49
|
# @param eager_loaders [OccamsRecord::EagerLoaders::Base]
|
50
50
|
# @param eval_block [Proc] block that will be eval'd on this instance. Can be used for eager loading. (optional)
|
@@ -66,8 +66,9 @@ module OccamsRecord
|
|
66
66
|
#
|
67
67
|
# @param assoc [Symbol] name of association
|
68
68
|
# @param scope [Proc] a scope to apply to the query (optional)
|
69
|
-
# @param use [Module] optional Module to include in the result class
|
69
|
+
# @param use [Array<Module>] optional Module to include in the result class (single or array)
|
70
70
|
# @param eval_block [Proc] a block where you may perform eager loading on *this* association (optional)
|
71
|
+
# @return [OccamsRecord::Query] returns self
|
71
72
|
#
|
72
73
|
def eager_load(assoc, scope = nil, use: nil, &eval_block)
|
73
74
|
ref = model.reflections[assoc.to_s]
|
@@ -12,12 +12,12 @@ module OccamsRecord
|
|
12
12
|
# @param model [ActiveRecord::Base] the AR model representing the table (it holds column & type info).
|
13
13
|
# @param column_names [Array<String>] the column names in the result set. The order MUST match the order returned by the query.
|
14
14
|
# @param association_names [Array<String>] names of associations that will be eager loaded into the results.
|
15
|
-
# @param
|
15
|
+
# @param included_modules [Array<Module>] (optional)
|
16
16
|
# @return [OccamsRecord::ResultRow] a class customized for this result set
|
17
17
|
#
|
18
|
-
def self.build_result_row_class(model, column_names, association_names,
|
18
|
+
def self.build_result_row_class(model, column_names, association_names, included_modules = nil)
|
19
19
|
Class.new(ResultRow) do
|
20
|
-
include
|
20
|
+
Array(included_modules).each { |mod| include mod } if included_modules
|
21
21
|
|
22
22
|
self.columns = column_names.map(&:to_s)
|
23
23
|
self.associations = association_names.map(&:to_s)
|
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: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jordan Hollinger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-08-
|
11
|
+
date: 2017-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|