#lang scheme/base
(require (for-syntax scheme/base
scheme/match
srfi/26/cut
(planet untyped/unlib:3/syntax)
"base.ss"
"persistent-struct-info.ss")
scheme/class
"quick-find-internal.ss"
"sql/sql.ss")
(define-for-syntax (make-quick-find stx count? struct-stx snooze-stx method-stx order-stxs)
(let* ([info (with-handlers ([exn? (lambda (exn)
(raise-syntax-error #f "not a persistent struct" stx struct-stx))])
(persistent-struct-info-ref struct-stx))]
[entity-stx (persistent-struct-info-entity-id info)]
[attr-stxs (persistent-struct-info-attribute-ids info)]
[key-stxs (map (lambda (sym)
(string->keyword (symbol->string sym)))
(persistent-struct-info-attribute-names info))]
[arg-stxs
(map (cut datum->syntax #f <>)
(persistent-struct-info-attribute-names info))]
[key+arg-stxs
(let loop ([key-stxs key-stxs] [arg-stxs arg-stxs])
(if (null? key-stxs)
null
(list* (car key-stxs)
#`(#,(car arg-stxs) (void))
(loop (cdr key-stxs) (cdr arg-stxs)))))])
(with-syntax ([struct struct-stx]
[struct-id (make-id struct-stx struct-stx '-id)]
[snooze snooze-stx]
[find-whatever method-stx]
[entity entity-stx]
[proc (make-id struct-stx 'custom- method-stx '/ struct-stx)]
[(attr ...) attr-stxs]
[(key ...) key-stxs]
[(arg ...) arg-stxs]
[(key+arg ...) key+arg-stxs]
[(*order* ...) order-stxs])
(quasisyntax/loc stx
(let-alias ([struct struct])
(letrec ([default-what #,(if count?
#'(sql (count struct-id))
#'(sql struct))]
[default-order (list (sql *order*) ...)]
[proc (lambda (key+arg ...
#:what [what #f]
#:order [order #f]
#:limit [limit #f]
#:offset [offset #f])
(send snooze find-whatever
(sql (select #:what ,(or what default-what)
#:from struct
#:where ,(sql:and (or (void? arg)
(quick-find-expression
(sql:attr struct attr)
arg))
...)
#:order ,(or order default-order)
#:limit ,limit
#:offset ,offset))))])
proc))))))
(define-for-syntax (parse-kws stx kw-stx)
(define order-stxs null)
(let loop ([kw-stx kw-stx])
(syntax-case kw-stx ()
[()
(values order-stxs)]
[(kw)
(if (keyword? (syntax->datum #'kw))
(raise-syntax-error #f "no value for keyword" stx #'kw)
(raise-syntax-error #f "not a valid keyword" stx #'kw))]
[(#:order val rest ...)
(begin (set! order-stxs (syntax->list #'val))
(loop #'(rest ...)))]
[(_ val rest ...)
(raise-syntax-error #f "not a valid keyword" stx #'kw)])))
(define-syntax (custom-find-count stx)
(syntax-case stx ()
[(_ struct snooze kw ...)
(make-quick-find stx #t #'struct #'snooze #'find-one null)]))
(define-syntax (custom-find-one stx)
(syntax-case stx ()
[(_ struct snooze kw ...)
(let ([order-stxs (parse-kws stx #'(kw ...))])
(make-quick-find stx #f #'struct #'snooze #'find-one order-stxs))]))
(define-syntax (custom-find-all stx)
(syntax-case stx ()
[(_ struct snooze kw ...)
(let ([order-stxs (parse-kws stx #'(kw ...))])
(make-quick-find stx #f #'struct #'snooze #'find-all order-stxs))]))
(define-syntax (custom-g:find stx)
(syntax-case stx ()
[(_ struct snooze kw ...)
(let ([order-stxs (parse-kws stx #'(kw ...))])
(make-quick-find stx #f #'struct #'snooze #'g:find order-stxs))]))
(provide custom-find-count
custom-find-one
custom-find-all
custom-g:find)