diff options
| author | Marius Peter <dev@marius-peter.com> | 2025-10-23 17:10:46 +0200 |
|---|---|---|
| committer | Marius Peter <dev@marius-peter.com> | 2025-10-23 17:10:46 +0200 |
| commit | 5ca8097a847e29c5cf1267cbc43f1949f9e04117 (patch) | |
| tree | 112c31de41b151f6603ca36336c8dd93643abcb9 | |
| parent | d7a96109d779acd25259d966ccfda05b5a154815 (diff) | |
Update nutrient target with out beautiful new logic.
| -rw-r--r-- | models/nutrient-target.rkt | 160 |
1 files changed, 104 insertions, 56 deletions
diff --git a/models/nutrient-target.rkt b/models/nutrient-target.rkt index 691d078..4e43ef1 100644 --- a/models/nutrient-target.rkt +++ b/models/nutrient-target.rkt @@ -4,7 +4,10 @@ ;; Struct definitions nutrient-target nutrient-target? - nutrient-target-id nutrient-target-effective-on + nutrient-target-id + (rename-out + [nutrient-target-effective-on nutrient-target-date] + [nutrient-target-nutrient-values nutrient-target-values]) ;; SQL CRUD (contract-out [create-nutrient-target! (-> string? @@ -17,7 +20,8 @@ (or/c nutrient-target? #f))] [get-nutrient-target-values (-> nutrient-target? (listof (cons/c nutrient? number?)))] [get-nutrient-target-value (-> nutrient-target? nutrient? number?)] - [get-latest-nutrient-target-value (-> nutrient? number?)] + ;; Before the first target is createed, the "latest" value is basically false. + [get-latest-nutrient-target-value (-> nutrient? (or/c number? #f))] [delete-nutrient-target! (-> nutrient-target? void?)])) (require racket/contract @@ -27,71 +31,115 @@ "nutrient.rkt") ;; Instances of this struct are persisted in the nutrient_targets table. -(struct nutrient-target (id effective-on) #:transparent) +(struct nutrient-target (id effective-on nutrient-values) #:transparent) ;; CREATE (define (create-nutrient-target! effective-on nutrient-values) - (define existing-nutrient-target (get-nutrient-target #:effective-on effective-on)) - (define (new-nutrient-target) - (with-tx - (query-exec (current-conn) - (insert #:into nutrient_targets - #:set [effective_on ,effective-on])) - (define nm-id (nutrient-target-id (get-nutrient-target #:effective-on effective-on))) - (query-exec (current-conn) - (insert #:into nutrient_value_sets - #:set [nutrient_target_id ,nm-id])) - (define nvs-id (query-value (current-conn) - (select id - #:from nutrient_value_sets - #:where (= nutrient_target_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-target #:effective-on effective-on)) - (or existing-nutrient-target - (new-nutrient-target))) + (or (get-nutrient-target #:effective-on effective-on) + (with-tx + (query-exec (current-conn) + (insert #:into nutrient_targets + #:set [effective_on ,effective-on])) + (define nt-id (query-value (current-conn) + (select id + #:from nutrient_targets + #:where (= effective_on ,effective-on)))) + (query-exec (current-conn) + (insert #:into nutrient_value_sets + #:set [nutrient_target_id ,nt-id])) + (define nvs-id (query-value (current-conn) + (select id + #:from nutrient_value_sets + #:where (= nutrient_target_id ,nt-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-target #:effective-on effective-on)))) ;; READ +(struct acc (effective-on pairs) #:transparent) + +(define joined + (table-expr-qq + (inner-join + (inner-join + (inner-join + (as nutrient_targets nt) + (as nutrient_value_sets nvs) + #:on (= nvs.nutrient_measurement_id nt.id)) + (as nutrient_values nv) + #:on (= nv.value_set_id nvs.id)) + (as nutrients n) + #:on (= n.id nv.nutrient_id)))) + (define (get-nutrient-targets) - (for/list ([(id* effective-on*) - (in-query (current-conn) - (select id effective_on - #:from nutrient_targets - #:order-by id ASC))]) - (nutrient-target id* effective-on*))) - -(define (get-nutrient-target #:id [id #f] - #:effective-on [effective-on #f]) - (define (where-expr) - (define clauses - (filter values - (list - (and id (format "id = ~e" id)) - (and effective-on (format "effective_on = ~e" effective-on))))) + (define query (select nt.id nt.effective_on + n.id n.canonical_name n.formula + nv.value_ppm + #:from (TableExpr:AST ,joined) + #:order-by nt.effective_on #:desc)) + (define rows (query-rows (current-conn) query)) + (define by-id + (for/fold ([h (hash)]) ([row (in-list rows)]) + (match-define (vector nt-id effective-on n-id n-name n-formula value-ppm) row) + (define nv-pair (cons (nutrient n-id n-name n-formula) value-ppm)) + (hash-update h nt-id + (λ (old-acc) + (acc (acc-effective-on old-acc) + (cons nv-pair (acc-pairs old-acc)))) + (λ () + (acc effective-on + (list nv-pair)))))) + (for/list ([(id a) (in-hash by-id)]) + (nutrient-target id + (acc-effective-on a) + (reverse (acc-pairs a))))) + +(define (get-nutrient-target #:id [nt-id #f] + #:effective-on [effective-on #f]) + (define where (cond - [(null? clauses) ""] - [else (format "WHERE ~a" (string-join clauses " AND "))])) - (define query (string-join - `("SELECT id, effective_on" - "FROM nutrient_targets" - ,(where-expr) - "ORDER BY id ASC" - "LIMIT 1"))) - (match (query-maybe-row (current-conn) query) - [(vector id* effective-on*) - (nutrient-target id* effective-on*)] - [#f #f])) + [(and nt-id effective-on) + (scalar-expr-qq (and (= nt.id ,nt-id) + (= nt.effective_on ,effective-on)))] + [nt-id + (scalar-expr-qq (= nt.id ,nt-id))] + [effective-on + (scalar-expr-qq (= nt.effective_on ,effective-on))])) + (define query (select nt.id nt.effective_on + n.id n.canonical_name n.formula + nv.value_ppm + #:from (TableExpr:AST ,joined) + #:where (ScalarExpr:AST ,where))) + (define rows (query-rows (current-conn) query)) + (cond + [(null? rows) #f] + [else + ;; Fold all nutrient rows belonging to the single target into one struct + (define the-id #f) + (define A #f) + (for ([row (in-list rows)]) + (match-define (vector nt-id effective-on n-id n-name n-formula value-ppm) row) + (unless the-id (set! the-id nt-id)) + (define nv-pair (cons (nutrient n-id n-name n-formula) value-ppm)) + (set! A (if A + (acc (acc-effective-on A) + (cons nv-pair (acc-pairs A))) + (acc effective-on (list nv-pair))))) + (and A + (nutrient-target the-id + (acc-effective-on A) + (reverse (acc-pairs A))))])) (define (get-nutrient-target-values nutrient-target) (for/list ([(nutrient-id name formula value_ppm) |