summaryrefslogtreecommitdiff
path: root/models/crop-requirement.rkt
blob: d4eb78bedee3028d75ab1a19df0433bee4d557be (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
151
152
153
154
155
156
157
#lang racket

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

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

;; Instances of this struct are persisted in the crop_requirements table.
(struct crop-requirement (id profile) #:transparent)


;; CREATE

(define (create-crop-requirement! profile nutrient-values [crop #f])
  (define existing-crop-requirement (get-crop-requirement #:profile profile))
  (define (new-crop-requirement)
    (with-tx
      (query-exec (current-conn)
                  (if crop
                      (insert #:into crop_requirements
                              #:set [crop_id ,(crop-id crop)] [profile ,profile])
                      (insert #:into crop_requirements
                              #:set [profile ,profile])))
      (define cr-id (crop-requirement-id (get-crop-requirement #:profile profile)))
      (query-exec (current-conn)
                  (insert #:into nutrient_value_sets
                          #:set [crop_requirement_id ,cr-id]))
      (define nvs-id (query-value (current-conn)
                                  (select id
                                          #:from nutrient_value_sets
                                          #:where (= crop_requirement_id ,cr-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-crop-requirement #:profile profile))
  (or existing-crop-requirement
      (new-crop-requirement)))


;; READ

(define (get-crop-requirements)
  (for/list ([(id* profile*)
              (in-query (current-conn)
                        (select id profile
                                #:from crop_requirements
                                #:order-by id #:asc))])
    (crop-requirement id* profile*)))

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

(define (get-crop-requirement-values crop-requirement)
  (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 crop_requirements cr ON cr.id = nvs.crop_requirement_id"
                           "JOIN nutrients n ON n.id = nv.nutrient_id"
                           "WHERE cr.id = $1"))
                        (crop-requirement-id crop-requirement))])
    (cons (nutrient nutrient-id name formula) value_ppm)))

(define (get-crop-requirement-value crop-requirement 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 crop_requirements cr ON cr.id = nvs.crop_requirement_id"
                        "WHERE cr.id = $1 AND nv.nutrient_id = $2"))
                     (crop-requirement-id crop-requirement)
                     (nutrient-id nutrient)))

(define (get-latest-crop-requirement-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 crop_requirements cr ON cr.id = nvs.crop_requirement_id"
                        "WHERE nv.nutrient_id = $1"
                        "ORDER BY cr.profile DESC"
                        "LIMIT 1"))
                     (nutrient-id nutrient)))


;; UPDATE


;; DELETE

(define (delete-crop-requirement! crop-requirement)
  (define id (crop-requirement-id crop-requirement))
  (query-exec (current-conn)
              (delete #:from crop_requirements
                      #:where (= id ,id))))
Copyright 2019--2025 Marius PETER