diff --git a/mocha-dotnet/src/lib/Mocha.Core/Oms.cs b/mocha-dotnet/src/lib/Mocha.Core/Oms.cs index a709dd6..82035f3 100644 --- a/mocha-dotnet/src/lib/Mocha.Core/Oms.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/Oms.cs @@ -18,7 +18,6 @@ namespace Mocha.Core; using System.Reflection; -using System.Runtime.Serialization; using System.Security.Cryptography; using System.Text; using System.Text.Json.Nodes; @@ -340,11 +339,16 @@ public abstract class Oms ValidateConstraintsForRelationship(source.GetHandle(), relationship, targets); AssignRelationshipInternal(source.GetHandle(), relationship, targets, dt); - if (!_InhibitStorage) + if (!InhibitStorageProcessing) { + List list = new List(); + foreach (InstanceHandle ih in targets) + { + list.Add(new InstanceReference(GetGlobalIdentifier(ih))); + } foreach (OmsStorage sto in Storages) { - sto.WriteRelationship(this, source.GetHandle(), relationship, targets, dt); + sto.WriteRelationship(new InstanceReference(GetGlobalIdentifier(source)), new InstanceReference(GetGlobalIdentifier(relationship)), list, dt, false); } } } @@ -447,11 +451,11 @@ public abstract class Oms //? this also means that we need to manually loop through storages and update the siblings //? if I had a nickel for every time I called AssignRelationshipInternal,... I'd have two nickels - if (!_InhibitStorage) + if (!InhibitStorageProcessing) { foreach (OmsStorage sto in Storages) { - sto.WriteRelationship(this, target, siblingRelationship, new InstanceHandle[] { source }, dt); + sto.WriteRelationship(new InstanceReference(GetGlobalIdentifier(target)), new InstanceReference(GetGlobalIdentifier(siblingRelationship)), new InstanceReference[] { new InstanceReference(GetGlobalIdentifier(source)) }, dt, false); } } } @@ -463,11 +467,11 @@ public abstract class Oms public void ClearRelationship(InstanceHandle source, InstanceHandle relationship) { ClearRelationshipInternal(source, relationship); - if (!_InhibitStorage) + if (!InhibitStorageProcessing) { foreach (OmsStorage sto in Storages) { - sto.ClearRelationship(this, source, relationship, DateTime.Now); + sto.ClearRelationship(new InstanceReference(GetGlobalIdentifier(source)), new InstanceReference(GetGlobalIdentifier(relationship)), DateTime.Now); } } } @@ -492,6 +496,15 @@ public abstract class Oms throw new KeyNotFoundException(String.Format("inst not found: {0}", globalIdentifier)); } + public InstanceHandle GetInstance(InstanceReference ir) + { + if (ir.GlobalIdentifier != Guid.Empty) + { + return GetInstance(ir.GlobalIdentifier); + } + return GetInstance(ir.InstanceKey); + } + private Dictionary _derivedInstances = new Dictionary(); public InstanceHandle GetInstance(InstanceKey ik) { @@ -620,11 +633,11 @@ public abstract class Oms */ DateTime dt = DateTime.Now; - if (!_InhibitStorage) + if (!InhibitStorageProcessing) { foreach (OmsStorage sto in Storages) { - sto.CreateInstance(this, ir, ir_class.GetHandle(), dt); + sto.CreateInstance(new InstanceReference(guid), dt); } } SetParentClass(ir, ir_class.GetHandle()); @@ -856,11 +869,11 @@ public abstract class Oms Log.WriteLine("oms: setting attribute value {0} . {1} = '{2}'", sh, attribute, value); SetAttributeValueInternal(sh, attribute, value, dt); - if (!_InhibitStorage) + if (!InhibitStorageProcessing) { foreach (OmsStorage sto in Storages) { - sto.WriteAttributeValue(this, source.GetHandle(), attribute, value, dt); + sto.WriteAttributeValue(new InstanceReference(GetGlobalIdentifier(source.GetHandle())), new InstanceReference(GetGlobalIdentifier(attribute)), value, dt); } } } @@ -2605,14 +2618,28 @@ public abstract class Oms return value; } - private bool _InhibitStorage = false; + internal bool InhibitStorageProcessing { get; set; } = false; public void ReloadStorages() { - _InhibitStorage = true; + InhibitStorageProcessing = true; foreach (OmsStorage sto in Storages) { sto.Load(this); } - _InhibitStorage = false; + InhibitStorageProcessing = false; + } + + internal InstanceHandle UnsafeCreateInstance(InstanceReference ir) + { + return UnsafeCreateInstance(ir.GlobalIdentifier, ir.InstanceKey); + } + internal InstanceHandle UnsafeCreateInstance(Guid guid, InstanceKey ik) + { + InstanceHandle ih = CreateInstance(guid); + if (ik != InstanceKey.Empty) + { + SetInstanceKey(ih, ik); + } + return ih; } } diff --git a/mocha-dotnet/src/lib/Mocha.Core/OmsStorage.cs b/mocha-dotnet/src/lib/Mocha.Core/OmsStorage.cs index 5a0cd7e..bb02025 100644 --- a/mocha-dotnet/src/lib/Mocha.Core/OmsStorage.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/OmsStorage.cs @@ -1,4 +1,4 @@ -// Copyright (C) 2025 Michael Becker +// Copyright (C) 2024 Michael Becker // // This file is part of Mocha.NET. // @@ -15,73 +15,108 @@ // You should have received a copy of the GNU General Public License // along with Mocha.NET. If not, see . - -using System.Net.Sockets; -using System.Runtime.Serialization; - namespace Mocha.Core; public abstract class OmsStorage { public class OmsStorageCollection : System.Collections.ObjectModel.Collection { - private Oms _parent; - public OmsStorageCollection(Oms parent) + public Oms Oms { get; private set; } + public OmsStorageCollection(Oms oms) { - _parent = parent; + Oms = oms; } } - protected abstract void CreateInstanceInternal(Oms oms, InstanceHandle source, InstanceHandle parentClass, DateTime effectiveDate); - public void CreateInstance(Oms oms, InstanceHandle source, InstanceHandle parentClass, DateTime effectiveDate) + private bool _ReadOnly = false; + public bool ReadOnly { get { return _ReadOnly; } } + + protected OmsStorage(bool readOnly) { - CreateInstanceInternal(oms, source, parentClass, effectiveDate); - if (AutoFlush) Flush(); + _ReadOnly = readOnly; } - protected abstract void WriteAttributeValueInternal(Oms oms, InstanceHandle source, InstanceHandle attribute, object value, DateTime effectiveDate); - public void WriteAttributeValue(Oms oms, InstanceHandle source, InstanceHandle attribute, object value, DateTime effectiveDate) - { - WriteAttributeValueInternal(oms, source, attribute, value, effectiveDate); - if (AutoFlush) Flush(); - } - - protected abstract void WriteRelationshipInternal(Oms oms, InstanceHandle source, InstanceHandle relationship, IEnumerable targets, DateTime effectiveDate); - public void WriteRelationship(Oms oms, InstanceHandle source, InstanceHandle relationship, IEnumerable targets, DateTime effectiveDate) - { - WriteRelationshipInternal(oms, source, relationship, targets, effectiveDate); - if (AutoFlush) Flush(); - } - - protected abstract void ClearRelationshipInternal(Oms oms, InstanceHandle source, InstanceHandle relationship, DateTime effectiveDate); - public void ClearRelationship(Oms oms, InstanceHandle source, InstanceHandle relationship, DateTime effectiveDate) - { - ClearRelationshipInternal(oms, source, relationship, effectiveDate); - if (AutoFlush) Flush(); - } - - protected abstract void OpenInternal(); - public void Open() - { - OpenInternal(); - } - - public bool AutoFlush { get; set; } = true; - - protected abstract void FlushInternal(); - public void Flush() - { - FlushInternal(); - } - protected abstract void CloseInternal(); + protected virtual void CloseInternal() { } public void Close() { CloseInternal(); } + protected virtual void ResolveDependenciesInternal(Oms oms) + { + } + internal void ResolveDependencies(Oms oms) + { + ResolveDependenciesInternal(oms); + } + + protected abstract void CreateInstanceInternal(InstanceReference instance, DateTime effectiveDate); + public void CreateInstance(InstanceReference instance, DateTime effectiveDate) + { + if (ReadOnly) + return; + + CreateInstanceInternal(instance, effectiveDate); + if (AutoFlush) + { + Flush(); + } + } + + protected abstract void WriteAttributeValueInternal(InstanceReference sourceInstance, InstanceReference attributeInstance, object value, DateTime effectiveDate); + public void WriteAttributeValue(InstanceReference sourceInstance, InstanceReference attributeInstance, object value, DateTime effectiveDate) + { + if (ReadOnly) + return; + + WriteAttributeValueInternal(sourceInstance, attributeInstance, value, effectiveDate); + if (AutoFlush) + { + Flush(); + } + } + + protected abstract void ClearRelationshipInternal(InstanceReference sourceInstance, InstanceReference relationshipInstance, DateTime effectiveDate); + public void ClearRelationship(InstanceReference sourceInstance, InstanceReference relationshipInstance, DateTime effectiveDate) + { + if (ReadOnly) + return; + + ClearRelationshipInternal(sourceInstance, relationshipInstance, effectiveDate); + if (AutoFlush) + { + Flush(); + } + } + + protected abstract void WriteRelationshipInternal(InstanceReference sourceInstance, InstanceReference attributeInstance, IEnumerable targetInstances, DateTime effectiveDate, bool remove); + public void WriteRelationship(InstanceReference sourceInstance, InstanceReference attributeInstance, IEnumerable targetInstances, DateTime effectiveDate, bool remove) + { + if (ReadOnly) + return; + + WriteRelationshipInternal(sourceInstance, attributeInstance, targetInstances, effectiveDate, remove); + if (AutoFlush) + { + Flush(); + } + } + protected abstract void LoadInternal(Oms oms); public void Load(Oms oms) { + oms.InhibitStorageProcessing = true; LoadInternal(oms); + oms.InhibitStorageProcessing = false; } -} \ No newline at end of file + + public bool AutoFlush { get; set; } = true; + + protected virtual void FlushInternal() + { + } + public void Flush() + { + FlushInternal(); + } +} diff --git a/mocha-dotnet/src/lib/Mocha.Core/Storage/Binary/BinaryOmsStorage.cs b/mocha-dotnet/src/lib/Mocha.Core/Storage/Binary/BinaryOmsStorage.cs new file mode 100644 index 0000000..fdddf42 --- /dev/null +++ b/mocha-dotnet/src/lib/Mocha.Core/Storage/Binary/BinaryOmsStorage.cs @@ -0,0 +1,214 @@ +// Copyright (C) 2025 Michael Becker +// +// This file is part of Mocha.NET. +// +// Mocha.NET 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 3 of the License, or +// (at your option) any later version. +// +// Mocha.NET 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 Mocha.NET. If not, see . + +namespace Mocha.Core.Storage.Binary; + +public class BinaryOmsStorage : OmsStorage +{ + private Stream _Stream; + public Stream Stream { get { return _Stream; } } + + private BinaryWriter _Writer; + private BinaryWriter Writer { get { return _Writer; } } + + private BinaryReader _Reader; + private BinaryReader Reader { get { return _Reader; } } + + public BinaryOmsStorage(Stream stream, bool readOnly = false) : base(readOnly) + { + _Stream = stream; + if (!readOnly) + { + _Writer = new BinaryWriter(stream); + } + _Reader = new BinaryReader(stream); + } + + private void WriteData(BinaryWriter writer, object value) + { + if (value is string) + { + writer.Write((int)BinaryOmsStorageAttributeType.Text); + writer.Write((string)value); + return; + } + else if (value is bool) + { + writer.Write((int)BinaryOmsStorageAttributeType.Boolean); + writer.Write((bool)value); + return; + } + else if (value is decimal) + { + writer.Write((int)BinaryOmsStorageAttributeType.Numeric); + writer.Write((decimal)value); + return; + } + else if (value is DateTime) + { + writer.Write((int)BinaryOmsStorageAttributeType.Date); + writer.Write(((DateTime)value).ToBinary()); + return; + } + throw new InvalidOperationException(); + } + + private object ReadData(BinaryReader reader) + { + BinaryOmsStorageAttributeType type = (BinaryOmsStorageAttributeType)reader.ReadInt32(); + if (type == BinaryOmsStorageAttributeType.Text) + { + return reader.ReadString(); + } + else if (type == BinaryOmsStorageAttributeType.Boolean) + { + return reader.ReadBoolean(); + } + else if (type == BinaryOmsStorageAttributeType.Numeric) + { + return reader.ReadDecimal(); + } + else if (type == BinaryOmsStorageAttributeType.Date) + { + return DateTime.FromBinary(reader.ReadInt64()); + } + throw new InvalidOperationException(); + } + protected override void CreateInstanceInternal(InstanceReference sourceInstance, DateTime effectiveDate) + { + Writer.Write((byte)BinaryOmsStorageOpCode.CreateInstance); + WriteInstance(sourceInstance); + Writer.Write(effectiveDate.ToBinary()); + } + + protected override void WriteAttributeValueInternal(InstanceReference sourceInstance, InstanceReference attributeInstance, object value, DateTime effectiveDate) + { + Writer.Write((byte)BinaryOmsStorageOpCode.AssignAttribute); + WriteInstance(sourceInstance); + WriteInstance(attributeInstance); + Writer.Write(effectiveDate.ToBinary()); + + WriteData(Writer, value); + } + + private void WriteInstance(InstanceReference instanceReference) + { + WriteInstanceKey(instanceReference.InstanceKey); + WriteGuid(instanceReference.GlobalIdentifier); + } + + protected override void ClearRelationshipInternal(InstanceReference sourceInstance, InstanceReference relationshipInstance, DateTime effectiveDate) + { + _Writer.Write((byte)BinaryOmsStorageOpCode.ClearRelationship); + WriteInstance(sourceInstance); + WriteInstance(relationshipInstance); + Writer.Write(effectiveDate.ToBinary()); + } + + protected override void WriteRelationshipInternal(InstanceReference sourceInstance, InstanceReference relationshipInstance, IEnumerable targetInstances, DateTime effectiveDate, bool remove) + { + _Writer.Write((byte)BinaryOmsStorageOpCode.AssignRelationship); + WriteInstance(sourceInstance); + WriteInstance(relationshipInstance); + Writer.Write(effectiveDate.ToBinary()); + + _Writer.Write(targetInstances.Count()); + foreach (InstanceReference ir in targetInstances) + { + WriteInstance(ir); + } + } + + private void WriteInstanceKey(InstanceKey instanceKey) + { + Writer.Write(instanceKey.ClassIndex); + Writer.Write(instanceKey.InstanceIndex); + } + private void WriteGuid(Guid guid) + { + Writer.Write(guid.ToByteArray()); + } + protected InstanceKey ReadInstanceKey() + { + int classIndex = Reader.ReadInt32(); + int instanceIndex = Reader.ReadInt32(); + return new InstanceKey(classIndex, instanceIndex); + } + protected Guid ReadGuid() + { + byte[] data = Reader.ReadBytes(16); + return new Guid(data); + } + + protected virtual void ApplyOperation(Oms oms, BinaryOmsStorageOpCode opcode) + { + if (opcode == BinaryOmsStorageOpCode.CreateInstance) + { + throw new NotImplementedException(); + } + else if (opcode == BinaryOmsStorageOpCode.AssignAttribute) + { + InstanceReference sourceInstance = ReadInstance(); + InstanceReference attributeInstance = ReadInstance(); + + DateTime effectiveDate = DateTime.FromBinary(Reader.ReadInt64()); + object value = ReadData(Reader); + + oms.SetAttributeValue(sourceInstance.GetHandle(oms), attributeInstance.GetHandle(oms), value, effectiveDate); + } + else if (opcode == BinaryOmsStorageOpCode.AssignRelationship) + { + InstanceReference sourceInstance = ReadInstance(); + InstanceReference relationshipInstance = ReadInstance(); + DateTime effectiveDate = DateTime.FromBinary(Reader.ReadInt64()); + + int instanceCount = Reader.ReadInt32(); + InstanceReference[] iks = new InstanceReference[instanceCount]; + for (int i = 0; i < instanceCount; i++) + { + InstanceReference ik = ReadInstance(); + iks[i] = ik; + } + oms.AssignRelationship(sourceInstance.GetHandle(oms), relationshipInstance.GetHandle(oms), InstanceReference.GetHandles(iks, oms), effectiveDate); + } + } + + protected override void LoadInternal(Oms oms) + { + while (true) + { + try + { + BinaryOmsStorageOpCode opcode = (BinaryOmsStorageOpCode)Reader.ReadByte(); + if (opcode == BinaryOmsStorageOpCode.Invalid) return; + + ApplyOperation(oms, opcode); + } + catch (EndOfStreamException ex) + { + break; + } + } + } + + protected InstanceReference ReadInstance() + { + InstanceKey sourceInstanceKey = ReadInstanceKey(); + Guid sourceInstanceGuid = ReadGuid(); + return new InstanceReference(sourceInstanceKey, sourceInstanceGuid); + } +} diff --git a/mocha-dotnet/tests/Mocha.Core.Tests/PersistenceTests.cs b/mocha-dotnet/src/lib/Mocha.Core/Storage/Binary/BinaryOmsStorageAttributeType.cs similarity index 79% rename from mocha-dotnet/tests/Mocha.Core.Tests/PersistenceTests.cs rename to mocha-dotnet/src/lib/Mocha.Core/Storage/Binary/BinaryOmsStorageAttributeType.cs index 6941291..08fbfd6 100644 --- a/mocha-dotnet/tests/Mocha.Core.Tests/PersistenceTests.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/Storage/Binary/BinaryOmsStorageAttributeType.cs @@ -15,9 +15,16 @@ // You should have received a copy of the GNU General Public License // along with Mocha.NET. If not, see . -using Mocha.Testing; +namespace Mocha.Core.Storage.Binary; -public class PersistenceTests : OmsTestsBase +public enum BinaryOmsStorageAttributeType : int { - + Text = 4, + Boolean = 5, + Numeric = 20, + Date = 21, + XML = 22, + Currency = 99, + File = 822, + RichText = 2737 } \ No newline at end of file diff --git a/mocha-dotnet/src/lib/Mocha.Core/Storage/Binary/BinaryOmsStorageOpcode.cs b/mocha-dotnet/src/lib/Mocha.Core/Storage/Binary/BinaryOmsStorageOpcode.cs new file mode 100644 index 0000000..f53a456 --- /dev/null +++ b/mocha-dotnet/src/lib/Mocha.Core/Storage/Binary/BinaryOmsStorageOpcode.cs @@ -0,0 +1,33 @@ +// Copyright (C) 2025 Michael Becker +// +// This file is part of Mocha.NET. +// +// Mocha.NET 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 3 of the License, or +// (at your option) any later version. +// +// Mocha.NET 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 Mocha.NET. If not, see . + +namespace Mocha.Core.Storage.Binary; + +public enum BinaryOmsStorageOpCode : byte +{ + Invalid = 0x00, + + CreateInstance = 0xC1, + DeleteInstance = 0xC0, + + AssignAttribute = 0xA1, + ClearAttribute = 0xA0, + + AssignRelationship = 0xB1, + RemoveRelationship = 0xB2, + ClearRelationship = 0xB0 +} \ No newline at end of file diff --git a/mocha-dotnet/src/lib/Mocha.Core/Storage/BinaryOmsStorage.cs b/mocha-dotnet/src/lib/Mocha.Core/Storage/BinaryOmsStorage.cs deleted file mode 100644 index 4b7e6e5..0000000 --- a/mocha-dotnet/src/lib/Mocha.Core/Storage/BinaryOmsStorage.cs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright (C) 2025 Michael Becker -// -// This file is part of Mocha.NET. -// -// Mocha.NET 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 3 of the License, or -// (at your option) any later version. -// -// Mocha.NET 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 Mocha.NET. If not, see . - -using System.Data; -using System.Text.Json; -using System.Text.Json.Nodes; - -namespace Mocha.Core.Storage; - -public class BinaryOmsStorage : OmsStorage -{ - public Stream Stream { get; } - - public BinaryWriter Writer { get; } - - public BinaryOmsStorage(string path) - { - Stream = System.IO.File.Open(path, FileMode.Create, FileAccess.Write, FileShare.Read); - Writer = new BinaryWriter(Stream); - - Open(); - } - public BinaryOmsStorage(Stream stream) - { - Stream = stream; - Writer = new BinaryWriter(Stream); - - Open(); - } - - protected override void OpenInternal() - { - Writer.Write(new char[] { 'M', 'c', 'J', '!' }); - Writer.Write(1.0f); - } - - protected override void CreateInstanceInternal(Oms oms, InstanceHandle source, InstanceHandle parentClass, DateTime effectiveDate) - { - Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source); - Guid classInstanceGuid = oms.GetGlobalIdentifier(parentClass); - - Writer.Write((byte)0xC1); - Writer.Write(sourceInstanceGuid.ToByteArray()); - Writer.Write(classInstanceGuid.ToByteArray()); - - InstanceKey ik = oms.GetInstanceKey(source); - Writer.Write(ik.ClassIndex); - Writer.Write(ik.InstanceIndex); - - Writer.Write(effectiveDate.ToBinary()); - Writer.Write(DateTime.Now.ToBinary()); - } - - protected override void WriteAttributeValueInternal(Oms oms, InstanceHandle source, InstanceHandle attribute, object value, DateTime effectiveDate) - { - Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source); - Guid attributeInstanceGuid = oms.GetGlobalIdentifier(attribute); - - Writer.Write((byte)0xA1); - Writer.Write(sourceInstanceGuid.ToByteArray()); - Writer.Write(attributeInstanceGuid.ToByteArray()); - WriteBinaryValue(Writer, value); - - Writer.Write(effectiveDate.ToBinary()); - Writer.Write(DateTime.Now.ToBinary()); - } - - private void WriteBinaryValue(BinaryWriter writer, object value) - { - if (value is string s) - { - writer.Write((int)1); - writer.Write(s); - } - } - - protected override void WriteRelationshipInternal(Oms oms, InstanceHandle source, InstanceHandle relationship, IEnumerable targets, DateTime effectiveDate) - { - Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source); - Guid relationshipInstanceGuid = oms.GetGlobalIdentifier(relationship); - - Writer.Write((byte)0xB1); - Writer.Write(sourceInstanceGuid.ToByteArray()); - Writer.Write(relationshipInstanceGuid.ToByteArray()); - - Writer.Write((int)targets.Count()); - foreach (InstanceHandle target in targets) - { - Writer.Write(oms.GetGlobalIdentifier(target).ToByteArray()); - } - - Writer.Write(effectiveDate.ToBinary()); - Writer.Write(DateTime.Now.ToBinary()); - } - - protected override void ClearRelationshipInternal(Oms oms, InstanceHandle source, InstanceHandle relationship, DateTime effectiveDate) - { - Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source); - Guid relationshipInstanceGuid = oms.GetGlobalIdentifier(relationship); - - Writer.Write((byte)0xB0); - Writer.Write(sourceInstanceGuid.ToByteArray()); - Writer.Write(relationshipInstanceGuid.ToByteArray()); - - Writer.Write(effectiveDate.ToBinary()); - Writer.Write(DateTime.Now.ToBinary()); - } - - protected override void FlushInternal() - { - Writer.Flush(); - } - - protected override void CloseInternal() - { - Writer.Flush(); - Stream.Close(); - } - - protected override void LoadInternal(Oms oms) - { - } - -} \ No newline at end of file diff --git a/mocha-dotnet/src/lib/Mocha.Core/Storage/CustomDefinition.cs b/mocha-dotnet/src/lib/Mocha.Core/Storage/CustomDefinition.cs new file mode 100644 index 0000000..38ac389 --- /dev/null +++ b/mocha-dotnet/src/lib/Mocha.Core/Storage/CustomDefinition.cs @@ -0,0 +1,25 @@ +// Copyright (C) 2025 Michael Becker +// +// This file is part of mochalite-dotnet. +// +// mochalite-dotnet 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 3 of the License, or +// (at your option) any later version. +// +// mochalite-dotnet 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 mochalite-dotnet. If not, see . + +namespace Mocha.Core.Storage; + +public class CustomDefinition +{ + public InstanceReference ClassInstance { get; set; } = null; + public Dictionary Attributes { get; } = new Dictionary(); + public Dictionary Relationships { get; } = new Dictionary(); +} \ No newline at end of file diff --git a/mocha-dotnet/src/lib/Mocha.Core/Storage/Json/JsonOmsStorage.cs b/mocha-dotnet/src/lib/Mocha.Core/Storage/Json/JsonOmsStorage.cs new file mode 100644 index 0000000..d5ac898 --- /dev/null +++ b/mocha-dotnet/src/lib/Mocha.Core/Storage/Json/JsonOmsStorage.cs @@ -0,0 +1,342 @@ +// Copyright (C) 2025 Michael Becker +// +// This file is part of mochalite-dotnet. +// +// mochalite-dotnet 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 3 of the License, or +// (at your option) any later version. +// +// mochalite-dotnet 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 mochalite-dotnet. If not, see . + + +using System.Data; +using System.Globalization; +using System.IO.Pipes; +using System.Linq.Expressions; +using System.Reflection.Metadata.Ecma335; +using System.Runtime.InteropServices; +using System.Text; +using System.Text.Json.Nodes; +using System.Threading.Tasks.Dataflow; +using Mocha.Core; + + +namespace Mocha.Core.Storage.Json; + +public class JsonOmsStorage : OmsStorage +{ + private Stream _Stream; + public Stream Stream { get { return _Stream; } } + + public List UnresolvedCustomDefinitions { get; } = new List(); + + protected JsonObject? MakeInstanceObj(InstanceReference instance) + { + if (instance.InstanceKey == InstanceKey.Empty && instance.GlobalIdentifier == Guid.Empty) + return null; + + JsonObject o = new JsonObject(); + if (instance.InstanceKey != InstanceKey.Empty) + { + o.Add("instanceKey", instance.InstanceKey.ToString()); + } + if (instance.GlobalIdentifier != Guid.Empty) + { + o.Add("globalIdentifier", instance.GlobalIdentifier.ToString()); + } + return o; + } + + public JsonOmsStorage(Stream stream, bool readOnly = false) : base(readOnly) + { + _Stream = stream; + + _obj.Add("type", "journal"); + _obj.Add("items", _ary); + + + } + + public static JsonOmsStorage FromPath(string path) + { + string[] jsonfiles = System.IO.Directory.GetFiles(path, "*.json", SearchOption.AllDirectories); + StringBuilder content = new StringBuilder(); + content.Append("{\"type\": \"journal\", \"items\": ["); + for (int i = 0; i < jsonfiles.Length; i++) + { + content.Append(System.IO.File.ReadAllText(jsonfiles[i])); + if (i < jsonfiles.Length - 1) + { + content.Append(','); + } + } + content.Append("]}"); + MemoryStream ms = new MemoryStream(System.Text.Encoding.UTF8.GetBytes(content.ToString())); + return new JsonOmsStorage(ms, true); + } + + private JsonArray _ary = new JsonArray(); + private JsonObject _obj = new JsonObject(); + + protected override void FlushInternal() + { + Stream.Seek(0, SeekOrigin.Begin); + + string text = _obj.ToJsonString(); + byte[] data = System.Text.Encoding.UTF8.GetBytes(text); + Stream.Write(data, 0, data.Length); + } + + protected override void ClearRelationshipInternal(InstanceReference sourceInstance, InstanceReference relationshipInstance, DateTime effectiveDate) + { + JsonObject o = new JsonObject(); + o.Add("type", "clearRelationship"); + o.Add("sourceInstance", MakeInstanceObj(sourceInstance)); + o.Add("relationshipInstance", MakeInstanceObj(relationshipInstance)); + o.Add("effectiveDate", effectiveDate.ToString("O")); + _ary.Add(o); + } + + protected override void CreateInstanceInternal(InstanceReference instance, DateTime effectiveDate) + { + JsonObject o = new JsonObject(); + o.Add("type", "createInstance"); + o.Add("instanceKey", instance.InstanceKey.ToString()); + o.Add("globalIdentifier", instance.GlobalIdentifier.ToString()); + o.Add("effectiveDate", effectiveDate.ToString("O")); + _ary.Add(o); + } + + protected override void WriteAttributeValueInternal(InstanceReference sourceInstance, InstanceReference attributeInstance, object value, DateTime effectiveDate) + { + JsonObject o = new JsonObject(); + o.Add("type", "assignAttribute"); + o.Add("sourceInstance", MakeInstanceObj(sourceInstance)); + o.Add("attributeInstance", MakeInstanceObj(attributeInstance)); + o.Add("value", JsonValue.Create(value)); + o.Add("effectiveDate", effectiveDate.ToString("O")); + _ary.Add(o); + } + + protected override void WriteRelationshipInternal(InstanceReference sourceInstance, InstanceReference relationshipInstance, IEnumerable targetInstances, DateTime effectiveDate, bool remove) + { + JsonObject o = new JsonObject(); + o.Add("type", "assignRelationship"); + o.Add("sourceInstance", MakeInstanceObj(sourceInstance)); + o.Add("relationshipInstance", MakeInstanceObj(relationshipInstance)); + + JsonArray ary = new JsonArray(); + foreach (InstanceReference inst in targetInstances) + { + ary.Add(MakeInstanceObj(inst)); + } + o.Add("targetInstances", ary); + + o.Add("effectiveDate", effectiveDate.ToString("O")); + _ary.Add(o); + } + + protected override void LoadInternal(Oms oms) + { + StreamReader sr = new StreamReader(Stream); + string text = sr.ReadToEnd(); + JsonObject? obj = (JsonObject?)JsonNode.Parse(text); + LoadObject(obj, oms); + } + + private Dictionary customDefinitions = new Dictionary(); + + private void LoadObject(JsonObject? obj, Oms oms) + { + if (obj == null) return; + + if (obj.ContainsKey("type")) + { + JsonNode? n = obj["type"]; + if (n != null) + { + string tagName = n.GetValue(); + if (tagName.Equals("journal")) + { + JsonArray? ary = obj["items"] as JsonArray; + if (ary != null) + { + foreach (JsonNode? n2 in ary) + { + if (n2 is JsonObject o2) + { + LoadObject(o2, oms); + } + } + } + } + else if (tagName.Equals("createInstance")) + { + InstanceReference? ir = ParseInstanceReference(obj); + InstanceHandle ih = oms.UnsafeCreateInstance(ir); + } + else if (tagName.Equals("clearRelationship")) + { + oms.ClearRelationship(oms.GetInstance(ParseInstanceReference(obj["sourceInstance"] as JsonObject)), oms.GetInstance(ParseInstanceReference(obj["relationshipInstance"] as JsonObject))); + } + else if (tagName.Equals("assignRelationship")) + { + List tgts = new List(); + foreach (JsonNode n1 in (obj["targetInstances"] as JsonArray)) + { + tgts.Add(oms.GetInstance(ParseInstanceReference(n1 as JsonObject))); + } + oms.AssignRelationship(oms.GetInstance(ParseInstanceReference(obj["sourceInstance"] as JsonObject)), oms.GetInstance(ParseInstanceReference(obj["relationshipInstance"] as JsonObject)), tgts); + } + else if (tagName.Equals("assignAttribute")) + { + object? value = obj["value"].GetValue(); + DateTime effectiveDate = DateTime.Parse(obj["effectiveDate"].GetValue()); + oms.SetAttributeValue(oms.GetInstance(ParseInstanceReference(obj["sourceInstance"] as JsonObject)), oms.GetInstance(ParseInstanceReference(obj["attributeInstance"] as JsonObject)), value, effectiveDate); + } + else if (tagName.Equals("instance")) + { + CustomDefinition? cd = null; + if (obj.ContainsKey("instanceKey")) + { + InstanceKey inst = InstanceKey.Parse(obj["instanceKey"].GetValue()); + if (obj.ContainsKey("customTagName")) + { + cd = new CustomDefinition(); + cd.ClassInstance = new InstanceReference(inst); + customDefinitions[obj["customTagName"].GetValue()] = cd; + } + + if (obj.ContainsKey("attributes")) + { + JsonArray ary = obj["attributes"].AsArray(); + foreach (JsonObject? node in ary) + { + if (node == null) continue; + + if (node.ContainsKey("instanceKey")) + { + if (node.ContainsKey("value")) + { + InstanceKey att = InstanceKey.Parse(node["instanceKey"].GetValue()); + if (node["value"].GetValueKind() == System.Text.Json.JsonValueKind.String) + { + oms.SetAttributeValue(oms.GetInstance(inst), oms.GetInstance(att), node["value"].GetValue()); + } + } + if (cd != null && node.ContainsKey("customTagName")) + { + cd.Attributes[node["customTagName"].GetValue()] = new InstanceReference(InstanceKey.Parse(node["instanceKey"].GetValue())); + } + } + } + } + if (obj.ContainsKey("relationships")) + { + JsonArray ary = obj["relationships"].AsArray(); + foreach (JsonObject? node in ary) + { + if (node == null) continue; + + if (node.ContainsKey("relationshipInstanceKey")) + { + InstanceKey rel = InstanceKey.Parse(node["relationshipInstanceKey"].GetValue()); + if (cd != null && node.ContainsKey("customTagName")) + { + cd.Attributes[node["customTagName"].GetValue()] = new InstanceReference(InstanceKey.Parse(node["relationshipInstanceKey"].GetValue())); + } + if (node.ContainsKey("targetInstances")) + { + JsonArray ary1 = node["targetInstances"].AsArray(); + List irs = new List(); + foreach (JsonObject? node1 in ary1) + { + InstanceReference ir = ParseInstanceReference(node1); + if (ir != null) + { + irs.Add(oms.GetInstance(ir)); + } + } + + oms.AssignRelationship(oms.GetInstance(inst), oms.GetInstance(rel), irs); + } + } + } + } + } + } + else + { + if (customDefinitions.ContainsKey(tagName)) + { + CreateCustomDefinition(oms, obj, customDefinitions[tagName]); + } + else + { + UnresolvedCustomDefinitions.Add(obj); + } + } + } + } + } + + protected override void ResolveDependenciesInternal(Oms oms) + { + base.ResolveDependenciesInternal(oms); + + foreach (JsonObject obj in UnresolvedCustomDefinitions) + { + if (obj.ContainsKey("type")) + { + JsonNode? n = obj["type"]; + if (n != null) + { + string tagName = n.GetValue(); + if (customDefinitions.ContainsKey(tagName)) + { + CreateCustomDefinition(oms, obj, customDefinitions[tagName]); + } + } + } + } + } + + private void CreateCustomDefinition(Oms oms, JsonObject obj, CustomDefinition cd) + { + InstanceHandle inst = oms.CreateInstanceOf(oms.GetInstance(cd.ClassInstance)); + foreach (KeyValuePair kvp in cd.Attributes) + { + if (obj.ContainsKey(kvp.Key)) + { + JsonNode n1 = obj[kvp.Key]; + oms.SetAttributeValue(inst, oms.GetInstance(kvp.Value), n1.GetValue()); + } + } + } + + private InstanceReference? ParseInstanceReference(JsonObject? obj) + { + if (obj == null) + return null; + + InstanceKey instanceKey = InstanceKey.Empty; + Guid globalIdentifier = Guid.Empty; + + if (obj.ContainsKey("instanceKey")) + { + instanceKey = InstanceKey.Parse(obj["instanceKey"].GetValue()); + } + if (obj.ContainsKey("globalIdentifier")) + { + globalIdentifier = Guid.Parse(obj["globalIdentifier"].GetValue()); + } + return new InstanceReference(instanceKey, globalIdentifier); + } +} diff --git a/mocha-dotnet/src/lib/Mocha.Core/Storage/JsonOmsStorage.cs b/mocha-dotnet/src/lib/Mocha.Core/Storage/JsonOmsStorage.cs deleted file mode 100644 index aa8f52c..0000000 --- a/mocha-dotnet/src/lib/Mocha.Core/Storage/JsonOmsStorage.cs +++ /dev/null @@ -1,147 +0,0 @@ -// Copyright (C) 2025 Michael Becker -// -// This file is part of Mocha.NET. -// -// Mocha.NET 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 3 of the License, or -// (at your option) any later version. -// -// Mocha.NET 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 Mocha.NET. If not, see . - -using System.Text.Json; -using System.Text.Json.Nodes; -using Mocha.Core.Oop.Methods; - -namespace Mocha.Core.Storage; - -public class JsonOmsStorage : StreamOmsStorage -{ - public JsonOmsStorage(string path) : base(path) { } - public JsonOmsStorage(Stream stream) : base(stream) { } - - private JsonArray PrimaryArray { get; } = new JsonArray(); - - protected override void OpenInternal() - { - } - - protected override void CreateInstanceInternal(Oms oms, InstanceHandle source, InstanceHandle parentClass, DateTime effectiveDate) - { - Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source); - Guid classInstanceGuid = oms.GetGlobalIdentifier(parentClass); // calling oms.GetParentClass(source) here is unreliable - - JsonObject obj = new JsonObject(); - obj.Add("type", "createInstance"); - obj.Add("globalIdentifier", sourceInstanceGuid.ToString("B")); - obj.Add("parentClassGlobalIdentifier", classInstanceGuid.ToString("B")); - obj.Add("iid", oms.GetInstanceKey(source).ToString()); - obj.Add("edate", effectiveDate); - obj.Add("cdate", DateTime.Now); - - PrimaryArray.Add(obj); - } - - protected override void WriteAttributeValueInternal(Oms oms, InstanceHandle source, InstanceHandle attribute, object value, DateTime effectiveDate) - { - Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source); - Guid attributeInstanceGuid = oms.GetGlobalIdentifier(attribute); - - JsonObject obj = new JsonObject(); - obj.Add("type", "assignAttribute"); - obj.Add("src", sourceInstanceGuid.ToString("B")); - obj.Add("att", attributeInstanceGuid.ToString("B")); - obj.Add("value", JsonValue.Create(value)); - obj.Add("edate", effectiveDate); - obj.Add("cdate", DateTime.Now); - - PrimaryArray.Add(obj); - } - - protected override void WriteRelationshipInternal(Oms oms, InstanceHandle source, InstanceHandle relationship, IEnumerable targets, DateTime effectiveDate) - { - Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source); - Guid relationshipInstanceGuid = oms.GetGlobalIdentifier(relationship); - - JsonObject obj = new JsonObject(); - obj.Add("type", "assignRelationship"); - obj.Add("src", sourceInstanceGuid.ToString("B")); - obj.Add("rel", relationshipInstanceGuid.ToString("B")); - - JsonArray ary = new JsonArray(); - foreach (InstanceHandle target in targets) - { - ary.Add(oms.GetGlobalIdentifier(target).ToString("B")); - } - - obj.Add("tgts", ary); - obj.Add("edate", effectiveDate); - obj.Add("cdate", DateTime.Now); - PrimaryArray.Add(obj); - } - - protected override void ClearRelationshipInternal(Oms oms, InstanceHandle source, InstanceHandle relationship, DateTime effectiveDate) - { - Guid sourceInstanceGuid = oms.GetGlobalIdentifier(source); - Guid relationshipInstanceGuid = oms.GetGlobalIdentifier(relationship); - - JsonObject obj = new JsonObject(); - obj.Add("type", "clearRelationship"); - obj.Add("src", sourceInstanceGuid.ToString("B")); - obj.Add("rel", relationshipInstanceGuid.ToString("B")); - obj.Add("edate", effectiveDate); - obj.Add("cdate", DateTime.Now); - PrimaryArray.Add(obj); - } - - protected override void CloseInternal() - { - JsonObject obj = new JsonObject(); - obj.Add("blocks", PrimaryArray); - - StreamWriter sw = new StreamWriter(Stream); - sw.Write(obj.ToString()); - sw.Flush(); - - base.CloseInternal(); - } - - protected override void LoadInternal(Oms oms) - { - StreamReader sr = new StreamReader(Stream); - string text = sr.ReadToEnd(); - - JsonObject? obj = (JsonObject?)JsonNode.Parse(text); - if (obj != null) - { - if (obj.ContainsKey("blocks")) - { - foreach (JsonObject obj2 in obj["blocks"].AsArray()) - { - string type = obj2["type"].AsValue().ToString(); - if (type == "createInstance") - { - Guid globalIdentifier = Guid.Parse(obj2["globalIdentifier"].ToString()); - Guid parentClassGlobalIdentifier = Guid.Parse(obj2["parentClassGlobalIdentifier"].ToString()); - InstanceKey iid = InstanceKey.Parse(obj2["iid"].ToString()); - - InstanceHandle ih = oms.CreateInstanceOf(oms.GetInstance(parentClassGlobalIdentifier), globalIdentifier); - oms.SetInstanceKey(ih, iid); - } - else if (type == "assignAttribute") - { - - } - } - } - - } - - } -} \ No newline at end of file diff --git a/mocha-dotnet/src/lib/Mocha.Core/Storage/StreamOmsStorage.cs b/mocha-dotnet/src/lib/Mocha.Core/Storage/StreamOmsStorage.cs index 4bb6530..fdad811 100644 --- a/mocha-dotnet/src/lib/Mocha.Core/Storage/StreamOmsStorage.cs +++ b/mocha-dotnet/src/lib/Mocha.Core/Storage/StreamOmsStorage.cs @@ -22,8 +22,8 @@ public abstract class StreamOmsStorage : OmsStorage { public Stream Stream { get; } - public StreamOmsStorage(string path) : this(System.IO.File.Open(path, FileMode.Create, FileAccess.ReadWrite, FileShare.Read)) { } - public StreamOmsStorage(Stream stream) + public StreamOmsStorage(string path, bool readOnly) : this(System.IO.File.Open(path, FileMode.Create, FileAccess.ReadWrite, FileShare.Read), readOnly) { } + public StreamOmsStorage(Stream stream, bool readOnly) : base(readOnly) { Stream = stream; } diff --git a/mocha-dotnet/src/lib/Mocha.Testing/OmsTestsBase.cs b/mocha-dotnet/src/lib/Mocha.Testing/OmsTestsBase.cs index c1de852..caf1df6 100644 --- a/mocha-dotnet/src/lib/Mocha.Testing/OmsTestsBase.cs +++ b/mocha-dotnet/src/lib/Mocha.Testing/OmsTestsBase.cs @@ -56,26 +56,6 @@ public abstract class OmsTestsBase public void ReloadOms() { Oms = CreateOms(); - } - - protected readonly Guid TEST_CLASS_GUID = new Guid("{5821fc28-6411-4339-a7d2-56dc05591501}"); - protected readonly Guid TEST_CLASS2_GUID = new Guid("{6351ecb7-da5d-4029-ba3a-196a6dc980e9}"); - protected readonly Guid TEST_CLASS_INST_GUID = new Guid("{12b4bd54-dabd-4074-be50-ffd78115a85a}"); - protected readonly Guid TEST_ATTR_GUID = new Guid("{e4f314a4-f4b1-4cf1-95d8-7a927fb7c8a0}"); - protected readonly Guid TEST_ATTR_BOOL_GUID = new Guid("{b8dc887c-9964-4a66-94b1-6dcd00b196dc}"); - protected readonly Guid TEST_ATTR_NUM_GUID = new Guid("{62d633df-47ef-43b7-a108-b0b47f5212f6}"); - /// - /// Test Class.has Test Class 2 - /// - /// - protected readonly Guid TEST_REL_GUID = new Guid("{969d98bc-95e0-45a9-92e5-d70c62980c0e}"); - protected readonly Guid TEST_REL2_GUID = new Guid("{235f025a-90a6-43a6-9be1-0b32716eb95a}"); - protected readonly string TEST_ATTR_VALUE = "The quick brown fox jumps over the lazy dog."; - - [SetUp] - public void Setup() - { - ReloadOms(); // create the Test Class InstanceHandle c_Class = Oms.GetInstance(KnownInstanceGuids.Classes.Class); @@ -101,6 +81,26 @@ public abstract class OmsTestsBase Relationship? irTestRelationship = Oms.CreateRelationship(irTestClass, "has", irTestClass2, TEST_REL_GUID, true, "for", TEST_REL2_GUID); Assert.That(irTestRelationship, Is.Not.Null); + } + + protected readonly Guid TEST_CLASS_GUID = new Guid("{5821fc28-6411-4339-a7d2-56dc05591501}"); + protected readonly Guid TEST_CLASS2_GUID = new Guid("{6351ecb7-da5d-4029-ba3a-196a6dc980e9}"); + protected readonly Guid TEST_CLASS_INST_GUID = new Guid("{12b4bd54-dabd-4074-be50-ffd78115a85a}"); + protected readonly Guid TEST_ATTR_GUID = new Guid("{e4f314a4-f4b1-4cf1-95d8-7a927fb7c8a0}"); + protected readonly Guid TEST_ATTR_BOOL_GUID = new Guid("{b8dc887c-9964-4a66-94b1-6dcd00b196dc}"); + protected readonly Guid TEST_ATTR_NUM_GUID = new Guid("{62d633df-47ef-43b7-a108-b0b47f5212f6}"); + /// + /// Test Class.has Test Class 2 + /// + /// + protected readonly Guid TEST_REL_GUID = new Guid("{969d98bc-95e0-45a9-92e5-d70c62980c0e}"); + protected readonly Guid TEST_REL2_GUID = new Guid("{235f025a-90a6-43a6-9be1-0b32716eb95a}"); + protected readonly string TEST_ATTR_VALUE = "The quick brown fox jumps over the lazy dog."; + + [SetUp] + public void Setup() + { + ReloadOms(); AfterSetup(); } diff --git a/mocha-dotnet/tests/Mocha.Core.Tests/Storage/BinaryStorageTests.cs b/mocha-dotnet/tests/Mocha.Core.Tests/Storage/BinaryStorageTests.cs new file mode 100644 index 0000000..235fd26 --- /dev/null +++ b/mocha-dotnet/tests/Mocha.Core.Tests/Storage/BinaryStorageTests.cs @@ -0,0 +1,58 @@ +// Copyright (C) 2025 Michael Becker +// +// This file is part of Mocha.NET. +// +// Mocha.NET 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 3 of the License, or +// (at your option) any later version. +// +// Mocha.NET 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 Mocha.NET. If not, see . + +namespace Mocha.Core.Tests.Storage; + +using Mocha.Core; +using Mocha.Core.Storage; +using Mocha.Core.Storage.Binary; +using Mocha.Testing; + +public class BinaryStorageTests : OmsTestsBase +{ + [Test] + public void BinaryOmsStorage_MemoryStream_Test() + { + System.IO.MemoryStream ms = new MemoryStream(); + Oms.Storages.Add(new BinaryOmsStorage(ms)); + + string value = Oms.GetAttributeValue(Oms.GetInstance(KnownInstanceGuids.Classes.Class), Oms.GetInstance(KnownAttributeGuids.Text.TargetURL)); + Assert.That(value, Is.Null); + + Oms.SetAttributeValue(Oms.GetInstance(KnownInstanceGuids.Classes.Class), Oms.GetInstance(KnownAttributeGuids.Text.TargetURL), "mahek_spamss"); + + value = Oms.GetAttributeValue(Oms.GetInstance(KnownInstanceGuids.Classes.Class), Oms.GetInstance(KnownAttributeGuids.Text.TargetURL)); + Assert.That(value, Is.EqualTo("mahek_spamss")); + + Oms.Storages[0].Flush(); + ms.Flush(); + + byte[] data = ms.ToArray(); + ReloadOms(); + + value = Oms.GetAttributeValue(Oms.GetInstance(KnownInstanceGuids.Classes.Class), Oms.GetInstance(KnownAttributeGuids.Text.TargetURL)); + Assert.That(value, Is.Null); + + ms = new MemoryStream(data); + + Oms.Storages.Add(new BinaryOmsStorage(ms)); + Oms.ReloadStorages(); + + value = Oms.GetAttributeValue(Oms.GetInstance(KnownInstanceGuids.Classes.Class), Oms.GetInstance(KnownAttributeGuids.Text.TargetURL)); + Assert.That(value, Is.EqualTo("mahek_spamss")); + } +} \ No newline at end of file diff --git a/mocha-dotnet/tests/Mocha.Core.Tests/Storage/JsonStorageTests.cs b/mocha-dotnet/tests/Mocha.Core.Tests/Storage/JsonStorageTests.cs index 3b4f067..21cb4c4 100644 --- a/mocha-dotnet/tests/Mocha.Core.Tests/Storage/JsonStorageTests.cs +++ b/mocha-dotnet/tests/Mocha.Core.Tests/Storage/JsonStorageTests.cs @@ -16,6 +16,7 @@ // along with Mocha.NET. If not, see . using Mocha.Core.Storage; +using Mocha.Core.Storage.Json; using Mocha.Testing; namespace Mocha.Core.Tests.Storage; @@ -66,5 +67,16 @@ public class JsonStorageTests : OmsTestsBase // and see if we have the newly-created instance Oms.TryGetInstance(new Guid("1e9b7101-13dc-4d97-9ae4-570a07bd3545"), out test); Assert.That(test, Is.Not.EqualTo(InstanceHandle.Empty)); + + // and check that the attribute was set correctly + v = Oms.GetAttributeValue(test, Oms.GetInstance(KnownAttributeGuids.Text.Name)); + Assert.That(v, Is.EqualTo("PICADILLY")); + + // and check relationships were assigned properly + IEnumerable ihs = Oms.GetRelatedInstances(test, Oms.GetInstance(TEST_REL_GUID)); + + InstanceHandle ihC2 = Oms.GetInstance(TEST_CLASS2_GUID); + InstanceHandle ihI2 = Oms.GetInstancesOf(ihC2).First(); + Assert.That(ihs.First(), Is.EqualTo(ihI2)); } } \ No newline at end of file