diff --git a/Console/Microsoft.DataTransfer.ConsoleHost/App.config b/Console/Microsoft.DataTransfer.ConsoleHost/App.config index f21de86..f9f6d98 100644 --- a/Console/Microsoft.DataTransfer.ConsoleHost/App.config +++ b/Console/Microsoft.DataTransfer.ConsoleHost/App.config @@ -7,6 +7,7 @@ + diff --git a/Console/Microsoft.DataTransfer.ConsoleHost/Microsoft.DataTransfer.ConsoleHost.csproj b/Console/Microsoft.DataTransfer.ConsoleHost/Microsoft.DataTransfer.ConsoleHost.csproj index 4fffd37..575139c 100644 --- a/Console/Microsoft.DataTransfer.ConsoleHost/Microsoft.DataTransfer.ConsoleHost.csproj +++ b/Console/Microsoft.DataTransfer.ConsoleHost/Microsoft.DataTransfer.ConsoleHost.csproj @@ -119,6 +119,10 @@ {af2a444f-cabd-45be-9b9e-9d53501b2041} Microsoft.DataTransfer.DynamoDb + + {236801a6-4ef6-42c6-8e1a-4ef4f1896e07} + Microsoft.DataTransfer.FirebaseJsonFile + {ad24db36-8623-4e11-9995-a6eb5ef50a38} Microsoft.DataTransfer.HBase diff --git a/DataTransfer.sln b/DataTransfer.sln index ff274e0..b8124e3 100644 --- a/DataTransfer.sln +++ b/DataTransfer.sln @@ -150,6 +150,12 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.DataTransfer.Basi EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.DataTransfer.MongoDb.UnitTests", "MongoDb\Microsoft.DataTransfer.MongoDb.UnitTests\Microsoft.DataTransfer.MongoDb.UnitTests.csproj", "{2AC0E216-9ED4-4D1D-A264-73905A37F6AA}" EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "FirebaseJsonFile", "FirebaseJsonFile", "{9EC73EB5-D2EB-457A-97FB-BA5A14B1BA3A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.DataTransfer.FirebaseJsonFile", "FirebaseJsonFile\Microsoft.DataTransfer.FirebaseJsonFile\Microsoft.DataTransfer.FirebaseJsonFile.csproj", "{236801A6-4EF6-42C6-8E1A-4EF4F1896E07}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Microsoft.DataTransfer.FirebaseJsonFile.Wpf", "Microsoft.DataTransfer.FirebaseJsonFile.Wpf\Microsoft.DataTransfer.FirebaseJsonFile.Wpf.csproj", "{851310F7-E600-4F99-B9DF-0176A6E97016}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|x64 = Debug|x64 @@ -368,6 +374,14 @@ Global {A5013A12-18EA-40B6-83E0-4A59DC1B9E74}.Debug|x64.Build.0 = Debug|x64 {A5013A12-18EA-40B6-83E0-4A59DC1B9E74}.Release|x64.ActiveCfg = Release|x64 {A5013A12-18EA-40B6-83E0-4A59DC1B9E74}.Release|x64.Build.0 = Release|x64 + {236801A6-4EF6-42C6-8E1A-4EF4F1896E07}.Debug|x64.ActiveCfg = Debug|Any CPU + {236801A6-4EF6-42C6-8E1A-4EF4F1896E07}.Debug|x64.Build.0 = Debug|Any CPU + {236801A6-4EF6-42C6-8E1A-4EF4F1896E07}.Release|x64.ActiveCfg = Release|Any CPU + {236801A6-4EF6-42C6-8E1A-4EF4F1896E07}.Release|x64.Build.0 = Release|Any CPU + {851310F7-E600-4F99-B9DF-0176A6E97016}.Debug|x64.ActiveCfg = Debug|Any CPU + {851310F7-E600-4F99-B9DF-0176A6E97016}.Debug|x64.Build.0 = Debug|Any CPU + {851310F7-E600-4F99-B9DF-0176A6E97016}.Release|x64.ActiveCfg = Release|Any CPU + {851310F7-E600-4F99-B9DF-0176A6E97016}.Release|x64.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -423,6 +437,8 @@ Global {6544F78F-4EE3-489E-87B7-5FCA9C4D50BD} = {1BD0D669-8E45-4E7C-A20F-707A1887E8ED} {DA182D5C-79F4-4AF6-BF15-6E4496353A6A} = {F9CAC1F5-436E-4406-BACC-FC18C8FE36C5} {2AC0E216-9ED4-4D1D-A264-73905A37F6AA} = {7F83D352-1039-4B8F-B63C-56231421056A} + {236801A6-4EF6-42C6-8E1A-4EF4F1896E07} = {9EC73EB5-D2EB-457A-97FB-BA5A14B1BA3A} + {851310F7-E600-4F99-B9DF-0176A6E97016} = {9EC73EB5-D2EB-457A-97FB-BA5A14B1BA3A} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {D06EC8A2-02FC-48D4-BC6B-D86A26FED0CC} diff --git a/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/ConfigurationResources.Designer.cs b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/ConfigurationResources.Designer.cs new file mode 100644 index 0000000..4535003 --- /dev/null +++ b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/ConfigurationResources.Designer.cs @@ -0,0 +1,117 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.DataTransfer.FirebaseJsonFile { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + public class ConfigurationResources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal ConfigurationResources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.DataTransfer.FirebaseJsonFile.ConfigurationResources", typeof(ConfigurationResources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + public static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Optional. If source files should be decompressed with GZip. + /// + public static string Source_Decompress { + get { + return ResourceManager.GetString("Source_Decompress", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to One or more file search patterns to read JSON from. + /// + public static string Source_Files { + get { + return ResourceManager.GetString("Source_Files", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Optional. If specified, the Firebase ID will be stored in the given field name. + /// + public static string Source_IdField { + get { + return ResourceManager.GetString("Source_IdField", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Optional. The node path to get items from. + /// + public static string Source_Node { + get { + return ResourceManager.GetString("Source_Node", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Optional. If specified, the item's parent node path will be stored in the given field name. + /// + public static string Source_NodeField { + get { + return ResourceManager.GetString("Source_NodeField", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to If true, prefixes item IDs with their parent's node name. + /// + public static string Source_PrefixIdWithNode { + get { + return ResourceManager.GetString("Source_PrefixIdWithNode", resourceCulture); + } + } + } +} diff --git a/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/ConfigurationResources.resx b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/ConfigurationResources.resx new file mode 100644 index 0000000..26a228e --- /dev/null +++ b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/ConfigurationResources.resx @@ -0,0 +1,138 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + Optional. If source files should be decompressed with GZip + + + One or more file search patterns to read JSON from + + + Optional. If specified, the Firebase ID will be stored in the given field name + + + Optional. The node path to get items from + + + Optional. If specified, the item's parent node path will be stored in the given field name + + + If true, prefixes item IDs with their parent's node name + + \ No newline at end of file diff --git a/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile.csproj b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile.csproj new file mode 100644 index 0000000..64d62a5 --- /dev/null +++ b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile.csproj @@ -0,0 +1,101 @@ + + + + + Debug + AnyCPU + {236801A6-4EF6-42C6-8E1A-4EF4F1896E07} + Library + Properties + Microsoft.DataTransfer.FirebaseJsonFile + Microsoft.DataTransfer.FirebaseJsonFile + v4.5.1 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\packages\Newtonsoft.Json.10.0.2\lib\net45\Newtonsoft.Json.dll + + + + + + + + + + + + + + Properties\CommonAssemblyInfo.cs + + + True + True + ConfigurationResources.resx + + + True + True + Resources.resx + + + + + + + + + + + + PublicResXFileCodeGenerator + ConfigurationResources.Designer.cs + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + + {83329196-46BE-4CD0-B498-74E9AC463ED9} + Microsoft.DataTransfer.Extensibility.Basics + + + {ACC3B08A-2706-4857-B374-8F6311DB0E6F} + Microsoft.DataTransfer.Extensibility + + + {da182d5c-79f4-4af6-bf15-6e4496353a6a} + Microsoft.DataTransfer.Basics.Files + + + {ccd5f3bd-e95e-46b6-8688-394f592c6a2a} + Microsoft.DataTransfer.Basics + + + {f00c15ab-fdcb-4e18-9009-e733f74cce38} + Microsoft.DataTransfer.JsonNet + + + + \ No newline at end of file diff --git a/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Properties/AssemblyInfo.cs b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0b0dccf --- /dev/null +++ b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Properties/AssemblyInfo.cs @@ -0,0 +1,13 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Microsoft.DataTransfer.FirebaseJsonFile")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyProduct("Microsoft.DataTransfer.FirebaseJsonFile")] +[assembly: AssemblyCulture("")] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("236801a6-4ef6-42c6-8e1a-4ef4f1896e07")] diff --git a/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Resources.Designer.cs b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Resources.Designer.cs new file mode 100644 index 0000000..b06446a --- /dev/null +++ b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Resources.Designer.cs @@ -0,0 +1,81 @@ +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// Runtime Version:4.0.30319.42000 +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace Microsoft.DataTransfer.FirebaseJsonFile { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "15.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.DataTransfer.FirebaseJsonFile.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to {0} ({1}, {2}). + /// + internal static string DataItemIdFormat { + get { + return ResourceManager.GetString("DataItemIdFormat", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Reads data from Firebase JSON files. + /// + internal static string SourceDescription { + get { + return ResourceManager.GetString("SourceDescription", resourceCulture); + } + } + } +} diff --git a/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Resources.resx b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Resources.resx new file mode 100644 index 0000000..396b54a --- /dev/null +++ b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Resources.resx @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + {0} ({1}, {2}) + + + Reads data from Firebase JSON files + + \ No newline at end of file diff --git a/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Source/FirebaseJsonFileSourceAdapterFactory.cs b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Source/FirebaseJsonFileSourceAdapterFactory.cs new file mode 100644 index 0000000..12eb82b --- /dev/null +++ b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Source/FirebaseJsonFileSourceAdapterFactory.cs @@ -0,0 +1,61 @@ +using Microsoft.DataTransfer.Basics; +using Microsoft.DataTransfer.Basics.Files.Source; +using Microsoft.DataTransfer.Extensibility; +using Microsoft.DataTransfer.Extensibility.Basics; +using Microsoft.DataTransfer.Extensibility.Basics.Source; +using Microsoft.DataTransfer.JsonNet.Serialization; +using Newtonsoft.Json; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; + +namespace Microsoft.DataTransfer.FirebaseJsonFile.Source +{ + public sealed class FirebaseJsonFileSourceAdapterFactory : DataAdapterFactoryBase, IDataSourceAdapterFactory + { + private readonly JsonSerializer serializer = CreateJsonSerializer(); + + /// + /// Gets the description of the data adapter. + /// + public string Description => Resources.SourceDescription; + + /// + /// Creates a new instance of with the provided configuration. + /// + /// Data source adapter configuration. + /// Data transfer operation context. + /// Cancellation token. + /// Task that represents asynchronous create operation. + public Task CreateAsync(IFirebaseJsonFileSourceAdapterConfiguration configuration, IDataTransferContext context, CancellationToken cancellation) + { + return Task.Factory.StartNew(() => Create(configuration), cancellation); + } + + private IDataSourceAdapter Create(IFirebaseJsonFileSourceAdapterConfiguration configuration) + { + Guard.NotNull("configuration", configuration); + + return new AggregateDataSourceAdapter( + configuration.Files + .SelectMany(f => SourceStreamProvidersFactory + .Create(f, configuration.Decompress) + .Select(p => new FirebaseJsonFileSourceAdapter(p, + configuration.Node, + configuration.IdField, + configuration.NodeField, + configuration.PrefixIdWithNode, + serializer)))); + } + + private static JsonSerializer CreateJsonSerializer() => + JsonSerializer.CreateDefault(new JsonSerializerSettings + { + Converters = + { + DataItemJsonConverter.Instance, + GeoJsonConverter.Instance + } + }); + } +} diff --git a/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Source/FirebaseJsonSourceAdapter.cs b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Source/FirebaseJsonSourceAdapter.cs new file mode 100644 index 0000000..2880098 --- /dev/null +++ b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Source/FirebaseJsonSourceAdapter.cs @@ -0,0 +1,122 @@ +using System; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Threading; +using System.Threading.Tasks; +using Microsoft.DataTransfer.Basics; +using Microsoft.DataTransfer.Basics.Files.Source; +using Microsoft.DataTransfer.Extensibility; +using Microsoft.DataTransfer.JsonNet.Serialization; +using Newtonsoft.Json; + +namespace Microsoft.DataTransfer.FirebaseJsonFile.Source +{ + sealed class FirebaseJsonFileSourceAdapter: IDataSourceAdapter + { + private readonly ISourceStreamProvider sourceStreamProvider; + private readonly string node; + private readonly string nodeField; + private readonly string idField; + private readonly string collectionField; + private readonly bool prefixIdWithNode; + private readonly JsonSerializer serializer; + + private StreamReader streamReader; + private JsonTextReader jsonReader; + + public FirebaseJsonFileSourceAdapter(ISourceStreamProvider sourceStreamProvider, string node, string idField, string nodeField, bool prefixIdWithNode, JsonSerializer serializer) + { + Guard.NotNull("sourceStreamProvider", sourceStreamProvider); + Guard.NotNull("serializer", serializer); + + this.sourceStreamProvider = sourceStreamProvider; + this.node = node; + this.nodeField = nodeField; + this.idField = idField; + this.serializer = serializer; + this.prefixIdWithNode = prefixIdWithNode; + } + + public async Task ReadNextAsync(ReadOutputByRef readOutput, CancellationToken cancellation) + { + try + { + // Create the JSON text reader if necessary + if (streamReader == null) + { + streamReader = new StreamReader(await sourceStreamProvider.CreateStream(cancellation)); + jsonReader = new JsonTextReader(streamReader) { SupportMultipleContent = true }; + } + + // Read until a DataItem + while (await jsonReader.ReadAsync() && !ReaderAtNextItem(jsonReader)) ; + + if (jsonReader.TokenType != JsonToken.PropertyName) + return null; + + // Firebase item's IDs are stored as property names and the + // items themselves are stored as property values + var id = prefixIdWithNode ? + $"{node}-{jsonReader.Value.ToString()}" : + jsonReader.Value.ToString(); + await jsonReader.ReadAsync(); + var dataItem = serializer.Deserialize(jsonReader) as JObjectDataItem; + + // If the user requested ID or Node name to be stored as + // fields (for use by the DT target), add/update those values + if (!string.IsNullOrEmpty(idField)) + { + dataItem.SetValue(idField, id); + } + if (!string.IsNullOrEmpty(nodeField)) + { + dataItem.SetValue(nodeField, node); + } + + return dataItem; + } + finally + { + int lineNumber = 0, linePosition = 0; + if (jsonReader != null) + { + lineNumber = jsonReader.LineNumber; + linePosition = jsonReader.LinePosition; + } + + readOutput.DataItemId = String.Format(CultureInfo.InvariantCulture, + Resources.DataItemIdFormat, sourceStreamProvider.Id, lineNumber, linePosition); + } + } + + private bool ReaderAtNextItem(JsonTextReader jsonReader) + { + // Firebase items begin with property names + // They are stored as properties with the ID as the + // property name and the item as the property value + if (jsonReader.TokenType != JsonToken.PropertyName) + { + return false; + } + + // If reading items from a particular top-level node, make sure + // that the path begins with that node and that the reader is + // deep enough to read the top-level node's children + if (!string.IsNullOrEmpty(node) && (jsonReader.Depth < 2 || !jsonReader.Path.StartsWith(node, StringComparison.OrdinalIgnoreCase))) + { + return false; + } + + return true; + } + + [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Usage", "CA2213:DisposableFieldsShouldBeDisposed", MessageId = "jsonReader", + Justification = "Disposed through TrashCan helper")] + public void Dispose() + { + TrashCan.Throw(ref jsonReader, r => r.Close()); + TrashCan.Throw(ref streamReader, f => f.Close()); + } + } +} diff --git a/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Source/IFirebaseJsonFileSourceAdapterConfiguration.cs b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Source/IFirebaseJsonFileSourceAdapterConfiguration.cs new file mode 100644 index 0000000..57a79ba --- /dev/null +++ b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/Source/IFirebaseJsonFileSourceAdapterConfiguration.cs @@ -0,0 +1,47 @@ +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; + +namespace Microsoft.DataTransfer.FirebaseJsonFile.Source +{ + /// + /// Contains configuration for Firebase JSON files data source adapter. + /// + public interface IFirebaseJsonFileSourceAdapterConfiguration + { + /// + /// Gets the list of file names to read JSON data from. + /// + [Display(ResourceType = typeof(ConfigurationResources), Description = "Source_Files")] + IEnumerable Files { get; } + + /// + /// Gets the value that indicates whether input files should be decompressed. + /// + [Display(ResourceType = typeof(ConfigurationResources), Description = "Source_Decompress")] + bool Decompress { get; } + + /// + /// Gets an optional value indicating the node path to import from the source files + /// + [Display(ResourceType = typeof(ConfigurationResources), Description = "Source_Node")] + string Node { get; } + + /// + /// Gets the field name to be used for storing the Firebase ID + /// + [Display(ResourceType = typeof(ConfigurationResources), Description = "Source_IdField")] + string IdField { get; } + + /// + /// Gets an optional field name used to store the name of this item's parent node + /// + [Display(ResourceType = typeof(ConfigurationResources), Description = "Source_NodeField")] + string NodeField { get; } + + /// + /// Indicates whether IDs should include the parent node name as a prefix + /// + [Display(ResourceType = typeof(ConfigurationResources), Description = "Source_PrefixIdWithNode")] + bool PrefixIdWithNode { get; } + } +} diff --git a/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/packages.config b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/packages.config new file mode 100644 index 0000000..8a2091a --- /dev/null +++ b/FirebaseJsonFile/Microsoft.DataTransfer.FirebaseJsonFile/packages.config @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Microsoft.DataTransfer.FirebaseJsonFile.Wpf.csproj b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Microsoft.DataTransfer.FirebaseJsonFile.Wpf.csproj new file mode 100644 index 0000000..ec4718a --- /dev/null +++ b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Microsoft.DataTransfer.FirebaseJsonFile.Wpf.csproj @@ -0,0 +1,98 @@ + + + + + Debug + AnyCPU + {851310F7-E600-4F99-B9DF-0176A6E97016} + Library + Properties + Microsoft.DataTransfer.FirebaseJsonFile.Wpf + Microsoft.DataTransfer.FirebaseJsonFile.Wpf + v4.5.1 + 512 + + + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + + + + + + + + + + + + + + + Properties\CommonAssemblyInfo.cs + + + + + FirebaseJsonFileSourceAdapterConfigurationPage.xaml + + + + FirebaseJsonFileSourceAdapterConfigurationSummaryPage.xaml + + + + + + {236801a6-4ef6-42c6-8e1a-4ef4f1896e07} + Microsoft.DataTransfer.FirebaseJsonFile + + + {ccd5f3bd-e95e-46b6-8688-394f592c6a2a} + Microsoft.DataTransfer.Basics + + + {da8ec2b9-b282-4438-98b2-612d6dfedf73} + Microsoft.DataTransfer.WpfHost.Basics + + + {1f2070f3-bd45-45b3-a143-7ce4073d3a69} + Microsoft.DataTransfer.WpfHost.Extensibility.Basics + + + {a020fbd4-0f13-4630-acb9-6cdb894e3b82} + Microsoft.DataTransfer.WpfHost.Extensibility + + + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + Designer + MSBuild:Compile + + + + \ No newline at end of file diff --git a/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Properties/AssemblyInfo.cs b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..0f66eb3 --- /dev/null +++ b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Properties/AssemblyInfo.cs @@ -0,0 +1,9 @@ +using System.Reflection; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Microsoft.DataTransfer.FirebaseJsonFile.Wpf")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyProduct("Microsoft.DataTransfer.FirebaseJsonFile.Wpf")] +[assembly: AssemblyCulture("")] diff --git a/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfiguration.cs b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfiguration.cs new file mode 100644 index 0000000..f5fec27 --- /dev/null +++ b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfiguration.cs @@ -0,0 +1,89 @@ +using Microsoft.DataTransfer.Basics.Extensions; +using Microsoft.DataTransfer.FirebaseJsonFile.Source; +using Microsoft.DataTransfer.WpfHost.Basics; +using System.Collections.Generic; +using System.Collections.ObjectModel; +using System.Collections.Specialized; + +namespace Microsoft.DataTransfer.FirebaseJsonFile.Wpf.Source +{ + class FirebaseJsonFileSourceAdapterConfiguration : ValidatableBindableBase, IFirebaseJsonFileSourceAdapterConfiguration + { + private static readonly string EditableFilesPropertyName = + ObjectExtensions.MemberName(c => c.EditableFiles); + + public static readonly string FilesPropertyName = + ObjectExtensions.MemberName(c => c.Files); + + public static readonly string DecompressPropertyName = + ObjectExtensions.MemberName(c => c.Decompress); + + public static readonly string NodePropertyName = + ObjectExtensions.MemberName(c => c.Node); + + public static readonly string NodeFieldPropertyName = + ObjectExtensions.MemberName(c => c.NodeField); + + public static readonly string IdFieldPropertyName = + ObjectExtensions.MemberName(c => c.IdField); + + public static readonly string PrefixIdWithNodePropertyName = + ObjectExtensions.MemberName(c => c.PrefixIdWithNode); + + private ObservableCollection files; + private bool decompress; + private string node; + private string nodeField; + private string idField; + private bool prefixIdWithNode; + + public IEnumerable Files => files; + + public ObservableCollection EditableFiles + { + get { return files; } + private set { SetProperty(ref files, value, ValidateNonEmptyCollection); } + } + + public bool Decompress + { + get => decompress; + set { SetProperty(ref decompress, value); } + } + + public string Node + { + get => node; + set { SetProperty(ref node, value); } + } + + public string NodeField + { + get => nodeField; + set { SetProperty(ref nodeField, value); } + } + + public string IdField + { + get => idField; + set { SetProperty(ref idField, value); } + } + + public bool PrefixIdWithNode + { + get => prefixIdWithNode; + set { SetProperty(ref prefixIdWithNode, value); } + } + + public FirebaseJsonFileSourceAdapterConfiguration() + { + EditableFiles = new ObservableCollection(); + EditableFiles.CollectionChanged += OnFilesCollectionChanged; + } + + private void OnFilesCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + { + SetErrors(EditableFilesPropertyName, ValidateNonEmptyCollection(files)); + } + } +} diff --git a/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfigurationPage.xaml b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfigurationPage.xaml new file mode 100644 index 0000000..e720176 --- /dev/null +++ b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfigurationPage.xaml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfigurationPage.xaml.cs b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfigurationPage.xaml.cs new file mode 100644 index 0000000..0bd5ed7 --- /dev/null +++ b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfigurationPage.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Microsoft.DataTransfer.FirebaseJsonFile.Wpf.Source +{ + /// + /// Interaction logic for FirebaseJsonFileSourceAdapterConfigurationPage.xaml + /// + public partial class FirebaseJsonFileSourceAdapterConfigurationPage : UserControl + { + public FirebaseJsonFileSourceAdapterConfigurationPage() + { + InitializeComponent(); + } + } +} diff --git a/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfigurationProvider.cs b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfigurationProvider.cs new file mode 100644 index 0000000..d95dafa --- /dev/null +++ b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfigurationProvider.cs @@ -0,0 +1,16 @@ +using Microsoft.DataTransfer.WpfHost.Extensibility.Basics; + +namespace Microsoft.DataTransfer.FirebaseJsonFile.Wpf.Source +{ + /// + /// Provides configuration for Firebase JSON files data source. + /// + class FirebaseJsonFileSourceAdapterConfigurationProvider : DataAdapterConfigurationProviderWrapper + { + /// + /// Creates a new instance of . + /// + public FirebaseJsonFileSourceAdapterConfigurationProvider() + : base(new FirebaseJsonFileSourceAdapterInternalConfigurationProvider()) { } + } +} diff --git a/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfigurationSummaryPage.xaml b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfigurationSummaryPage.xaml new file mode 100644 index 0000000..337495d --- /dev/null +++ b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfigurationSummaryPage.xaml @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfigurationSummaryPage.xaml.cs b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfigurationSummaryPage.xaml.cs new file mode 100644 index 0000000..d809446 --- /dev/null +++ b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterConfigurationSummaryPage.xaml.cs @@ -0,0 +1,28 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Data; +using System.Windows.Documents; +using System.Windows.Input; +using System.Windows.Media; +using System.Windows.Media.Imaging; +using System.Windows.Navigation; +using System.Windows.Shapes; + +namespace Microsoft.DataTransfer.FirebaseJsonFile.Wpf.Source +{ + /// + /// Interaction logic for FirebaseJsonFileSourceAdapterConfigurationSummaryPage.xaml + /// + public partial class FirebaseJsonFileSourceAdapterConfigurationSummaryPage : UserControl + { + public FirebaseJsonFileSourceAdapterConfigurationSummaryPage() + { + InitializeComponent(); + } + } +} diff --git a/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterInternalConfigurationProvider.cs b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterInternalConfigurationProvider.cs new file mode 100644 index 0000000..8019241 --- /dev/null +++ b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/Source/FirebaseJsonFileSourceAdapterInternalConfigurationProvider.cs @@ -0,0 +1,49 @@ +using Microsoft.DataTransfer.Basics; +using Microsoft.DataTransfer.WpfHost.Extensibility.Basics; +using System; +using System.Collections.Generic; +using System.Windows.Controls; + +namespace Microsoft.DataTransfer.FirebaseJsonFile.Wpf.Source +{ + class FirebaseJsonFileSourceAdapterInternalConfigurationProvider : DataAdapterValidatableConfigurationProviderBase + { + protected override UserControl CreatePresenter(FirebaseJsonFileSourceAdapterConfiguration configuration) + { + return new FirebaseJsonFileSourceAdapterConfigurationPage { DataContext = configuration }; + } + + protected override UserControl CreateSummaryPresenter(FirebaseJsonFileSourceAdapterConfiguration configuration) + { + return new FirebaseJsonFileSourceAdapterConfigurationSummaryPage { DataContext = configuration }; + } + + protected override FirebaseJsonFileSourceAdapterConfiguration CreateValidatableConfiguration() + { + return new FirebaseJsonFileSourceAdapterConfiguration(); + } + + protected override void PopulateCommandLineArguments(FirebaseJsonFileSourceAdapterConfiguration configuration, IDictionary arguments) + { + Guard.NotNull("configuration", configuration); + Guard.NotNull("arguments", arguments); + + arguments.Add(FirebaseJsonFileSourceAdapterConfiguration.FilesPropertyName, AsCollectionArgument(configuration.Files)); + + if (configuration.Decompress) + arguments.Add(FirebaseJsonFileSourceAdapterConfiguration.DecompressPropertyName, null); + + if (!string.IsNullOrEmpty(configuration.Node)) + arguments.Add(FirebaseJsonFileSourceAdapterConfiguration.NodePropertyName, configuration.Node); + + if (!string.IsNullOrEmpty(configuration.NodeField)) + arguments.Add(FirebaseJsonFileSourceAdapterConfiguration.NodeFieldPropertyName, configuration.NodeField); + + if (!string.IsNullOrEmpty(configuration.IdField)) + arguments.Add(FirebaseJsonFileSourceAdapterConfiguration.IdFieldPropertyName, configuration.IdField); + + if (configuration.PrefixIdWithNode) + arguments.Add(FirebaseJsonFileSourceAdapterConfiguration.PrefixIdWithNodePropertyName, null); + } + } +} diff --git a/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/XamlResources.xaml b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/XamlResources.xaml new file mode 100644 index 0000000..e090aad --- /dev/null +++ b/Microsoft.DataTransfer.FirebaseJsonFile.Wpf/XamlResources.xaml @@ -0,0 +1,34 @@ + + + + + + + + Decompress data + Data from the source files will be decompressed with GZip + Decompress data: + + ID Field + Field to store item ID + ID Field: + + Node Field + Optional field to store item's parent node path + Node Field: + + Node + Optionally specify the top-level node to read items from + Node: + + Files: + JSON Documents|*.json|GZip Files|*.gz|All Files|*.* + *.json + + Prefix ID with Node + If true, prefix item IDs with node name + Prefix ID with Node: + + \ No newline at end of file diff --git a/Shared/Microsoft.DataTransfer.JsonNet/Serialization/JObjectDataItem.cs b/Shared/Microsoft.DataTransfer.JsonNet/Serialization/JObjectDataItem.cs index 7a46929..5ea20f2 100644 --- a/Shared/Microsoft.DataTransfer.JsonNet/Serialization/JObjectDataItem.cs +++ b/Shared/Microsoft.DataTransfer.JsonNet/Serialization/JObjectDataItem.cs @@ -49,6 +49,17 @@ public object GetValue(string fieldName) return GetValue(token); } + /// + /// Sets the value of a specified field. + /// + /// Name of the field. + /// Value of the field. + public void SetValue(string fieldName, string fieldValue) + { + Guard.NotNull("fieldName", fieldName); + data[fieldName] = fieldValue; + } + private object GetValue(JToken token) { if (token is JObject) diff --git a/Wpf/Microsoft.DataTransfer.WpfHost/App.config b/Wpf/Microsoft.DataTransfer.WpfHost/App.config index ec8863a..2351a54 100644 --- a/Wpf/Microsoft.DataTransfer.WpfHost/App.config +++ b/Wpf/Microsoft.DataTransfer.WpfHost/App.config @@ -7,6 +7,8 @@ + + @@ -39,6 +41,7 @@ + diff --git a/Wpf/Microsoft.DataTransfer.WpfHost/Microsoft.DataTransfer.WpfHost.csproj b/Wpf/Microsoft.DataTransfer.WpfHost/Microsoft.DataTransfer.WpfHost.csproj index 32e17d0..bcacb62 100644 --- a/Wpf/Microsoft.DataTransfer.WpfHost/Microsoft.DataTransfer.WpfHost.csproj +++ b/Wpf/Microsoft.DataTransfer.WpfHost/Microsoft.DataTransfer.WpfHost.csproj @@ -295,6 +295,10 @@ {af2a444f-cabd-45be-9b9e-9d53501b2041} Microsoft.DataTransfer.DynamoDb + + {236801a6-4ef6-42c6-8e1a-4ef4f1896e07} + Microsoft.DataTransfer.FirebaseJsonFile + {98706c69-8f15-4d97-9dd9-d7fd6f5a038f} Microsoft.DataTransfer.HBase.Wpf @@ -311,6 +315,10 @@ {792b2799-af90-4f15-b042-7f47f4fa1c78} Microsoft.DataTransfer.JsonFile + + {851310f7-e600-4f99-b9df-0176a6e97016} + Microsoft.DataTransfer.FirebaseJsonFile.Wpf + {72422fe7-eefd-4f80-9515-80bb362352d3} Microsoft.DataTransfer.MongoDb.Wpf