trivial/private/db/postgres.rkt
2016-03-09 21:40:19 -05:00

124 lines
2.1 KiB
Racket

#lang racket/base
;; sql basics, belongs in a new file?
(provide
postgres-parameter?
;; (-> Any (Option Natural))
;; If input is a Postgres parameter, return the parameter number.
;; i.e $2 -> 2
;; Otherwise return #f.
;; -- also exports predicates defined with `define-sql-keyword-predicate`
)
(require
(for-syntax
typed/racket/base
racket/syntax
syntax/parse))
(define-syntax (define-sql-keyword-predicate stx)
(syntax-parse stx
[(_ kwd*:id ...)
#:with (kwd?* ...) (for/list ([kwd (in-list (syntax-e #'(kwd* ...)))])
(format-id stx "~a?" (syntax-e kwd)))
(syntax/loc stx
(begin (begin (provide kwd?*) (define (kwd?* v) (symbol-ci=? v 'kwd*))) ...))]))
;; -----------------------------------------------------------------------------
(define (symbol-ci=? s1 s2)
(and
(symbol? s1)
(symbol? s2)
(string-ci=? (symbol->string s1) (symbol->string s2))))
(define-sql-keyword-predicate
select
from
where
and)
;; Check for query parameters. Currently only for Postgres.
(define (postgres-parameter? s)
(and
(or (string? s) (symbol? s))
(let ([str (if (string? s) s (symbol->string s))])
(and
(= 2 (string-length str))
(eq? #\$ (string-ref str 0))
(string->number (string (string-ref str 1)))))))
(module+ test
(require rackunit rackunit-abbrevs)
(check-apply* symbol-ci=?
['a 'a
=> #t]
['a 'A
=> #t]
['yellow 'YeLLOW
=> #t]
['wait 'forME
=> #f]
['x 'y
=> #f]
["A" 'A
=> #f]
[315 "bage"
=> #f]
)
(check-apply* select?
['select
=> #t]
['SELECT
=> #t]
['yolo
=> #f]
)
(check-apply* from?
['from
=> #t]
['FROM
=> #t]
['yolo
=> #f]
)
(check-apply* where?
['where
=> #t]
['WHERE
=> #t]
['yolo
=> #f]
)
(check-apply* and?
['and
=> #t]
['AND
=> #t]
['yolo
=> #f]
)
(check-apply* postgres-parameter?
["$1"
=> 1]
['$1
=> 1]
["$125"
=> #f]
['$555
=> #f]
['wepa
=> #f]
[3
=> #f]
)
)