Added functions to show distribution of donations by account.
This commit is contained in:
parent
b396015e34
commit
74afa02516
2 changed files with 65 additions and 11 deletions
|
|
@ -5,6 +5,7 @@
|
||||||
[com.widdindustries/cljc.java-time "0.1.22"]
|
[com.widdindustries/cljc.java-time "0.1.22"]
|
||||||
[org.xerial/sqlite-jdbc "3.7.15-M1"]]
|
[org.xerial/sqlite-jdbc "3.7.15-M1"]]
|
||||||
:description "FIXME: write description"
|
:description "FIXME: write description"
|
||||||
|
:jvm-opts ["-Xmx4g"]
|
||||||
:license {:name "GNU General Public License,version 2.0 or (at your option) an
|
:license {:name "GNU General Public License,version 2.0 or (at your option) an
|
||||||
y later version"
|
y later version"
|
||||||
:url "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html"}
|
:url "https://www.gnu.org/licenses/old-licenses/gpl-2.0.en.html"}
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,15 @@
|
||||||
(:require [clojure.string :refer [capitalize]]
|
(:require [clojure.string :refer [capitalize]]
|
||||||
[cljc.java-time.local-date :as ld]
|
[cljc.java-time.local-date :as ld]
|
||||||
[com.hypirion.clj-xchart :refer [xy-chart]]
|
[com.hypirion.clj-xchart :refer [xy-chart]]
|
||||||
[korma.core :refer [fields join select where]]
|
[korma.core :refer [as-sql fields join select where]]
|
||||||
[korma.db :refer [defdb sqlite3]]))
|
[korma.db :refer [defdb sqlite3]]))
|
||||||
|
|
||||||
;; create db
|
;; create db
|
||||||
(defdb db (sqlite3
|
(def db-spec {:classname "org.sqlite.JDBC"
|
||||||
{:classname "org.sqlite.JDBC"
|
:subprotocol "sqlite"
|
||||||
:subprotocol "sqlite"
|
:subname "resources/app.db"})
|
||||||
:subname "resources/app.db"}))
|
|
||||||
|
(defdb db (sqlite3 db-spec))
|
||||||
|
|
||||||
(defmacro date? [x]
|
(defmacro date? [x]
|
||||||
`(instance? java.time.LocalDate ~x))
|
`(instance? java.time.LocalDate ~x))
|
||||||
|
|
@ -22,11 +23,13 @@
|
||||||
returned."
|
returned."
|
||||||
([start-date]
|
([start-date]
|
||||||
(let [sd (cond (date? start-date) start-date
|
(let [sd (cond (date? start-date) start-date
|
||||||
(string? start-date) (ld/parse start-date))]
|
(string? start-date) (ld/parse start-date)
|
||||||
|
:else (ld/parse "2024-01-01"))]
|
||||||
(total-donations-by-weeks sd (ld/plus-days sd 7))))
|
(total-donations-by-weeks sd (ld/plus-days sd 7))))
|
||||||
([start-date end-date]
|
([start-date end-date]
|
||||||
(let [sd (cond (date? start-date) start-date
|
(let [sd (cond (date? start-date) start-date
|
||||||
(string? start-date) (ld/parse start-date))
|
(string? start-date) (ld/parse start-date)
|
||||||
|
:else (ld/parse "2024-01-01"))
|
||||||
ed (cond (date? end-date) end-date
|
ed (cond (date? end-date) end-date
|
||||||
(string? end-date) (ld/parse end-date)
|
(string? end-date) (ld/parse end-date)
|
||||||
:else (ld/now))]
|
:else (ld/now))]
|
||||||
|
|
@ -37,7 +40,7 @@
|
||||||
(fields :amount)
|
(fields :amount)
|
||||||
(where (and {:created_at [> s]}
|
(where (and {:created_at [> s]}
|
||||||
{:created_at [<= i]})))
|
{:created_at [<= i]})))
|
||||||
amounts (map :amount data)
|
amounts (map :amount data)
|
||||||
r' (cons
|
r' (cons
|
||||||
[s {:total (reduce + amounts)
|
[s {:total (reduce + amounts)
|
||||||
:n (count data)
|
:n (count data)
|
||||||
|
|
@ -49,8 +52,8 @@
|
||||||
|
|
||||||
(defmacro datetime->date [x]
|
(defmacro datetime->date [x]
|
||||||
`(java.util.Date/from
|
`(java.util.Date/from
|
||||||
(.toInstant (.atStartOfDay ~x)
|
(.toInstant (.atStartOfDay ~x)
|
||||||
(java.time.ZoneOffset/ofHours 0))))
|
(java.time.ZoneOffset/ofHours 0))))
|
||||||
|
|
||||||
(defn chart-donations-by-weeks
|
(defn chart-donations-by-weeks
|
||||||
"Create and return an XY chart of data on field represented by `key` of
|
"Create and return an XY chart of data on field represented by `key` of
|
||||||
|
|
@ -62,7 +65,6 @@
|
||||||
[(map #(datetime->date (first %)) data)
|
[(map #(datetime->date (first %)) data)
|
||||||
(map #(:n (nth % 1)) data)]})))
|
(map #(:n (nth % 1)) data)]})))
|
||||||
|
|
||||||
|
|
||||||
(defn chart-total-donations-by-weeks
|
(defn chart-total-donations-by-weeks
|
||||||
"Create and return an XY chart of data on total donations made between
|
"Create and return an XY chart of data on total donations made between
|
||||||
`start-date` and `end-date`. Arguments may be supplied as
|
`start-date` and `end-date`. Arguments may be supplied as
|
||||||
|
|
@ -76,3 +78,54 @@
|
||||||
`java.time.LocalDate` objects, or as strings in the format `yyyy-mm-dd`."
|
`java.time.LocalDate` objects, or as strings in the format `yyyy-mm-dd`."
|
||||||
[start-date end-date]
|
[start-date end-date]
|
||||||
(chart-donations-by-weeks start-date end-date :n))
|
(chart-donations-by-weeks start-date end-date :n))
|
||||||
|
|
||||||
|
(defn enhance-account-with-donations
|
||||||
|
"Take this `account_map`, which must at least have a valid value for the
|
||||||
|
key `:campaign_url` and return a similar map including the key `:donations`,
|
||||||
|
whose value is a float representing the total donations received by that
|
||||||
|
campaign URL between the dates `sd` (exclusive) and `ed` (inclusive). Date
|
||||||
|
arguments should be supplied as `java.time.LocalDate` objects."
|
||||||
|
[account-map sd ed]
|
||||||
|
(assoc account-map :donations
|
||||||
|
(reduce + 0 (map :amount
|
||||||
|
(select 'campaign_donations
|
||||||
|
(fields :amount)
|
||||||
|
(where (and
|
||||||
|
{:campaign_url [= (:campaign_url account-map)]}
|
||||||
|
{:created_at [> sd]}
|
||||||
|
{:created_at [<= ed]})))))))
|
||||||
|
|
||||||
|
(defn accounts-with-donations-by-date-range
|
||||||
|
"Return a list of maps, each representing one account from the `gaza.onl`
|
||||||
|
database, with a key `:donations`, whose value is a float representing the
|
||||||
|
total donations received by that account between the dates `start-date`
|
||||||
|
(exclusive) and `end-date` (inclusive). Date arguments should be supplied
|
||||||
|
as `java.time.LocalDate` objects, or as strings in the format `yyyy-mm-dd`."
|
||||||
|
[start-date end-date]
|
||||||
|
(let [sd (cond (date? start-date) start-date
|
||||||
|
(string? start-date) (ld/parse start-date))
|
||||||
|
ed (cond (date? end-date) end-date
|
||||||
|
(string? end-date) (ld/parse end-date)
|
||||||
|
:else (ld/now))
|
||||||
|
accounts (select 'accounts
|
||||||
|
(fields :id :display_name :created_at :campaign_url)
|
||||||
|
(where {:created_at [< sd]}))]
|
||||||
|
(map #(enhance-account-with-donations % sd ed) accounts)))
|
||||||
|
|
||||||
|
(defn chart-donations-by-accounts-in-date-range
|
||||||
|
"Return a chart of donations received by individual accounts between
|
||||||
|
`start-date` (exclusive) and `end-date` (inclusive). Arguments should be
|
||||||
|
supplied as `java.time.LocalDate` objects, or as strings in the format
|
||||||
|
`yyyy-mm-dd`. Accounts are identified in the chart only by rank order."
|
||||||
|
[start-date end-date]
|
||||||
|
(let [data (accounts-with-donations-by-date-range start-date end-date)]
|
||||||
|
(xy-chart {(format "Donations between\n%s and\n%s" start-date end-date)
|
||||||
|
[(range (count data)) (sort (map :donations data))]})))
|
||||||
|
|
||||||
|
;; this does not work and I don't know why
|
||||||
|
;; (as-sql '(select 'campaign_donations
|
||||||
|
;; (fields :amount :campaign_url :created_at)
|
||||||
|
;; (where (and
|
||||||
|
;; {:campaign_url [= "https://www.chuffed.org/project/128261-photographer-from-gaza-rebuilding-life-dreams"]}
|
||||||
|
;; {:created_at [> "2024-04-01"]}
|
||||||
|
;; {:created_at [<= "2o24-04-30"]}))))
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue