feat: add cart read queries #93
Loading…
Reference in a new issue
No description provided.
Delete branch "feat/cart-queries"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
PR Review: feat: add cart read queries
Good work on this PR! The implementation follows the existing patterns in the codebase well. Here are my findings:
✅ Strengths
Consistent architecture — The new
CartBatch,CartItemBatch,CartClient, andCartItemClientclasses follow the establishedBatch/BatchRows/Serializablepatterns used for products.Proper security checks — Both
CartBatch.forUserandCartItemBatch.forUsercorrectly validate that carts/items belong to the requesting user. Theexistssubquery inCartItemBatch.forUseris the right approach for cross-table ownership verification.Bug fix — The
cartItemValuetable foreign key was corrected fromproducttoproductOption(cartItemValue.ts). This was a real bug — cart item values should reference product options, not products.Good use of
query.batch— All remote queries usequery.batchfor efficient batched server-side resolution.CartBatch.getClients()is sync — This is a nice optimization since it only needs the ID already present in the batch, unlike othergetClients()methods that require DB queries.🔍 Observations & Suggestions
1.
CartItemValuetype placement (src/lib/entities/cart/cart-item/index.ts)The
CartItemValuetype is defined here, but it's also used in theCart.addItemmethod insrc/lib/entities/cart/index.ts. Consider whether this should live in a shared location or if the current placement is fine. Currently it's a circular dependency concern —cart/index.tsimports fromcart-item/index.tswhich definesCartItemValue, andcart/index.tsis imported bycart-item/index.tsfor theProductimport. This works but feels slightly tangled.2.
ProductOptionClient.getSchema()return type (src/lib/entities/products/option/client.ts)The
v.GenericSchematype is quite broad. Consider if a more specific type would be better, or if this is intentionally loose to accommodate the different schema types (boolean, text, number).3.
CartItemBatch.forUsersubquery (src/lib/entities/cart/cart-item/batch.ts)The
existssubquery is correct but could be slightly simplified. Consider whether aJOINwithinArrayoncart.userIdwould be more performant for large datasets:Both approaches are valid — the
existsis more explicit about intent.4.
ProductOptionBatchimport style (src/lib/entities/products/batch.ts)This is a new import that wasn't needed before. The change from returning raw
ProductOptionData[]to returning aProductOptionBatchis a good architectural improvement for consistency, but it does add a new dependency.5. Minor:
order.tscartId changeChanging
cartIdfrom.notNull()to.primaryKey()is correct and makes semantic sense — an order IS a cart. Just want to confirm this doesn't affect any existing migration or data.✅ No blocking issues found
The code is well-structured, follows existing patterns, and the security model is sound. The bug fix in
cartItemValue.tsis particularly valuable.Recommendation: Approve 🚀
@ -0,0 +12,4 @@const rows = await db.select({ id: s.cartItem.id }).from(s.cartItem).where(The exists subquery here is correct but consider whether a JOIN with inArray on cart.userId might be more performant for large datasets.
@ -0,0 +2,4 @@import type { ProductOptionValue } from "#lib/entities/products/option/index.ts";import type { CartItemId } from "./id.ts";export type CartItemValue = { productOptionId: ProductOptionId; value: ProductOptionValue };The CartItemValue type is defined in cart-item/index.ts but also used in Cart.addItem in cart/index.ts. This creates a slight circular dependency feel. Consider if this type belongs in a shared location.
@ -9,4 +9,4 @@const columns = {productOptionId: text().$type<ProductOptionId>().notNull()Good catch fixing this foreign key — cart item values should reference product options, not products.