-
Notifications
You must be signed in to change notification settings - Fork 89
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
refactor: Simplify Causality Lot stitching #3026
Conversation
}) | ||
}) | ||
|
||
describe("auctionsLotStandingConnection", () => { |
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.
All of this test code can be removed, because we no longer need to assert against what causality's stitched pass-through returns as we're now just making a simple query and attaching it to the Lot.lot
field.
it("adds #auctionsLotStandingConnection to me", async () => { | ||
const { getFields } = await useCausalityStitching() | ||
expect(await getFields("Me")).toContain("auctionsLotStandingConnection") | ||
it("resolves a SaleArtwork on an AuctionsLotStanding", async () => { |
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.
Most of this is just reorganizing to match the order of whats in the stitching
file.
@artsy/purchase-devs cc & breadcrumbs |
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.
One question about a possible breaking change to the schema (field becomes nullable) but I am okay with the overall approach. Thanks for taking the time to understand and simplify this wacky code.
type Lot implements Node { | ||
# A globally unique ID. | ||
id: ID! | ||
|
||
# A type-specific ID likely used as a database ID. | ||
internalID: ID! | ||
lot: AuctionsLotState |
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.
correct me if i'm wrong, but this is a breaking change, isn't it? Eigen clients will need to adapt to check lot state is present before rendering anything that requires it.
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.
Yup, this is the follow-up I mentioned. The MyBids component will need to check if null in the loop, but its not a breaking schema change since the same query fields are still in place.
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.
I think maybe we are talking about two slightly different different things. Isn't it possible this change would break eigen right here if a current app version loaded a lot with no lot
state? https://github.com/artsy/eigen/blob/fcdad03ed67580286af2af27cf69a5eb71243c6e/src/lib/Scenes/MyBids/Components/WatchedLot.tsx#L18-L20
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.
Ahh, I see what you mean. Here's a q. Outside of weird staging env, is it possible for there to be a lot with no lot state?
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.
Almost certainly not!
@@ -9006,6 +9004,9 @@ type Query { | |||
id: String! | |||
): AuctionResult | |||
|
|||
# Returns a lot with specific `id`. | |||
auctionsLot(id: ID!): AuctionsLotState |
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.
Not going to solve it in this PR but am reminded that we have a sticky situation building up with our naming conventions around 'lots':
SaleArtwork
-> gravity's DB/model name for an auction lotLot
-> Causality's name for an auction lot, lot id is same as gravity SaleArtwork idlot
/lotState
-> two different names for the same thing in causality's graphql schema. I think we updated the schema to havelot
be favored andlotState
is deprecated, reasoning that state was redundant (the type is stillLotState
), but ...Lot
-> Metaphysics' name for the new, authoritative lot type that makes a causalitylot
field (of typeAuctionsLotState
) from causality available on the same object as sale artwork metadata. Thus it is possible to wind up with code that looks likelot.lot.reserveStatus
which might be confusing.
Only saying this here to observe - if I had it to redo I would have kept the lotState
version of the name.
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.
Related to this comment on naming, I'm hesitant to introduce another new name to our schema.
Can this just be lot
? Or is that reserved somewhere?
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.
This is actually lot
, but what we're doing is prefixing it with the stitched auctions
prefix. Do you mean: don't do this?
(Also sorry, didn't see this comment before merging!)
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 this automagic? (Like how we append commerce
to fields from exchange?) If so that's 👍 with me. If we were consciously making a decision here to add auctions-
then I'd ask we don't add another name 😄.
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.
Yup, it indeed is automagic ✨
@@ -10,7 +10,7 @@ import { | |||
import { readFileSync } from "fs" | |||
|
|||
const blacklistedTypes: string[] = [] | |||
const whitelistedRootFields: string[] = [] | |||
const whitelistedRootFields: string[] = ["lot"] |
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.
similar comment here, if folks thought it was a good idea I would propose moving towards preferring fields named lotState
when referring to the causality states. If there's no interest in this change I will get over it.
As I started working on moving the MyBids logic from Eigen to MP, I noticed some places where we might run into confusion/trouble later and wanted to open a PR up for discussion.
This refactors a previous PR to simplify our Causality
Lot
stitching code by deferring to more conventional stitching patterns seen throughout MP, removing indirection, and deleting a good amount of code.All in all, no breaking changes have been made to the schema, and everything should be backwards compatible; however, as detailed below, we're now returning all
watchedLotConnection
nodes, versus just some. I'll defer to @erikdstock as to whether follow-up work is necessary in Eigen and am happy to tackle that as well.Changes:
Previously, we created a new type
Lot
which handles lot state from Causality. In order to add alot
field to theLot
type (Lot
being the node on a newWatchedLotConnection
), we needed to make a request to causality by using a dataloader in ourwatchedLotConnection
resolver, and then we added that response to the express req/res cyclecontext
in order to pass it to our causality stitching logic, which is in a distant area of the codebase. This then extended the stitched causalityAuctionLotState
type with data fetched from causality via thecausalityLoader
, not from stitching.The original assumption behind this was: how do we take a selection of all watched lots and then make one request to causality to get an array of lot state for all arworks, and then interleave the response in with the watched lots in a connection. This isn't exactly easy directly within stitched code. And the
context
solution was a clever one! But I think it might be a case of premature optimization in the sense that for given user who watches artworks, there's only going to be a small number of sales going on at any given time, and so we'd never be dealing with situation where suddenly the watched lots connection gets blown up with like 500 artworks. When we do get to that point and real world performance concerns are observed, we should solve it, but not until then. In meantime keep things as vanilla as we can.And so this solution defers exclusively to conventional stitching techniques in that for n number of watched lots, we call causality's
delegateToSchema
and execute thelot(id: ...)
query with theinternalID
of the artwork, which simplifies the feature substantially.Additionally, I broke out the coupling between
me.watchedLotConnection
andLot
, sinceLot
is a more general type, wherewatchedLotConnection
is a sub-field ofme
, and should be co-located there.Another change is, previously if a sale artwork lacked
lot
state, it was excluded completely from thewatchedLotConnection
array, leading to confusion. A user could be watching x number of lots, but hasn't bid yet; those lots should still be represented in the connection ("a users watched lots") and for the purposes of the My Bids component, filtered at the UI level.In the tests, indirection was also removed around testing MP-centric fields within causality's stitching code. Meaning: we were testing
watchedLotsConnection
far away from wherewatchedLotsConnection
was defined.--
In a follow-up PR I think some similar refactoring can be done around
auctionsLotStandingConnection
(based on discussions that Erik and I have been having), which will then put us in a good place to formally migrate the MyBids logic out of Eigen and into MP, to be shared with force.