#24
authoradam <adamansky@gmail.com>
Thu, 20 Jun 2013 10:37:57 +0000 (17:37 +0700)
committeradam <adamansky@gmail.com>
Thu, 20 Jun 2013 10:37:57 +0000 (17:37 +0700)
nejdb/Ejdb.DB/EJDB.cs
nejdb/Ejdb.DB/EJDBQuery.cs
nejdb/Ejdb.JSON/JSONElement.cs [deleted file]
nejdb/Ejdb.JSON/JSONReader.cs [deleted file]
nejdb/Ejdb.Tests/TestEJDB.cs
nejdb/nejdb.csproj
nejdb/nejdb.userprefs
node/ejdb_native.cc
tcejdb/ejdb.c
tcejdb/ejdb.h

index 94cbf50..5bacc00 100644 (file)
@@ -36,28 +36,107 @@ namespace Ejdb.DB {
                public int cachedrecords;
        }
 
+       /// <summary>
+       /// EJDB database native wrapper.
+       /// </summary>
        public class EJDB : IDisposable {
-               //Open modes
+               //.//////////////////////////////////////////////////////////////////
+               //                                              Native open modes                                                                         
+               //.//////////////////////////////////////////////////////////////////
+               /// <summary>
+               /// Open as a reader.
+               /// </summary>
                public const int JBOREADER = 1 << 0;
 
+               /// <summary>
+               /// Open as a writer.
+               /// </summary>
                public const int JBOWRITER = 1 << 1;
 
+               /// <summary>
+               /// Create if db file not exists. 
+               /// </summary>
                public const int JBOCREAT = 1 << 2;
 
+               /// <summary>
+               /// Truncate db on open.
+               /// </summary>
                public const int JBOTRUNC = 1 << 3;
 
+               /// <summary>
+               /// Open without locking. 
+               /// </summary>
                public const int JBONOLCK = 1 << 4;
 
+               /// <summary>
+               /// Lock without blocking.
+               /// </summary>
                public const int JBOLCKNB = 1 << 5;
 
+               /// <summary>
+               /// Synchronize every transaction with storage.
+               /// </summary>
                public const int JBOTSYNC = 1 << 6;
 
+               /// <summary>
+               /// The default open mode <c>(JBOWRITER | JBOCREAT)</c>
+               /// </summary>
                public const int DEFAULT_OPEN_MODE = (JBOWRITER | JBOCREAT);
+               //.//////////////////////////////////////////////////////////////////
+               //                               Native index operations & types (ejdb.h)                                                                         
+               //.//////////////////////////////////////////////////////////////////
+               /// <summary>
+               /// Drop index.
+               /// </summary>
+               const int JBIDXDROP = 1 << 0;
+
+               /// <summary>
+               /// Drop index for all types.
+               /// </summary>
+               const int JBIDXDROPALL = 1 << 1;
+
+               /// <summary>
+               /// Optimize indexes.
+               /// </summary>
+               const int JBIDXOP = 1 << 2;
+
+               /// <summary>
+               /// Rebuild index.
+               /// </summary>
+               const int JBIDXREBLD = 1 << 3;
 
+               /// <summary>
+               /// Number index.
+               /// </summary>
+               const int JBIDXNUM = 1 << 4;
+
+               /// <summary>
+               /// String index.
+               /// </summary>
+               const int JBIDXSTR = 1 << 5;
+
+               /// <summary>
+               /// Array token index.
+               /// </summary>
+               const int JBIDXARR = 1 << 6;
+
+               /// <summary>
+               /// Case insensitive string index.
+               /// </summary>
+               const int JBIDXISTR = 1 << 7;
+
+               /// <summary>
+               /// Name if EJDB library
+               /// </summary>
                public const string EJDB_LIB_NAME = "tcejdb";
 
+               /// <summary>
+               /// Pointer to the native EJDB instance.
+               /// </summary>
                IntPtr _db = IntPtr.Zero;
-               //
+               //.//////////////////////////////////////////////////////////////////
+               //                              Native functions refs                                                                     
+               //.//////////////////////////////////////////////////////////////////
                #region NativeRefs
                [DllImport(EJDB_LIB_NAME, EntryPoint="ejdbnew")]
                internal static extern IntPtr _ejdbnew();
@@ -112,6 +191,18 @@ namespace Ejdb.DB {
                                UnixMarshal.FreeHeap(cptr);
                        }
                }
+               //EJDB_EXPORT bool ejdbrmcoll(EJDB *jb, const char *colname, bool unlinkfile);
+               [DllImport(EJDB_LIB_NAME, EntryPoint="ejdbrmcoll")]
+               internal static extern bool _ejdbrmcoll([In] IntPtr db, [In] IntPtr cname, bool unlink);
+
+               internal static bool _ejdbrmcoll(IntPtr db, string cname, bool unlink) {
+                       IntPtr cptr = UnixMarshal.StringToHeap(cname, Encoding.UTF8);
+                       try {
+                               return _ejdbrmcoll(db, cptr, unlink);
+                       } finally {
+                               UnixMarshal.FreeHeap(cptr);
+                       }
+               }
                //EJDB_EXPORT bool ejdbsavebson3(EJCOLL *jcoll, void *bsdata, bson_oid_t *oid, bool merge);
                [DllImport(EJDB_LIB_NAME, EntryPoint="ejdbsavebson3")]
                internal static extern bool _ejdbsavebson([In] IntPtr coll, [In] byte[] bsdata, [Out] byte[] oid, [In] bool merge);
@@ -124,6 +215,30 @@ namespace Ejdb.DB {
                //EJDB_EXPORT void bson_del(bson *b);
                [DllImport(EJDB_LIB_NAME, EntryPoint="bson_del")]
                internal static extern void _bson_del([In] IntPtr bsptr);
+               //EJDB_EXPORT bool ejdbrmbson(EJCOLL *coll, bson_oid_t *oid);
+               [DllImport(EJDB_LIB_NAME, EntryPoint="ejdbrmbson")]
+               internal static extern bool _ejdbrmbson([In] IntPtr cptr, [In] byte[] oid);
+               //EJDB_EXPORT bool ejdbsyncdb(EJDB *jb)
+               [DllImport(EJDB_LIB_NAME, EntryPoint="ejdbsyncdb")]
+               internal static extern bool _ejdbsyncdb([In] IntPtr db);
+               //EJDB_EXPORT bool ejdbsyncoll(EJDB *jb)
+               [DllImport(EJDB_LIB_NAME, EntryPoint="ejdbsyncoll")]
+               internal static extern bool _ejdbsyncoll([In] IntPtr coll);
+               //EJDB_EXPORT bool ejdbsetindex(EJCOLL *coll, const char *ipath, int flags);
+               [DllImport(EJDB_LIB_NAME, EntryPoint="ejdbsetindex")]
+               internal static extern bool _ejdbsetindex([In] IntPtr coll, [In] IntPtr ipathptr, int flags);
+               //EJDB_EXPORT bson* ejdbmeta(EJDB *jb)
+               [DllImport(EJDB_LIB_NAME, EntryPoint="ejdbmeta")]
+               internal static extern IntPtr _ejdbmeta([In] IntPtr db);
+
+               internal static bool _ejdbsetindex(IntPtr coll, string ipath, int flags) {
+                       IntPtr ipathptr = UnixMarshal.StringToHeap(ipath, Encoding.UTF8);
+                       try {
+                               return _ejdbsetindex(coll, ipathptr, flags);
+                       } finally {
+                               UnixMarshal.FreeHeap(ipathptr);
+                       }
+               }
                #endregion
                /// <summary>
                /// Gets the last DB error code or <c>null</c> if underlying native database object does not exist.
@@ -159,6 +274,22 @@ namespace Ejdb.DB {
                }
 
                /// <summary>
+               /// Gets description of EJDB database and its collections.
+               /// </summary>
+               /// <value>The DB meta.</value>
+               public BSONDocument DBMeta {
+                       get {
+                               CheckDisposed(true);
+                               //internal static extern IntPtr ejdbmeta([In] IntPtr db);
+                               //IntPtr bsptr = 
+
+
+                               BSONDocument meta = new BSONDocument();
+                               return meta;
+                       }
+               }
+
+               /// <summary>
                /// Initializes a new instance of the <see cref="Ejdb.DB.EJDB"/> class.
                /// </summary>
                /// <param name="path">The main database file path.</param>
@@ -211,6 +342,186 @@ namespace Ejdb.DB {
                }
 
                /// <summary>
+               /// Removes collection indetified by <c>cname</c>.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of the collection.</param>
+               /// <param name="unlink">If set to <c>true</c> then the collection data file will be removed.</param>
+               public bool DropCollection(string cname, bool unlink = false) {
+                       CheckDisposed();
+                       return _ejdbrmcoll(_db, cname, unlink);
+               }
+
+               /// <summary>
+               /// Synchronize entire EJDB database and
+               /// all of its collections with storage.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               public bool Sync() {
+                       CheckDisposed();
+                       //internal static extern bool _ejdbsyncdb([In] IntPtr db);
+                       return _ejdbsyncdb(_db);
+               }
+
+               /// <summary>
+               /// Synchronize content of a EJDB collection database with the file on device.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of collection.</param>
+               public bool SyncCollection(string cname) {
+                       CheckDisposed();
+                       IntPtr cptr = _ejdbgetcoll(_db, cname);
+                       if (cptr == IntPtr.Zero) {
+                               return true;
+                       }
+                       //internal static extern bool _ejdbsyncoll([In] IntPtr coll);
+                       return _ejdbsyncoll(cptr);
+               }
+
+               /// <summary>
+               /// DROP indexes of all types for JSON field path.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of collection.</param>
+               /// <param name="ipath">JSON indexed field path</param>
+               public bool DropIndexes(string cname, string ipath) {
+                       return IndexOperation(cname, ipath, JBIDXDROPALL);
+               }
+
+               /// <summary>
+               /// OPTIMIZE indexes of all types for JSON field path.
+               /// </summary>
+               /// <remarks>
+               /// Performs B+ tree index file optimization.
+               /// </remarks>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of collection.</param>
+               /// <param name="ipath">JSON indexed field path</param>
+               public bool OptimizeIndexes(string cname, string ipath) {
+                       return IndexOperation(cname, ipath, JBIDXOP);
+               }
+
+               /// <summary>
+               /// Ensure index presence of String type for JSON field path.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of collection.</param>
+               /// <param name="ipath">JSON indexed field path</param>
+               public bool EnsureStringIndex(string cname, string ipath) {
+                       return IndexOperation(cname, ipath, JBIDXSTR);
+               }
+
+               /// <summary>
+               /// Rebuild index of String type for JSON field path.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of collection.</param>
+               /// <param name="ipath">JSON indexed field path</param>
+               public bool RebuildStringIndex(string cname, string ipath) {
+                       return IndexOperation(cname, ipath, JBIDXSTR | JBIDXREBLD);
+               }
+
+               /// <summary>
+               /// Drop index of String type for JSON field path.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of collection.</param>
+               /// <param name="ipath">JSON indexed field path</param>
+               public bool DropStringIndex(string cname, string ipath) {
+                       return IndexOperation(cname, ipath, JBIDXSTR | JBIDXDROP);
+               }
+
+               /// <summary>
+               /// Ensure case insensitive String index for JSON field path.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of collection.</param>
+               /// <param name="ipath">JSON indexed field path</param>
+               public bool EnsureIStringIndex(string cname, string ipath) {
+                       return IndexOperation(cname, ipath, JBIDXISTR);
+               }
+
+               /// <summary>
+               /// Rebuild case insensitive String index for JSON field path.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of collection.</param>
+               /// <param name="ipath">JSON indexed field path</param>
+               public bool RebuildIStringIndex(string cname, string ipath) {
+                       return IndexOperation(cname, ipath, JBIDXISTR | JBIDXREBLD);
+               }
+
+               /// <summary>
+               /// Drop case insensitive String index for JSON field path.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of collection.</param>
+               /// <param name="ipath">JSON indexed field path</param>
+               public bool DropIStringIndex(string cname, string ipath) {
+                       return IndexOperation(cname, ipath, JBIDXISTR | JBIDXDROP);
+               }
+
+               /// <summary>
+               /// Ensure index presence of Number type for JSON field path.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of collection.</param>
+               /// <param name="ipath">JSON indexed field path</param>
+               public bool EnsureNumberIndex(string cname, string ipath) {
+                       return IndexOperation(cname, ipath, JBIDXNUM);
+               }
+
+               /// <summary>
+               /// Rebuild index of Number type for JSON field path.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of collection.</param>
+               /// <param name="ipath">JSON indexed field path</param>
+               public bool RebuildNumberIndex(string cname, string ipath) {
+                       return IndexOperation(cname, ipath, JBIDXNUM | JBIDXREBLD);
+               }
+
+               /// <summary>
+               /// Drop index of Number type for JSON field path.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of collection.</param>
+               /// <param name="ipath">JSON indexed field path</param>
+               public bool DropNumberIndex(string cname, string ipath) {
+                       return IndexOperation(cname, ipath, JBIDXNUM | JBIDXDROP);
+               }
+
+               /// <summary>
+               /// Ensure index presence of Array type for JSON field path.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of collection.</param>
+               /// <param name="ipath">JSON indexed field path</param>
+               public bool EnsureArrayIndex(string cname, string ipath) {
+                       return IndexOperation(cname, ipath, JBIDXARR);
+               }
+
+               /// <summary>
+               /// Rebuild index of Array type for JSON field path.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of collection.</param>
+               /// <param name="ipath">JSON indexed field path</param>
+               public bool RebuildArrayIndex(string cname, string ipath) {
+                       return IndexOperation(cname, ipath, JBIDXARR | JBIDXREBLD);
+               }
+
+               /// <summary>
+               /// Drop index of Array type for JSON field path.
+               /// </summary>
+               /// <returns><c>false</c>, if error occurred.</returns>
+               /// <param name="cname">Name of collection.</param>
+               /// <param name="ipath">JSON indexed field path</param>
+               public bool DropArrayIndex(string cname, string ipath) {
+                       return IndexOperation(cname, ipath, JBIDXARR | JBIDXDROP);
+               }
+
+               /// <summary>
                /// Save the BSON document doc into the collection.
                /// </summary>
                /// <param name="cname">Name of collection.</param>
@@ -287,6 +598,26 @@ namespace Ejdb.DB {
                }
 
                /// <summary>
+               /// Removes stored objects from the collection.
+               /// </summary>
+               /// <param name="cname">Name of collection.</param>
+               /// <param name="oids">Object identifiers.</param>
+               public bool Remove(string cname, params BSONOid[] oids) {
+                       CheckDisposed();
+                       IntPtr cptr = _ejdbgetcoll(_db, cname);
+                       if (cptr == IntPtr.Zero) {
+                               return true;
+                       }
+                       //internal static extern bool _ejdbrmbson([In] IntPtr cptr, [In] byte[] oid);
+                       foreach (var oid in oids) {
+                               if (!_ejdbrmbson(cptr, oid.ToBytes())) {
+                                       return false;
+                               }
+                       }
+                       return true;
+               }
+
+               /// <summary>
                /// Creates the query.
                /// </summary>
                /// <returns>The query object.</returns>
@@ -325,10 +656,25 @@ namespace Ejdb.DB {
                        return bsdata;
                }
 
-               internal void CheckDisposed() {
+               bool IndexOperation(string cname, string ipath, int flags) {
+                       CheckDisposed(true);
+                       IntPtr cptr = _ejdbgetcoll(_db, cname);
+                       if (cptr == IntPtr.Zero) {
+                               return true;
+                       }
+                       //internal static bool _ejdbsetindex(IntPtr coll, string ipath, int flags)
+                       return _ejdbsetindex(cptr, ipath, flags);
+               }
+
+               internal void CheckDisposed(bool checkopen = false) {
                        if (_db == IntPtr.Zero) {
                                throw new ObjectDisposedException("Database is disposed");
                        }
+                       if (checkopen) {
+                               if (!IsOpen) {
+                                       throw new ObjectDisposedException("Operation on closed EJDB instance"); 
+                               }
+                       }
                }
        }
 }
index 16415bb..6a948f8 100644 (file)
@@ -124,8 +124,9 @@ namespace Ejdb.DB {
                /// </summary>
                /// <returns>This query object.</returns>
                /// <param name="doc">Query document.</param>
-               public EJDBQuery AppendOR(BSONDocument doc) {
+               public EJDBQuery AddOR(object docobj) {
                        CheckDisposed();
+                       BSONDocument doc = BSONDocument.ValueOf(docobj);
                        //static extern IntPtr _ejdbqueryaddor([In] IntPtr jb, [In] IntPtr qptr, [In] byte[] bsdata);
                        IntPtr qptr = _ejdbqueryaddor(_jb.DBPtr, _qptr, doc.ToByteArray());
                        if (qptr == IntPtr.Zero) {
diff --git a/nejdb/Ejdb.JSON/JSONElement.cs b/nejdb/Ejdb.JSON/JSONElement.cs
deleted file mode 100644 (file)
index 39cfad3..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-// ============================================================================================
-//   .NET API for EJDB database library http://ejdb.org
-//   Copyright (C) 2012-2013 Softmotions Ltd <info@softmotions.com>
-//
-//   This file is part of EJDB.
-//   EJDB is free software; you can redistribute it and/or modify it under the terms of
-//   the GNU Lesser General Public License as published by the Free Software Foundation; either
-//   version 2.1 of the License or any later version.  EJDB is distributed in the hope
-//   that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-//   License for more details.
-//   You should have received a copy of the GNU Lesser General Public License along with EJDB;
-//   if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
-//   Boston, MA 02111-1307 USA.
-// ============================================================================================
-using System;
-
-namespace Ejdb.JSON {
-
-       public class JSONElement {
-               public JSONElement() {
-               }
-       }
-}
-
diff --git a/nejdb/Ejdb.JSON/JSONReader.cs b/nejdb/Ejdb.JSON/JSONReader.cs
deleted file mode 100644 (file)
index ac8f116..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-// ============================================================================================
-//   .NET API for EJDB database library http://ejdb.org
-//   Copyright (C) 2012-2013 Softmotions Ltd <info@softmotions.com>
-//
-//   This file is part of EJDB.
-//   EJDB is free software; you can redistribute it and/or modify it under the terms of
-//   the GNU Lesser General Public License as published by the Free Software Foundation; either
-//   version 2.1 of the License or any later version.  EJDB is distributed in the hope
-//   that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
-//   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
-//   License for more details.
-//   You should have received a copy of the GNU Lesser General Public License along with EJDB;
-//   if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
-//   Boston, MA 02111-1307 USA.
-// ============================================================================================
-using System;
-using System.IO;
-using System.Collections.Generic;
-
-namespace Ejdb.JSON {
-
-       public class JSONReader : IEnumerable<JSONElement>, IDisposable {
-
-               BinaryReader _input;
-
-               public JSONReader(Stream jstream) {
-                       this._input = new BinaryReader(jstream);                                
-               }
-
-               public IEnumerator<JSONElement> GetEnumerator() {
-
-
-
-                       yield return new JSONElement();
-               }
-
-               System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() {
-                       return GetEnumerator();
-               }
-
-               public void Dispose() {
-                       if (_input != null) {
-                               _input.Close();
-                               _input = null;
-                       }
-               }
-       }
-}
-
index 0b11d37..192302a 100644 (file)
@@ -64,6 +64,17 @@ namespace Ejdb.Tests {
                        BSONDocument doc2 = it.ToBSONDocument();
                        Assert.AreEqual(doc.ToDebugDataString(), doc2.ToDebugDataString());
                        Assert.IsTrue(doc == doc2);
+
+                       Assert.AreEqual(1, jb.CreateQueryFor("mycoll").Count());
+                       Assert.IsTrue(jb.Remove("mycoll", doc["_id"] as BSONOid));
+                       Assert.AreEqual(0, jb.CreateQueryFor("mycoll").Count());
+
+                       jb.Save("mycoll", doc);
+                       Assert.AreEqual(1, jb.CreateQueryFor("mycoll").Count());
+                       Assert.IsTrue(jb.DropCollection("mycoll"));
+                       Assert.AreEqual(0, jb.CreateQueryFor("mycoll").Count());
+
+                       Assert.IsTrue(jb.Sync());
                        jb.Dispose(); 
                }
 
@@ -149,6 +160,18 @@ namespace Ejdb.Tests {
                                Assert.AreEqual("Grenny", doc["name"]);
                                Assert.AreEqual(1, doc["age"]);
                        }
+                       q.Dispose();
+
+                       q = jb.CreateQueryFor("parrots");
+                       Assert.AreEqual(2, q.Count());
+                       q.AddOR(new{
+                               name = "Grenny"
+                       });
+                       Assert.AreEqual(1, q.Count());
+                       q.AddOR(new{
+                               name = "Bounty"
+                       });
+                       Assert.AreEqual(2, q.Count());
 
                        q.Dispose();
                        jb.Dispose();
index 715da57..0b3b68b 100644 (file)
@@ -37,7 +37,6 @@
       <Private>False</Private>
     </Reference>
     <Reference Include="System.Core" />
-    <Reference Include="System.Runtime.Serialization" />
     <Reference Include="Mono.Posix" />
   </ItemGroup>
   <ItemGroup>
@@ -60,8 +59,6 @@
     <Compile Include="Ejdb.BSON\BSONBinData.cs" />
     <Compile Include="Ejdb.BSON\BSONDocument.cs" />
     <Compile Include="Ejdb.BSON\BSONConstants.cs" />
-    <Compile Include="Ejdb.JSON\JSONReader.cs" />
-    <Compile Include="Ejdb.JSON\JSONElement.cs" />
     <Compile Include="Ejdb.DB\EJDBException.cs" />
     <Compile Include="Ejdb.Tests\TestEJDB.cs" />
     <Compile Include="Ejdb.DB\EJDBQuery.cs" />
@@ -77,7 +74,6 @@
     <Folder Include="Ejdb.IO\" />
     <Folder Include="Ejdb.Utils\" />
     <Folder Include="Ejdb.BSON\" />
-    <Folder Include="Ejdb.JSON\" />
   </ItemGroup>
   <ProjectExtensions>
     <MonoDevelop>
index 9f80e0d..36c0d1a 100644 (file)
@@ -1,14 +1,16 @@
 <Properties>
   <MonoDevelop.Ide.Workspace ActiveConfiguration="Debug" />
-  <MonoDevelop.Ide.Workbench ActiveDocument="Ejdb.Tests/TestEJDB.cs">
+  <MonoDevelop.Ide.Workbench ActiveDocument="Ejdb.DB/EJDB.cs">
     <Files>
-      <File FileName="Ejdb.DB/EJDB.cs" Line="295" Column="16" />
-      <File FileName="Ejdb.DB/EJDBQuery.cs" Line="286" Column="16" />
-      <File FileName="Ejdb.DB/EJDBQCursor.cs" Line="71" Column="60" />
-      <File FileName="Ejdb.BSON/BSONDocument.cs" Line="224" Column="35" />
-      <File FileName="Ejdb.Tests/TestEJDB.cs" Line="112" Column="4" />
-      <File FileName="Ejdb.BSON/BSONRegexp.cs" Line="53" Column="3" />
-      <File FileName="Ejdb.BSON/BSONIterator.cs" Line="133" Column="20" />
+      <File FileName="Ejdb.DB/EJDB.cs" Line="278" Column="17" />
+      <File FileName="Ejdb.DB/EJDBQuery.cs" Line="124" Column="5" />
+      <File FileName="Ejdb.DB/EJDBQCursor.cs" Line="1" Column="1" />
+      <File FileName="Ejdb.BSON/BSONDocument.cs" Line="1" Column="1" />
+      <File FileName="Ejdb.Tests/TestEJDB.cs" Line="77" Column="29" />
+      <File FileName="Ejdb.BSON/BSONRegexp.cs" Line="1" Column="1" />
+      <File FileName="Ejdb.BSON/BSONIterator.cs" Line="1" Column="1" />
+      <File FileName="Ejdb.JSON/JSONElement.cs" Line="15" Column="96" />
+      <File FileName="Ejdb.BSON/BSONType.cs" Line="20" Column="29" />
     </Files>
     <Pads>
       <Pad Id="ProjectPad">
             <Node name="Ejdb.BSON" expanded="True" />
             <Node name="Ejdb.DB" expanded="True" />
             <Node name="Ejdb.IO" expanded="True" />
-            <Node name="Ejdb.JSON" expanded="True" />
-            <Node name="Ejdb.Tests" expanded="True">
-              <Node name="TestEJDB.cs" selected="True" />
-            </Node>
+            <Node name="Ejdb.Tests" expanded="True" />
             <Node name="Ejdb.Utils" expanded="True" />
           </Node>
         </State>
         <State selected="True" />
       </Pad>
       <Pad Id="MonoDevelop.NUnit.TestPad">
-        <State expanded="True" selected="True">
+        <State expanded="True">
           <Node name="nejdb" expanded="True">
             <Node name="Ejdb" expanded="True">
               <Node name="Tests" expanded="True">
-                <Node name="TestEJDB" expanded="True" />
+                <Node name="TestBSON" expanded="True" />
+                <Node name="TestEJDB" expanded="True" selected="True" />
               </Node>
             </Node>
           </Node>
index 58297ba..fd9b58a 100644 (file)
@@ -837,65 +837,17 @@ namespace ejdb {
         static Handle<Value> s_db_meta(const Arguments& args) {
             HandleScope scope;
             NodeEJDB *njb = ObjectWrap::Unwrap< NodeEJDB > (args.This());
-            Local<Object> ret = Object::New();
             if (!ejdbisopen(njb->m_jb)) {
                 return scope.Close(ThrowException(Exception::Error(String::New("Operation on closed EJDB instance"))));
             }
-            TCLIST *cols = ejdbgetcolls(njb->m_jb);
-            if (!cols) {
+            bson *meta = ejdbmeta(njb->m_jb);
+            if (!meta) {
                 return scope.Close(ThrowException(Exception::Error(String::New(njb->_jb_error_msg()))));
             }
-            Local<Array> cinfo = Array::New();
-            for (int i = 0; i < TCLISTNUM(cols); ++i) {
-                EJCOLL *coll = (EJCOLL*) TCLISTVALPTR(cols, i);
-                assert(coll);
-                if (!ejcollockmethod(coll, false)) continue;
-                Local<Object> cm = Object::New();
-                cm->Set(sym_name, String::New(coll->cname, coll->cnamesz));
-                cm->Set(sym_file, String::New(coll->tdb->hdb->path));
-                cm->Set(sym_records, Integer::NewFromUnsigned((uint32_t) coll->tdb->hdb->rnum));
-                Local<Object> opts = Object::New();
-                opts->Set(sym_buckets, Integer::NewFromUnsigned((uint32_t) coll->tdb->hdb->bnum));
-                opts->Set(sym_cachedrecords, Integer::NewFromUnsigned(coll->tdb->hdb->rcnum));
-                opts->Set(sym_large, Boolean::New(coll->tdb->opts & TDBTLARGE));
-                opts->Set(sym_compressed, Boolean::New((coll->tdb->opts & TDBTDEFLATE) ? true : false));
-                cm->Set(sym_options, opts);
-                Local<Array> indexes = Array::New();
-                int ic = 0;
-                for (int j = 0; j < coll->tdb->inum; ++j) {
-                    TDBIDX *idx = (coll->tdb->idxs + j);
-                    assert(idx);
-                    if (idx->type != TDBITLEXICAL && idx->type != TDBITDECIMAL && idx->type != TDBITTOKEN) {
-                        continue;
-                    }
-                    Local<Object> imeta = Object::New();
-                    imeta->Set(sym_field, String::New(idx->name + 1));
-                    imeta->Set(sym_iname, String::New(idx->name));
-                    switch (idx->type) {
-                        case TDBITLEXICAL:
-                            imeta->Set(sym_type, String::New("lexical"));
-                            break;
-                        case TDBITDECIMAL:
-                            imeta->Set(sym_type, String::New("decimal"));
-                            break;
-                        case TDBITTOKEN:
-                            imeta->Set(sym_type, String::New("token"));
-                            break;
-                    }
-                    TCBDB *idb = (TCBDB*) idx->db;
-                    if (idb) {
-                        imeta->Set(sym_records, Integer::NewFromUnsigned((uint32_t) idb->rnum));
-                        imeta->Set(sym_file, String::New(idb->hdb->path));
-                    }
-                    indexes->Set(Integer::New(ic++), imeta);
-                }
-                cm->Set(sym_indexes, indexes);
-                cinfo->Set(Integer::New(i), cm);
-                ejcollunlockmethod(coll);
-            }
-            tclistdel(cols);
-            ret->Set(sym_file, String::New(njb->m_jb->metadb->hdb->path));
-            ret->Set(String::New("collections"), cinfo);
+            bson_iterator it;
+            bson_iterator_init(&it, meta);
+            Handle<Object> ret = toV8Object(&it);
+            bson_del(meta);
             return scope.Close(ret);
         }
 
index b22ec52..c569ef7 100644 (file)
@@ -524,7 +524,7 @@ EJQ* ejdbqueryaddor(EJDB *jb, EJQ *q, const void *orbsdata) {
     if (q->orqobjsnum == 1) {
         TCMALLOC(q->orqobjs, sizeof (*(q->orqobjs)) * q->orqobjsnum);
     } else {
-        TCREALLOC(q->orqobjs, q->orqobjs, q->orqobjsnum);
+        TCREALLOC(q->orqobjs, q->orqobjs, sizeof (*(q->orqobjs)) * q->orqobjsnum);
     }
     q->orqobjs[q->orqobjsnum - 1] = *oq; //copy
     TCFREE(oq);
@@ -868,6 +868,76 @@ bool ejdbtranstatus(EJCOLL *jcoll, bool *txactive) {
     return true;
 }
 
+bson* ejdbmeta(EJDB *jb) {
+    if (!JBISOPEN(jb)) {
+        _ejdbsetecode(jb, TCEINVALID, __FILE__, __LINE__, __func__);
+        return NULL;
+    }
+    char nbuff[TCNUMBUFSIZ];
+    bson *bs = bson_create();
+    bson_init(bs);
+    bson_append_string(bs, "file", jb->metadb->hdb->path);
+    bson_append_start_array(bs, "collections");
+    TCLIST *cols = ejdbgetcolls(jb);
+    for (int i = 0; i < TCLISTNUM(cols); ++i) {
+        if (!JBISOPEN(jb)) {
+            break;
+        }
+        EJCOLL *coll = (EJCOLL*) TCLISTVALPTR(cols, i);
+        if (!coll || !_ejcollockmethod(coll, false)) continue;
+        bson_numstrn(nbuff, TCNUMBUFSIZ, i);
+        bson_append_start_object(bs, nbuff); //coll obj
+        bson_append_string_n(bs, "name", coll->cname, coll->cnamesz);
+        bson_append_string(bs, "file", coll->tdb->hdb->path);
+        bson_append_long(bs, "records", coll->tdb->hdb->rnum);
+
+        bson_append_start_object(bs, "options"); //coll.options
+        bson_append_long(bs, "buckets", coll->tdb->hdb->bnum);
+        bson_append_long(bs, "cachedrecords", coll->tdb->hdb->rcnum);
+        bson_append_bool(bs, "large", (coll->tdb->opts & TDBTLARGE));
+        bson_append_bool(bs, "compressed", (coll->tdb->opts & TDBTDEFLATE));
+        bson_append_finish_object(bs); //eof coll.options
+
+        bson_append_start_array(bs, "indexes"); //coll.indexes[]
+        for (int j = 0; j < coll->tdb->inum; ++j) {
+            TDBIDX *idx = (coll->tdb->idxs + j);
+            if (idx->type != TDBITLEXICAL &&
+                    idx->type != TDBITDECIMAL &&
+                    idx->type != TDBITTOKEN) {
+                continue;
+            }
+            bson_numstrn(nbuff, TCNUMBUFSIZ, j);
+            bson_append_start_object(bs, nbuff); //coll.indexes.index
+            bson_append_string(bs, "field", idx->name + 1);
+            bson_append_string(bs, "iname", idx->name);
+            switch (idx->type) {
+                case TDBITLEXICAL:
+                    bson_append_string(bs, "type", "lexical");
+                    break;
+                case TDBITDECIMAL:
+                    bson_append_string(bs, "type", "decimal");
+                    break;
+                case TDBITTOKEN:
+                    bson_append_string(bs, "type", "token");
+                    break;
+            }
+            TCBDB *idb = (TCBDB*) idx->db;
+            if (idb) {
+                bson_append_long(bs, "records", idb->rnum);
+                bson_append_string(bs, "file", idb->hdb->path);
+            }
+            bson_append_finish_object(bs); //eof coll.indexes.index
+        }
+        bson_append_finish_array(bs); //eof coll.indexes[]
+        bson_append_finish_object(bs); //eof coll
+        _ejcollunlockmethod(coll);
+    }
+    bson_append_finish_array(bs); //eof collections
+    bson_finish(bs);
+    tclistdel(cols);
+    return bs;
+}
+
 /*************************************************************************************************
  * private features
  *************************************************************************************************/
@@ -3103,7 +3173,7 @@ static bool _qrypreprocess(EJCOLL *jcoll, EJQ *ejq, int qflags, EJQF **mqf,
             ejq->skip = (uint32_t) ((v < 0) ? 0 : v);
         }
         bt = bson_find(&it, ejq->hints, "$max");
-         if (qflags & JBQRYFINDONE) {
+        if (qflags & JBQRYFINDONE) {
             ejq->max = (uint32_t) 1;
         } else if (BSON_IS_NUM_TYPE(bt)) {
             int64_t v = bson_iterator_long(&it);
index 85f8f96..69b4fd0 100644 (file)
@@ -468,7 +468,7 @@ EJDB_EXPORT bool ejdbsyncoll(EJCOLL *jcoll);
 
 /**
  * Synchronize entire EJDB database and
- * all its collections with storage.
+ * all of its collections with storage.
  * @param jb Database hand
  */
 EJDB_EXPORT bool ejdbsyncdb(EJDB *jb);
@@ -485,6 +485,9 @@ EJDB_EXPORT bool ejdbtranabort(EJCOLL *coll);
 /** Get current transaction status, it will be placed into txActive*/
 EJDB_EXPORT bool ejdbtranstatus(EJCOLL *jcoll, bool *txactive);
 
+/** Gets description of EJDB database and its collections. */
+EJDB_EXPORT bson* ejdbmeta(EJDB *jb);
+
 EJDB_EXTERN_C_END
 
 #endif        /* EJDB_H */