/db/mongodb/orm/struct.rkt

http://github.com/jeapostrophe/mongodb · Racket · 152 lines · 148 code · 4 blank · 0 comment · 24 complexity · 96f01f060c3b00326c38e122c2a6ce39 MD5 · raw file

  1. #lang racket/base
  2. (require (for-syntax racket/base
  3. syntax/parse
  4. racket/list
  5. syntax/stx
  6. racket/syntax)
  7. "dict.rkt")
  8. (define-syntax (define-mongo-struct stx)
  9. (syntax-parse
  10. stx
  11. [(_ struct:id collection:str
  12. ([field:id given-opt:keyword ...]
  13. ...))
  14. (with-syntax*
  15. ([make-struct
  16. (format-id stx "make-~a" #'struct)]
  17. [((required? opt ...) ...)
  18. (stx-map (lambda (opts-stx)
  19. (define opts (syntax->list opts-stx))
  20. (define immutable?
  21. (findf (lambda (stx)
  22. (syntax-parse
  23. stx
  24. [#:immutable #t]
  25. [_ #f]))
  26. opts))
  27. (define required?
  28. (or immutable?
  29. (findf (lambda (stx)
  30. (syntax-parse
  31. stx
  32. [#:required #t]
  33. [_ #f]))
  34. opts)))
  35. (define null?
  36. (findf (lambda (stx)
  37. (syntax-parse
  38. stx
  39. [#:null #t]
  40. [_ #f]))
  41. opts))
  42. (define base-opts
  43. (filter (lambda (stx)
  44. (syntax-parse
  45. stx
  46. [#:required #f]
  47. [#:immutable #f]
  48. [_ #t]))
  49. opts))
  50. (define ref-opts
  51. (list* #'#:ref base-opts))
  52. (define set-opts
  53. (if immutable?
  54. ref-opts
  55. (list* #'#:set! ref-opts)))
  56. (when (and immutable? (not (zero? (length base-opts))))
  57. (raise-syntax-error 'define-mongo-struct "Immutable fields cannot have mutation operators" opts-stx (first base-opts)))
  58. (when (and required? null?)
  59. (raise-syntax-error 'define-mongo-struct "Required fields cannot have a null operator" opts-stx null?))
  60. (cons (and required? #t) set-opts))
  61. #'((given-opt ...) ...))]
  62. [(field-kw ...)
  63. (stx-map (lambda (field)
  64. (datum->syntax field (string->keyword (symbol->string (syntax->datum field)))))
  65. #'(field ...))]
  66. [(field-arg ...)
  67. (for/fold ([arg-stx #'()])
  68. ([field (in-list (syntax->list #'(field ...)))]
  69. [required? (in-list (syntax->list #'(required? ...)))]
  70. [field-kw (in-list (syntax->list #'(field-kw ...)))])
  71. (if (syntax->datum required?)
  72. (quasisyntax/loc stx
  73. (#,field-kw #,field #,@arg-stx))
  74. (quasisyntax/loc stx
  75. (#,field-kw [#,field (void)] #,@arg-stx))))])
  76. (syntax/loc stx
  77. (begin
  78. (define the-collection collection)
  79. (define (make-struct field-arg ...)
  80. (define the-struct
  81. (create-mongo-dict the-collection))
  82. (unless (void? field)
  83. (mongo-dict-set! the-struct 'field field))
  84. ...
  85. the-struct)
  86. (define-mongo-struct-field struct field (opt ...))
  87. ...)))]))
  88. (define-syntax (define-mongo-struct-field stx)
  89. (syntax-parse
  90. stx
  91. [(_ struct:id field:id (opt:keyword ...))
  92. (with-syntax
  93. ([((name fun) ...)
  94. (filter-map
  95. (lambda (stx)
  96. (syntax-parse
  97. stx
  98. [#:ref
  99. (list (format-id #'struct "~a-~a" #'struct #'field)
  100. #'mongo-dict-ref)]
  101. [#:set!
  102. (list (format-id #'struct "set-~a-~a!" #'struct #'field)
  103. #'mongo-dict-set!)]
  104. [#:inc
  105. (list (format-id #'struct "inc-~a-~a!" #'struct #'field)
  106. #'mongo-dict-inc!)]
  107. [#:null
  108. (list (format-id #'struct "null-~a-~a!" #'struct #'field)
  109. #'mongo-dict-remove!)]
  110. [#:push
  111. (list (format-id #'struct "push-~a-~a!" #'struct #'field)
  112. #'mongo-dict-push!)]
  113. [#:append
  114. (list (format-id #'struct "append-~a-~a!" #'struct #'field)
  115. #'mongo-dict-append!)]
  116. [#:set-add
  117. (list (format-id #'struct "set-add-~a-~a!" #'struct #'field)
  118. #'mongo-dict-set-add!)]
  119. [#:set-add*
  120. (list (format-id #'struct "set-add*-~a-~a!" #'struct #'field)
  121. #'mongo-dict-set-add*!)]
  122. [#:pop
  123. (list (format-id #'struct "pop-~a-~a!" #'struct #'field)
  124. #'mongo-dict-pop!)]
  125. [#:shift
  126. (list (format-id #'struct "shift-~a-~a!" #'struct #'field)
  127. #'mongo-dict-shift!)]
  128. [#:pull
  129. (list (format-id #'struct "pull-~a-~a!" #'struct #'field)
  130. #'mongo-dict-pull!)]
  131. [#:pull*
  132. (list (format-id #'struct "pull*-~a-~a!" #'struct #'field)
  133. #'mongo-dict-pull*!)]
  134. [_
  135. (raise-syntax-error 'define-mongo-struct "Invalid field option" stx)]))
  136. (syntax->list #'(opt ...)))])
  137. (syntax/loc stx
  138. (begin
  139. (define-mongo-struct-field* field name fun)
  140. ...)))]))
  141. (define-syntax (define-mongo-struct-field* stx)
  142. (syntax-parse
  143. stx
  144. [(_ field:id name:id opt-fun:id)
  145. (syntax/loc stx
  146. (define (name the-struct . args)
  147. (apply opt-fun the-struct 'field args)))]))
  148. (provide define-mongo-struct)