occams-record 0.19.0 → 0.20.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|