summaryrefslogtreecommitdiff
path: root/models/fertilizer-product.rkt
blob: f9cf5fd7630e5dbf6455064a0383ed908e7c8d3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
#lang racket

(provide
 ;; Struct definitions
 fertilizer-product
 fertilizer-product?
 fertilizer-product-id fertilizer-product-brand-name
 ;; SQL CRUD
 (contract-out
  [create-fertilizer-product! (->* (string?
                                    (listof (cons/c nutrient? number?)))
                                   (string?)
                                   fertilizer-product?)]
  [get-fertilizer-products (-> (listof fertilizer-product?))]
  [get-fertilizer-product (->* ()
                               (#:id (or/c #f exact-nonnegative-integer?)
                                #:brand-name (or/c #f string?))
                               (or/c fertilizer-product? #f))]
  [get-fertilizer-product-values (-> fertilizer-product? (listof (cons/c nutrient? number?)))]
  [get-fertilizer-product-value (-> fertilizer-product? nutrient? number?)]
  [get-latest-fertilizer-product-value (-> nutrient? number?)]
  [delete-fertilizer-product! (-> fertilizer-product? void?)]))

(require racket/contract
         db
         sql
         "../db/conn.rkt"
         "nutrient.rkt")

;; Instances of this struct are persisted in the fertilizer_products table.
(struct fertilizer-product (id canonical-name brand-name) #:transparent)


;; CREATE

(define (create-fertilizer-product! canonical-name nutrient-values [brand-name #f])
  (define existing-fertilizer-product (get-fertilizer-product #:canonical-name canonical-name))
  (define (new-fertilizer-product)
    (with-tx
      (query-exec (current-conn)
                  (cond
                    [brand-name
                     (insert #:into fertilizer_products
                             #:set [canonical_name ,canonical-name] [brand_name ,brand-name])]
                    [else
                     (insert #:into fertilizer_products
                             #:set [canonical_name ,canonical-name])]))
      (define nm-id (fertilizer-product-id (get-fertilizer-product #:canonical-name canonical-name)))
      (query-exec (current-conn)
                  (insert #:into nutrient_value_sets
                          #:set [fertilizer_product_id ,nm-id]))
      (define nvs-id (query-value (current-conn)
                                  (select id
                                          #:from nutrient_value_sets
                                          #:where (= fertilizer_product_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-fertilizer-product #:canonical-name canonical-name))
  (or existing-fertilizer-product
      (new-fertilizer-product)))


;; READ

(define (get-fertilizer-products)
  (for/list ([(id* brand-name*)
              (in-query (current-conn)
                        (select id brand_name
                                #:from fertilizer_products
                                #:order-by canonical_name #:asc))])
    (fertilizer-product id* brand-name*)))

(define (get-fertilizer-product #:id [id #f]
                                #:canonical-name [canonical-name #f]
                                #:brand-name [brand-name #f])
  (define (where-expr)
    (define clauses
      (filter values
              (list
               (and id (format "id = ~e" id))
               (and canonical-name (format "canonical_name = ~e" canonical-name))
               (and brand-name (format "brand_name = ~e" brand-name)))))
    (cond
      [(null? clauses) ""]
      [else (format "WHERE ~a" (string-join clauses " AND "))]))
  (match (query-maybe-row (current-conn)
                          (string-join
                           `("SELECT id, canonical_name, brand_name"
                             "FROM fertilizer_products"
                             ,(where-expr)
                             "ORDER BY id ASC"
                             "LIMIT 1")))
    [(vector id* canonical-name* brand-name*)
     (fertilizer-product id* canonical-name* brand-name*)]
    [#f #f]))

(define (get-fertilizer-product-values fertilizer-product)
  (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 fertilizer_products nm ON nm.id = nvs.fertilizer_product_id"
                           "JOIN nutrients n ON n.id = nv.nutrient_id"
                           "WHERE nm.id = $1"))
                        (fertilizer-product-id fertilizer-product))])
    (cons (nutrient nutrient-id name formula) value_ppm)))

(define (get-fertilizer-product-value fertilizer-product 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 fertilizer_products nm ON nm.id = nvs.fertilizer_product_id"
                        "WHERE nm.id = $1 AND nv.nutrient_id = $2"))
                     (fertilizer-product-id fertilizer-product)
                     (nutrient-id nutrient)))

(define (get-latest-fertilizer-product-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 fertilizer_products nm ON nm.id = nvs.fertilizer_product_id"
                        "WHERE nv.nutrient_id = $1"
                        "ORDER BY nm.brand_name DESC"
                        "LIMIT 1"))
                     (nutrient-id nutrient)))


;; UPDATE


;; DELETE

(define (delete-fertilizer-product! fertilizer-product)
  (define id (fertilizer-product-id fertilizer-product))
  (query-exec (current-conn)
              (delete #:from fertilizer_products
                      #:where (= id ,id))))
Copyright 2019--2025 Marius PETER