json-mapping.scm 3.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869
  1. ;; this is based on the json reader code from guile-mastodon
  2. (define-module (tapris json-mapping)
  3. #:use-module (json)
  4. #:use-module (srfi srfi-9)
  5. #:use-module (srfi srfi-69)
  6. #:export (define-json-mapping))
  7. ;; TODO: maybe not go through a hashtable?
  8. (define-syntax-rule (define-json-reader json->record ctor spec ...)
  9. "Define JSON->RECORD as a procedure that converts a JSON representation,
  10. read from a port, string, or hash table, into a record created by CTOR and
  11. following SPEC, a series of field specifications."
  12. (define (json->record input)
  13. (let ((table (cond ((port? input)
  14. (alist->hash-table (json->scm input)))
  15. ((string? input)
  16. (alist->hash-table (json-string->scm input)))
  17. ((hash-table? input)
  18. input)
  19. (else (alist->hash-table input)))))
  20. (if (not (hash-table? table))
  21. (throw 'pleroma `(("errror" . "couldn't convert to a hash table")
  22. ("input" . ,`input))))
  23. (let-syntax ((extract-field (syntax-rules ()
  24. ((_ table (field key json->value value->json))
  25. (json->value (hash-table-ref/default table key #f)))
  26. ((_ table (field key json->value))
  27. (json->value (hash-table-ref/default table key #f)))
  28. ((_ table (field key))
  29. (hash-table-ref/default table key #f))
  30. ((_ table (field))
  31. (hash-table-ref/default table
  32. (symbol->string 'field)
  33. #f)))))
  34. (ctor (extract-field table spec) ...)))))
  35. (define-syntax-rule (define-json-writer record->json spec ...)
  36. "Define RECORD->JSON as a procedure that converts a record to a JSON
  37. representation."
  38. (define* (record->json input #:optional #:key (pretty #f))
  39. (let-syntax ((extract-field (syntax-rules ()
  40. ((_ rec (field getter))
  41. `(,(symbol->string 'field) . ,(getter rec)))
  42. ((_ rec (field getter key))
  43. `(key . ,(getter rec)))
  44. ((_ rec (field getter key json->value))
  45. `(key . ,(getter rec)))
  46. ((_ rec (field getter key json->value value->json))
  47. `(key . ,(value->json (getter rec)))))))
  48. (scm->json-string
  49. (list (extract-field input spec) ...)
  50. #:pretty pretty))))
  51. (define-syntax-rule (define-json-mapping rtd ctor pred json->record record->json
  52. (field getter spec ...) ...)
  53. "Define RTD as a record type with the given FIELDs and GETTERs, à la SRFI-9,
  54. and define JSON->RECORD (RECORD->JSON) as a conversion from (to) JSON
  55. to (from) a record of this type."
  56. (begin
  57. (define-record-type rtd
  58. (ctor field ...)
  59. pred
  60. (field getter) ...)
  61. (define-json-reader json->record ctor
  62. (field spec ...) ...)
  63. (define-json-writer record->json (field getter spec ...) ...)))