[longomatch] Reuse the IDResolver as a cache for objects



commit 779ce55c45744ed6a3b00ef43f1b8987388b8f88
Author: Andoni Morales Alastruey <ylatuya gmail com>
Date:   Wed Mar 18 15:56:50 2015 +0100

    Reuse the IDResolver as a cache for objects

 LongoMatch.DB/DocumentsSerializer.cs |  139 +++++++++++++++++++++-------------
 Tests/DB/TestStorage.cs              |   43 ++++++++++-
 2 files changed, 129 insertions(+), 53 deletions(-)
---
diff --git a/LongoMatch.DB/DocumentsSerializer.cs b/LongoMatch.DB/DocumentsSerializer.cs
index 3c21a5b..8e13d3d 100644
--- a/LongoMatch.DB/DocumentsSerializer.cs
+++ b/LongoMatch.DB/DocumentsSerializer.cs
@@ -35,11 +35,11 @@ namespace LongoMatch.DB
        public static class DocumentsSerializer
        {
 
-               public static void SaveObject (IStorable obj, Database db, StorablesConverter 
storablesConverter = null)
+               public static void SaveObject (IStorable obj, Database db, IDReferenceResolver resolver = 
null)
                {
                        Document doc = db.GetDocument (obj.ID.ToString ());
                        doc.Update ((UnsavedRevision rev) => {
-                               JObject jo = SerializeObject (obj, rev, db, storablesConverter);
+                               JObject jo = SerializeObject (obj, rev, db, resolver);
                                IDictionary<string, object> props = jo.ToObject<IDictionary<string, object>> 
();
                                /* SetProperties sets a new properties dictionary, removing the attachments we
                                         * added in the serialization */
@@ -51,10 +51,10 @@ namespace LongoMatch.DB
                        });
                }
 
-               public static object LoadObject (Type objType, Guid id, Database db, StorablesConverter 
storablesConverter = null)
+               public static object LoadObject (Type objType, Guid id, Database db, IDReferenceResolver 
resolver = null)
                {
                        Document doc = db.GetExistingDocument (id.ToString ());
-                       return DeserializeObject (objType, doc, db, storablesConverter);
+                       return DeserializeObject (objType, doc, db, resolver);
                }
 
                /// <summary>
@@ -66,10 +66,10 @@ namespace LongoMatch.DB
                /// <param name="localStorables">A list of <see cref="LongoMatch.Core.Interfaces.IStorable"/>
                /// types that should be serialized as local referencies instead of by document ID.</param>
                internal static JObject SerializeObject (IStorable obj, Revision rev, Database db,
-                                                        StorablesConverter storablesConverter = null)
+                                                        IDReferenceResolver resolver = null)
                {
                        JsonSerializer serializer = GetSerializer (obj.GetType (), rev, db,
-                                                           storablesConverter, GetLocalTypes (obj.GetType 
()));
+                                                           resolver, GetLocalTypes (obj.GetType ()));
 
                        JObject jo = JObject.FromObject (obj, serializer);
                        jo ["DocType"] = obj.GetType ().Name;
@@ -85,30 +85,31 @@ namespace LongoMatch.DB
                /// <param name = "serializer">The serializer to use when deserializing the object</param>
                /// <typeparam name="T">The 1st type parameter.</typeparam>
                internal static object DeserializeObject (Type type, Document doc, Database db,
-                                                         StorablesConverter storablesConverter = null)
+                                                         IDReferenceResolver resolver = null)
                {
                        JObject jo = JObject.FromObject (doc.Properties);
                        JsonSerializer serializer = GetSerializer (type, doc.CurrentRevision, db,
-                                                           storablesConverter, GetLocalTypes (type));
+                                                           resolver, GetLocalTypes (type));
                        return jo.ToObject (type, serializer);
                }
 
-               static List<Type> GetLocalTypes (Type objType)
+               internal static List<Type> GetLocalTypes (Type objType)
                {
                        List<Type> localStorables = new List<Type> ();
                        if (objType == typeof(Project)) {
                                localStorables.Add (typeof(Team));
                                localStorables.Add (typeof(Dashboard));
                                localStorables.Add (typeof(Player));
+                               localStorables.Add (typeof(AnalysisEventType));
                        }
                        return localStorables;
                }
 
                static JsonSerializer GetSerializer (Type serType, Revision rev, Database db,
-                                                    StorablesConverter storablesConverter, List<Type> 
localTypes)
+                                                    IDReferenceResolver resolver, List<Type> localTypes)
                {
-                       if (storablesConverter == null) {
-                               storablesConverter = new StorablesConverter (db, localTypes);
+                       if (resolver == null) {
+                               resolver = new IDReferenceResolver ();
                        }
                        if (localTypes == null) {
                                localTypes = new List<Type> ();
@@ -120,9 +121,9 @@ namespace LongoMatch.DB
                        settings.TypeNameHandling = TypeNameHandling.Objects;
                        settings.Converters.Add (new ImageConverter (rev));
                        settings.Converters.Add (new VersionConverter ());
-                       settings.Converters.Add (storablesConverter);
+                       settings.Converters.Add (new StorablesConverter (db, resolver, localTypes));
                        settings.Converters.Add (new LongoMatchConverter (false));
-                       settings.ReferenceResolver = storablesConverter;
+                       settings.ReferenceResolver = resolver;
                        return JsonSerializer.Create (settings);
                }
        }
@@ -199,55 +200,25 @@ namespace LongoMatch.DB
                }
        }
 
-       /// <summary>
-       /// Serialize objects matching any of the types lists passed in the constructor
-       /// using their object ID.
-       /// </summary>
-       public class StorablesConverter : JsonConverter, IReferenceResolver
+       public class IDReferenceResolver: IReferenceResolver
        {
-               List<Type> localTypes;
-               Database db;
                int _references;
                readonly Dictionary<string, object> _idtoobjects;
                readonly Dictionary<object, string> _objectstoid;
 
-               public StorablesConverter (Database db, List<Type> localTypes)
+               public IDReferenceResolver ()
                {
-                       this.db = db;
-                       this.localTypes = localTypes;
-                       if (this.localTypes == null) {
-                               this.localTypes = new List<Type> ();
-                       }
-
                        _references = 0;
                        _idtoobjects = new Dictionary<string, object> ();
                        _objectstoid = new Dictionary<object, string> ();
                }
 
-               public override void WriteJson (JsonWriter writer, object value, JsonSerializer serializer)
+               public bool IsCached (string id)
                {
-                       IStorable storable = value as IStorable;
-                       writer.WriteValue (storable.ID);
-                       DocumentsSerializer.SaveObject (storable, db);
+                       return _idtoobjects.ContainsKey (id);
                }
 
-               public override object ReadJson (JsonReader reader, Type objectType, object existingValue, 
JsonSerializer serializer)
-               {
-                       Guid id = Guid.Parse (reader.Value as string);
-                       return DocumentsSerializer.LoadObject (objectType, id, db);
-               }
-
-               public override bool CanConvert (Type objectType)
-               {
-                       bool ret;
-
-                       if (!typeof(IStorable).IsAssignableFrom (objectType)) {
-                               ret = false;
-                       } else {
-                               ret = !localTypes.Contains (objectType);
-                       }
-                       return ret;
-               }
+               #region IReferenceResolver implementation
 
                public object ResolveReference (object context, string reference)
                {
@@ -259,9 +230,8 @@ namespace LongoMatch.DB
                public string GetReference (object context, object value)
                {
                        string referenceStr;
-                       if (value is IStorable) {
-                               IStorable p = value as IStorable;
-                               referenceStr = p.ID.ToString ();
+                       if (value is IIDObject) {
+                               referenceStr = (value as IIDObject).ID.ToString ();
                        } else {
                                if (!_objectstoid.TryGetValue (value, out referenceStr)) {
                                        _references++;
@@ -275,6 +245,10 @@ namespace LongoMatch.DB
 
                public bool IsReferenced (object context, object value)
                {
+                       /* IStorable are always serialized by ID and not by reference */
+                       if (value is IStorable) {
+                               return false;
+                       }
                        return _objectstoid.ContainsKey (value);
                }
 
@@ -283,6 +257,67 @@ namespace LongoMatch.DB
                        _idtoobjects [reference] = value;
                        _objectstoid [value] = reference;
                }
+
+               #endregion
+       }
+
+       /// <summary>
+       /// Serialize objects matching any of the types lists passed in the constructor
+       /// using their object ID.
+       /// </summary>
+       public class StorablesConverter : JsonConverter
+       {
+               List<Type> localTypes;
+               Database db;
+               IDReferenceResolver idResolver;
+
+               public StorablesConverter (Database db, IDReferenceResolver idResolver, List<Type> localTypes)
+               {
+                       this.db = db;
+                       this.idResolver = idResolver;
+                       this.localTypes = localTypes;
+                       if (this.localTypes == null) {
+                               this.localTypes = new List<Type> ();
+                       }
+               }
+
+               public override void WriteJson (JsonWriter writer, object value, JsonSerializer serializer)
+               {
+                       IStorable storable = value as IStorable;
+                       writer.WriteValue (storable.ID);
+                       /* Only persist objects once per session */
+                       if (!idResolver.IsCached (storable.ID.ToString ())) {
+                               DocumentsSerializer.SaveObject (storable, db, idResolver);
+                               idResolver.AddReference (this, storable.ID.ToString (), storable);
+                       }
+               }
+
+               public override object ReadJson (JsonReader reader, Type objectType, object existingValue, 
JsonSerializer serializer)
+               {
+                       string idStr = reader.Value as string;
+                       object obj;
+
+                       /* Return the cached object instance instead a new one */
+                       obj = idResolver.ResolveReference (this, idStr);
+                       if (obj == null) {
+                               obj = DocumentsSerializer.LoadObject (objectType, Guid.Parse (idStr), db, 
idResolver);
+                               idResolver.AddReference (this, idStr, obj);
+                       }
+                       return obj;
+               }
+
+               public override bool CanConvert (Type objectType)
+               {
+                       bool ret;
+
+                       if (!typeof(IStorable).IsAssignableFrom (objectType)) {
+                               ret = false;
+                       } else {
+                               ret = !localTypes.Contains (objectType);
+                       }
+                       return ret;
+               }
+
        }
 }
 
diff --git a/Tests/DB/TestStorage.cs b/Tests/DB/TestStorage.cs
index f6c9539..407115d 100644
--- a/Tests/DB/TestStorage.cs
+++ b/Tests/DB/TestStorage.cs
@@ -240,6 +240,38 @@ namespace Tests.DB
                }
 
                [Test ()]
+               [Ignore ("FIXME")]
+               public void TestSaveLoadTimelineEvent ()
+               {
+                       IDReferenceResolver resolver = new IDReferenceResolver ();
+                       Player p = new Player ();
+                       AnalysisEventType evtType = new AnalysisEventType ();
+                       TimelineEvent evt = new TimelineEvent ();
+
+                       resolver.AddReference (null, p.ID.ToString (), p);
+                       resolver.AddReference (null, evtType.ID.ToString (), evtType);
+                       evt.Players.Add (p);
+                       evt.EventType = evtType;
+
+                       Document doc = db.GetDocument (evt.ID.ToString ());
+                       doc.Update ((UnsavedRevision rev) => {
+                               JObject jo = DocumentsSerializer.SerializeObject (evt, rev, db, resolver);
+                               Assert.AreEqual (p.ID, jo ["Players"] [0].Value<Guid> ());
+                               Assert.AreEqual (evtType.ID, jo ["EventType"].Value<Guid> ());
+                               IDictionary<string, object> props = jo.ToObject<IDictionary<string, object>> 
();
+                               rev.SetProperties (props);
+                               return true;
+                       });
+
+                       /* Player has not been added to the db, as it was already referenced
+                        * by the IDReferenceResolver */
+                       Assert.AreEqual (1, db.DocumentCount);
+
+                       TimelineEvent evt2 = storage.Retrieve <TimelineEvent> (evt.ID);
+                       Assert.IsNotNull (evt2.EventType);
+               }
+
+               [Test ()]
                public void TestSaveLoadProjectDescription ()
                {
                        MediaFile mf = new MediaFile ("path", 34000, 25, true, true, "mp4", "h264",
@@ -293,7 +325,13 @@ namespace Tests.DB
                        p.Description = pd;
 
                        for (int i = 0; i < 10; i++) {
-                               p.AddEvent (p.EventTypes [i], new Time (1000), new Time (2000), null, null, 
null, null);
+                               TimelineEvent evt = new TimelineEvent {
+                                       EventType = p.EventTypes [i],
+                                       Start = new Time (1000),
+                                       Stop = new Time (2000),
+                                       Players = new List<Player> { p.LocalTeamTemplate.List [0] }, 
+                               };
+                               p.Timeline.Add (evt);
                        }
 
                        storage.Store<Project> (p);
@@ -303,6 +341,9 @@ namespace Tests.DB
 
                        Project p2 = storage.Retrieve<Project> (p.ID);
                        Assert.AreEqual (p.Timeline.Count, p2.Timeline.Count);
+                       Assert.AreEqual (p2.LocalTeamTemplate.List [0], p2.Timeline [0].Players [0]);
+                       //Assert.AreEqual ((p2.Dashboard.List [0] as AnalysisEventButton).EventType,
+                       //      p2.Timeline [0].EventType);
                }
        }
 }


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