Forem

Cover image for Clojure Is Awesome!!! [PART 5]
André Borba
André Borba

Posted on

2 1 1 1 1

Clojure Is Awesome!!! [PART 5]

(ns v2
  (:require [clojure.spec.alpha :as s]
            [clojure.string :as str]))

(s/def ::distance (s/and number? pos?))
(s/def ::package string?)
(s/def ::destination string?)
(s/def ::delivery-type #{"air" "land" "sea"})

(defprotocol DeliveryService
  (calculate-cost [this distance] "Calculates the delivery cost based on the distance.")
  (process-delivery [this package destination] "Executes the delivery of the package to the destination.")
  (estimated-time [this distance] "Estimates delivery time in hours."))

(defrecord AirDelivery []
  DeliveryService
  (calculate-cost [_ distance]
    (* 5 distance))
  (process-delivery [_ package destination]
    (str "Package '" package "' will be delivered via Air to " destination))
  (estimated-time [_ distance]
    (Math/ceil (/ distance 800))))

(defrecord LandDelivery []
  DeliveryService
  (calculate-cost [_ distance]
    (* 2 distance))
  (process-delivery [_ package destination]
    (str "Package '" package "' will be delivered via Land to " destination))
  (estimated-time [_ distance]
    (Math/ceil (/ distance 60))))

(defrecord SeaDelivery []
  DeliveryService
  (calculate-cost [_ distance]
    (* 1 distance))
  (process-delivery [_ package destination]
    (str "Package '" package "' will be delivered via Sea to " destination))
  (estimated-time [_ distance]
    (Math/ceil (/ distance 30))))

(defmulti create-delivery-service
  "Factory multi-method for creating delivery services"
  (fn [type & _] (str/lower-case type)))

(defmethod create-delivery-service "air" [_]
  (->AirDelivery))

(defmethod create-delivery-service "land" [_]
  (->LandDelivery))

(defmethod create-delivery-service "sea" [_]
  (->SeaDelivery))

(defmethod create-delivery-service :default [type]
  (throw (ex-info "Invalid delivery type"
                  {:type type
                   :available-types #{"air" "land" "sea"}})))

(defn calculate-and-deliver
  "Service that uses the factory to calculate the cost and deliver a package.
   Returns a map with :cost, :delivery, and :estimated-time keys."
  [type package destination distance]
  {:pre [(s/valid? ::delivery-type type)
         (s/valid? ::package package)
         (s/valid? ::destination destination)
         (s/valid? ::distance distance)]}
  (try
    (let [service (create-delivery-service type)]
      {:cost (calculate-cost service distance)
       :delivery (process-delivery service package destination)
       :estimated-time (estimated-time service distance)})
    (catch Exception e
      (throw (ex-info "Delivery calculation failed"
                      {:cause (.getMessage e)
                       :type type
                       :package package
                       :destination destination
                       :distance distance})))))

(defn find-cheapest-delivery
  "Finds the cheapest delivery service for given parameters"
  [package destination distance]
  (->> ["air" "land" "sea"]
       (map #(-> [(calculate-and-deliver % package destination distance) %]))
       (sort-by (comp :cost first))
       first))

(comment
  (calculate-and-deliver "air" "Electronics" "São Paulo" 1000)
  ;; => {:cost 5000
  ;;     :delivery "Package 'Electronics' will be delivered via Air to São Paulo"
  ;;     :estimated-time 2}

  (find-cheapest-delivery "Heavy Machinery" "Porto Alegre" 800)
  ;; => [{:cost 800
  ;;      :delivery "Package 'Heavy Machinery' will be delivered via Sea to Porto Alegre"
  ;;      :estimated-time 27}
  ;;     "sea"]

  ;; Validation error example
  (calculate-and-deliver "air" "Books" "Curitiba" -100)
  ;; => Assertion Error: Invalid input
)
Enter fullscreen mode Exit fullscreen mode

Image of Timescale

🚀 pgai Vectorizer: SQLAlchemy and LiteLLM Make Vector Search Simple

We built pgai Vectorizer to simplify embedding management for AI applications—without needing a separate database or complex infrastructure. Since launch, developers have created over 3,000 vectorizers on Timescale Cloud, with many more self-hosted.

Read more →

Top comments (0)

Image of Docusign

🛠️ Bring your solution into Docusign. Reach over 1.6M customers.

Docusign is now extensible. Overcome challenges with disconnected products and inaccessible data by bringing your solutions into Docusign and publishing to 1.6M customers in the App Center.

Learn more