#lang scheme/base
(require (planet bzlib/base)
"base.ss"
scheme/file
scheme/path
)
(define (key-declaration? line)
(if-it (regexp-match #px"^--;;--\\s*([\\w\\:\\-\\?\\!\\/\\_]+)" line)
(string->symbol (cadr it))
#f))
(define (comment? line)
(or (regexp-match #px"^\\s*$" line)
(regexp-match #px"^\\s*--" line)))
(define (parse-statements lines)
(define (skip-until-key-then-parse rest)
(cond ((null? rest) (error 'parse-statements "No key declaraction found - the whole file checked and skipped"))
((key-declaration? (car rest)) (parse-rest rest '()))
(else (skip-until-key-then-parse (cdr rest)))))
(define (parse-rest rest stmts)
(cond ((null? rest) (reverse stmts))
(else
(let-values (((stmt rest)
(parse (key-declaration? (car rest)) (cdr rest) '())))
(parse-rest rest (cons stmt stmts))))))
(define (parse key rest acc)
(define (return key acc rest)
(values (cons key (string-join (reverse acc) "\n"))
rest))
(cond ((null? rest) (if (null? acc) (error 'parse-statements "key ~a had no following statement" key)
(return key acc rest)))
((key-declaration? (car rest)) (return key acc rest))
((comment? (car rest)) (parse key (cdr rest) acc))
(else
(parse key (cdr rest) (cons (car rest) acc)))))
(skip-until-key-then-parse lines))
(define (file->statements path)
(define (file->lines path)
(call-with-input-file path
(lambda (in)
(let loop ((b (read-line in 'any))
(lines '()))
(if (eof-object? b)
(reverse lines)
(loop (read-line in 'any) (cons b lines)))))))
(parse-statements (file->lines path)))
(define (load-file! handle path)
(for-each (lambda (stmt)
(prepare handle (car stmt) (cdr stmt)))
(file->statements path)))
(define (directory-list/regex path pat)
(define (match? file)
(regexp-match pat (path->string file)))
(map (lambda (p)
(normalize-path (build-path path p)))
(filter match? (directory-list path))))
(define (load-files! handle paths)
(define (helper path)
(if (directory-exists? path)
(for-each (lambda (path)
(load-file! handle path))
(directory-list/regex path #px"\\.sql$"))
(load-file! handle path)))
(for-each helper paths))
(define (filter-file-loader/attrs attrs)
(define (helper rest acc loader)
(cond ((null? rest) (values loader (reverse acc)))
((equal? (car rest) '#:load)
(if (null? (cdr rest))
(error 'connect "invalid attribute ~a - no values" (car rest))
(helper (cddr rest) acc (cadr rest))))
(else
(helper (cdr rest) (cons (car rest) acc) loader))))
(helper attrs '() '()))
(provide/contract
(key-declaration? (-> string? (or/c false/c symbol?)))
(load-file! (-> handle? path-string? any))
(load-files! (-> handle? (listof path-string?) any))
(filter-file-loader/attrs (-> (listof any/c) any))
)