Browse Source

Reducing duplicate code for importers.

Kenric Nugteren 1 year ago
parent
commit
3c697b7bd8

+ 15 - 1
InABox.Core/Imports/BaseImporter.cs

@@ -40,6 +40,7 @@ namespace InABox.Core
         public string[] Fields { get; protected set; }
 
         public List<ImportMapping> Mappings { get; private set; }
+
         public IEnumerable<string> Log => _log;
 
         public event ImportNotificationEvent OnNotify;
@@ -149,7 +150,20 @@ namespace InABox.Core
                 Dictionary<string, string> values;
                 try
                 {
-                    values = ReadLine();
+                    var lineValues = ReadLine();
+                    values = Mappings.ToDictionary(
+                        x => x.Property,
+                        x =>
+                        {
+                            if (!x.Field.IsNullOrWhiteSpace())
+                            {
+                                return lineValues.GetValueOrDefault(x.Field) ?? "";
+                            }
+                            else
+                            {
+                                return x.Constant;
+                            }
+                        });
                 }
                 catch(Exception e)
                 {

+ 5 - 13
InABox.Core/Imports/DelimitedImporter.cs

@@ -22,14 +22,12 @@ namespace InABox.Core
 
         public override void Close()
         {
-            if (_parser != null)
-                _parser.Dispose();
+            _parser?.Dispose();
             _parser = null;
         }
 
         public override bool ReadHeader()
         {
-            var result = true;
             for (var i = 1; i < HeaderRow; i++)
             {
                 if (_parser.EndOfData)
@@ -52,16 +50,10 @@ namespace InABox.Core
         {
             var results = new Dictionary<string, string>();
             var fields = _parser.ReadFields();
-            foreach (var mapping in Mappings)
-                if (!string.IsNullOrWhiteSpace(mapping.Field))
-                {
-                    var iIndex = Array.IndexOf(Fields, mapping.Field);
-                    results[mapping.Property] = fields[iIndex];
-                }
-                else
-                {
-                    results[mapping.Property] = mapping.Constant;
-                }
+            for(int i = 0; i < Fields.Length; ++i)
+            {
+                results[Fields[i]] = fields[i];
+            }
 
             return results;
         }

+ 4 - 10
InABox.Core/Imports/FixedWidthImporter.cs

@@ -88,16 +88,10 @@ namespace InABox.Core
                 iOffset += columnwidth;
             }
 
-            foreach (var mapping in Mappings)
-                if (!string.IsNullOrWhiteSpace(mapping.Field))
-                {
-                    var iIndex = Array.IndexOf(Fields, mapping.Field);
-                    results[mapping.Property] = fields[iIndex];
-                }
-                else if (!string.IsNullOrWhiteSpace(mapping.Constant))
-                {
-                    results[mapping.Property] = mapping.Constant;
-                }
+            for(int i = 0; i < Fields.Length; ++i)
+            {
+                results[Fields[i]] = fields[i];
+            }
 
             return results;
         }

+ 45 - 0
InABox.Core/Imports/IImporter.cs

@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using System.IO;
 
 namespace InABox.Core
@@ -20,12 +21,23 @@ namespace InABox.Core
     {
         string[] Properties { get; }
 
+        /// <summary>
+        /// Represents the fields in the header of the imported file, and therefore what fields <see cref="Mappings"/> can map from.
+        /// These should be populated by <see cref="ReadHeader"/>.
+        /// </summary>
         string[] Fields { get; }
 
         bool HasHeader { get; set; }
 
         int HeaderRow { get; set; }
 
+        /// <summary>
+        /// While <see cref="Fields"/> represents the fields that this importer recognises, <see cref="Mappings"/> represents how the properties of
+        /// the imported object are populated, so while there may be a one to one mapping from <see cref="Fields"/>, this does not have to be the case.
+        /// </summary>
+        /// <remarks>
+        /// These mappings must be initialised to get any data from <see cref="Import"/>.
+        /// </remarks>
         List<ImportMapping> Mappings { get; }
 
         IEnumerable<string> Log { get; }
@@ -42,12 +54,45 @@ namespace InABox.Core
 
         void Close();
 
+        /// <summary>
+        /// Import the data from the stream specified when <see cref="Open(Stream)"/> was called, using <see cref="OnSave"/> to for each line.
+        /// </summary>
+        /// <remarks>
+        /// This method <i>must</i> be called after <see cref="Open(Stream)"/> and <see cref="ReadHeader"/>.
+        /// 
+        /// One should also have set <see cref="OnSave"/> and <see cref="OnLoad"/>.
+        /// </remarks>
+        /// <returns>The number of items imported.</returns>
         int Import();
 
+        /// <summary>
+        /// Move to the next line in the import.
+        /// </summary>
+        /// <remarks>
+        /// While not all importers will need to do anything with this method, it <i>must</i> be called before <see cref="ReadLine"/>.
+        /// </remarks>
+        /// <returns><see langword="true"/> if there is still data to be read.</returns>
         bool MoveNext();
 
+        /// <summary>
+        /// Read the header of the file, populating <see cref="Fields"/>.
+        /// </summary>
+        /// <remarks>
+        /// This is called regardless of whether <see cref="HasHeader"/> is <see langword="true"/>.
+        /// </remarks>
+        /// <returns><see langword="true"/> if the header was read successfully.</returns>
         bool ReadHeader();
 
+        /// <summary>
+        /// Read the values of a line.
+        /// </summary>
+        /// <remarks>
+        /// The keys of the results are those present in <see cref="Fields"/>.
+        /// </remarks>
+        /// <returns>
+        /// A dictionary of values, where the keys are given by <see cref="Fields"/>.
+        /// </returns>
         Dictionary<string, string> ReadLine();
     }
+
 }

+ 36 - 3
InABox.Core/Imports/ImportFactory.cs

@@ -115,10 +115,43 @@ namespace InABox.Core
                 _definitions.Add(new ImportDefinition(type, description, filter));
         }
 
-        public static IImporter Create(ImportDefinition definition, Type type)
+        private static int[] ExtractColumnWidths(string widths)
         {
-            var importer = definition.Type.MakeGenericType(type);
-            var result = (Activator.CreateInstance(importer) as IImporter)!;
+            if (string.IsNullOrWhiteSpace(widths))
+                return new[] { 1024 };
+
+            try
+            {
+                return widths.Split(',').Select(int.Parse).ToArray();
+            }
+            catch
+            {
+                return new[] { 1024 };
+            }
+        }
+
+        public static IImporter Create(ImportDefinition definition, Type type, Importer importer)
+        {
+            var iimporter = definition.Type.MakeGenericType(type);
+            var result = (Activator.CreateInstance(iimporter) as IImporter)!;
+
+            if (result is IFixedWidthImporter fixedImporter)
+                fixedImporter.ColumnWidths = ExtractColumnWidths(importer.ColumnWidths);
+            if (result is ISettingsImporter settingsImporter)
+            {
+                if (!importer.Settings.IsNullOrWhiteSpace())
+                {
+                    var settings = Serialization.Deserialize(settingsImporter.SettingsType, importer.Settings);
+                    if (settings != null)
+                    {
+                        settingsImporter.SetSettings(settings);
+                    }
+                }
+            }
+
+            result.HasHeader = importer.HasHeader;
+            result.HeaderRow = Math.Max(1, importer.HeaderRows);
+
             return result;
         }
 

+ 1 - 16
inabox.wpf/DynamicGrid/DynamicImportForm.xaml.cs

@@ -96,23 +96,8 @@ namespace InABox.DynamicGrid
                 return;
             }
 
-            var importer = ImportFactory.Create(definition, _entitytype);
+            var importer = ImportFactory.Create(definition, _entitytype, _importer);
 
-            if (importer is IFixedWidthImporter)
-                ((IFixedWidthImporter)importer).ColumnWidths = ExtractColumnWidths();
-            if (importer is ISettingsImporter settingsImporter)
-            {
-                if (!_importer.Settings.IsNullOrWhiteSpace())
-                {
-                    var settings = Serialization.Deserialize(settingsImporter.SettingsType, _importer.Settings);
-                    if (settings is not null)
-                    {
-                        settingsImporter.SetSettings(settings);
-                    }
-                }
-            }
-
-            importer.HeaderRow = _importer.HeaderRows;
             try
             {
                 using (var stream = new FileStream(filename, FileMode.Open, FileAccess.Read))

+ 1 - 32
inabox.wpf/DynamicGrid/DynamicImportGrid.cs

@@ -91,21 +91,6 @@ namespace InABox.DynamicGrid
             return arg != null ? run : null;
         }
 
-        private static int[] ExtractColumnWidths(string widths)
-        {
-            if (string.IsNullOrWhiteSpace(widths))
-                return new[] { 1024 };
-
-            try
-            {
-                return widths.Split(',').Select(int.Parse).ToArray();
-            }
-            catch
-            {
-                return new[] { 1024 };
-            }
-        }
-
         public static bool CreateImporter(Importer importer,
             [NotNullWhen(true)]
             ref string? filename,
@@ -174,23 +159,7 @@ namespace InABox.DynamicGrid
                     filename = Path.ChangeExtension(Path.Combine(path, filename2), extension);
                 }
 
-                iimporter = ImportFactory.Create(definition, entityType);
-                if (iimporter is IFixedWidthImporter fixedImporter)
-                    fixedImporter.ColumnWidths = ExtractColumnWidths(importer.ColumnWidths);
-                if(iimporter is ISettingsImporter settingsImporter)
-                {
-                    if (!importer.Settings.IsNullOrWhiteSpace())
-                    {
-                        var settings = Serialization.Deserialize(settingsImporter.SettingsType, importer.Settings);
-                        if(settings is not null)
-                        {
-                            settingsImporter.SetSettings(settings);
-                        }
-                    }
-                }
-
-                iimporter.HasHeader = importer.HasHeader;
-                iimporter.HeaderRow = Math.Max(1, importer.HeaderRows);
+                iimporter = ImportFactory.Create(definition, entityType, importer);
 
                 iimporter.BeforeProcess += (sender, values) =>
                 {