]> git.jsancho.org Git - bongodb.git/blobdiff - src/bongodb.scm
Replace VHashes with Hash Tables
[bongodb.git] / src / bongodb.scm
index c6b2571605ba23e3a9b4e1ef64a5796ea57760ba..24ced3684c04aba6302c46a7818b7893f1bbd3e5 100644 (file)
@@ -1,4 +1,3 @@
-;;;
 ;;; BongoDB, an embedded document-based engine
 ;;; Copyright (C) 2016 by Javier Sancho Fernandez <jsf at jsancho dot org>
 ;;;
 
 
 (define-module (bongodb)
-  #:use-module (ice-9 receive)
-  #:use-module (ice-9 vlist)
   #:use-module (srfi srfi-9)
-  #:use-module (srfi srfi-9 gnu))
+  #:use-module (srfi srfi-9 gnu)
+  #:use-module (srfi srfi-69)
+  #:export (make-collection
+           collection?
+           count
+           insert
+           find
+           update
+           $eq
+           $exists
+           $not
+           $and
+           $set))
 
 
 ;;; Collection Definition
   (table get-table))
 
 (define (make-collection)
-  (make-collection-record vlist-null))
+  (make-collection-record (make-hash-table)))
+
+(define (count col)
+  (hash-table-size (get-table col)))
 
 (set-record-type-printer! collection
   (lambda (record port)
     (format port
            "#<collection with ~a documents>"
-           (vlist-length (get-table record)))))
+           (count record))))
 
 
 ;;; Working with documents
 
 (define (format-document document)
-  "Return a vhash document ready to store in a collection"
+  "Return an alist document ready to store in a collection"
   (document-with-id
-   (cond ((vhash? document)
-         document)
+   (cond ((hash-table? document)
+         (hash-table->alist document))
         (else
-         (alist->vhash document)))))
+         document))))
 
 (define (document-with-id document)
   "Return always a document with an id"
-  (or (and (vhash-assoc '_id document)
+  (or (and (assoc '_id document)
           document)
-      (vhash-cons '_id (gensym) document)))
+      (assoc-set! document '_id (gensym))))
 
 (define (insert col . documents)
-  "Insert documents into the collection and return the new collection"
+  "Insert documents into the collection and return document ids"
   (cond ((null? documents)
-        (values col '()))
+        '())
        (else
         (let* ((document (format-document (car documents)))
-               (docid (cdr (vhash-assoc '_id document)))
-               (newcol (make-collection-record (vhash-cons docid document (get-table col)))))
-          (receive (rescol docids)
-              (apply insert (cons newcol (cdr documents)))
-            (values rescol (cons docid docids)))))))
+               (docid (assoc-ref document '_id)))
+          (hash-table-set! (get-table col) docid document)
+          (cons docid (apply insert (cons col (cdr documents))))))))
 
 (define (find col filter)
   "Query the collection and return the documents that match with filter"
-  (let ((table (get-table col)))
-    (vhash-fold
-     (lambda (key value result) (cons (vhash->alist value) result))
-     '()
-     table)))
+  (hash-table-fold
+   (get-table col)
+   (lambda (key document result)
+     (cond ((match-document? document filter)
+           (cons document result))
+          (else
+           result)))
+   '()))
+
+(define (match-document? document filter)
+  "Try to match the given document with a given filter"
+  (cond ((equal? filter #t)
+        #t)
+       (else
+        (filter document))))
+
+(define (update col filter . changes)
+  "Update selected documents using the given filter"
+  (let ((documents (find col filter)))
+    (apply insert (cons col (map (lambda (doc) (update-document doc changes)) documents)))))
+
+(define (update-document document changes)
+  "Update a document with the appropiate changes"
+  (cond ((null? changes)
+        document)
+       (else
+        (update-document ((car changes) document) (cdr changes)))))
+
+
+;;; Queries
+
+(define ($eq field value)
+  (lambda (document)
+    (let ((stored (assoc field document)))
+      (and stored
+          (equal? (cdr stored) value)))))
 
+(define ($exists field)
+  (lambda (document)
+    (and (assoc field document)
+        #t)))
 
-;;; Tools
+(define ($not expr)
+  (lambda (document)
+    (not (expr document))))
 
-(define (vhash->alist vhash)
-  (vhash-fold-right
-   (lambda (key value result) (assoc-set! result key value))
-   '()
-   vhash))
+(define-syntax $and
+  (syntax-rules ()
+    ((_ expr ...)
+     (lambda (document)
+       (and (expr document)
+           ...)))))
 
 
-;;; Testing
+;;; Updates
 
-(define (sample-test)
-  (let ((col (make-collection)))
-    (format #t "1 New collection: ~a~%" col)
-    (set! col (insert col '((a . 1) (b . 2)) '((a . 10) (b . 20)) '((a . 1) (b . "hello world"))))
-    (format #t "2 Insert 3 documents: ~a~%" col)
-    (format #t "3 Search (a . 1): ~a~%" (find col '((a . 1))))))
+(define ($set field value)
+  (lambda (document)
+    (assoc-set! document field value)))