<commit_before>(ns workflo.macros.query
  (:require #?(:cljs [cljs.spec :as s]
               :clj  [clojure.spec :as s])
            [workflo.macros.query.util :as util]
            [workflo.macros.specs.conforming-query]
            [workflo.macros.specs.parsed-query]
            [workflo.macros.specs.query]))

;;;; Properties specification parsing

(declare conform-and-parse)
(declare parse)

(s/fdef conform
  :args (s/cat :query :workflo.macros.specs.query/query)
  :ret  :workflo.macros.specs.conforming-query/query)

(defn conform
  "Validates a query and returns the parsed, conforming result."
  [query]
  (s/conform :workflo.macros.specs.query/query query))

(s/def ::subquery
  (s/or :regular-query
        :workflo.macros.specs.conforming-query/regular-query
        :parameterized-query
        :workflo.macros.specs.conforming-query/parameterized-query
        :nested-properties
        :workflo.macros.specs.conforming-query/nested-properties
        :property :workflo.macros.specs.conforming-query/property
        :simple :workflo.macros.specs.conforming-query/simple-property
        :link :workflo.macros.specs.conforming-query/link
        :join :workflo.macros.specs.conforming-query/join
        :model-join :workflo.macros.specs.conforming-query/model-join
        :recursive-join
        :workflo.macros.specs.conforming-query/recursive-join
        :properties-join
        :workflo.macros.specs.conforming-query/properties-join))

(s/fdef parse-subquery
  :args (s/cat :query ::subquery)
  :ret  :workflo.macros.specs.parsed-query/query)

(defn parse-subquery
  "Takes a subquery and returns a vector of parsed properties, each
   in one of the following forms:

       {:name user/name :type :property}
       {:name user/email :type :property}
       {:name user/friends :type :join :join-target User}
       {:name user/friends :type :join
        :join-target [{:name user/name :type :property}]}
       {:name current-user :type :link :link-id _}.

   Each of these may in addition contain an optional :parameters
   key with a {symbol ?variable}-style map."
  [[type query]]
  (case type
    :regular-query       (parse-subquery query)
    :parameterized-query (->> (:regular-query-value query)
                              (parse-subquery)
                              (mapv (fn [parsed]
                                      (assoc parsed :parameters
                                             (:parameters query)))))
    :nested-properties   (let [{:keys [base children]} query]
                           (->> children
                                (map parse-subquery)
                                (apply concat)
                                (mapv (fn [child]
                                        (update child :name
                                                (fn [sym]
                                                  (symbol
                                                   (name base)
                                                   (name sym))))))))
    :property            (parse-subquery query)
    :simple              [{:name query :type :property}]
    :link                (let [[name link-id] query]
                           [{:name name :type :link :link-id link-id}])
    :join                (parse-subquery query)
    :model-join          (let [[name target] (first query)]
                           [{:name name :type :join
                             :join-target target}])
    :recursive-join      (let [[name target] (first query)]
                           [{:name name :type :join
                             :join-target
                             #?(:cljs target
                                :clj  (second target))}])
    :properties-join     (let [[name target] (first query)]
                           [{:name name :type :join
                             :join-target
                             #?(:cljs (conform-and-parse target)
                                :clj  (parse target))}])))<commit_msg>In parse-subquery, use parsing the first query segment as a fallback<commit_after>(ns workflo.macros.query
  (:require #?(:cljs [cljs.spec :as s]
               :clj  [clojure.spec :as s])
            [workflo.macros.query.util :as util]
            [workflo.macros.specs.conforming-query]
            [workflo.macros.specs.parsed-query]
            [workflo.macros.specs.query]))

;;;; Properties specification parsing

(declare conform-and-parse)
(declare parse)

(s/fdef conform
  :args (s/cat :query :workflo.macros.specs.query/query)
  :ret  :workflo.macros.specs.conforming-query/query)

(defn conform
  "Validates a query and returns the parsed, conforming result."
  [query]
  (s/conform :workflo.macros.specs.query/query query))

(s/def ::subquery
  (s/or :regular-query
        :workflo.macros.specs.conforming-query/regular-query
        :parameterized-query
        :workflo.macros.specs.conforming-query/parameterized-query
        :nested-properties
        :workflo.macros.specs.conforming-query/nested-properties
        :property :workflo.macros.specs.conforming-query/property
        :simple :workflo.macros.specs.conforming-query/simple-property
        :link :workflo.macros.specs.conforming-query/link
        :join :workflo.macros.specs.conforming-query/join
        :model-join :workflo.macros.specs.conforming-query/model-join
        :recursive-join
        :workflo.macros.specs.conforming-query/recursive-join
        :properties-join
        :workflo.macros.specs.conforming-query/properties-join))

(s/fdef parse-subquery
  :args (s/cat :query ::subquery)
  :ret  :workflo.macros.specs.parsed-query/query)

(defn parse-subquery
  "Takes a subquery and returns a vector of parsed properties, each
   in one of the following forms:

       {:name user/name :type :property}
       {:name user/email :type :property}
       {:name user/friends :type :join :join-target User}
       {:name user/friends :type :join
        :join-target [{:name user/name :type :property}]}
       {:name current-user :type :link :link-id _}.

   Each of these may in addition contain an optional :parameters
   key with a {symbol ?variable}-style map."
  [[type query]]
  (case type
    :regular-query       (parse-subquery query)
    :parameterized-query (->> (:regular-query-value query)
                              (parse-subquery)
                              (mapv (fn [parsed]
                                      (assoc parsed :parameters
                                             (:parameters query)))))
    :nested-properties   (let [{:keys [base children]} query]
                           (->> children
                                (map parse-subquery)
                                (apply concat)
                                (mapv (fn [child]
                                        (update child :name
                                                (fn [sym]
                                                  (symbol
                                                   (name base)
                                                   (name sym))))))))
    :property            (parse-subquery query)
    :simple              [{:name query :type :property}]
    :link                (let [[name link-id] query]
                           [{:name name :type :link :link-id link-id}])
    :join                (parse-subquery query)
    :model-join          (let [[name target] (first query)]
                           [{:name name :type :join
                             :join-target target}])
    :recursive-join      (let [[name target] (first query)]
                           [{:name name :type :join
                             :join-target
                             #?(:cljs target
                                :clj  (second target))}])
    :properties-join     (let [[name target] (first query)]
                           [{:name name :type :join
                             :join-target
                             #?(:cljs (conform-and-parse target)
                                :clj  (parse target))}])
    (parse-subquery type)))
{'fraction_non_alphanumeric': 0.11146772003456364, 'fraction_numerical': 0.0, 'mean_word_length': 1.504482225656878, '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': 24, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '1192944', 'n_tokens_mistral': 2274, 'n_tokens_neox': 2194, 'n_words': 513}