<commit_before>(ns twigs.snapshot
  #?(:clj (:import [com.firebase.client DataSnapshot]
                   [clojure.lang IPending IDeref ILookup MapEntry
                                 Associative Seqable Counted])))

;; wrapper type around firebase datasnapshot.

;; This is the main motivation for this library. It's tempting to just handle
;; all firebase snapshots with (-> ss .val js->clj) to get clojure
;; datastructures and all their goodness.

;; However I think it's reasonable to assume that firebase doesn't directly give
;; you raw data because .val can be expensive and wasteful (walking down a
;; firebase datasnapshot before calling .val removes a lot of uneeded work).
;; Otherwise why not just return the data?

;; we represent a firebase datasnapshot as a tuple [k v]
;; k is ss.key()
;; v is a TwigSnapshot which is a delayed clojure datastructure (derefable).
;; v is also associative, seqable, countable and supports lookup

(deftype TwigSnapshot [ss d]
  Object
  (toString [_] "TwigSnapshot")

  IPending
  (#?(:cljs -realized? :clj isRealized) [_] (realized? d))

  IDeref
  (#?(:cljs -deref :clj deref) [_] @d)

  #?(:cljs ICounted :clj Counted)
  #?(:cljs (-count [_] (.numChildren ss))
     :clj (count [_] (.getChildrenCount ss)))

  #?(:cljs ISeqable :clj Seqable)
  (#?(:cljs -seq :clj seq) [this]
     (if (.hasChildren ss)
       (let [snaps #?(:cljs (array) :clj (.getChildren ss))]
         #?(:cljs (.forEach ss (fn [css] (.push snaps css) false)))
         (map (fn [css]
                (let [k (#?(:cljs .key :clj .getKey) css)]
                  #?(:cljs [k (-lookup this k)]
                     :clj (MapEntry. k (.valAt this k)))))
              snaps))))

  ILookup
  #?(:cljs (-lookup [this k] (-lookup this k nil))
     :clj (valAt [this k] (.valAt this k nil)))
  (#?(:cljs -lookup :clj valAt) [_ k nf]
    (if (.hasChild ss (name k))
      (let [css (.child ss (name k))]
        (TwigSnapshot. css
          (if (realized? d)
            (doto (delay (get @d (keyword k)) deref))
            (delay (-> css #?(:cljs .exportVal :clj (.getValue true))
                       #?(:cljs (js->clj :keywordize-keys true)))))))
      nf)))

(defn wrap-snapshot [raw-ss]
  (let [k (-> raw-ss #?(:cljs .key :clj .getKey) keyword)
        ss (TwigSnapshot. raw-ss
             (delay (-> raw-ss #?(:cljs .exportVal :clj (.getValue true))
                        #?(:cljs (js->clj :keywordize-keys true)))))]
    #?(:cljs [k ss] :clj (MapEntry. k ss))))
<commit_msg>lookup should always return a derefable even if nothing is found<commit_after>(ns twigs.snapshot
  #?(:clj (:import [com.firebase.client DataSnapshot]
                   [clojure.lang IPending IDeref ILookup MapEntry
                                 Associative Seqable Counted])))

;; wrapper type around firebase datasnapshot.

;; This is the main motivation for this library. It's tempting to just handle
;; all firebase snapshots with (-> ss .val js->clj) to get clojure
;; datastructures and all their goodness.

;; However I think it's reasonable to assume that firebase doesn't directly give
;; you raw data because .val can be expensive and wasteful (walking down a
;; firebase datasnapshot before calling .val removes a lot of uneeded work).
;; Otherwise why not just return the data?

;; we represent a firebase datasnapshot as a tuple [k v]
;; k is ss.key()
;; v is a TwigSnapshot which is a delayed clojure datastructure (derefable).
;; v is also associative, seqable, countable and supports lookup

(deftype TwigSnapshot [ss d]
  Object
  (toString [_] "TwigSnapshot")

  IPending
  (#?(:cljs -realized? :clj isRealized) [_] (realized? d))

  IDeref
  (#?(:cljs -deref :clj deref) [_] @d)

  #?(:cljs ICounted :clj Counted)
  #?(:cljs (-count [_] (.numChildren ss))
     :clj (count [_] (.getChildrenCount ss)))

  #?(:cljs ISeqable :clj Seqable)
  (#?(:cljs -seq :clj seq) [this]
     (if (.hasChildren ss)
       (let [snaps #?(:cljs (array) :clj (.getChildren ss))]
         #?(:cljs (.forEach ss (fn [css] (.push snaps css) false)))
         (map (fn [css]
                (let [k (#?(:cljs .key :clj .getKey) css)]
                  #?(:cljs [k (-lookup this k)]
                     :clj (MapEntry. k (.valAt this k)))))
              snaps))))

  ILookup
  #?(:cljs (-lookup [this k] (-lookup this k (delay nil)))
     :clj (valAt [this k] (.valAt this k (delay nil))))
  (#?(:cljs -lookup :clj valAt) [_ k nf]
    (if (.hasChild ss (name k))
      (let [css (.child ss (name k))]
        (TwigSnapshot. css
          (if (realized? d)
            (doto (delay (get @d (keyword k)) deref))
            (delay (-> css #?(:cljs .exportVal :clj (.getValue true))
                       #?(:cljs (js->clj :keywordize-keys true)))))))
      nf)))

(defn wrap-snapshot [raw-ss]
  (let [k (-> raw-ss #?(:cljs .key :clj .getKey) keyword)
        ss (TwigSnapshot. raw-ss
             (delay (-> raw-ss #?(:cljs .exportVal :clj (.getValue true))
                        #?(:cljs (js->clj :keywordize-keys true)))))]
    #?(:cljs [k ss] :clj (MapEntry. k ss))))

{'fraction_non_alphanumeric': 0.1524522355721883, 'fraction_numerical': 0.0, 'mean_word_length': 2.5635087719298246, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 17, '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': '3480005', 'n_tokens_mistral': 1767, 'n_tokens_neox': 1674, 'n_words': 602}