occams-record 0.19.0 → 0.20.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 +4 -4
- data/lib/occams-record.rb +1 -0
- data/lib/occams-record/eager_loaders.rb +1 -1
- data/lib/occams-record/eager_loaders/ad_hoc_base.rb +7 -1
- data/lib/occams-record/eager_loaders/base.rb +0 -2
- data/lib/occams-record/eager_loaders/belongs_to.rb +7 -1
- data/lib/occams-record/eager_loaders/habtm.rb +18 -3
- data/lib/occams-record/eager_loaders/has_one.rb +7 -1
- data/lib/occams-record/eager_loaders/polymorphic_belongs_to.rb +7 -1
- data/lib/occams-record/errors.rb +34 -0
- data/lib/occams-record/merge.rb +4 -23
- data/lib/occams-record/query.rb +25 -1
- data/lib/occams-record/results.rb +2 -30
- data/lib/occams-record/version.rb +1 -1
- 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: 1731e8d0d0a676f2f94e5b019795eb3a1d5560be4e66f1d38df73cb876946de0
|
4
|
+
data.tar.gz: 92af45a6d871c13a344926319fd26a45380a3f0527ac1d3fda6f042885cb00bc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: df7d5ebd7e07c4bc75ae4e895f9d362fb99ff6cfb56e24ad6d8cfc4c7b3bcd3e63e5af943573f818988be0ff0083ba2f62094c0375feb97776860fbc59f7f018
|
7
|
+
data.tar.gz: 7c7b58321d235b00c00da9f77fcd1275e92358ddbce580e12795dd0eb6c4dc6eabd752ebe85d89e48ba7ea52b66a49566a9028822ca926f9d0c93ede32feac84
|
data/lib/occams-record.rb
CHANGED
@@ -49,7 +49,13 @@ module OccamsRecord
|
|
49
49
|
# @yield
|
50
50
|
#
|
51
51
|
def calc_ids(rows)
|
52
|
-
ids = rows.map { |
|
52
|
+
ids = rows.map { |row|
|
53
|
+
begin
|
54
|
+
row.send @foreign_key
|
55
|
+
rescue NoMethodError => e
|
56
|
+
raise MissingColumnError.new(row, e.name)
|
57
|
+
end
|
58
|
+
}.compact.uniq
|
53
59
|
yield ids
|
54
60
|
end
|
55
61
|
|
@@ -11,7 +11,13 @@ module OccamsRecord
|
|
11
11
|
# @yield
|
12
12
|
#
|
13
13
|
def query(rows)
|
14
|
-
ids = rows.map { |
|
14
|
+
ids = rows.map { |row|
|
15
|
+
begin
|
16
|
+
row.send @ref.foreign_key
|
17
|
+
rescue NoMethodError => e
|
18
|
+
raise MissingColumnError.new(row, e.name)
|
19
|
+
end
|
20
|
+
}.compact.uniq
|
15
21
|
yield base_scope.where(@ref.active_record_primary_key => ids) if ids.any?
|
16
22
|
end
|
17
23
|
|
@@ -30,14 +30,22 @@ module OccamsRecord
|
|
30
30
|
}
|
31
31
|
|
32
32
|
assoc_rows_by_id = assoc_rows.reduce({}) { |a, row|
|
33
|
-
|
33
|
+
begin
|
34
|
+
id = row.send(@ref.association_primary_key).to_s
|
35
|
+
rescue NoMethodError => e
|
36
|
+
raise MissingColumnError.new(row, e.name)
|
37
|
+
end
|
34
38
|
a[id] = row
|
35
39
|
a
|
36
40
|
}
|
37
41
|
|
38
42
|
assign = "#{name}="
|
39
43
|
rows.each do |row|
|
40
|
-
|
44
|
+
begin
|
45
|
+
id = row.send(@ref.active_record_primary_key).to_s
|
46
|
+
rescue NoMethodError => e
|
47
|
+
raise MissingColumnError.new(row, e.name)
|
48
|
+
end
|
41
49
|
assoc_fkeys = (joins_by_id[id] || []).uniq
|
42
50
|
associations = assoc_rows_by_id.values_at(*assoc_fkeys).compact.uniq
|
43
51
|
row.send assign, associations
|
@@ -59,7 +67,14 @@ module OccamsRecord
|
|
59
67
|
join_table = conn.quote_table_name @ref.join_table
|
60
68
|
assoc_fkey = conn.quote_column_name @ref.association_foreign_key
|
61
69
|
fkey = conn.quote_column_name @ref.foreign_key
|
62
|
-
quoted_ids = rows.map { |
|
70
|
+
quoted_ids = rows.map { |row|
|
71
|
+
begin
|
72
|
+
id = row.send @ref.active_record_primary_key
|
73
|
+
rescue NoMethodError => e
|
74
|
+
raise MissingColumnError.new(row, e.name)
|
75
|
+
end
|
76
|
+
conn.quote id
|
77
|
+
}
|
63
78
|
|
64
79
|
@join_rows = conn.
|
65
80
|
exec_query("SELECT #{fkey}, #{assoc_fkey} FROM #{join_table} WHERE #{fkey} IN (#{quoted_ids.join ','})").
|
@@ -12,7 +12,13 @@ module OccamsRecord
|
|
12
12
|
#
|
13
13
|
def query(rows)
|
14
14
|
return if rows.empty?
|
15
|
-
ids = rows.map { |
|
15
|
+
ids = rows.map { |row|
|
16
|
+
begin
|
17
|
+
row.send @ref.active_record_primary_key
|
18
|
+
rescue NoMethodError => e
|
19
|
+
raise MissingColumnError.new(row, e.name)
|
20
|
+
end
|
21
|
+
}.compact.uniq
|
16
22
|
q = base_scope.where(@ref.foreign_key => ids)
|
17
23
|
q.where!(@ref.type => rows[0].class&.model_name) if @ref.options[:as]
|
18
24
|
yield q if ids.any?
|
@@ -57,7 +57,13 @@ module OccamsRecord
|
|
57
57
|
def merge!(assoc_rows_of_type, rows)
|
58
58
|
return if assoc_rows_of_type.empty?
|
59
59
|
type = assoc_rows_of_type[0].class.model_name
|
60
|
-
rows_of_type = rows.select { |
|
60
|
+
rows_of_type = rows.select { |row|
|
61
|
+
begin
|
62
|
+
row.send(@foreign_type) == type
|
63
|
+
rescue NoMethodError => e
|
64
|
+
raise MissingColumnError.new(row, e.name)
|
65
|
+
end
|
66
|
+
}
|
61
67
|
model = type.constantize
|
62
68
|
Merge.new(rows_of_type, name).
|
63
69
|
single!(assoc_rows_of_type, @ref.foreign_key.to_s, model.primary_key.to_s)
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module OccamsRecord
|
2
|
+
# Exception raised when a record wasn't loaded with all requested data
|
3
|
+
class MissingDataError < StandardError
|
4
|
+
# @return [String]
|
5
|
+
attr_reader :model_name
|
6
|
+
# @return [OccamsRecord::Result::Row]
|
7
|
+
attr_reader :record
|
8
|
+
# @return [Symbol]
|
9
|
+
attr_reader :name
|
10
|
+
|
11
|
+
# @param record [OccamsRecord::Result::Row]
|
12
|
+
# @param name [Symbol]
|
13
|
+
def initialize(record, name)
|
14
|
+
@record, @name = record, name
|
15
|
+
@model_name = record.class.model_name
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Exception when an unselected column is called on a result row
|
20
|
+
class MissingColumnError < MissingDataError
|
21
|
+
# @return [String]
|
22
|
+
def message
|
23
|
+
"Column '#{name}' is unavailable on #{model_name} because it was not included in the SELECT statement!"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Exception when an unloaded association is called on a result row
|
28
|
+
class MissingEagerLoadError < MissingDataError
|
29
|
+
# @return [String]
|
30
|
+
def message
|
31
|
+
"Association '#{name}' is unavailable on #{model_name} because it was not eager loaded!"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/occams-record/merge.rb
CHANGED
@@ -9,25 +9,6 @@ module OccamsRecord
|
|
9
9
|
# @return [Array<OccamsRecord::Results::Row>] the rows into which associated rows will be merged
|
10
10
|
attr_reader :target_rows
|
11
11
|
|
12
|
-
# Exception raised when a foreign or primary key is missing from a record
|
13
|
-
class MissingFieldError < StandardError
|
14
|
-
# @return [OccamsRecord::Result::Row]
|
15
|
-
attr_reader :record
|
16
|
-
# @return [Symbol]
|
17
|
-
attr_reader :field
|
18
|
-
|
19
|
-
# @param record [OccamsRecord::Result::Row]
|
20
|
-
# @param field [Symbol]
|
21
|
-
def initialize(record, field)
|
22
|
-
@record, @field = record, field
|
23
|
-
end
|
24
|
-
|
25
|
-
# @return [String]
|
26
|
-
def message
|
27
|
-
"Missing field '#{field}' on #{record.inspect}. Did you forget to select it?"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
12
|
#
|
32
13
|
# Initialize a new Merge operation.
|
33
14
|
#
|
@@ -52,7 +33,7 @@ module OccamsRecord
|
|
52
33
|
begin
|
53
34
|
id = assoc_row.send assoc_attr
|
54
35
|
rescue NoMethodError => e
|
55
|
-
raise
|
36
|
+
raise MissingColumnError.new(assoc_row, e.name)
|
56
37
|
end
|
57
38
|
a[id] = assoc_row
|
58
39
|
a
|
@@ -62,7 +43,7 @@ module OccamsRecord
|
|
62
43
|
begin
|
63
44
|
attr = row.send target_attr
|
64
45
|
rescue NoMethodError => e
|
65
|
-
raise
|
46
|
+
raise MissingColumnError.new(row, e.name)
|
66
47
|
end
|
67
48
|
row.send @assign, attr ? assoc_rows_by_id[attr] : nil
|
68
49
|
end
|
@@ -77,14 +58,14 @@ module OccamsRecord
|
|
77
58
|
begin
|
78
59
|
assoc_rows_by_attr = assoc_rows.group_by(&assoc_attr.to_sym)
|
79
60
|
rescue NoMethodError => e
|
80
|
-
raise
|
61
|
+
raise MissingColumnError.new(assoc_rows[0], e.name)
|
81
62
|
end
|
82
63
|
|
83
64
|
target_rows.each do |row|
|
84
65
|
begin
|
85
66
|
pkey = row.send target_attr
|
86
67
|
rescue NoMethodError => e
|
87
|
-
raise
|
68
|
+
raise MissingColumnError.new(row, e.name)
|
88
69
|
end
|
89
70
|
row.send @assign, assoc_rows_by_attr[pkey] || []
|
90
71
|
end
|
data/lib/occams-record/query.rb
CHANGED
@@ -60,10 +60,25 @@ module OccamsRecord
|
|
60
60
|
#
|
61
61
|
# Run the query and return the results.
|
62
62
|
#
|
63
|
+
# You may optionally pass a block to modify the query just before it's run (the change will NOT persist).
|
64
|
+
# This is very useful for running paginated queries.
|
65
|
+
#
|
66
|
+
# occams = OccamsRecord.query(Widget.all)
|
67
|
+
#
|
68
|
+
# # returns first 100 rows
|
69
|
+
# occams.run { |q| q.offset(0).limit(100) }
|
70
|
+
#
|
71
|
+
# # returns second 100 rows
|
72
|
+
# occams.run { |q| q.offset(100).limit(100) }
|
73
|
+
#
|
74
|
+
# # returns ALL rows
|
75
|
+
# occams.run
|
76
|
+
#
|
63
77
|
# @return [Array<OccamsRecord::Results::Row>]
|
78
|
+
# @yield [ActiveRecord::Relation] You may use this to return and run a modified relation
|
64
79
|
#
|
65
80
|
def run
|
66
|
-
sql = scope.to_sql
|
81
|
+
sql = block_given? ? yield(scope).to_sql : scope.to_sql
|
67
82
|
@query_logger << sql if @query_logger
|
68
83
|
result = model.connection.exec_query sql
|
69
84
|
row_class = OccamsRecord::Results.klass(result.columns, result.column_types, @eager_loaders.map(&:name), model: model, modules: @use)
|
@@ -74,6 +89,15 @@ module OccamsRecord
|
|
74
89
|
|
75
90
|
alias_method :to_a, :run
|
76
91
|
|
92
|
+
#
|
93
|
+
# Returns the number of rows that will be returned if the query is run.
|
94
|
+
#
|
95
|
+
# @return [Integer]
|
96
|
+
#
|
97
|
+
def count
|
98
|
+
scope.count
|
99
|
+
end
|
100
|
+
|
77
101
|
#
|
78
102
|
# Run the query and return the first result (which could be nil). This WILL append a LIMIT 1 to the query.
|
79
103
|
#
|
@@ -107,9 +107,9 @@ module OccamsRecord
|
|
107
107
|
model = self.class.model_name.constantize
|
108
108
|
|
109
109
|
if model.reflections.has_key? name.to_s
|
110
|
-
raise MissingEagerLoadError.new(
|
110
|
+
raise MissingEagerLoadError.new(self, name)
|
111
111
|
elsif model.columns_hash.has_key? name.to_s
|
112
|
-
raise
|
112
|
+
raise MissingColumnError.new(self, name)
|
113
113
|
else
|
114
114
|
super
|
115
115
|
end
|
@@ -124,33 +124,5 @@ module OccamsRecord
|
|
124
124
|
"#<OccamsRecord::Results::Row @model_name=#{self.class.model_name} @raw_values=#{@raw_values}>"
|
125
125
|
end
|
126
126
|
end
|
127
|
-
|
128
|
-
# Exception when an unloaded association is called on a result row
|
129
|
-
class MissingEagerLoadError < StandardError
|
130
|
-
attr_reader :model_name
|
131
|
-
attr_reader :name
|
132
|
-
|
133
|
-
def initialize(model_name, name)
|
134
|
-
@model_name, @name = model_name, name
|
135
|
-
end
|
136
|
-
|
137
|
-
def message
|
138
|
-
"The association '#{name}' is unavailable on #{model_name} because it has not been eager loaded!"
|
139
|
-
end
|
140
|
-
end
|
141
|
-
|
142
|
-
# Exception when an unselected column is called on a result row
|
143
|
-
class MissingColumnSelectError < StandardError
|
144
|
-
attr_reader :model_name
|
145
|
-
attr_reader :name
|
146
|
-
|
147
|
-
def initialize(model_name, name)
|
148
|
-
@model_name, @name = model_name, name
|
149
|
-
end
|
150
|
-
|
151
|
-
def message
|
152
|
-
"The column '#{name}' is unavailable on #{model_name} because it was not included in the SELECT statement!"
|
153
|
-
end
|
154
|
-
end
|
155
127
|
end
|
156
128
|
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: 0.
|
4
|
+
version: 0.20.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: 2018-03
|
11
|
+
date: 2018-04-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -50,6 +50,7 @@ files:
|
|
50
50
|
- lib/occams-record/eager_loaders/has_many.rb
|
51
51
|
- lib/occams-record/eager_loaders/has_one.rb
|
52
52
|
- lib/occams-record/eager_loaders/polymorphic_belongs_to.rb
|
53
|
+
- lib/occams-record/errors.rb
|
53
54
|
- lib/occams-record/merge.rb
|
54
55
|
- lib/occams-record/query.rb
|
55
56
|
- lib/occams-record/raw_query.rb
|