occams-record 1.0.0.rc4 → 1.0.0.rc5

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: 3c40b0d44fb2db1881bda281bc83b8bf475c0fea2ea6fd86ea90258d865bfffa
4
- data.tar.gz: 793a87b8f7d859cd42a4e629616e59487aeed0ff3c63dcc89910ad6ab6766ccc
3
+ metadata.gz: a370b14fabfecd12e219d2bdf5c0719e95c71518e283a5aa5601e9de69c5b3d4
4
+ data.tar.gz: dbfab334da683c11342efeece655780c59272f2ac51c1ddf6c5382fea926571a
5
5
  SHA512:
6
- metadata.gz: 42fe66a1f8dcea058db1f694dcf201292068f18623625d7aa289f162887b16653a9811a7c27d784e3ca9f7e128fc4ea16727d928acf7aa14ce5122881c742f65
7
- data.tar.gz: ff4f8ed12de31bb6762c70ba12264781c7d51341f1a20480affd121494f3c75da9f0aae683e587540e2d69ec452ea97cd29f6d71ddbb8e9cbdb0748842dc262e
6
+ metadata.gz: 35e38ad43a0cbe41adfcbffa72badd4cf3b6f1f716a74fe1e752e419fb4697903156445360f5b159d951983faa716c71ad157edce704dbfa7155f8d51921b44d
7
+ data.tar.gz: bf2e41947e4366243b3a45ce9a4f4a8bf3fd2dea1f7314f85a61cc3268be3c514fb08e6a5a6fcf6c0a83de35e7a0905ffea3d2d9f64c4511433ec56fc3088174
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  > Do not multiply entities beyond necessity. -- Occam's Razor
4
4
 
5
- **Breaking change in 1.0.0 RC1** See HISTORY.md.
5
+ **Breaking change in 1.0.0 RC1** See [HISTORY.md](https://github.com/jhollinger/occams-record/blob/master/HISTORY.md#100rc1-2018-12-01).
6
6
 
7
7
  Occam's Record is a high-efficiency, advanced query library for ActiveRecord apps. It is **not** an ORM or an ActiveRecord replacement. Use it to solve pain points in your existing ActiveRecord app. Occams Record gives you two things:
8
8
 
@@ -228,6 +228,14 @@ The following ActiveRecord features are not supported, and likely never will be.
228
228
 
229
229
  ---
230
230
 
231
+ # Benchmarking
232
+
233
+ `bundle exec rake bench` will run a suite of performance benchmarks comparing Occams Record with Active Record. These are primarily used during development to prevent performance regressions. An in-memory Sqlite database is used.
234
+
235
+ If you run your own benchmarks, keep in mind exactly what you're measuring. For example if you're benchmarking a report written in AR vs OR, there are many constants in that measurement: the time spent in the database, the time spent transfering the database results back to your Ruby process, any calculations you're doing on your results, and the time spent building your html/json/csv/etc. So if OR is 3x fastr than AR, the total runtime of said report *won't* improve by 3x.
236
+
237
+ On the other hand, Active Record makes it *very* easy to forget to eager load associations (the N+1 query problem). Occams Record fixes that. So if your report was missing some associations you could see easily see performance improvements well over 3x.
238
+
231
239
  # Testing
232
240
 
233
241
  To run the tests, simply run:
@@ -11,6 +11,8 @@ module OccamsRecord
11
11
  # @yield
12
12
  #
13
13
  def query(rows)
14
+ return if rows.empty?
15
+
14
16
  ids = rows.map { |row|
15
17
  begin
16
18
  row.send @ref.foreign_key
@@ -18,7 +20,9 @@ module OccamsRecord
18
20
  raise MissingColumnError.new(row, e.name)
19
21
  end
20
22
  }.compact.uniq
21
- yield base_scope.where(@ref.association_primary_key => ids) if ids.any?
23
+
24
+ q = base_scope.where(@ref.association_primary_key => ids)
25
+ yield q if ids.any?
22
26
  end
23
27
 
24
28
  #
@@ -12,6 +12,7 @@ module OccamsRecord
12
12
  #
13
13
  def query(rows)
14
14
  return if rows.empty?
15
+
15
16
  ids = rows.map { |row|
16
17
  begin
17
18
  row.send @ref.active_record_primary_key
@@ -19,9 +20,10 @@ module OccamsRecord
19
20
  raise MissingColumnError.new(row, e.name)
20
21
  end
21
22
  }.compact.uniq
23
+
22
24
  q = base_scope.where(@ref.foreign_key => ids)
23
25
  q.where!(@ref.type => rows[0].class&.model_name) if @ref.options[:as]
24
- yield ids.any? ? q : nil
26
+ yield q if ids.any?
25
27
  end
26
28
 
27
29
  #
@@ -29,27 +29,53 @@ module OccamsRecord
29
29
  # for the associated rows.
30
30
  #
31
31
  def single!(assoc_rows, mapping)
32
- target_attrs = mapping.keys.map
32
+ target_attrs = mapping.keys
33
33
  assoc_attrs = mapping.values
34
34
 
35
- assoc_rows_by_ids = assoc_rows.reduce({}) { |a, assoc_row|
36
- begin
37
- ids = assoc_attrs.map { |attr| assoc_row.send attr }
38
- rescue NoMethodError => e
39
- raise MissingColumnError.new(assoc_row, e.name)
35
+ # Optimized for merges where there's a single mapping key pair (which is the vast majority)
36
+ if mapping.size == 1
37
+ target_attr, assoc_attr = target_attrs[0], assoc_attrs[0]
38
+ assoc_rows_by_ids = assoc_rows.reduce({}) { |a, assoc_row|
39
+ #begin
40
+ id = assoc_row.send assoc_attr
41
+ #rescue NoMethodError => e
42
+ # raise MissingColumnError.new(assoc_row, e.name)
43
+ #end
44
+ a[id] ||= assoc_row
45
+ a
46
+ }
47
+
48
+ target_rows.each do |row|
49
+ begin
50
+ attr = row.send target_attr
51
+ rescue NoMethodError => e
52
+ raise MissingColumnError.new(row, e.name)
53
+ end
54
+ row.send @assign, attr ? assoc_rows_by_ids[attr] : nil
40
55
  end
41
- a[ids] ||= assoc_row
42
- a
43
- }
44
56
 
45
- target_rows.each do |row|
46
- begin
47
- attrs = target_attrs.map { |attr| row.send attr }
48
- rescue NoMethodError => e
49
- raise MissingColumnError.new(row, e.name)
57
+ # Slower but works with any number of mapping key pairs
58
+ else
59
+ assoc_rows_by_ids = assoc_rows.reduce({}) { |a, assoc_row|
60
+ begin
61
+ ids = assoc_attrs.map { |attr| assoc_row.send attr }
62
+ rescue NoMethodError => e
63
+ raise MissingColumnError.new(assoc_row, e.name)
64
+ end
65
+ a[ids] ||= assoc_row
66
+ a
67
+ }
68
+
69
+ target_rows.each do |row|
70
+ begin
71
+ attrs = target_attrs.map { |attr| row.send attr }
72
+ rescue NoMethodError => e
73
+ raise MissingColumnError.new(row, e.name)
74
+ end
75
+ row.send @assign, attrs.any? ? assoc_rows_by_ids[attrs] : nil
50
76
  end
51
- row.send @assign, attrs.any? ? assoc_rows_by_ids[attrs] : nil
52
77
  end
78
+
53
79
  nil
54
80
  end
55
81
 
@@ -65,22 +91,46 @@ module OccamsRecord
65
91
  target_attrs = mapping.keys
66
92
  assoc_attrs = mapping.values
67
93
 
68
- begin
69
- assoc_rows_by_attrs = assoc_rows.group_by { |r|
70
- assoc_attrs.map { |attr| r.send attr }
71
- }
72
- rescue NoMethodError => e
73
- raise MissingColumnError.new(assoc_rows[0], e.name)
74
- end
94
+ # Optimized for merges where there's a single mapping key pair (which is the vast majority)
95
+ if mapping.size == 1
96
+ target_attr, assoc_attr = target_attrs[0], assoc_attrs[0]
97
+ begin
98
+ assoc_rows_by_attr = assoc_rows.group_by { |r|
99
+ r.send assoc_attr
100
+ }
101
+ rescue NoMethodError => e
102
+ raise MissingColumnError.new(assoc_rows[0], e.name)
103
+ end
75
104
 
76
- target_rows.each do |row|
105
+ target_rows.each do |row|
106
+ begin
107
+ pkey = row.send target_attr
108
+ rescue NoMethodError => e
109
+ raise MissingColumnError.new(row, e.name)
110
+ end
111
+ row.send @assign, assoc_rows_by_attr[pkey] || []
112
+ end
113
+
114
+ # Slower but works with any number of mapping key pairs
115
+ else
77
116
  begin
78
- pkeys = target_attrs.map { |attr| row.send attr }
117
+ assoc_rows_by_attrs = assoc_rows.group_by { |r|
118
+ assoc_attrs.map { |attr| r.send attr }
119
+ }
79
120
  rescue NoMethodError => e
80
- raise MissingColumnError.new(row, e.name)
121
+ raise MissingColumnError.new(assoc_rows[0], e.name)
122
+ end
123
+
124
+ target_rows.each do |row|
125
+ begin
126
+ pkeys = target_attrs.map { |attr| row.send attr }
127
+ rescue NoMethodError => e
128
+ raise MissingColumnError.new(row, e.name)
129
+ end
130
+ row.send @assign, assoc_rows_by_attrs[pkeys] || []
81
131
  end
82
- row.send @assign, assoc_rows_by_attrs[pkeys] || []
83
132
  end
133
+
84
134
  nil
85
135
  end
86
136
  end
@@ -3,5 +3,5 @@
3
3
  #
4
4
  module OccamsRecord
5
5
  # Library version
6
- VERSION = '1.0.0.rc4'.freeze
6
+ VERSION = '1.0.0.rc5'.freeze
7
7
  end
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.0.0.rc4
4
+ version: 1.0.0.rc5
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jordan Hollinger
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-07 00:00:00.000000000 Z
11
+ date: 2018-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord