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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4835c655a7c4f9e68b567bc5727d9d99c13e638bb457a7615bb5ee598ae0499b
4
- data.tar.gz: 7a3ec8be97cbcb06f1b74bfd5e55e163b2fd6bacd163764551581ccdee92f16f
3
+ metadata.gz: 1731e8d0d0a676f2f94e5b019795eb3a1d5560be4e66f1d38df73cb876946de0
4
+ data.tar.gz: 92af45a6d871c13a344926319fd26a45380a3f0527ac1d3fda6f042885cb00bc
5
5
  SHA512:
6
- metadata.gz: b38f0a2f9fb329ee1ea9d0fe098a9dc8854744effef9f6699209b5375e2cd1f68b2dcb557821c074653396ad4607db75f38c054b2b72b3736714a13b3ea49050
7
- data.tar.gz: 5c9869505a2bf795156252e81871166fa0a5818798cae9ad51d6a1099938fd3a3e00922aabd22259f4073f0f8f68f4d5cb83f27bed58d01bc02a1b793e48ac99
6
+ metadata.gz: df7d5ebd7e07c4bc75ae4e895f9d362fb99ff6cfb56e24ad6d8cfc4c7b3bcd3e63e5af943573f818988be0ff0083ba2f62094c0375feb97776860fbc59f7f018
7
+ data.tar.gz: 7c7b58321d235b00c00da9f77fcd1275e92358ddbce580e12795dd0eb6c4dc6eabd752ebe85d89e48ba7ea52b66a49566a9028822ca926f9d0c93ede32feac84
data/lib/occams-record.rb CHANGED
@@ -5,3 +5,4 @@ require 'occams-record/eager_loaders'
5
5
  require 'occams-record/results'
6
6
  require 'occams-record/query'
7
7
  require 'occams-record/raw_query'
8
+ require 'occams-record/errors'
@@ -117,7 +117,7 @@ module OccamsRecord
117
117
  when :has_many
118
118
  HasMany
119
119
  when :has_and_belongs_to_many
120
- EagerLoaders::Habtm
120
+ Habtm
121
121
  else
122
122
  raise "Unsupported association type `#{macro}`"
123
123
  end
@@ -49,7 +49,13 @@ module OccamsRecord
49
49
  # @yield
50
50
  #
51
51
  def calc_ids(rows)
52
- ids = rows.map { |r| r.send @foreign_key }.compact.uniq
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
 
@@ -55,8 +55,6 @@ module OccamsRecord
55
55
  raise 'Not Implemented'
56
56
  end
57
57
 
58
- private
59
-
60
58
  #
61
59
  # Returns the base scope for the relation, including any scope defined on the association itself,
62
60
  # and any optional scope passed into the eager loader.
@@ -11,7 +11,13 @@ module OccamsRecord
11
11
  # @yield
12
12
  #
13
13
  def query(rows)
14
- ids = rows.map { |r| r.send @ref.foreign_key }.compact.uniq
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
- id = row.send(@ref.association_primary_key).to_s
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
- id = row.send(@ref.active_record_primary_key).to_s
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 { |r| conn.quote r.send @ref.active_record_primary_key }
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 { |r| r.send @ref.active_record_primary_key }.compact.uniq
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 { |r| r.send(@foreign_type) == type }
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
@@ -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 MissingFieldError.new(assoc_row, e.name)
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 MissingFieldError.new(row, e.name)
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 MissingFieldError.new(assoc_rows[0], e.name)
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 MissingFieldError.new(row, e.name)
68
+ raise MissingColumnError.new(row, e.name)
88
69
  end
89
70
  row.send @assign, assoc_rows_by_attr[pkey] || []
90
71
  end
@@ -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(model.name, name)
110
+ raise MissingEagerLoadError.new(self, name)
111
111
  elsif model.columns_hash.has_key? name.to_s
112
- raise MissingColumnSelectError.new(model.name, name)
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
@@ -3,5 +3,5 @@
3
3
  #
4
4
  module OccamsRecord
5
5
  # Library version
6
- VERSION = '0.19.0'.freeze
6
+ VERSION = '0.20.0'.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: 0.19.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-27 00:00:00.000000000 Z
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