Click here to Skip to main content
15,860,859 members
Articles / Web Development / HTML

RaptorDB - The Document Store

Rate me:
Please Sign up or sign in to vote.
4.96/5 (278 votes)
24 Jul 2019CPOL86 min read 2.3M   16.3K   653  
NoSql, JSON based, Document store database with compiled .net map functions and automatic hybrid bitmap indexing and LINQ query filters (now with standalone Server mode, Backup and Active Restore, Transactions, Server side queries, MonoDroid support, HQ-Branch Replication, working in Linux, .net
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using RaptorDB.Common;
using System.Linq.Expressions;

namespace RaptorDB
{
    public class RaptorDBClient : IRaptorDB
    {
        public RaptorDBClient(string server, int port, string username, string password)
        {
            _username = username;
            _password = password;
            _client = new NetworkClient(server, port);
        }

        private NetworkClient _client;
        private string _username;
        private string _password;

        /// <summary>
        /// Save a document to RaptorDB
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="docID"></param>
        /// <param name="document"></param>
        /// <returns></returns>
        public bool Save<T>(Guid docID, T document)
        {
            Packet p = CreatePacket();
            p.Command = "save";
            p.Docid = docID;
            p.Data = document;
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return ret.OK;
        }

        /// <summary>
        /// Save a file to RaptorDB
        /// </summary>
        /// <param name="fileID"></param>
        /// <param name="bytes"></param>
        /// <returns></returns>
        public bool SaveBytes(Guid fileID, byte[] bytes)
        {
            Packet p = CreatePacket();
            p.Command = "savebytes";
            p.Docid = fileID;
            p.Data = bytes;
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return ret.OK;
        }

        /// <summary>
        /// Query any view -> get all rows
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="viewname"></param>
        /// <returns></returns>
        public Result<object> Query(string viewname)
        {
            return Query(viewname, 0, 0);
        }

        /// <summary>
        /// Query a primary view -> get all rows
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="view"></param>
        /// <returns></returns>
        public Result<object> Query(Type type)
        {
            return Query(type, 0, 0);
        }

        /// <summary>
        /// Query a view using a string filter
        /// </summary>
        /// <param name="viewname"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public Result<object> Query(string viewname, string filter)
        {
            return Query(viewname, filter, 0, 0);
        }

        // FEATURE : add paging to queries -> start, count
        /// <summary>
        /// Query any view with filters
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="viewname">view name</param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public Result<object> Query<T>(string viewname, Expression<Predicate<T>> filter)
        {
            return Query(viewname, filter, 0, 0);
        }

        /// <summary>
        /// Query a view with filters
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="view">base entity type, or typeof the view </param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public Result<object> Query<T>(Type view, Expression<Predicate<T>> filter)
        {
            return Query<T>(view, filter, 0, 0);
        }

        /// <summary>
        /// Query a view with filters
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="view">base entity type, or typeof the view </param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public Result<object> Query(Type view, string filter)
        {
            return Query(view, filter, 0, 0);
        }

        /// <summary>
        /// Fetch a document by it's ID
        /// </summary>
        /// <param name="docID"></param>
        /// <returns></returns>
        public object Fetch(Guid docID)
        {
            Packet p = CreatePacket();
            p.Command = "fetch";
            p.Docid = docID;
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            if (ret.OK)
                return ret.Data;
            else
                return null;
        }

        /// <summary>
        /// Fetch file data by it's ID
        /// </summary>
        /// <param name="fileID"></param>
        /// <returns></returns>
        public byte[] FetchBytes(Guid fileID)
        {
            Packet p = CreatePacket();
            p.Command = "fetchbytes";
            p.Docid = fileID;
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            if (ret.OK)
                return (byte[])ret.Data;
            else
                return null;
        }

        /// <summary>
        /// Shutdown and cleanup 
        /// </summary>
        public void Shutdown()
        {
            _client.Close();
        }

        /// <summary>
        /// Backup the data file in incremental mode to the RaptorDB folder
        /// </summary>
        /// <returns></returns>
        public bool Backup()
        {
            Packet p = CreatePacket();
            p.Command = "backup";
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return ret.OK;
        }

        /// <summary>
        /// Restore backup files stored in RaptorDB folder
        /// </summary>
        public void Restore()
        {
            Packet p = CreatePacket();
            p.Command = "restore";
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
        }

        /// <summary>
        /// Delete a document (the actual data is not deleted just marked so) 
        /// </summary>
        /// <param name="docid"></param>
        /// <returns></returns>
        public bool Delete(Guid docid)
        {
            Packet p = CreatePacket();
            p.Command = "delete";
            p.Docid = docid;
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return ret.OK;
        }

        /// <summary>
        /// Delete a file (the actual data is not deleted just marked so) 
        /// </summary>
        /// <param name="fileid"></param>
        /// <returns></returns>
        public bool DeleteBytes(Guid fileid)
        {
            Packet p = CreatePacket();
            p.Command = "deletebytes";
            p.Docid = fileid;
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return ret.OK;
        }

        /// <summary>
        /// Add a user for server mode login
        /// </summary>
        /// <param name="username"></param>
        /// <param name="oldpassword"></param>
        /// <param name="newpassword"></param>
        /// <returns></returns>
        public bool AddUser(string username, string oldpassword, string newpassword)
        {
            Packet p = CreatePacket();
            p.Command = "adduser";
            p.Data = new object[] { username, oldpassword, newpassword };
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return ret.OK;
        }

        /// <summary>
        /// Execute server side queries
        /// </summary>
        /// <param name="func"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public object[] ServerSide(ServerSideFunc func, string filter)
        {
            Packet p = CreatePacket();
            p.Command = "serverside";
            p.Data = new object[] { func.Method.ReflectedType.AssemblyQualifiedName, func.Method.Name, filter };
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (object[])ret.Data;
        }

        /// <summary>
        /// Execute server side queries
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="func"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public object[] ServerSide<T>(ServerSideFunc func, Expression<Predicate<T>> filter)
        {
            LINQString ls = new LINQString();
            ls.Visit(filter);

            Packet p = CreatePacket();
            p.Command = "serverside";
            p.Data = new object[] { func.Method.ReflectedType.AssemblyQualifiedName, func.Method.Name, ls.sb.ToString() };
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (object[])ret.Data;
        }

        /// <summary>
        /// Full text search the complete original document 
        /// </summary>
        /// <param name="filter"></param>
        /// <returns></returns>
        public int[] FullTextSearch(string filter)
        {
            Packet p = CreatePacket();
            p.Command = "fulltext";
            p.Data = new object[] { filter };
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (int[])ret.Data;
        }

        private Packet CreatePacket()
        {
            Packet p = new Packet();
            p.Username = _username;
            p.PasswordHash = Helper.MurMur.Hash(Encoding.UTF8.GetBytes(_username + "|" + _password)).ToString();

            return p;
        }

        /// <summary>
        /// Query all data in a view with paging
        /// </summary>
        /// <param name="viewname"></param>
        /// <param name="start"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public Result<object> Query(string viewname, int start, int count)
        {
            Packet p = CreatePacket();
            p.Command = "querystr";
            p.Viewname = viewname;
            p.Data = "";
            p.Start = start;
            p.Count = count;
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (Result<object>)ret.Data;
        }

        /// <summary>
        /// Query all data associated with the Documnet Type or the View Type with paging
        /// </summary>
        /// <param name="view"></param>
        /// <param name="start"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public Result<object> Query(Type view, int start, int count)
        {
            Packet p = CreatePacket();
            p.Command = "querytype";
            p.Start = start;
            p.Count = count;
            p.Data = new object[] { view.AssemblyQualifiedName, "" };
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (Result<object>)ret.Data;
        }

        /// <summary>
        /// Query a View with a string filter with paging
        /// </summary>
        /// <param name="viewname"></param>
        /// <param name="filter"></param>
        /// <param name="start"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public Result<object> Query(string viewname, string filter, int start, int count)
        {
            Packet p = CreatePacket();
            p.Command = "querystr";
            p.Viewname = viewname;
            p.Data = filter;
            p.Start = start;
            p.Count = count;
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (Result<object>)ret.Data;
        }

        /// <summary>
        /// Query a View with a LINQ filter with paging
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="viewname"></param>
        /// <param name="filter"></param>
        /// <param name="start"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public Result<object> Query<T>(string viewname, Expression<Predicate<T>> filter, int start, int count)
        {
            LINQString ls = new LINQString();
            ls.Visit(filter);
            Packet p = CreatePacket();
            p.Command = "querystr";
            p.Viewname = viewname;
            p.Start = start;
            p.Count = count;
            p.Data = ls.sb.ToString();
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (Result<object>)ret.Data;
        }

        /// <summary>
        /// Query a View Type with a LINQ filter with paging
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <param name="filter"></param>
        /// <param name="start"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public Result<object> Query<T>(Type type, Expression<Predicate<T>> filter, int start, int count)
        {
            LINQString ls = new LINQString();
            ls.Visit(filter);
            Packet p = CreatePacket();
            p.Command = "querytype";
            p.Start = start;
            p.Count = count;
            p.Data = new object[] { type.AssemblyQualifiedName, ls.sb.ToString() };
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (Result<object>)ret.Data;
        }

        /// <summary>
        /// Query a View Type with a string filter with paging
        /// </summary>
        /// <param name="type"></param>
        /// <param name="filter"></param>
        /// <param name="start"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public Result<object> Query(Type type, string filter, int start, int count)
        {
            Packet p = CreatePacket();
            p.Command = "querytype";
            p.Start = start;
            p.Count = count;
            p.Data = new object[] { type.AssemblyQualifiedName, filter };
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (Result<object>)ret.Data;
        }

        /// <summary>
        /// Count rows
        /// </summary>
        /// <param name="type"></param>
        /// <returns></returns>
        public int Count(Type type)
        {
            return Count(type, "");
        }

        /// <summary>
        /// Count rows with a string filter
        /// </summary>
        /// <param name="type"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public int Count(Type type, string filter)
        {
            Packet p = CreatePacket();
            p.Command = "counttype";
            p.Data = new object[] { type.AssemblyQualifiedName, filter };
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (int)ret.Data;
        }

        /// <summary>
        /// Count rows with a LINQ query
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="type"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public int Count<T>(Type type, Expression<Predicate<T>> filter)
        {
            LINQString ls = new LINQString();
            ls.Visit(filter);
            Packet p = CreatePacket();
            p.Command = "counttype";
            p.Data = new object[] { type.AssemblyQualifiedName, ls.sb.ToString() };
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (int)ret.Data;
        }

        /// <summary>
        /// Count rows
        /// </summary>
        /// <param name="viewname"></param>
        /// <returns></returns>
        public int Count(string viewname)
        {
            return Count(viewname, "");
        }

        /// <summary>
        /// Count rows with a string filter
        /// </summary>
        /// <param name="viewname"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public int Count(string viewname, string filter)
        {
            Packet p = CreatePacket();
            p.Command = "countstr";
            p.Viewname = viewname;
            p.Data = filter;
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (int)ret.Data;
        }

        /// <summary>
        /// Count rows with a LINQ query
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="viewname"></param>
        /// <param name="filter"></param>
        /// <returns></returns>
        public int Count<T>(string viewname, Expression<Predicate<T>> filter)
        {
            LINQString ls = new LINQString();
            ls.Visit(filter);
            Packet p = CreatePacket();
            p.Command = "countstr";
            p.Viewname = viewname;
            p.Data = ls.sb.ToString();
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (int)ret.Data;
        }

        /// <summary>
        /// Query with LINQ filter
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <returns></returns>
        public Result<T> Query<T>(Expression<Predicate<T>> filter)
        {
            return Query<T>(filter, 0, 0);           
        }

        /// <summary>
        /// Query with LINQ filter and paging
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <param name="start"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public Result<T> Query<T>(Expression<Predicate<T>> filter, int start, int count)
        {
            LINQString ls = new LINQString();
            ls.Visit(filter);
            Packet p = CreatePacket();
            p.Command = "querytype";
            p.Start = start;
            p.Count = count;
            p.Data = new object[] { typeof(T).AssemblyQualifiedName, ls.sb.ToString() };
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            Result<object> res = (Result<object>)ret.Data;
            return GenericResult<T>(res);
        }

        private static Result<T> GenericResult<T>(Result<object> res)
        {
            // dirty hack here to cleanup
            Result<T> result = new Result<T>();
            result.Count = res.Count;
            result.EX = res.EX;
            result.OK = res.OK;
            result.TotalCount = res.TotalCount;
            result.Rows = res.Rows.Cast<T>().ToList<T>();
            return result;
        }

        /// <summary>
        /// Query with string filter
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <returns></returns>
        public Result<T> Query<T>(string filter)
        {
            return Query<T>(filter, 0, 0);
        }

        /// <summary>
        /// Query with string filter and paging
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <param name="start"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public Result<T> Query<T>(string filter, int start, int count)
        {
            Packet p = CreatePacket();
            p.Command = "querytype";
            p.Start = start;
            p.Count = count;
            p.Data = new object[] { typeof(T).AssemblyQualifiedName, filter };
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            Result<object> res = (Result<object>)ret.Data;
            return GenericResult<T>(res);
        }

        /// <summary>
        /// Count with LINQ filter
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="filter"></param>
        /// <returns></returns>
        public int Count<T>(Expression<Predicate<T>> filter)
        {
            LINQString ls = new LINQString();
            ls.Visit(filter);
            Packet p = CreatePacket();
            p.Command = "gcount";
            p.Viewname = typeof(T).AssemblyQualifiedName;
            p.Data = ls.sb.ToString();
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (int)ret.Data;
        }

        /// <summary>
        /// Fetch the document change history
        /// </summary>
        /// <param name="docid"></param>
        /// <returns></returns>
        public int[] FetchHistory(Guid docid)
        {
            Packet p = CreatePacket();
            p.Command = "dochistory";
            p.Docid = docid;
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (int[])ret.Data;
        }

        /// <summary>
        /// Fetch the file change history
        /// </summary>
        /// <param name="fileid"></param>
        /// <returns></returns>
        public int[] FetchBytesHistory(Guid fileid)
        {
            Packet p = CreatePacket();
            p.Command = "filehistory";
            p.Docid = fileid;
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (int[])ret.Data;
        }

        /// <summary>
        /// Fetch a specific document version
        /// </summary>
        /// <param name="versionNumber"></param>
        /// <returns></returns>
        public object FetchVersion(int versionNumber)
        {
            Packet p = CreatePacket();
            p.Command = "fetchversion";
            p.Data = versionNumber;
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return ret.Data;
        }

        /// <summary>
        /// Fetch a specific file version
        /// </summary>
        /// <param name="versionNumber"></param>
        /// <returns></returns>
        public byte[] FetchBytesVersion(int versionNumber)
        {
            Packet p = CreatePacket();
            p.Command = "fetchfileversion";
            p.Data = versionNumber;
            ReturnPacket ret = (ReturnPacket)_client.Send(p);
            return (byte[])ret.Data;
        }
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect -
United Kingdom United Kingdom
Mehdi first started programming when he was 8 on BBC+128k machine in 6512 processor language, after various hardware and software changes he eventually came across .net and c# which he has been using since v1.0.
He is formally educated as a system analyst Industrial engineer, but his programming passion continues.

* Mehdi is the 5th person to get 6 out of 7 Platinum's on Code-Project (13th Jan'12)
* Mehdi is the 3rd person to get 7 out of 7 Platinum's on Code-Project (26th Aug'16)

Comments and Discussions