Skip to content

Commit 83432aa

Browse files
authored
Add Indexed#find_by! to reduce repetition (#590)
2 parents 5c1e69b + 7968909 commit 83432aa

10 files changed

+36
-26
lines changed

dev/lib/product_taxonomy/commands/add_attributes_to_categories_command.rb

+2-14
Original file line numberDiff line numberDiff line change
@@ -18,20 +18,8 @@ def execute
1818
private
1919

2020
def add_attributes_to_categories!
21-
@attributes = attribute_friendly_ids.map do |friendly_id|
22-
attribute = Attribute.find_by(friendly_id:)
23-
next attribute if attribute
24-
25-
raise "Attribute with friendly ID `#{friendly_id}` not found"
26-
end
27-
28-
@categories = category_ids.map do |id|
29-
category = Category.find_by(id:)
30-
next category if category
31-
32-
raise "Category with ID `#{id}` not found"
33-
end
34-
21+
@attributes = attribute_friendly_ids.map { |friendly_id| Attribute.find_by!(friendly_id:) }
22+
@categories = category_ids.map { |id| Category.find_by!(id:) }
3523
@categories = @categories.flat_map(&:descendants_and_self) if @include_descendants
3624

3725
@categories.each do |category|

dev/lib/product_taxonomy/commands/add_category_command.rb

+1-3
Original file line numberDiff line numberDiff line change
@@ -18,9 +18,7 @@ def execute
1818
private
1919

2020
def create_category!
21-
parent = Category.find_by(id: @parent_id)
22-
raise "Parent category `#{@parent_id}` not found" if parent.nil?
23-
21+
parent = Category.find_by!(id: @parent_id)
2422
@new_category = Category.new(id: @id || parent.next_child_id, name: @name, parent:)
2523
raise "Failed to create category: #{@new_category.errors.full_messages.to_sentence}" unless @new_category.valid?
2624

dev/lib/product_taxonomy/commands/add_value_command.rb

+1-2
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ def execute
1717
private
1818

1919
def create_value!
20-
@attribute = Attribute.find_by(friendly_id: @attribute_friendly_id)
21-
raise "Attribute `#{@attribute_friendly_id}` not found" if @attribute.nil?
20+
@attribute = Attribute.find_by!(friendly_id: @attribute_friendly_id)
2221
if @attribute.extended?
2322
raise "Attribute `#{@attribute.name}` is an extended attribute, please use a primary attribute instead"
2423
end

dev/lib/product_taxonomy/commands/dump_categories_command.rb

+1-2
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,7 @@ def execute
1212
logger.info("Dumping #{@verticals.size} verticals")
1313

1414
@verticals.each do |vertical_id|
15-
vertical_root = Category.find_by(id: vertical_id)
16-
raise "Vertical not found: #{vertical_id}" unless vertical_root
15+
vertical_root = Category.find_by!(id: vertical_id)
1716
raise "Category #{vertical_id} is not a vertical" unless vertical_root.root?
1817

1918
logger.info("Updating `#{vertical_root.name}`...")

dev/lib/product_taxonomy/models/mixins/indexed.rb

+16
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
module ProductTaxonomy
44
# Mixin providing indexing for a model, using hashes to support fast uniqueness checks and lookups by field value.
55
module Indexed
6+
NotFoundError = Class.new(StandardError)
7+
68
class << self
79
# Keep track of which model class used "extend Indexed" so that the model can be subclassed while still storing
810
# model objects in a shared index on the superclass.
@@ -67,6 +69,20 @@ def find_by(**conditions)
6769
hashed_models[field][value]
6870
end
6971

72+
# Find a model by field value. Returns the first matching record or raises an error if not found. Only works for
73+
# fields marked unique.
74+
#
75+
# @param conditions [Hash] Hash of field-value pairs to search by
76+
# @return [Object] The matching model
77+
def find_by!(**conditions)
78+
record = find_by(**conditions)
79+
return record if record
80+
81+
field, value = conditions.first
82+
field = field.to_s.humanize(capitalize: false, keep_id_suffix: true)
83+
raise NotFoundError, "#{self.name.demodulize} with #{field} \"#{value}\" not found"
84+
end
85+
7086
# Get the hash of models indexed by a given field. Only works for fields marked unique.
7187
#
7288
# @param field [Symbol] The field to get the hash for.

dev/test/commands/add_attributes_to_categories_command_test.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -137,7 +137,7 @@ class AddAttributesToCategoriesCommandTest < TestCase
137137
end
138138

139139
test "execute raises error when attribute is not found" do
140-
assert_raises(RuntimeError) do
140+
assert_raises(Indexed::NotFoundError) do
141141
AddAttributesToCategoriesCommand.new(
142142
attribute_friendly_ids: "nonexistent",
143143
category_ids: "aa-1",
@@ -147,7 +147,7 @@ class AddAttributesToCategoriesCommandTest < TestCase
147147
end
148148

149149
test "execute raises error when category is not found" do
150-
assert_raises(RuntimeError) do
150+
assert_raises(Indexed::NotFoundError) do
151151
AddAttributesToCategoriesCommand.new(
152152
attribute_friendly_ids: "color",
153153
category_ids: "nonexistent",

dev/test/commands/add_category_command_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@ class AddCategoryCommandTest < TestCase
4444
end
4545

4646
test "execute raises error when parent category not found" do
47-
assert_raises(RuntimeError) do
47+
assert_raises(Indexed::NotFoundError) do
4848
AddCategoryCommand.new(name: "New Category", parent_id: "nonexistent").execute
4949
end
5050
end

dev/test/commands/add_value_command_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ class AddValueCommandTest < TestCase
5757
end
5858

5959
test "execute raises error when attribute not found" do
60-
assert_raises(RuntimeError) do
60+
assert_raises(Indexed::NotFoundError) do
6161
AddValueCommand.new(name: "Blue", attribute_friendly_id: "nonexistent").execute
6262
end
6363
end

dev/test/commands/dump_categories_command_test.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ class DumpCategoriesCommandTest < TestCase
5454
Category.stubs(:find_by).with(id: "nonexistent").returns(nil)
5555

5656
command = DumpCategoriesCommand.new(verticals: ["nonexistent"])
57-
assert_raises(RuntimeError) do
57+
assert_raises(Indexed::NotFoundError) do
5858
command.execute
5959
end
6060
end

dev/test/models/mixins/indexed_test.rb

+10
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,16 @@ class SubModel < Model
9494
assert_raises(ArgumentError) { Model.find_by(name: "test") }
9595
end
9696

97+
test "find_by! returns the model with the specified field value" do
98+
assert_equal @model, Model.find_by!(id: 1)
99+
end
100+
101+
test "find_by! raises NotFoundError if the model with the specified field value is not in the index" do
102+
assert_raises(ProductTaxonomy::Indexed::NotFoundError) do
103+
Model.find_by!(id: 2)
104+
end
105+
end
106+
97107
test "all returns all models in the index" do
98108
assert_equal [@model], Model.all
99109
end

0 commit comments

Comments
 (0)