;; lib/commerce/cart.sx — cart as an ordered list of line items. ;; ;; A cart is a native list of lines; a line is (list sku variant qty). ;; All operations are pure: they return a new cart, never mutate. Line ;; order is insertion order (stable) so totals are reproducible. ;; ;; cart-lineo is the relational view — because a line *is* a (sku variant qty) ;; tuple, membero queries the cart directly, forward or backward. (define empty-cart (list)) (define make-line (fn (sku variant qty) (list sku variant qty))) (define line-sku (fn (l) (nth l 0))) (define line-variant (fn (l) (nth l 1))) (define line-qty (fn (l) (nth l 2))) (define same-line? (fn (l sku variant) (and (= (line-sku l) sku) (= (line-variant l) variant)))) (define cart-qty (fn (cart sku variant) (let ((m (filter (fn (l) (same-line? l sku variant)) cart))) (if (empty? m) 0 (line-qty (first m)))))) (define cart-remove (fn (cart sku variant) (filter (fn (l) (not (same-line? l sku variant))) cart))) ;; Add qty units; merges into an existing (sku,variant) line in place, ;; otherwise appends a new line at the end. (define cart-add (fn (cart sku variant qty) (let ((existing (cart-qty cart sku variant))) (if (= existing 0) (append cart (list (make-line sku variant qty))) (map (fn (l) (if (same-line? l sku variant) (make-line sku variant (+ existing qty)) l)) cart))))) ;; Set the absolute quantity; qty <= 0 removes the line. (define cart-set-qty (fn (cart sku variant qty) (if (<= qty 0) (cart-remove cart sku variant) (if (= (cart-qty cart sku variant) 0) (append cart (list (make-line sku variant qty))) (map (fn (l) (if (same-line? l sku variant) (make-line sku variant qty) l)) cart))))) (define cart-empty? (fn (cart) (empty? cart))) (define cart-lines (fn (cart) cart)) (define cart-skus (fn (cart) (map line-sku cart))) ;; Total number of units across all lines. (define cart-count (fn (cart) (reduce (fn (acc l) (+ acc (line-qty l))) 0 cart))) ;; Relational view of cart lines. (define cart-lineo (fn (cart sku variant qty) (membero (list sku variant qty) cart)))