[smuxi] Engine(-Tests): initial SqliteMessageBuffer implementation (closes: #908)



commit d43370523187518cbecb0595007eb16b9f098a83
Author: Mirco Bauer <meebey meebey net>
Date:   Tue Feb 25 23:01:13 2014 +0100

    Engine(-Tests): initial SqliteMessageBuffer implementation (closes: #908)

 configure.ac                                     |    4 +-
 src/Engine-Tests/Engine-Tests.csproj             |    1 +
 src/Engine-Tests/SqliteMessageBufferTests.cs     |  100 +++++++++++++
 src/Engine/Engine.csproj                         |    1 +
 src/Engine/Makefile.am                           |    3 +
 src/Engine/MessageBuffers/SqliteMessageBuffer.cs |  172 ++++++++++++++++++++++
 6 files changed, 280 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 09fe7a4..b5f6840 100644
--- a/configure.ac
+++ b/configure.ac
@@ -143,10 +143,12 @@ SHAMROCK_FIND_MONO_2_0_COMPILER_OR_HIGHER
 SHAMROCK_CHECK_MONO_2_0_GAC_ASSEMBLIES([
        System
        System.Core
-       System.Xml
+       System.Data
        System.Runtime.Remoting
        System.Runtime.Serialization
+       System.Xml
        Mono.Posix
+       Mono.Data.Sqlite
 ])
 
 PROFILE=debug
diff --git a/src/Engine-Tests/Engine-Tests.csproj b/src/Engine-Tests/Engine-Tests.csproj
index 040336f..1c30005 100644
--- a/src/Engine-Tests/Engine-Tests.csproj
+++ b/src/Engine-Tests/Engine-Tests.csproj
@@ -44,6 +44,7 @@
     <Compile Include="GitMessageBufferTests.cs" />
     <Compile Include="JsonMessageBufferTests.cs" />
     <Compile Include="MessageDtoModelV1Tests.cs" />
+    <Compile Include="SqliteMessageBufferTests.cs" />
   </ItemGroup>
   <ItemGroup>
     <Reference Include="System" />
diff --git a/src/Engine-Tests/SqliteMessageBufferTests.cs b/src/Engine-Tests/SqliteMessageBufferTests.cs
new file mode 100644
index 0000000..49be73e
--- /dev/null
+++ b/src/Engine-Tests/SqliteMessageBufferTests.cs
@@ -0,0 +1,100 @@
+// Smuxi - Smart MUltipleXed Irc
+//
+// Copyright (c) 2014 Mirco Bauer <meebey meebey net>
+//
+// Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; 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;
+using NUnit.Framework;
+using Smuxi.Common;
+
+namespace Smuxi.Engine
+{
+    [TestFixture]
+    public class SqliteMessageBufferTests : MessageBufferTestsBase
+    {
+        protected override IMessageBuffer CreateBuffer()
+        {
+            var dbFile = Path.Combine(Platform.GetBuffersPath("testuser"),
+                                      "testprot");
+            dbFile = Path.Combine(dbFile, "testnet");
+            dbFile = Path.Combine(dbFile, "testchat.sqlite3");
+            if (File.Exists(dbFile)) {
+                File.Delete(dbFile);
+            }
+
+            return OpenBuffer();
+        }
+
+        protected override IMessageBuffer OpenBuffer()
+        {
+            return new SqliteMessageBuffer("testuser", "testprot", "testnet", "testchat");
+        }
+
+        [Test]
+        public void Reopen()
+        {
+            Buffer.Dispose();
+            OpenBuffer();
+            Enumerator();
+        }
+
+        [Test]
+        public void ImplicitFlush()
+        {
+            // generate 32 extra messsages to exceed the buffer size which
+            // forces a flush of the buffer to db4o
+            var bufferCount = Buffer.Count;
+            var msgs = new List<MessageModel>(Buffer);
+            for (int i = 1; i <= 32; i++) {
+                var builder = new MessageBuilder();
+                builder.AppendText("msg{0}", bufferCount + i);
+                var msg = builder.ToMessage();
+                msgs.Add(msg);
+                Buffer.Add(msg);
+            }
+
+            int j = 0;
+            foreach (var msg in Buffer) {
+                Assert.AreEqual(msgs[j++].ToString(), msg.ToString());
+            }
+            Assert.AreEqual(msgs.Count, j);
+        }
+
+        [Test]
+        public void ImplicitRemoveAt()
+        {
+            Buffer.MaxCapacity = 16;
+            // generate 32 extra messsages to exceed the max capacity which
+            // forces a RemoveAt() call of the oldest messages
+            var bufferCount = Buffer.Count;
+            var msgs = new List<MessageModel>(Buffer);
+            for (int i = 1; i <= 32; i++) {
+                var builder = new MessageBuilder();
+                builder.AppendText("msg{0}", bufferCount + i);
+                var msg = builder.ToMessage();
+                msgs.Add(msg);
+                Buffer.Add(msg);
+            }
+
+            Assert.AreEqual(Buffer.MaxCapacity, Buffer.Count);
+            Assert.AreEqual(msgs[19].ToString(), Buffer[0].ToString());
+        }
+    }
+}
diff --git a/src/Engine/Engine.csproj b/src/Engine/Engine.csproj
index 2c74ef3..ff441e0 100644
--- a/src/Engine/Engine.csproj
+++ b/src/Engine/Engine.csproj
@@ -112,6 +112,7 @@
     <Compile Include="MessageBuffers\GitMessageBuffer.cs" />
     <Compile Include="MessageBuffers\JsonMessageBuffer.cs" />
     <Compile Include="Messages\Dto\MessageDtoModelV1.cs" />
+    <Compile Include="MessageBuffers\SqliteMessageBuffer.cs" />
   </ItemGroup>
   <ItemGroup>
     <Folder Include="Protocols\" />
diff --git a/src/Engine/Makefile.am b/src/Engine/Makefile.am
index 83183d1..e5a0719 100644
--- a/src/Engine/Makefile.am
+++ b/src/Engine/Makefile.am
@@ -67,6 +67,7 @@ FILES = \
        MessageBuffers/ListMessageBuffer.cs \
        MessageBuffers/MessageBufferBase.cs \
        MessageBuffers/MessageBufferPersistencyType.cs \
+       MessageBuffers/SqliteMessageBuffer.cs \
        Messages/FeedMessageBuilder.cs \
        Messages/MessageBuilder.cs \
        Messages/MessageModel.cs \
@@ -125,11 +126,13 @@ EXTRAS = \
 REFERENCES =  \
        System \
        System.Core \
+       System.Data \
        System.Runtime.Remoting \
        System.Runtime.Serialization \
        System.Web \
        System.Xml \
        Mono.Posix \
+       Mono.Data.Sqlite \
        $(NINI_LIBS) \
        $(LOG4NET_LIBS) \
        $(DB4O_LIBS) \
diff --git a/src/Engine/MessageBuffers/SqliteMessageBuffer.cs 
b/src/Engine/MessageBuffers/SqliteMessageBuffer.cs
new file mode 100644
index 0000000..c8cc377
--- /dev/null
+++ b/src/Engine/MessageBuffers/SqliteMessageBuffer.cs
@@ -0,0 +1,172 @@
+// Smuxi - Smart MUltipleXed Irc
+//
+// Copyright (c) 2014 Mirco Bauer <meebey meebey net>
+//
+// Full GPL License: <http://www.gnu.org/licenses/gpl.txt>
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// This program 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 General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; 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.Text;
+using System.Linq;
+using System.Collections.Generic;
+using Mono.Data.Sqlite;
+using ServiceStack.Text;
+using Smuxi.Engine.Dto;
+
+namespace Smuxi.Engine
+{
+    public class SqliteMessageBuffer : MessageBufferBase
+    {
+#if LOG4NET
+        static readonly log4net.ILog f_Logger = 
log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
+#endif
+        string DBPath { get; set; }
+        SqliteConnection Connection { get; set; }
+
+        public override int Count {
+            get {
+                var cmd = Connection.CreateCommand();
+                cmd.CommandText = "SELECT COUNT(*) FROM Messages";
+                return (int) Convert.ChangeType(cmd.ExecuteScalar(), typeof(int));
+            }
+        }
+
+        public override MessageModel this[int index] {
+            get {
+                return GetRange(index, 1).First();
+            }
+            set {
+                throw new NotImplementedException();
+            }
+        }
+
+        public SqliteMessageBuffer(string sessionUsername, string protocol,
+                                   string networkId, string chatId) :
+                              base(sessionUsername, protocol, networkId, chatId)
+        {
+            DBPath = GetBufferPath() + ".sqlite3";
+            Connection = new SqliteConnection("URI=file:" + DBPath);
+            Connection.Open();
+
+            var sql = "CREATE TABLE IF NOT EXISTS Messages (" +
+                          "ID INTEGER PRIMARY KEY," +
+                          "JSON TEXT" +
+                      ")";
+            var cmd = Connection.CreateCommand();
+            cmd.CommandText = sql;
+            cmd.ExecuteNonQuery();
+        }
+
+        public override void Add(MessageModel msg)
+        {
+            if (msg == null) {
+                throw new ArgumentNullException("msg");
+            }
+
+            var dto = new MessageDtoModelV1(msg);
+            var json = JsonSerializer.SerializeToString(dto);
+
+            var cmd = Connection.CreateCommand();
+            cmd.CommandText = "INSERT INTO Messages (JSON)" +
+                              " VALUES(@json)";
+            var param = cmd.CreateParameter();
+            param.ParameterName = "json";
+            param.Value = json;
+            cmd.Parameters.Add(param);
+
+            cmd.ExecuteNonQuery();
+        }
+
+        public override IList<MessageModel> GetRange(int offset, int limit)
+        {
+            using (var cmd = Connection.CreateCommand()) {
+                cmd.CommandText = "SELECT ID, JSON FROM Messages " +
+                                  " ORDER BY ID" +
+                                  " LIMIT @limit OFFSET @offset ";
+                var param = cmd.CreateParameter();
+                param.ParameterName = "offset";
+                param.Value = offset.ToString();
+                cmd.Parameters.Add(param);
+
+                param = cmd.CreateParameter();
+                param.ParameterName = "limit";
+                param.Value = limit.ToString();
+                cmd.Parameters.Add(param);
+
+                var reader = cmd.ExecuteReader();
+                var msgs = new List<MessageModel>(limit);
+                while (reader.Read()) {
+                    var json = (string) reader["JSON"];
+                    var dto = JsonSerializer.DeserializeFromString<MessageDtoModelV1>(json);
+                    var msg = dto.ToMessage();
+                    msgs.Add(msg);
+                }
+                return msgs;
+            }
+        }
+
+        public override void Clear()
+        {
+            var cmd = Connection.CreateCommand();
+            cmd.CommandText = "DELETE FROM Messages";
+            cmd.ExecuteNonQuery();
+        }
+
+        public override bool Contains(MessageModel item)
+        {
+            throw new NotImplementedException ();
+        }
+
+        public override void CopyTo(MessageModel[] array, int arrayIndex)
+        {
+            throw new NotImplementedException ();
+        }
+
+        public override bool Remove(MessageModel item)
+        {
+            throw new NotImplementedException ();
+        }
+
+        public override IEnumerator<MessageModel> GetEnumerator()
+        {
+            throw new NotImplementedException ();
+        }
+
+        public override int IndexOf(MessageModel item)
+        {
+            throw new NotImplementedException ();
+        }
+
+        public override void Insert(int index, MessageModel item)
+        {
+            throw new NotImplementedException ();
+        }
+
+        public override void RemoveAt(int index)
+        {
+            throw new NotImplementedException ();
+        }
+
+        public override void Flush()
+        {
+        }
+
+        public override void Dispose()
+        {
+            Flush();
+        }
+    }
+}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]