#lang scheme (require "query.ss" "relation.ss" "tuple.ss" "optimize.ss") (define current-database/c (-> symbol? relation?)) (define current-database (make-parameter (lambda (rel-id) (error 'current-database "Unknown relation: ~e" rel-id)))) (define (raw-execute-query cache q) (hash-ref cache q (lambda () (match q [(struct q:relation (id)) ((current-database) id)] [(struct q:singleton (schema)) (singleton-relation schema NULL)] [(struct q:union (r s)) (relation-union (raw-execute-query cache r) (raw-execute-query cache s))] [(struct q:difference (r s)) (relation-difference (raw-execute-query cache r) (raw-execute-query cache s))] [(struct q:intersection (r s)) (relation-intersection (raw-execute-query cache r) (raw-execute-query cache s))] [(struct q:product (r s)) (relation-product (raw-execute-query cache r) (raw-execute-query cache s))] [(struct q:projection (schema r)) (relation-projection schema (raw-execute-query cache r))] [(struct q:selection (prop r)) (relation-selection prop (raw-execute-query cache r))] [(struct q:rename* (old->new r)) (relation-rename* old->new (raw-execute-query cache r))])))) (define (execute-query q) (define cache (make-hash)) (define oq (optimize-query q)) (printf "Executing: ~S~n~n" q) (printf "Optimized: ~S~n~n" oq) (raw-execute-query cache oq)) (define database/c (and/c immutable? hash-eq?)) (define-syntax-rule (with-database db e ...) (call-with-database db (lambda () e ...))) (define (call-with-database db thnk) (parameterize ([current-database (lambda (rel-id) (hash-ref db rel-id))] [current-database-schema (lambda (rel-id) (relation-schema (hash-ref db rel-id)))]) (thnk))) (define (database-insert db rel-id tup) (define rel-schema (relation-schema (hash-ref db rel-id (lambda () (error 'database-insert "Unknown relation: ~e" rel-id))))) (unless (= (length rel-schema) (tuple-length tup)) (error 'database-insert "Tuple ~a does not match ~a's schema: ~a" tup rel-id rel-schema)) (hash-update db rel-id (lambda (rel) (relation-insert rel tup)))) (define (database-delete db rel-id tup) (define rel-schema (relation-schema (hash-ref db rel-id (lambda () (error 'database-delete "Unknown relation: ~e" rel-id))))) (unless (= (length rel-schema) (tuple-length tup)) (error 'database-delete "Tuple ~a does not match ~a's schema: ~a" tup rel-id rel-schema)) (hash-update db rel-id (lambda (rel) (relation-delete rel tup)))) (define-syntax-rule (Database [relation-id schema tuples ...] ...) (make-immutable-hasheq (list (cons 'relation-id (Relation schema tuples ...)) ...))) (provide with-database Database) (provide/contract [current-database/c contract?] [current-database (parameter/c current-database/c)] [execute-query (query? . -> . relation?)] [database/c contract?] [database-insert (database/c symbol? tuple? . -> . database/c)] [database-delete (database/c symbol? tuple? . -> . database/c)] [call-with-database (database/c (-> any) . -> . any)])