#lang racket (provide seed-database!) (require csv-reading racket/runtime-path "conn.rkt" "../models/nutrient.rkt" "../models/nutrient-measurement.rkt" "../models/crop.rkt" "../models/crop-requirement.rkt" "../models/fertilizer-product.rkt") (define (seed-database!) (for ([phase (in-list seed-sequence)]) (match-define (cons entity seed-function) phase) (seed-function) (displayln (format "Seeded entity: ~a" entity)))) (define (seed-nutrients!) (define nutrient-names (map nutrient-name (get-nutrients))) (define default-nutrients '(("Nitrate Nitrogen" . "NNO3") ("Phosphorus" . "P") ("Potassium" . "K") ("Calcium" . "Ca") ("Magnesium" . "Mg") ("Sulfur" . "S") ("Sodium" . "Na") ("Chloride" . "Cl") ("Silicon" . "Si") ("Iron" . "Fe") ("Zinc" . "Zn") ("Boron" . "B") ("Manganese" . "Mn") ("Copper" . "Cu") ("Molybdenum" . "Mo") ("Ammonium Nitrogen" . "NNH4"))) (with-tx (for ([pair (in-list default-nutrients)]) (match-define (cons name formula) pair) ;; Ensure idempotence (unless (member name nutrient-names) (create-nutrient! name formula))))) (define-runtime-path measurement-csv "data/dolibarr_nutrient_measurements_ppm.csv") (define (seed-historical-nutrient-measurements!) (define next-row (make-csv-reader (open-input-file measurement-csv))) (define header (next-row)) (define (row->seed! row) (define row-alist (map cons header row)) (define measured-on (cdr (first row-alist))) (define nutrient-values (for/hash ([nm (in-list (cdr row-alist))]) (define formula (car nm)) (define n (get-nutrient #:formula formula)) (define v (string->number (cdr nm))) (values n v))) (create-nutrient-measurement! measured-on nutrient-values)) (with-tx (csv-for-each row->seed! next-row))) (define (seed-crops!) (define crop-names (map crop-name (get-crops))) (define default-crops '("salade" "laitue" "tomate" "framboise")) (with-tx (for ([name (in-list default-crops)]) ;; Ensure idempotence (unless (member name crop-names) (create-crop! name))))) (define-runtime-path requirements-csv "data/dolibarr_crop_requirements_ppm.csv") (define (seed-crop-requirements!) (define next-row (make-csv-reader (open-input-file requirements-csv))) (define header (next-row)) (define (row->seed! row) (define row-alist (map cons header row)) (define crop-name (string-downcase (cdr (assoc "Plante" row-alist)))) (define profile (cdr (assoc "Profil" row-alist))) (define nutrient-values (for/hash ([crop-requirement (in-list (list-tail row-alist 2))]) (define formula (car crop-requirement)) (define n (get-nutrient #:formula formula)) (define v (string->number (cdr crop-requirement))) (values n v))) (cond [(non-empty-string? crop-name) (define crop (get-crop #:name crop-name)) (create-crop-requirement! profile nutrient-values crop)] [else (create-crop-requirement! profile nutrient-values)])) (with-tx (csv-for-each row->seed! next-row))) (define-runtime-path fertilizer-csv "data/dolibarr_fertilizer_compositions_percentage.csv") (define (seed-existing-fertilizer-products!) (define next-row (make-csv-reader (open-input-file fertilizer-csv))) (define header (next-row)) (define (row->seed! row) (define row-alist (map cons header row)) (define canonical-name (cdr (assoc "Libellé" row-alist))) (define brand-name (cdr (assoc "Nom commercial" row-alist))) (define nutrient-values (for/hash ([fertilizer-component (in-list (list-tail row-alist 3))]) (define n (get-nutrient #:formula (car fertilizer-component))) (define v (string->number (cdr fertilizer-component))) (values n v))) (cond [(non-empty-string? brand-name) (create-fertilizer-product! canonical-name nutrient-values brand-name)] [else (create-fertilizer-product! canonical-name nutrient-values)])) (with-tx (csv-for-each row->seed! next-row))) (define seed-sequence (list (cons "nutrients" seed-nutrients!) (cons "nutrient measurements" seed-historical-nutrient-measurements!) (cons "crops" seed-crops!) (cons "crop requirements" seed-crop-requirements!) (cons "fertilizer products" seed-existing-fertilizer-products!))) (module+ test (require "migrations.rkt") (connect! #:path 'memory) (migrate-all!) (seed-database!))