Refine documentation
authorMarvin Killing <marvinkilling@gmail.com>
Sat, 13 Jul 2013 13:08:20 +0000 (15:08 +0200)
committerMarvin Killing <marvinkilling@gmail.com>
Sat, 13 Jul 2013 13:13:07 +0000 (15:13 +0200)
goejdb/README
goejdb/src/github.com/mkilling/ejdb/goejdb/ejcoll.go
goejdb/src/github.com/mkilling/ejdb/goejdb/ejdb.go
goejdb/src/github.com/mkilling/ejdb/goejdb/ejdb_test.go
goejdb/src/github.com/mkilling/ejdb/goejdb/ejquery.go

index 838ac9b..6c37f76 100644 (file)
@@ -15,32 +15,33 @@ import (
 )
 
 func main() {
+    // Create a new database file and open it
     jb, err := goejdb.Open("addressbook", JBOWRITER | JBOCREAT | JBOTRUNC)
     if err != nil {
         os.Exit(1)
     }
-    //Get or create collection 'contacts'
+    // Get or create collection 'contacts'
     coll, _ := jb.CreateColl("contacts", nil)
 
-    //Insert one record:
-    //JSON: {'name' : 'Bruce', 'phone' : '333-222-333', 'age' : 58}
+    // Insert one record:
+    // JSON: {'name' : 'Bruce', 'phone' : '333-222-333', 'age' : 58}
     rec := map[string]interface{} {"name" : "Bruce", "phone" : "333-222-333", "age" : 58}
     bsrec, _ := bson.Marshal(rec)
     coll.SaveBson(bsrec)
     fmt.Printf("\nSaved Bruce")
 
-    //Now execute query
-    res, _ := coll.Find(`{"name" : {"$begin" : "Bru"}}`) //Name starts with 'Bru' string
+    // Now execute query
+    res, _ := coll.Find(`{"name" : {"$begin" : "Bru"}}`) // Name starts with 'Bru' string
     fmt.Printf("\n\nRecords found: %d\n", len(res))
 
-    //Now print the result set records
+    // Now print the result set records
     for _, bs := range res {
         var m map[string]interface{}
         bson.Unmarshal(bs, &m)
         fmt.Println(m)
     }
 
-    //Close database
+    // Close database
     jb.Close()
 }
 ~~~~~~
index af0a0bd..85ecdba 100644 (file)
@@ -6,26 +6,41 @@ import "C"
 
 import "unsafe"
 
+// Index modes, index types.
 const (
+       // Drop index.
        JBIDXDROP    = C.JBIDXDROP
+       // Drop index for all types.
        JBIDXDROPALL = C.JBIDXDROPALL
+       // Optimize indexes.
        JBIDXOP      = C.JBIDXOP
+       // Rebuild index.
        JBIDXREBLD   = C.JBIDXREBLD
+       // Number index.
        JBIDXNUM     = C.JBIDXNUM
+       // String index.*/
        JBIDXSTR     = C.JBIDXSTR
+       // Array token index.
        JBIDXARR     = C.JBIDXARR
+       // Case insensitive string index
        JBIDXISTR    = C.JBIDXISTR
 )
 
+// An EJDB collection
 type EjColl struct {
        ptr  *[0]byte
        ejdb *Ejdb
 }
 
+// EJDB collection tuning options
 type EjCollOpts struct {
+       // Large collection. It can be larger than 2GB. Default false
        large         bool
+       // Collection records will be compressed with DEFLATE compression. Default: false
        compressed    bool
+       // Expected records number in the collection. Default: 128K
        records       int
+       // Maximum number of cached records. Default: 0
        cachedrecords int
 }
 
@@ -65,7 +80,8 @@ func (coll *EjColl) LoadBson(oid string) []byte {
        return bson_to_byte_slice(bson)
 }
 
-// EJDB_EXPORT EJQRESULT ejdbqryexecute(EJCOLL *jcoll, const EJQ *q, uint32_t *count, int qflags, TCXSTR *log);
+// Execute a query specified by JSON strings query, queries and return the results as a slice of BSON objects
+// See the documentation of EjQuery  for a description of the query format.
 func (coll *EjColl) Find(query string, queries ...string) ([][]byte, *EjdbError) {
        q, err := coll.ejdb.CreateQuery(query, queries...)
        defer q.Del()
@@ -76,6 +92,8 @@ func (coll *EjColl) Find(query string, queries ...string) ([][]byte, *EjdbError)
        }
 }
 
+// Execute a query specified by JSON strings query, queries and return only the first result as a BSON object
+// See the documentation of EjQuery  for a description of the query format.
 func (coll *EjColl) FindOne(query string, queries ...string) (*[]byte, *EjdbError) {
        q, err := coll.ejdb.CreateQuery(query, queries...)
        defer q.Del()
@@ -86,6 +104,8 @@ func (coll *EjColl) FindOne(query string, queries ...string) (*[]byte, *EjdbErro
        }
 }
 
+// Execute a query specified by JSON strings query, queries and return the number of results, not the results themselves.
+// See the documentation of EjQuery  for a description of the query format.
 func (coll *EjColl) Count(query string, queries ...string) (int, *EjdbError) {
        q, err := coll.ejdb.CreateQuery(query, queries...)
        if err != nil {
@@ -112,7 +132,30 @@ func (coll *EjColl) Update(query string, queries ...string) (int, *EjdbError) {
        return int(count), coll.ejdb.check_error()
 }
 
-// EJDB_EXPORT bool ejdbsetindex(EJCOLL *coll, const char *ipath, int flags);
+// Set index for JSON field in EJDB collection.
+//
+//  - Available index types:
+//      - `JBIDXSTR` String index for JSON string values.
+//      - `JBIDXISTR` Case insensitive string index for JSON string values.
+//      - `JBIDXNUM` Index for JSON number values.
+//      - `JBIDXARR` Token index for JSON arrays and string values.
+//
+//  - One JSON field can have several indexes for different types.
+//
+//  - Available index operations:
+//      - `JBIDXDROP` Drop index of specified type.
+//              - Eg: flag = JBIDXDROP | JBIDXNUM (Drop number index)
+//      - `JBIDXDROPALL` Drop index for all types.
+//      - `JBIDXREBLD` Rebuild index of specified type.
+//      - `JBIDXOP` Optimize index of specified type. (Optimize the B+ tree index file)
+//
+//  Examples:
+//      - Set index for JSON path `addressbook.number` for strings and numbers:
+//          `ccoll.SetIndex("album.number", JBIDXSTR | JBIDXNUM)`
+//      - Set index for array:
+//          `ccoll.SetIndex("album.tags", JBIDXARR)`
+//      - Rebuild previous index:
+//          `ccoll.SetIndex("album.tags", JBIDXARR | JBIDXREBLD)`
 func (coll *EjColl) SetIndex(ipath string, flags int) *EjdbError {
        c_ipath := C.CString(ipath)
        defer C.free(unsafe.Pointer(c_ipath))
@@ -124,7 +167,7 @@ func (coll *EjColl) SetIndex(ipath string, flags int) *EjdbError {
        }
 }
 
-// EJDB_EXPORT bool ejdbtranbegin(EJCOLL *coll);
+// Begin transaction for EJDB collection.
 func (coll *EjColl) BeginTransaction() *EjdbError {
        res := C.ejdbtranbegin(coll.ptr)
        if res {
@@ -134,7 +177,7 @@ func (coll *EjColl) BeginTransaction() *EjdbError {
        }
 }
 
-//EJDB_EXPORT bool ejdbtrancommit(EJCOLL *coll);
+// Commit transaction for EJDB collection.
 func (coll *EjColl) CommitTransaction() *EjdbError {
        res := C.ejdbtrancommit(coll.ptr)
        if res {
@@ -144,7 +187,7 @@ func (coll *EjColl) CommitTransaction() *EjdbError {
        }
 }
 
-// EJDB_EXPORT bool ejdbtranabort(EJCOLL *coll);
+// Abort transaction for EJDB collection.
 func (coll *EjColl) AbortTransaction() *EjdbError {
        res := C.ejdbtranabort(coll.ptr)
        if res {
@@ -154,16 +197,14 @@ func (coll *EjColl) AbortTransaction() *EjdbError {
        }
 }
 
-// EJDB_EXPORT bool ejdbtranstatus(EJCOLL *jcoll, bool *txactive);
+// Get current transaction status. Return true if a transaction is active, false otherwise.
 func (coll *EjColl) IsTransactionActive() bool {
        var ret C.bool
        C.ejdbtranstatus(coll.ptr, &ret)
        return bool(ret)
 }
 
-// EJDB_EXPORT void ejdbqresultdispose(EJQRESULT qr);
-
-// EJDB_EXPORT bool ejdbsyncoll(EJCOLL *jcoll);
+// Synchronize content of a EJDB collection database with the file on device. On success return true.
 func (coll *EjColl) Sync() (bool, *EjdbError) {
        ret := C.ejdbsyncoll(coll.ptr)
        if ret {
index 74b4310..c9f5dcc 100644 (file)
@@ -10,23 +10,67 @@ import (
        "unsafe"
 )
 
+// Database open modes
 const (
+       // Open as a reader.
        JBOREADER = C.JBOREADER
+       // Open as a writer.
        JBOWRITER = C.JBOWRITER
+       // Create if db file not exists.
        JBOCREAT  = C.JBOCREAT
+       // Truncate db on open.
        JBOTRUNC  = C.JBOTRUNC
+       // Open without locking.
        JBONOLCK  = C.JBONOLCK
+       // Lock without blocking.
        JBOLCKNB  = C.JBOLCKNB
+       // Synchronize every transaction.
        JBOTSYNC  = C.JBOTSYNC
 )
 
+// Error codes
+const (
+    // Invalid collection name.
+    JBEINVALIDCOLNAME = C.JBEINVALIDCOLNAME
+    // Invalid bson object.
+    JBEINVALIDBSON = C.JBEINVALIDBSON
+    // Invalid bson object id.
+    JBEINVALIDBSONPK = C.JBEINVALIDBSONPK
+    // Invalid query control field starting with '$'.
+    JBEQINVALIDQCONTROL = C.JBEQINVALIDQCONTROL
+    // $strand, $stror, $in, $nin, $bt keys requires not empty array value.
+    JBEQINOPNOTARRAY = C.JBEQINOPNOTARRAY
+    // Inconsistent database metadata.
+    JBEMETANVALID = C.JBEMETANVALID
+    // Invalid field path value.
+    JBEFPATHINVALID = C.JBEFPATHINVALID
+    // Invalid query regexp value.
+    JBEQINVALIDQRX = C.JBEQINVALIDQRX
+    // Result set sorting error.
+    JBEQRSSORTING = C.JBEQRSSORTING
+    // Query generic error.
+    JBEQERROR = C.JBEQERROR
+    // Updating failed.
+    JBEQUPDFAILED = C.JBEQUPDFAILED
+    // Only one $elemMatch allowed in the fieldpath.
+    JBEQONEEMATCH = C.JBEQONEEMATCH
+    // $fields hint cannot mix include and exclude fields
+    JBEQINCEXCL = C.JBEQINCEXCL
+    // action key in $do block can only be one of: $join
+    JBEQACTKEY = C.JBEQACTKEY
+    // Exceeded the maximum number of collections per database
+    JBEMAXNUMCOLS = C.JBEMAXNUMCOLS
+)
+
 const maxslice = 1<<31 - 1
 
+// An EJDB database
 type Ejdb struct {
        ptr *[0]byte
 }
 
 type EjdbError struct {
+       // Error code returned by EJDB
        ErrorCode int
        error
 }
@@ -41,11 +85,13 @@ func new_ejdb() *Ejdb {
        }
 }
 
+// Returns EJDB library version string. Eg: "1.1.13"
 func Version() string {
        cs := C.ejdbversion()
        return C.GoString(cs)
 }
 
+// Return true if passed `oid` string cat be converted to valid 12 bit BSON object identifier (OID).
 func IsValidOidStr(oid string) bool {
        c_oid := C.CString(oid)
        res := C.ejdbisvalidoidstr(c_oid)
@@ -54,6 +100,9 @@ func IsValidOidStr(oid string) bool {
        return bool(res)
 }
 
+// Returns a new open EJDB database.
+// path is the path to the database file.
+// options specify the open mode bitmask flags.
 func Open(path string, options int) (*Ejdb, *EjdbError) {
        ejdb := new_ejdb()
        if ejdb != nil {
@@ -75,20 +124,27 @@ func (ejdb *Ejdb) check_error() *EjdbError {
        return &EjdbError{int(ecode), errors.New(fmt.Sprintf("EJDB error: %v", msg))}
 }
 
+// Return true if database is in open state, false otherwise
 func (ejdb *Ejdb) IsOpen() bool {
        ret := C.ejdbisopen(ejdb.ptr)
        return bool(ret)
 }
 
+// Delete database object. If the database is not closed, it is closed implicitly.
+// Note that the deleted object and its derivatives can not be used anymore
 func (ejdb *Ejdb) Del() {
        C.ejdbdel(ejdb.ptr)
 }
 
+// Close a table database object. If a writer opens a database but does not close it appropriately, the database will be broken.
+// If successful return true, otherwise return false.
 func (ejdb *Ejdb) Close() *EjdbError {
        C.ejdbclose(ejdb.ptr)
        return ejdb.check_error()
 }
 
+// Retrieve collection handle for collection specified `collname`.
+// If collection with specified name does't exists it will return nil.
 func (ejdb *Ejdb) GetColl(colname string) (*EjColl, *EjdbError) {
        c_colname := C.CString(colname)
        defer C.free(unsafe.Pointer(c_colname))
@@ -100,6 +156,7 @@ func (ejdb *Ejdb) GetColl(colname string) (*EjColl, *EjdbError) {
        return ejcoll, ejdb.check_error()
 }
 
+// Return a slice containing shallow copies of all collection handles (EjColl) currently open.
 func (ejdb *Ejdb) GetColls() ([]*EjColl, *EjdbError) {
        ret := make([]*EjColl, 0)
        lst := C.ejdbgetcolls(ejdb.ptr)
@@ -116,6 +173,7 @@ func (ejdb *Ejdb) GetColls() ([]*EjColl, *EjdbError) {
        return ret, nil
 }
 
+// Same as GetColl() but automatically creates new collection if it doesn't exists.
 func (ejdb *Ejdb) CreateColl(colname string, opts *EjCollOpts) (*EjColl, *EjdbError) {
        c_colname := C.CString(colname)
        defer C.free(unsafe.Pointer(c_colname))
@@ -141,6 +199,9 @@ func (ejdb *Ejdb) CreateColl(colname string, opts *EjCollOpts) (*EjColl, *EjdbEr
        }
 }
 
+// Removes collections specified by `colname`.
+// If `unlinkfile` is true the collection db file and all of its index files will be removed.
+// If removal was successful return true, otherwise return false.
 func (ejdb *Ejdb) RmColl(colname string, unlinkfile bool) (bool, *EjdbError) {
        c_colname := C.CString(colname)
        defer C.free(unsafe.Pointer(c_colname))
@@ -152,7 +213,7 @@ func (ejdb *Ejdb) RmColl(colname string, unlinkfile bool) (bool, *EjdbError) {
        }
 }
 
-// EJDB_EXPORT bool ejdbsyncdb(EJDB *jb);
+// Synchronize entire EJDB database and all of its collections with storage.
 func (ejdb *Ejdb) Sync() (bool, *EjdbError) {
        ret := C.ejdbsyncdb(ejdb.ptr)
        if ret {
@@ -162,7 +223,7 @@ func (ejdb *Ejdb) Sync() (bool, *EjdbError) {
        }
 }
 
-// EJDB_EXPORT bson* ejdbmeta(EJDB *jb);
+// Gets description of EJDB database and its collections as a BSON object.
 func (ejdb *Ejdb) Meta() ([]byte, *EjdbError) {
        bson := C.ejdbmeta(ejdb.ptr)
        err := ejdb.check_error()
index f0544be..f3253a4 100644 (file)
@@ -366,32 +366,34 @@ func TestTransactions(t *testing.T) {
 }
 
 func TestOneSnippetIntroFromReadme(t *testing.T) {
-    jb, err := Open("addressbook", JBOWRITER | JBOCREAT | JBOTRUNC)
+       // Create a new database file and open it
+    jb, err := Open("/tmp/addressbook", JBOWRITER | JBOCREAT | JBOTRUNC)
     if err != nil {
         os.Exit(1)
     }
-    //Get or create collection 'contacts'
+
+    // Get or create collection 'contacts'
     coll, _ := jb.CreateColl("contacts", nil)
 
-    //Insert one record:
-    //JSON: {'name' : 'Bruce', 'phone' : '333-222-333', 'age' : 58}
+    // Insert one record:
+    // JSON: {'name' : 'Bruce', 'phone' : '333-222-333', 'age' : 58}
     rec := map[string]interface{} {"name" : "Bruce", "phone" : "333-222-333", "age" : 58}
     bsrec, _ := bson.Marshal(rec)
     coll.SaveBson(bsrec)
     fmt.Printf("\nSaved Bruce")
 
-    //Now execute query
-    res, _ := coll.Find(`{"name" : {"$begin" : "Bru"}}`) //Name starts with 'Bru' string
+    // Now execute query
+    res, _ := coll.Find(`{"name" : {"$begin" : "Bru"}}`) // Name starts with 'Bru' string
     fmt.Printf("\n\nRecords found: %d\n", len(res))
 
-    //Now print the result set records
+    // Now print the result set records
     for _, bs := range res {
         var m map[string]interface{}
         bson.Unmarshal(bs, &m)
         fmt.Println(m)
     }
 
-    //Close database
+    // Close database
     jb.Close()
 }
 
index a5f85ce..adce729 100644 (file)
@@ -6,17 +6,87 @@ import "C"
 
 import "unsafe"
 
+// Query search mode flags in ejdbqryexecute()
 const (
-       JBQRYCOUNT   = C.JBQRYCOUNT
-       JBQRYFINDONE = C.JBQRYFINDONE
+       // Query only count(*)
+       jbqrycount   = C.JBQRYCOUNT
+       // Fetch first record only
+       jbqryfindone = C.JBQRYFINDONE
 )
 
+// An EJDB query
 type EjQuery struct {
        ptr  *[0]byte
        ejdb *Ejdb
 }
 
-// EJDB_EXPORT EJQ* ejdbcreatequery(EJDB *jb, bson *qobj, bson *orqobjs, int orqobjsnum, bson *hints);
+// Create query object.
+// Sucessfully created queries must be destroyed with Query.Del().
+//
+// EJDB queries inspired by MongoDB (mongodb.org) and follows same philosophy.
+//
+//  - Supported queries:
+//      - Simple matching of String OR Number OR Array value:
+//          -   {'fpath' : 'val', ...}
+//      - $not Negate operation.
+//          -   {'fpath' : {'$not' : val}} //Field not equal to val
+//          -   {'fpath' : {'$not' : {'$begin' : prefix}}} //Field not begins with val
+//      - $begin String starts with prefix
+//          -   {'fpath' : {'$begin' : prefix}}
+//      - $gt, $gte (>, >=) and $lt, $lte for number types:
+//          -   {'fpath' : {'$gt' : number}, ...}
+//      - $bt Between for number types:
+//          -   {'fpath' : {'$bt' : [num1, num2]}}
+//      - $in String OR Number OR Array val matches to value in specified array:
+//          -   {'fpath' : {'$in' : [val1, val2, val3]}}
+//      - $nin - Not IN
+//      - $strand String tokens OR String array val matches all tokens in specified array:
+//          -   {'fpath' : {'$strand' : [val1, val2, val3]}}
+//      - $stror String tokens OR String array val matches any token in specified array:
+//          -   {'fpath' : {'$stror' : [val1, val2, val3]}}
+//      - $exists Field existence matching:
+//          -   {'fpath' : {'$exists' : true|false}}
+//      - $icase Case insensitive string matching:
+//          -    {'fpath' : {'$icase' : 'val1'}} //icase matching
+//          Ignore case matching with '$in' operation:
+//          -    {'name' : {'$icase' : {'$in' : ['théâtre - театр', 'hello world']}}}
+//          For case insensitive matching you can create special index of type: `JBIDXISTR`
+//      - $elemMatch The $elemMatch operator matches more than one component within an array element.
+//          -    { array: { $elemMatch: { value1 : 1, value2 : { $gt: 1 } } } }
+//          Restriction: only one $elemMatch allowed in context of one array field.
+//
+//  - Queries can be used to update records:
+//
+//      $set Field set operation.
+//          - {.., '$set' : {'field1' : val1, 'fieldN' : valN}}
+//      $upsert Atomic upsert. If matching records are found it will be '$set' operation,
+//              otherwise new record will be inserted
+//              with fields specified by argment object.
+//          - {.., '$upsert' : {'field1' : val1, 'fieldN' : valN}}
+//      $inc Increment operation. Only number types are supported.
+//          - {.., '$inc' : {'field1' : number, ...,  'field1' : number}
+//      $dropall In-place record removal operation.
+//          - {.., '$dropall' : true}
+//      $addToSet Atomically adds value to the array only if its not in the array already.
+//                If containing array is missing it will be created.
+//          - {.., '$addToSet' : {'fpath' : val1, 'fpathN' : valN, ...}}
+//      $addToSetAll Batch version if $addToSet
+//          - {.., '$addToSetAll' : {'fpath' : [array of values to add], ...}}
+//      $pull  Atomically removes all occurrences of value from field, if field is an array.
+//          - {.., '$pull' : {'fpath' : val1, 'fpathN' : valN, ...}}
+//      $pullAll Batch version of $pull
+//          - {.., '$pullAll' : {'fpath' : [array of values to remove], ...}}
+//
+// - Collection joins supported in the following form:
+//
+//      {..., $do : {fpath : {$join : 'collectionname'}} }
+//      Where 'fpath' value points to object's OIDs from 'collectionname'. Its value
+//      can be OID, string representation of OID or array of this pointers.
+//
+//  NOTE: Negate operations: $not and $nin not using indexes
+//  so they can be slow in comparison to other matching operations.
+//
+//  NOTE: Only one index can be used in search query operation.
 func (ejdb *Ejdb) CreateQuery(query string, queries ...string) (*EjQuery, *EjdbError) {
        query_bson := bson_from_json(query)
        defer C.bson_destroy(query_bson)
@@ -38,7 +108,23 @@ func (ejdb *Ejdb) CreateQuery(query string, queries ...string) (*EjQuery, *EjdbE
        }
 }
 
-// EJDB_EXPORT EJQ* ejdbqueryhints(EJDB *jb, EJQ *q, const void *hintsbsdata);
+//  Set query hints. `hints` is a JSON string
+//      - $max Maximum number in the result set
+//      - $skip Number of skipped results in the result set
+//      - $orderby Sorting order of query fields.
+//      - $fields Set subset of fetched fields
+//          If a field presented in $orderby clause it will be forced to include in resulting records.
+//          Example:
+//          hints:    {
+//                      "$orderby" : { //ORDER BY field1 ASC, field2 DESC
+//                          "field1" : 1,
+//                          "field2" : -1
+//                      },
+//                      "$fields" : { //SELECT ONLY {_id, field1, field2}
+//                          "field1" : 1,
+//                          "field2" : 1
+//                      }
+//                    }
 func (q *EjQuery) SetHints(hints string) *EjdbError {
        bsdata := bson_from_json(hints).data
        ret := C.ejdbqueryhints(q.ejdb.ptr, q.ptr, unsafe.Pointer(bsdata))
@@ -49,6 +135,7 @@ func (q *EjQuery) SetHints(hints string) *EjdbError {
        }
 }
 
+// Execute the query and return all results as a slice of BSON objects
 func (q *EjQuery) Execute(coll *EjColl) ([][]byte, *EjdbError) {
        // execute query
        var count C.uint32_t
@@ -67,10 +154,11 @@ func (q *EjQuery) Execute(coll *EjColl) ([][]byte, *EjdbError) {
        return ret, err
 }
 
+// Execute the query and return only the first result as a BSON object
 func (q *EjQuery) ExecuteOne(coll *EjColl) (*[]byte, *EjdbError) {
        // execute query
        var count C.uint32_t
-       res := C.ejdbqryexecute(coll.ptr, q.ptr, &count, JBQRYFINDONE, nil)
+       res := C.ejdbqryexecute(coll.ptr, q.ptr, &count, jbqryfindone, nil)
        defer C.ejdbqresultdispose(res)
        err := coll.ejdb.check_error()
 
@@ -85,14 +173,15 @@ func (q *EjQuery) ExecuteOne(coll *EjColl) (*[]byte, *EjdbError) {
        }
 }
 
+// Execute the query and only return the number of results it returned, not the results themselves
 func (q *EjQuery) Count(coll *EjColl) (int, *EjdbError) {
        var count C.uint32_t
-       C.ejdbqryexecute(coll.ptr, q.ptr, &count, JBQRYCOUNT, nil)
+       C.ejdbqryexecute(coll.ptr, q.ptr, &count, jbqrycount, nil)
        err := coll.ejdb.check_error()
        return int(count), err
 }
 
-// EJDB_EXPORT void ejdbquerydel(EJQ *q);
+// Delete the query. This must be called in order to not leak memory.
 func (q *EjQuery) Del() {
        C.ejdbquerydel(q.ptr)
 }