-
-
Notifications
You must be signed in to change notification settings - Fork 512
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Improve product drive index page performance #4881
base: main
Are you sure you want to change the base?
Changes from 1 commit
596f5a6
1bf1b63
d8f1f4e
b927a12
3c68ccb
c69ba55
6eadfea
fed367f
185fbbf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
class ProductDriveSummaryService | ||
def initialize(product_drives:, within_date_range:, item_category_id:) | ||
@product_drives = product_drives | ||
@within_date_range = within_date_range | ||
@item_category_id = item_category_id | ||
end | ||
|
||
def call | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we turn this into a class method rather than requiring an instance? I find it much easier to work with (e.g. for stubbing methods). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done. |
||
calculate_summary | ||
self | ||
end | ||
|
||
def fetch_quantity(product_drive_id) | ||
@summary.dig(product_drive_id, :quantity) | ||
end | ||
|
||
def fetch_unique_item_count(product_drive_id) | ||
@summary.dig(product_drive_id, :unique_item_count) | ||
end | ||
|
||
def fetch_value(product_drive_id) | ||
@summary.dig(product_drive_id, :value) | ||
end | ||
|
||
private | ||
|
||
# Returns hash of total quantity, unique item count and value per product drive | ||
# Example return: { 1 => { quantity: 15, unique_item_count: 2, value: 100 }, ...} | ||
# | ||
# @return [Hash<Hash<Symbol, Integer>>] | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can we use a Data object instead of a Hash? It seems like this is trying to do two things:
IMO the service class should just do the calculation with a class method, and return an object that you can use to interrogate the results. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Refactored the class a bit. Now returns a hash of ids mapped to data summary objects. Let me know what you think. |
||
def calculate_summary | ||
@summary ||= begin | ||
query = ProductDrive | ||
.left_joins(donations: {line_items: [:item]}) | ||
.where(id: @product_drives.ids) | ||
.within_date_range(@within_date_range) | ||
.group("product_drives.id") | ||
.distinct | ||
|
||
query = query.where(items: {item_category_id: @item_category_id}) if @item_category_id.present? | ||
|
||
query.pluck(Arel.sql( | ||
"product_drives.id AS id, | ||
COALESCE(SUM(line_items.quantity), 0) AS quantity, | ||
COUNT(DISTINCT line_items.item_id) AS unique_item_count, | ||
COALESCE(SUM(COALESCE(items.value_in_cents, 0) * line_items.quantity), 0) AS value" | ||
)).to_h do |(id, quantity, unique_item_count, value)| | ||
[id, {quantity:, unique_item_count:, value:}] | ||
end | ||
end | ||
end | ||
end |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is there a reason we're using that date range to get the initial list and then passing it again into the service?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's a little confusing I know. We are doing two things with this date range:
So a product drive could overlap with a given date range, but have no donations during that range, so the quanitity/value/item count would all show as zero.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
But I was previously incorrectly filtering by the date range on the product drives a second time in the service, which indeed didn't make any sense.