summaryrefslogtreecommitdiff
path: root/models/nutrient-measurement.rkt
diff options
context:
space:
mode:
Diffstat (limited to 'models/nutrient-measurement.rkt')
-rw-r--r--models/nutrient-measurement.rkt212
1 files changed, 212 insertions, 0 deletions
diff --git a/models/nutrient-measurement.rkt b/models/nutrient-measurement.rkt
new file mode 100644
index 0000000..8364aa7
--- /dev/null
+++ b/models/nutrient-measurement.rkt
@@ -0,0 +1,212 @@
+#lang racket
+
+(provide
+ ;; Struct definitions
+ nutrient-measurement
+ nutrient-measurement?
+ nutrient-measurement-id nutrient-measurement-measured-on
+ ;; SQL CRUD
+ (contract-out
+ [create-nutrient-measurement! (-> string?
+ (listof (cons/c
+ nutrient?
+ number?))
+ nutrient-measurement?)]
+ [get-nutrient-measurements (->* ()
+ (#:id (or/c #f exact-nonnegative-integer?)
+ #:measured-on (or/c #f string?))
+ (listof nutrient-measurement?))]
+ [get-nutrient-measurement (->* ()
+ (#:id (or/c #f exact-nonnegative-integer?)
+ #:measured-on (or/c #f string?))
+ (or/c nutrient-measurement? #f))]
+ [get-nutrient-measurement-values (-> nutrient-measurement?
+ (listof (cons/c
+ nutrient?
+ number?)))]
+ [get-nutrient-measurement-value (-> nutrient-measurement?
+ nutrient?
+ number?)]
+ [get-latest-nutrient-measurement-value (-> nutrient? number?)]
+ #; [update-nutrient-measurement! (->* (nutrient-measurement?)
+ (#:measured-on (or/c #f string?)
+ #:nutrient-values (or/c #f (listof (cons/c
+ nutrient?
+ number?))))
+ (or/c nutrient-measurement? #f))]
+ [delete-nutrient-measurement! (-> nutrient-measurement?
+ void?)]))
+
+(require racket/contract
+ db
+ sql
+ "../db/conn.rkt"
+ "nutrient.rkt")
+
+;; Instances of this struct are persisted in the nutrient_measurements table.
+(struct nutrient-measurement (id measured-on) #:transparent)
+
+
+;; CREATE
+
+(define (create-nutrient-measurement! measured-on nutrient-values)
+ (define existing-nutrient-measurement (get-nutrient-measurement #:measured-on measured-on))
+ (define (new-nutrient-measurement)
+ (with-tx
+ (query-exec (current-conn)
+ (insert #:into nutrient_measurements
+ #:set [measured_on ,measured-on]))
+ (define nm-id (nutrient-measurement-id (get-nutrient-measurement #:measured-on measured-on)))
+ (query-exec (current-conn)
+ (insert #:into nutrient_value_sets
+ #:set [nutrient_measurement_id ,nm-id]))
+ (define nvs-id (query-value (current-conn)
+ (select id
+ #:from nutrient_value_sets
+ #:where (= nutrient_measurement_id ,nm-id))))
+ (for ([nv nutrient-values])
+ (match nv
+ [(cons n v)
+ (query-exec (current-conn)
+ (insert #:into nutrient_values
+ #:set
+ [value_set_id ,nvs-id]
+ [nutrient_id ,(nutrient-id n)]
+ [value_ppm ,v]))])))
+ (get-nutrient-measurement #:measured-on measured-on))
+ (or existing-nutrient-measurement
+ (new-nutrient-measurement)))
+
+
+;; READ
+
+(define (get-nutrient-measurements #:id [id #f]
+ #:measured-on [measured-on #f])
+ (define (where-expr)
+ (define clauses
+ (filter values
+ (list (and id (format "id = ~e" id))
+ (and measured-on (format "measured_on = ~e" measured-on)))))
+ (cond
+ [(null? clauses) ""]
+ [else (format "WHERE ~a" (string-join clauses " AND "))]))
+ (define query (string-join
+ `("SELECT id, measured_on"
+ "FROM nutrient_measurements"
+ ,(where-expr)
+ "ORDER BY id ASC")))
+ (for/list ([(id* measured-on*)
+ (in-query (current-conn) query)])
+ (nutrient-measurement id* measured-on*)))
+
+(define (get-nutrient-measurement #:id [id #f]
+ #:measured-on [measured-on #f])
+ (define (where-expr)
+ (define clauses
+ (filter values
+ (list
+ (and id (format "id = ~e" id))
+ (and measured-on (format "measured_on = ~e" measured-on)))))
+ (cond
+ [(null? clauses) ""]
+ [else (format "WHERE ~a" (string-join clauses " AND "))]))
+ (define query (string-join
+ `("SELECT id, measured_on"
+ "FROM nutrient_measurements"
+ ,(where-expr)
+ "ORDER BY id ASC"
+ "LIMIT 1")))
+ (match (query-maybe-row (current-conn) query)
+ [(vector id* measured-on*)
+ (nutrient-measurement id* measured-on*)]
+ [#f #f]))
+
+(define (get-nutrient-measurement-values nutrient-measurement)
+ (for/list ([(nutrient-id name formula value_ppm)
+ (in-query (current-conn)
+ (string-join
+ '("SELECT n.id, n.canonical_name, n.formula, nv.value_ppm"
+ "FROM nutrient_values nv"
+ "JOIN nutrient_value_sets nvs ON nvs.id = nv.value_set_id"
+ "JOIN nutrient_measurements nm ON nm.id = nvs.nutrient_measurement_id"
+ "JOIN nutrients n ON n.id = nv.nutrient_id"
+ "WHERE nm.id = $1"))
+ (nutrient-measurement-id nutrient-measurement))])
+ (cons (nutrient nutrient-id name formula) value_ppm)))
+
+(define (get-nutrient-measurement-value nutrient-measurement nutrient)
+ (query-maybe-value (current-conn)
+ (string-join
+ '("SELECT value_ppm"
+ "FROM nutrient_values nv"
+ "JOIN nutrient_value_sets nvs ON nvs.id = nv.value_set_id"
+ "JOIN nutrient_measurements nm ON nm.id = nvs.nutrient_measurement_id"
+ "WHERE nm.id = $1 AND nv.nutrient_id = $2"))
+ (nutrient-measurement-id nutrient-measurement)
+ (nutrient-id nutrient)))
+
+(define (get-latest-nutrient-measurement-value nutrient)
+ (query-maybe-value (current-conn)
+ (string-join
+ '("SELECT value_ppm"
+ "FROM nutrient_values nv"
+ "JOIN nutrient_value_sets nvs ON nvs.id = nv.value_set_id"
+ "JOIN nutrient_measurements nm ON nm.id = nvs.nutrient_measurement_id"
+ "WHERE nv.nutrient_id = $1"
+ "ORDER BY nm.measured_on DESC"
+ "LIMIT 1"))
+ (nutrient-id nutrient)))
+
+
+;; UPDATE
+
+#; (define (update-nutrient-measurement! nutrient-measurement
+ #:measured-on [measured-on #f]
+ #:nutrient-values [nutrient-values '()])
+ (define nm-id (nutrient-measurement-id nutrient-measurement))
+ (define (nvs-id nm-id)
+ (query-maybe-row (current-conn)
+ (select id
+ #:from nutrient_value_sets
+ #:where (= nutrient_measurement_id ,nm-id))))
+ (with-tx
+ (when measured-on
+ (query-exec (current-conn)
+ (update nutrient_measurements
+ #:set [measured_on ,measured-on]
+ #:where (= id ,id))))
+ (unless (null? nutrient-values)
+ (upsert-nutrient-values nm-id))
+ (get-nutrient-measurement #:id id)))
+
+#; (define (upsert-nutrient-values nutrient-measurement-id)
+ (define maybe-nvs-id (nvs-id nm-id))
+ (case maybe-nvs-id
+ [(#f)
+ (query-exec (current-conn)
+ (insert #:into nutrient_values_sets
+ #:set
+ [nutrient_measurement_id ,id]))
+ (define new-nvs-id (nvs-id nm-id))
+ (query-exec (current-conn)
+ (string-join
+ '("INSERT INTO nutrient_values"
+ "VALUES $1 $2 $3"
+ ""))
+ new-nvs-id
+ )]
+ [else
+ (query-exec (current-conn)
+ (update nutrient_measurement_values
+ #:set [value ,value]
+ #:where (and (= measurement_id ,measurement-id)
+ (= nutrient_id ,nutrient-id))))]))
+
+
+;; DELETE
+
+(define (delete-nutrient-measurement! nutrient-measurement)
+ (define id (nutrient-measurement-id nutrient-measurement))
+ (query-exec (current-conn)
+ (delete #:from nutrient_measurements
+ #:where (= id ,id))))
Copyright 2019--2025 Marius PETER