<commit_before>(ns cmr.search.services.parameters.legacy-parameters
  "Contains functions for tranforming legacy parameters to the CMR format."
  (:require [clojure.set :as set]
            [clojure.string :as s]
            [ring.util.codec :as rc]
            [cmr.common.util :as cu]
            [clojure.walk :as w]
            [cmr.common.services.messages :as msg]
            [cmr.search.services.messages.attribute-messages :as a-msg]
            [cmr.common.services.errors :as errors]))

(def param-aliases
  "A map of non UMM parameter names to their UMM fields."
  {:dataset-id :entry-title
   :campaign :project
   :echo-collection-id :concept-id
   :echo-granule-id :concept-id
   :online-only :downloadable
   :provider-id :provider
   :day-night-flag :day-night
   :browse-only :browsable
   :processing-level :processing-level-id
   :grid :two-d-coordinate-system})

(def sort-key-replacements
  "A map of legacy sort keys with all variations of +/- to use for substitutions."
  (into {} (mapcat (fn [[a orig]]
                     (let [a (name a)
                           orig (name orig)]
                       [[a orig]
                        [(str "+" a) (str "+" orig)]
                        [(str "-" a) (str "-" orig)]]))
                   param-aliases)))

(defn merger
  "Make a sequence from supplied values."
  [v1 v2]
  (let [make-seq #(if (sequential? %) % [%])]
    (concat (make-seq v1) (make-seq v2))))

(defn- replace-legacy-sort-key
  "Replace legacy sort key with CMR version. Takes a sort key with +,-, or nothing as a prefix
  and replaces the appropriate part."
  [sort-key]
  (get sort-key-replacements sort-key sort-key))

(defn- replace-legacy-sort-keys
  "Replace legacy sort keys with CMR versions."
  [params]
  (if-let [sort-key (:sort-key params)]
    (assoc params :sort-key
           (if (sequential? sort-key)
             (map replace-legacy-sort-key sort-key)
             (replace-legacy-sort-key sort-key)))
    params))

(defn replace-parameter-aliases
  "Walk the request params tree to replace aliases of parameter names."
  [params]
  (->> params
       (w/postwalk #(if (map? %)
                      (cu/rename-keys-with % param-aliases merger)
                      %))
       replace-legacy-sort-keys))

(defn- psa-pre-validation
  "Check to see if the client has specified BOTH legacy format psa parameters and the current csv
  format, which is an error. Also check to make sure that cmr style uses 'attribute[]=' and not
  'attribute='."
  [attributes]
  (when-let [attributes (if (map? attributes)
                          ;; treat it as legacy style
                          (vec (vals attributes))
                          attributes)]
    (if (vector? attributes)
      (reduce (fn [memo x]
                (cond
                  (or (and (string? x) (= :legacy-style memo))
                      (and (map? x) (= :cmr-style memo)))
                  (msg/data-error :bad-request a-msg/mixed-legacy-and-cmr-style-parameters-msg)

                  (string? x)
                  :cmr-style

                  (map? x)
                  :legacy-style

                  :else
                  (errors/internal-error! (a-msg/expected-map-or-str-parameter-msg x))))
              nil
              attributes)
      (msg/data-error :bad-request a-msg/attributes-must-be-sequence-msg))))

(defn- escape-commas
  "Escape commas in an attribute parameter field"
  [value]
  (when value (s/replace value "," "\\,")))

(defn- attr-map->cmr-param
  "Create an attribute string from a map of attribute key/values."
  [{:keys [name type value minValue maxValue]}]
  (let [[name type value minValue maxValue] (map escape-commas [name type value minValue maxValue])
        base (str type "," name ",")]
    (if value
      (str base value)
      (str base minValue "," maxValue))))

(defn- checked-merge
  "Merge the given attribute map into the result map only if the key does not already exist.
  Throws an exception if it does. This allows us to catch client errors where they try to specify
  the same attribute field twice, e.g., &attribute[][name]=a&attribute[][name]=b."
  [result attr-map]
  (if (get result (first (keys attr-map)))
    (msg/data-error :bad-request a-msg/duplicate-parameter-msg (first attr-map))
    (merge result attr-map)))

(defn process-legacy-psa
  "Process legacy product specific attributes by updating params with attributes
  matching the new cmr csv style"
  [params]
  (let [attributes (:attribute params)
        attribute-type (psa-pre-validation attributes)
        attr-maps (when (= :legacy-style attribute-type)
                    (if (vector? attributes)
                      (vector (reduce checked-merge attributes))
                      (vec (vals attributes))))
        psa (map attr-map->cmr-param attr-maps)]
    (if (seq psa)
      (assoc params :attribute psa)
      params)))

(defn- process-legacy-range-maps
  "Changes legacy map range conditions in the param[minValue]/param[maxValue] format
  to the cmr format: min,max."
  [concept-type params]
  (reduce-kv (fn [memo k v]
               ;; look for parameters in the map form
               (if (and (map? v) (not= :options k))
                 (let [{:keys [value min-value max-value min max]} v]
                   (cond
                     (or min-value max-value)
                     ;; convert the map into a comma separated string
                     (assoc memo k (str min-value "," max-value))

                     (or min max)<commit_msg>CMR-2755: Addressed review comments.<commit_after>(ns cmr.search.services.parameters.legacy-parameters
  "Contains functions for tranforming legacy parameters to the CMR format."
  (:require [clojure.set :as set]
            [clojure.string :as s]
            [ring.util.codec :as rc]
            [cmr.common.util :as cu]
            [clojure.walk :as w]
            [cmr.common.services.messages :as msg]
            [cmr.search.services.messages.attribute-messages :as a-msg]
            [cmr.common.services.errors :as errors]))

(def param-aliases
  "A map of non UMM parameter names to their UMM fields."
  {:dataset-id :entry-title
   :campaign :project
   :echo-collection-id :concept-id
   :echo-granule-id :concept-id
   :online-only :downloadable
   :provider-id :provider
   :day-night-flag :day-night
   :browse-only :browsable
   :processing-level :processing-level-id
   :grid :two-d-coordinate-system})

(def sort-key-replacements
  "A map of legacy sort keys with all variations of +/- to use for substitutions."
  (into {} (mapcat (fn [[a orig]]
                     (let [a (name a)
                           orig (name orig)]
                       [[a orig]
                        [(str "+" a) (str "+" orig)]
                        [(str "-" a) (str "-" orig)]]))
                   param-aliases)))

(defn merger
  "Make a sequence from supplied values."
  [v1 v2]
  (let [make-seq #(if (sequential? %) % [%])]
    (concat (make-seq v1) (make-seq v2))))

(defn- replace-legacy-sort-key
  "Replace legacy sort key with CMR version. Takes a sort key with +,-, or nothing as a prefix
  and replaces the appropriate part."
  [sort-key]
  (get sort-key-replacements sort-key sort-key))

(defn- replace-legacy-sort-keys
  "Replace legacy sort keys with CMR versions."
  [params]
  (if-let [sort-key (:sort-key params)]
    (assoc params :sort-key
           (if (sequential? sort-key)
             (map replace-legacy-sort-key sort-key)
             (replace-legacy-sort-key sort-key)))
    params))

(defn replace-parameter-aliases
  "Walk the request params tree to replace aliases of parameter names."
  [params]
  (->> params
       (w/postwalk #(if (map? %)
                      (cu/rename-keys-with % param-aliases merger)
                      %))
       replace-legacy-sort-keys))

(defn- psa-pre-validation
  "Check to see if the client has specified BOTH legacy format psa parameters and the current csv
  format, which is an error. Also check to make sure that cmr style uses 'attribute[]=' and not
  'attribute='."
  [attributes]
  (when-let [attributes (if (map? attributes)
                          ;; treat it as legacy style
                          (vec (vals attributes))
                          attributes)]
    (if (vector? attributes)
      (reduce (fn [memo x]
                (cond
                  (or (and (string? x) (= :legacy-style memo))
                      (and (map? x) (= :cmr-style memo)))
                  (msg/data-error :bad-request a-msg/mixed-legacy-and-cmr-style-parameters-msg)

                  (string? x)
                  :cmr-style

                  (map? x)
                  :legacy-style

                  :else
                  (errors/internal-error! (a-msg/expected-map-or-str-parameter-msg x))))
              nil
              attributes)
      (msg/data-error :bad-request a-msg/attributes-must-be-sequence-msg))))

(defn- escape-commas
  "Escape commas in an attribute parameter field"
  [value]
  (when value (s/replace value "," "\\,")))

(defn- attr-map->cmr-param
  "Create an attribute string from a map of attribute key/values."
  [{:keys [name type value minValue maxValue]}]
  (let [[name type value minValue maxValue] (map escape-commas [name type value minValue maxValue])
        base (str type "," name ",")]
    (if value
      (str base value)
      (str base minValue "," maxValue))))

(defn- checked-merge
  "Merge the given attribute map into the result map only if the key does not already exist.
  Throws an exception if it does. This allows us to catch client errors where they try to specify
  the same attribute field twice, e.g., &attribute[][name]=a&attribute[][name]=b."
  [result attr-map]
  (if (get result (first (keys attr-map)))
    (msg/data-error :bad-request a-msg/duplicate-parameter-msg (first attr-map))
    (merge result attr-map)))

(defn process-legacy-psa
  "Process legacy product specific attributes by updating params with attributes
  matching the new cmr csv style"
  [params]
  (let [attributes (:attribute params)
        attribute-type (psa-pre-validation attributes)
        attr-maps (when (= :legacy-style attribute-type)
                    (if (vector? attributes)
                      [(reduce checked-merge attributes)]
                      (vec (vals attributes))))
        psa (map attr-map->cmr-param attr-maps)]
    (if (seq psa)
      (assoc params :attribute psa)
      params)))

(defn- process-legacy-range-maps
  "Changes legacy map range conditions in the param[minValue]/param[maxValue] format
  to the cmr format: min,max."
  [concept-type params]
  (reduce-kv (fn [memo k v]
               ;; look for parameters in the map form
               (if (and (map? v) (not= :options k))
                 (let [{:keys [value min-value max-value min max]} v]
                   (cond
                     (or min-value max-value)
                     ;; convert the map into a comma separated string
                     (assoc memo k (str min-value "," max-value))

                     (or min max)
{'fraction_non_alphanumeric': 0.11938278289117488, 'fraction_numerical': 0.0010828370330265296, 'mean_word_length': 2.0743411927877946, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 11, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 2, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '4670409', 'n_tokens_mistral': 3355, 'n_tokens_neox': 3226, 'n_words': 1061}